<commit_before>const {
  describe, it, beforeEach, afterEach,
} = require('mocha');
const sinon = require('sinon');
const assert = require('assert');
const logger = require('../../lib/util/logger');
const pkg = require('../../package.json');

describe('logger', () => {
  let sandbox;
  const testMessage = 'test message';
  const infoLogLevel = 'INFO';
  const warnLogLevel = 'WARN';
  const errorLogLevel = 'ERR';

  beforeEach(() => {
    sandbox = sinon.sandbox.create();
  });

  afterEach(() => {
    sandbox.restore();
  });

  describe('#info()', () => {
    it('should log an info message with package name and log level', () => {
      const consoleInfoSpy = sinon.stub(console, 'info');

      logger.info(testMessage);

      assert.ok(consoleInfoSpy.calledOnce, 'console.info() was not called once');
      [pkg.name, infoLogLevel, testMessage]
        .forEach(m => assert.ok(consoleInfoSpy.args[0][0].indexOf(m) !== -1, `'${m}' was expected to be logged`));
    });
  });

  describe('#warn()', () => {
    it('should log a warning with package name and log level', () => {
      const consoleWarnSpy = sinon.stub(console, 'warn');

      logger.warn(testMessage);

      assert.ok(consoleWarnSpy.calledOnce, 'console.warn() was not called once');
      [pkg.name, warnLogLevel, testMessage]
        .forEach(m => assert.ok(consoleWarnSpy.args[0][0].indexOf(m) !== -1, `'${m}' was expected to be logged`));
    });
  });

  describe('#error()', () => {
    it('should log an error with package name and log level', () => {
      const consoleErrorSpy = sinon.stub(console, 'error');

      logger.error(testMessage);

      assert.ok(consoleErrorSpy.calledOnce, 'console.error() was not called once');
      [pkg.name, errorLogLevel, testMessage]
        .forEach(m => assert.ok(consoleErrorSpy.args[0][0].indexOf(m) !== -1, `'${m}' was expected to be logged`));
    });
  });
});
<commit_msg>refactor(logger): remove duplicate code from logger tests<commit_after>const {
  describe, it, beforeEach, afterEach,
} = require('mocha');
const sinon = require('sinon');
const assert = require('assert');
const logger = require('../../lib/util/logger');
const pkg = require('../../package.json');

describe('logger', () => {
  let sandbox;
  const testMessage = 'test message';
  const infoLogLevel = 'INFO';
  const warnLogLevel = 'WARN';
  const errorLogLevel = 'ERR';

  beforeEach(() => {
    sandbox = sinon.sandbox.create();
  });

  afterEach(() => {
    sandbox.restore();
  });

  function loggerTestHelper(methodName, logLevel) {
    const consoleMethodSpy = sandbox.stub(console, methodName);

    logger[methodName](testMessage);

    assert.ok(consoleMethodSpy.calledOnce, `console.${methodName}() was not called once`);
    [pkg.name, logLevel, testMessage]
      .forEach(m => assert.ok(consoleMethodSpy.args[0][0].indexOf(m) !== -1, `'${m}' was expected to be logged`));
  }

  describe('#info()', () => {
    it('should log an info message with package name and log level', () => {
      loggerTestHelper('info', infoLogLevel);
    });
  });

  describe('#warn()', () => {
    it('should log a warning with package name and log level', () => {
      loggerTestHelper('warn', warnLogLevel);
    });
  });

  describe('#error()', () => {
    it('should log an error with package name and log level', () => {
      loggerTestHelper('error', errorLogLevel);
    });
  });
});
<|endoftext|>


<commit_before>require('list-view/list_item_view_mixin');

var get = Ember.get, set = Ember.set;

Ember.ReusableListItemView = Ember.View.extend(Ember.ListItemViewMixin, {
  init: function(){
    this._super();
    this.set('context', Ember.ObjectProxy.create());
  },
  isVisible: Ember.computed('context.content', function(){
    return !!this.get('context.content');
  }),
  updateContext: function(newContext){
    var context = get(this, 'context.content');
    if (context !== newContext) {
      if (this.state === 'inDOM') {
        this.prepareForReuse(newContext);
      }

      set(this, 'context.content', newContext);

      if (newContext && newContext.isController) {
        set(this, 'controller', newContext);
      }
    }
  },
  prepareForReuse: Ember.K
});
<commit_msg>reduce extra gets/sets<commit_after>require('list-view/list_item_view_mixin');

var get = Ember.get, set = Ember.set;

Ember.ReusableListItemView = Ember.View.extend(Ember.ListItemViewMixin, {
  init: function(){
    this._super();
    var context = Ember.ObjectProxy.create();
    this.set('context', context);
    this._proxyContext = context;
  },
  isVisible: Ember.computed('context.content', function(){
    return !!this.get('context.content');
  }),
  updateContext: function(newContext){
    var context = get(this._proxyContext, 'content');
    if (context !== newContext) {
      if (this.state === 'inDOM') {
        this.prepareForReuse(newContext);
      }

      set(this._proxyContext, 'content', newContext);

      if (newContext && newContext.isController) {
        set(this, 'controller', newContext);
      }
    }
  },
  prepareForReuse: Ember.K
});
<|endoftext|>


<commit_before>import { isValidElement, Children } from 'react'
import _ from 'lodash'

/**
 * Resolves all plugins provided by the configuration
 * @param {Object} pluginInterface - interface containing all configurations to resolve
 */
export function resolvePlugins(pluginInterface) {
  let { styles, config } = pluginInterface

  // Triggers plugin resolving
  // Uses the exact plugin lineup defined within Config
  config.plugins.forEach(plugin => {
    // If the plugin is a function it gets called when there are dynamic styles to resolve
    if (plugin instanceof Function) {
      if (pluginInterface.dynamicStylesNotNull) {
        styles = plugin({
          ...pluginInterface,
          styles
        })
      }
    } else {
      // The plugin could also be an object containing `mode` and `plugin`
      // Force mode calls the plugin every time when this function is called
      if (plugin.mode === 'force') {
        styles = plugin.plugin({
          ...pluginInterface,
          styles
        })
        return
      }
      // Default/fallback mode: Same as if the plugin would be a function
      if (pluginInterface.dynamicStylesNotNull) {
        styles = plugin.plugin({
          ...pluginInterface,
          styles
        })
      }
    }
  })

  return styles
}

/**
 * Checks if a given element is a look-enhanced Component itself
 * @param {Object} element - React element to be validated
 */
export function isLookEnhanced(element) {
  return element._isLookEnhanced || element.type && element.type._isLookEnhanced ? true : false
}

/**
 * Resolves provided styles for an elements children
 * @param {Object} Component - wrapping React Component providing looks and elements
 * @param {Array|string|number} children - children that get resolved
 * @param {Object} config - configuration containing plugins and plugin-specific configs
 */
export function resolveChildren(Component, newProps, config) {
  if (newProps.children) {

    const { children } = newProps
    // directly return primitive children
    if (_.isString(children) || _.isNumber(children)) {
      return
    }

    if (children.type) {
      newProps.children = config._resolveStyles(Component, children, config)
    }

    // if there are more than one child, iterate over them
    if (_.isArray(children)) {
      // flattening children prevents deeper nested children
      const flatChildren = _.flattenDeep(children)

      // recursively resolve styles for child elements if it is a valid React Component
      newProps.children = Children.map(flatChildren, child => {
        if (isValidElement(child)) {
          return config._resolveStyles(Component, child, config)
        }
        return child; // eslint-disable-line
      })
    }
  }
}

/**
* Resolves Components passed as a property
* @param {Object} Component - wrapping React Component providing looks and elements
* @param {Object} newProps - element's properties to iterate
* @param {Object} config - configuration containing plugins and plugin-specific configs
*/
export function resolveProps(Component, newProps, config) {
  Object.keys(newProps).forEach(property => {
    if (property === 'children') {
      return
    }

    // Resolving styles for elements passed by props
    // Skip children as they've been resolved already
    const propElement = newProps[property]
    if (isValidElement(propElement)) {
      newProps[property] = config._resolveStyles(Component, propElement, config)
      newProps._lookShouldUpdate = true
    }
  })
}
<commit_msg>param forceModePossible added for backwards compatibility<commit_after>import { isValidElement, Children } from 'react'
import _ from 'lodash'

/**
 * Resolves all plugins provided by the configuration
 * @param {Object} pluginInterface - interface containing all configurations to resolve
 */
export function resolvePlugins(pluginInterface, forceModePossible = false) {
  let { styles, config } = pluginInterface

  // Triggers plugin resolving
  // Uses the exact plugin lineup defined within Config
  config.plugins.forEach(plugin => {
    // If the plugin is a function it gets called when there are dynamic styles to resolve
    if (forceModePossible !== true || plugin instanceof Function) {
      if (pluginInterface.dynamicStylesNotNull === true || forceModePossible !== true) {
        styles = plugin({
          ...pluginInterface,
          styles
        })
      }
    } else {
      // The plugin could also be an object containing `mode` and `plugin`
      // Force mode calls the plugin every time when this function is called
      if (plugin.mode === 'force') {
        styles = plugin.plugin({
          ...pluginInterface,
          styles
        })
        return
      }
      // Default/fallback mode: Same as if the plugin would be a function
      if (pluginInterface.dynamicStylesNotNull) {
        styles = plugin.plugin({
          ...pluginInterface,
          styles
        })
      }
    }
  })

  return styles
}

/**
 * Checks if a given element is a look-enhanced Component itself
 * @param {Object} element - React element to be validated
 */
export function isLookEnhanced(element) {
  return element._isLookEnhanced || element.type && element.type._isLookEnhanced ? true : false
}

/**
 * Resolves provided styles for an elements children
 * @param {Object} Component - wrapping React Component providing looks and elements
 * @param {Array|string|number} children - children that get resolved
 * @param {Object} config - configuration containing plugins and plugin-specific configs
 */
export function resolveChildren(Component, newProps, config) {
  if (newProps.children) {

    const { children } = newProps
    // directly return primitive children
    if (_.isString(children) || _.isNumber(children)) {
      return
    }

    if (children.type) {
      newProps.children = config._resolveStyles(Component, children, config)
    }

    // if there are more than one child, iterate over them
    if (_.isArray(children)) {
      // flattening children prevents deeper nested children
      const flatChildren = _.flattenDeep(children)

      // recursively resolve styles for child elements if it is a valid React Component
      newProps.children = Children.map(flatChildren, child => {
        if (isValidElement(child)) {
          return config._resolveStyles(Component, child, config)
        }
        return child; // eslint-disable-line
      })
    }
  }
}

/**
* Resolves Components passed as a property
* @param {Object} Component - wrapping React Component providing looks and elements
* @param {Object} newProps - element's properties to iterate
* @param {Object} config - configuration containing plugins and plugin-specific configs
*/
export function resolveProps(Component, newProps, config) {
  Object.keys(newProps).forEach(property => {
    if (property === 'children') {
      return
    }

    // Resolving styles for elements passed by props
    // Skip children as they've been resolved already
    const propElement = newProps[property]
    if (isValidElement(propElement)) {
      newProps[property] = config._resolveStyles(Component, propElement, config)
      newProps._lookShouldUpdate = true
    }
  })
}
<|endoftext|>


<commit_before>import { Component, NodeComponent, isEqual } from 'substance'
import ValueComponent from '../shared/ValueComponent'
import CodeEditor from '../shared/CodeEditor'
import { getCellState, getErrorMessage } from '../shared/cellHelpers'
import { toString as stateToString, OK, BROKEN, FAILED } from '../engine/CellStates'
import NodeMenu from './NodeMenu'

const LANG_LABELS = {
  'mini': 'Mini',
  'js': 'JS',
  'node': 'Node',
  'sql': 'SQL',
  'py': 'Py',
  'r': 'R',
}

const SHOW_ERROR_DELAY = 500

export default
class CellComponent extends NodeComponent {

  constructor(...args) {
    super(...args)

    this.handleActions({
      // triggered by CodeEditorComponent and MiniLangEditor
      'execute': this._onExecute,
      'break': this._onBreak
    })
  }

  getInitialState() {
    return {
      hideCode: false,
      forceOutput: false
    }
  }

  _renderStatus($$) {
    const cellState = getCellState(this.props.node)
    let statusName = cellState ? stateToString(cellState.status) : 'unknown'
    return $$('div').addClass(`se-status sm-${statusName}`)
  }

  render($$) {
    const cell = this.props.node
    const cellState = getCellState(cell)
    let el = $$('div').addClass('sc-cell')
    el.attr('data-id', cell.id)

    if (!this.state.hideCode) {
      let source = cell.find('source-code')
      let cellEditorContainer = $$('div').addClass('se-cell-editor-container')
      cellEditorContainer.append(
        this._renderStatus($$),
        $$('div').addClass('se-expression').append(
          $$(CodeEditor, {
            path: source.getPath(),
            excludedCommands: this._getBlackListedCommands(),
            language: source.attributes.language,
            multiline: true
          }).ref('expressionEditor')
            .on('escape', this._onEscapeFromCodeEditor)
        )
      )
      el.append(cellEditorContainer)
      el.append(
        this._renderEllipsis($$)
      )
      el.append(
        $$('div').addClass('se-language').append(
          LANG_LABELS[source.attributes.language]
        )
      )
    } else {
      // TODO: Create proper visual style
      el.append(
        $$('button').append(
          this._renderStatus($$)
        )
        .addClass('se-show-code')
        .attr('title', 'Show Code')
        .on('click', this._showCode)
      )
    }

    if (cellState) {
      let valueDisplay = $$(ValueDisplay, {
        status: cellState.status,
        value: cellState.value,
        errors: cellState.errors,
        showOutput: this._showOutput(),
      }).ref('valueDisplay')
      el.append(valueDisplay)
    }
    return el
  }

  /*
    Move this into an overlay, shown depending on app state
  */
  _renderEllipsis($$) {
    let Button = this.getComponent('button')
    let el = $$('div').addClass('se-ellipsis')
    let configurator = this.context.editorSession.getConfigurator()
    let button = $$(Button, {
      icon: 'ellipsis',
      active: false,
      theme: 'light'
    }).on('click', this._toggleMenu)
    el.append(button)

    let sel = this.context.editorSession.getSelection()
    if (sel.isNodeSelection() && sel.getNodeId() === this.props.node.id) {
      el.append(
        $$(NodeMenu, {
          toolPanel: configurator.getToolPanel('node-menu')
        }).ref('menu')
      )
    }
    return el
  }

  getExpression() {
    return this.refs.expressionEditor.getContent()
  }

  _renderMenu($$) {
    let menuEl = $$('div').addClass('se-menu')
    menuEl.append(
      this._renderToggleCode($$),
      this._renderToggleOutput($$)
    )
    return menuEl
  }

  _getBlackListedCommands() {
    const commandGroups = this.context.commandGroups
    let result = []
    ;['annotations', 'insert', 'prompt', 'text-types'].forEach((name) => {
      if (commandGroups[name]) {
        result = result.concat(commandGroups[name])
      }
    })
    return result
  }

  _showCode() {
    this.extendState({
      hideCode: false
    })
  }

  /*
    Generally output is shown when cell is not a definition, however it can be
    enforced
  */
  _showOutput() {
    return !this._isDefinition() || this.state.forceOutput
  }

  _isDefinition() {
    const cellState = getCellState(this.props.node)
    return cellState && cellState.hasOutput()
  }

  _toggleMenu() {
    this.context.editorSession.setSelection({
      type: 'node',
      containerId: 'body-content-1',
      surfaceId: 'bodyEditor',
      nodeId: this.props.node.id,
    })
  }

  _onExecute() {
    this.context.cellEngine.recompute(this.props.node.id)
  }

  _onBreak() {
    this.context.editorSession.transaction((tx) => {
      tx.selection = this._afterNode()
      tx.insertBlockNode({
        type: 'p'
      })
    })
  }

  _onEscapeFromCodeEditor(event) {
    event.stopPropagation()
    this.send('escape')
  }

  _afterNode() {
    // TODO: not too happy about how difficult it is to set the selection
    const node = this.props.node
    const isolatedNode = this.context.isolatedNodeComponent
    const parentSurface = isolatedNode.getParentSurface()
    return {
      type: 'node',
      nodeId: node.id,
      mode: 'after',
      containerId: parentSurface.getContainerId(),
      surfaceId: parentSurface.id
    }
  }

}

class ValueDisplay extends Component {

  shouldRerender(newProps) {
    return (
      (newProps.showOutput !== this.props.showOutput) ||
      (newProps.status !== this.props.status) ||
      (newProps.value !== this.props.value) ||
      (!isEqual(newProps.errors, this.props.errors))
    )
  }

  willReceiveProps(newProps) {
    let newStatus = newProps.status
    if (newStatus === OK) {
      this._cachedValue = newProps.value
      // this._cachedError = null
    } else if (newStatus === BROKEN || newStatus === FAILED) {
      this._cachedError = newProps.errors[0]
      // this._cachedValue = null
    }
  }

  didUpdate() {
    const errors = this.props.errors
    if (errors && errors.length > 0) {
      let token = this._token
      setTimeout(() => {
        // if this is still the same update
        if (token === this._token) {
          if (this.refs.cachedValue) {
            this.refs.cachedValue.css('display', 'none')
          }
          if (this.refs.error) {
            this.refs.error.css('display', 'block')
          }
        }
      }, SHOW_ERROR_DELAY)
    }
  }

  render($$) {
    const status = this.props.status
    const value = this.props.value
    const showOutput = this.props.showOutput
    const errors = this.props.errors
    let el = $$('div')
    // whenever there are errors we will renew the token
    // so that an already triggered updater can be canceled
    this._token = Math.random()
    if(status === BROKEN || status === FAILED) {
      // rendering the last value as hidden to achieve a bit more resilient spacing
      if (this._cachedValue && showOutput) {
        el.append(
          $$(ValueComponent, this._cachedValue).ref('cachedValue').css('visibility', 'hidden')
        )
      }
      // alternatively if there is a cached error, use that to reserve the space
      else if (this._cachedError) {
        el.append(
          $$('div').addClass('se-error').append(
            getErrorMessage(this._cachedError)
          ).ref('cachedValue').css('visibility', 'hidden')
        )
      }
      // the error is not shown at first, but didUpdate() will show it after some delay
      // this way the error is a bit delayed, potentially becoming superseded by a new update in the meantime
      el.append(
        $$('div').addClass('se-error').append(
          getErrorMessage(errors[0])
        ).ref('error').css('display', 'none')
      )
    } else if (showOutput) {
      if (value && status === OK) {
        el.append(
          $$(ValueComponent, value).ref('value')
        )
      }
      // to have a less jumpy experience, we show the last valid value grey'd out
      else if (this._cachedValue) {
        el.append(
          $$(ValueComponent, this._cachedValue).ref('value').addClass('sm-pending')
        )
      }
    }
    return el
  }
}

CellComponent.noBlocker = true
<commit_msg>Add language label PyJp<commit_after>import { Component, NodeComponent, isEqual } from 'substance'
import ValueComponent from '../shared/ValueComponent'
import CodeEditor from '../shared/CodeEditor'
import { getCellState, getErrorMessage } from '../shared/cellHelpers'
import { toString as stateToString, OK, BROKEN, FAILED } from '../engine/CellStates'
import NodeMenu from './NodeMenu'

const LANG_LABELS = {
  'mini': 'Mini',
  'js': 'JS',
  'node': 'Node',
  'sql': 'SQL',
  'py': 'Py',
  'pyjp': 'PyJp',
  'r': 'R',
}

const SHOW_ERROR_DELAY = 500

export default
class CellComponent extends NodeComponent {

  constructor(...args) {
    super(...args)

    this.handleActions({
      // triggered by CodeEditorComponent and MiniLangEditor
      'execute': this._onExecute,
      'break': this._onBreak
    })
  }

  getInitialState() {
    return {
      hideCode: false,
      forceOutput: false
    }
  }

  _renderStatus($$) {
    const cellState = getCellState(this.props.node)
    let statusName = cellState ? stateToString(cellState.status) : 'unknown'
    return $$('div').addClass(`se-status sm-${statusName}`)
  }

  render($$) {
    const cell = this.props.node
    const cellState = getCellState(cell)
    let el = $$('div').addClass('sc-cell')
    el.attr('data-id', cell.id)

    if (!this.state.hideCode) {
      let source = cell.find('source-code')
      let cellEditorContainer = $$('div').addClass('se-cell-editor-container')
      cellEditorContainer.append(
        this._renderStatus($$),
        $$('div').addClass('se-expression').append(
          $$(CodeEditor, {
            path: source.getPath(),
            excludedCommands: this._getBlackListedCommands(),
            language: source.attributes.language,
            multiline: true
          }).ref('expressionEditor')
            .on('escape', this._onEscapeFromCodeEditor)
        )
      )
      el.append(cellEditorContainer)
      el.append(
        this._renderEllipsis($$)
      )
      el.append(
        $$('div').addClass('se-language').append(
          LANG_LABELS[source.attributes.language]
        )
      )
    } else {
      // TODO: Create proper visual style
      el.append(
        $$('button').append(
          this._renderStatus($$)
        )
        .addClass('se-show-code')
        .attr('title', 'Show Code')
        .on('click', this._showCode)
      )
    }

    if (cellState) {
      let valueDisplay = $$(ValueDisplay, {
        status: cellState.status,
        value: cellState.value,
        errors: cellState.errors,
        showOutput: this._showOutput(),
      }).ref('valueDisplay')
      el.append(valueDisplay)
    }
    return el
  }

  /*
    Move this into an overlay, shown depending on app state
  */
  _renderEllipsis($$) {
    let Button = this.getComponent('button')
    let el = $$('div').addClass('se-ellipsis')
    let configurator = this.context.editorSession.getConfigurator()
    let button = $$(Button, {
      icon: 'ellipsis',
      active: false,
      theme: 'light'
    }).on('click', this._toggleMenu)
    el.append(button)

    let sel = this.context.editorSession.getSelection()
    if (sel.isNodeSelection() && sel.getNodeId() === this.props.node.id) {
      el.append(
        $$(NodeMenu, {
          toolPanel: configurator.getToolPanel('node-menu')
        }).ref('menu')
      )
    }
    return el
  }

  getExpression() {
    return this.refs.expressionEditor.getContent()
  }

  _renderMenu($$) {
    let menuEl = $$('div').addClass('se-menu')
    menuEl.append(
      this._renderToggleCode($$),
      this._renderToggleOutput($$)
    )
    return menuEl
  }

  _getBlackListedCommands() {
    const commandGroups = this.context.commandGroups
    let result = []
    ;['annotations', 'insert', 'prompt', 'text-types'].forEach((name) => {
      if (commandGroups[name]) {
        result = result.concat(commandGroups[name])
      }
    })
    return result
  }

  _showCode() {
    this.extendState({
      hideCode: false
    })
  }

  /*
    Generally output is shown when cell is not a definition, however it can be
    enforced
  */
  _showOutput() {
    return !this._isDefinition() || this.state.forceOutput
  }

  _isDefinition() {
    const cellState = getCellState(this.props.node)
    return cellState && cellState.hasOutput()
  }

  _toggleMenu() {
    this.context.editorSession.setSelection({
      type: 'node',
      containerId: 'body-content-1',
      surfaceId: 'bodyEditor',
      nodeId: this.props.node.id,
    })
  }

  _onExecute() {
    this.context.cellEngine.recompute(this.props.node.id)
  }

  _onBreak() {
    this.context.editorSession.transaction((tx) => {
      tx.selection = this._afterNode()
      tx.insertBlockNode({
        type: 'p'
      })
    })
  }

  _onEscapeFromCodeEditor(event) {
    event.stopPropagation()
    this.send('escape')
  }

  _afterNode() {
    // TODO: not too happy about how difficult it is to set the selection
    const node = this.props.node
    const isolatedNode = this.context.isolatedNodeComponent
    const parentSurface = isolatedNode.getParentSurface()
    return {
      type: 'node',
      nodeId: node.id,
      mode: 'after',
      containerId: parentSurface.getContainerId(),
      surfaceId: parentSurface.id
    }
  }

}

class ValueDisplay extends Component {

  shouldRerender(newProps) {
    return (
      (newProps.showOutput !== this.props.showOutput) ||
      (newProps.status !== this.props.status) ||
      (newProps.value !== this.props.value) ||
      (!isEqual(newProps.errors, this.props.errors))
    )
  }

  willReceiveProps(newProps) {
    let newStatus = newProps.status
    if (newStatus === OK) {
      this._cachedValue = newProps.value
      // this._cachedError = null
    } else if (newStatus === BROKEN || newStatus === FAILED) {
      this._cachedError = newProps.errors[0]
      // this._cachedValue = null
    }
  }

  didUpdate() {
    const errors = this.props.errors
    if (errors && errors.length > 0) {
      let token = this._token
      setTimeout(() => {
        // if this is still the same update
        if (token === this._token) {
          if (this.refs.cachedValue) {
            this.refs.cachedValue.css('display', 'none')
          }
          if (this.refs.error) {
            this.refs.error.css('display', 'block')
          }
        }
      }, SHOW_ERROR_DELAY)
    }
  }

  render($$) {
    const status = this.props.status
    const value = this.props.value
    const showOutput = this.props.showOutput
    const errors = this.props.errors
    let el = $$('div')
    // whenever there are errors we will renew the token
    // so that an already triggered updater can be canceled
    this._token = Math.random()
    if(status === BROKEN || status === FAILED) {
      // rendering the last value as hidden to achieve a bit more resilient spacing
      if (this._cachedValue && showOutput) {
        el.append(
          $$(ValueComponent, this._cachedValue).ref('cachedValue').css('visibility', 'hidden')
        )
      }
      // alternatively if there is a cached error, use that to reserve the space
      else if (this._cachedError) {
        el.append(
          $$('div').addClass('se-error').append(
            getErrorMessage(this._cachedError)
          ).ref('cachedValue').css('visibility', 'hidden')
        )
      }
      // the error is not shown at first, but didUpdate() will show it after some delay
      // this way the error is a bit delayed, potentially becoming superseded by a new update in the meantime
      el.append(
        $$('div').addClass('se-error').append(
          getErrorMessage(errors[0])
        ).ref('error').css('display', 'none')
      )
    } else if (showOutput) {
      if (value && status === OK) {
        el.append(
          $$(ValueComponent, value).ref('value')
        )
      }
      // to have a less jumpy experience, we show the last valid value grey'd out
      else if (this._cachedValue) {
        el.append(
          $$(ValueComponent, this._cachedValue).ref('value').addClass('sm-pending')
        )
      }
    }
    return el
  }
}

CellComponent.noBlocker = true
<|endoftext|>


<commit_before>'use strict';

var mongoose = require('mongoose'),
  Schema = mongoose.Schema,
  archive = require('./archive.js');

var ProjectSchema = new Schema({
  created: {
    type: Date,
    default: Date.now
  },
  updated: {
    type: Date
  },
  title: {
    type: String
  },
  parent : {
    type: Schema.ObjectId,
    ref: 'Project'
  },
  discussion : {
    type: Schema.ObjectId,
    ref: 'Discussion'
  },
  creator: {
    type: Schema.ObjectId,
    ref: 'User'
  },
  manager: {
    type: Schema.ObjectId,
    ref: 'User'
  },
  signature : {
    circles : {},
    codes: {}
  },
  color: {
    type: String,
    required: true
  },
  status: {
    type: String,
    enum: ['New', 'Archived', 'Cancelled', 'In-Progress', 'Completed'],
    default: 'New'
  },
  description: {
    type: String
  },
  //should we maybe have finer grain control on this
  watchers : [{
    type: Schema.ObjectId,
    ref: 'User'
  }],
  room: {
    type: String
  }
});

/**
 * Validations
 */
ProjectSchema.path('color').validate(function(color) {
  return /^([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/i.test(color);
}, 'Invalid HEX color.');

/**
 * Statics
 */
ProjectSchema.statics.load = function(id, cb) {
  this.findOne({
    _id: id
  }).populate('creator', 'name username').exec(cb);
};

/**
 * Post middleware
 */
var elasticsearch  = require('../controllers/elasticsearch');

ProjectSchema.post('save', function (req, next) {
  elasticsearch.save(this, 'project', this.room);
  next();
});

ProjectSchema.pre('remove', function (next) {
  elasticsearch.delete(this, 'project',this.room, next);
  next();
});

ProjectSchema.plugin(archive, 'project');

mongoose.model('Project', ProjectSchema);
<commit_msg>Fix project status<commit_after>'use strict';

var mongoose = require('mongoose'),
  Schema = mongoose.Schema,
  archive = require('./archive.js');

var ProjectSchema = new Schema({
  created: {
    type: Date,
    default: Date.now
  },
  updated: {
    type: Date
  },
  title: {
    type: String
  },
  parent : {
    type: Schema.ObjectId,
    ref: 'Project'
  },
  discussion : {
    type: Schema.ObjectId,
    ref: 'Discussion'
  },
  creator: {
    type: Schema.ObjectId,
    ref: 'User'
  },
  manager: {
    type: Schema.ObjectId,
    ref: 'User'
  },
  signature : {
    circles : {},
    codes: {}
  },
  color: {
    type: String,
    required: true
  },
  status: {
    type: String,
    enum: ['New', 'Archived', 'Cancelled', 'In Progress', 'Completed'],
    default: 'New'
  },
  description: {
    type: String
  },
  //should we maybe have finer grain control on this
  watchers : [{
    type: Schema.ObjectId,
    ref: 'User'
  }],
  room: {
    type: String
  }
});

/**
 * Validations
 */
ProjectSchema.path('color').validate(function(color) {
  return /^([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/i.test(color);
}, 'Invalid HEX color.');

/**
 * Statics
 */
ProjectSchema.statics.load = function(id, cb) {
  this.findOne({
    _id: id
  }).populate('creator', 'name username').exec(cb);
};

/**
 * Post middleware
 */
var elasticsearch  = require('../controllers/elasticsearch');

ProjectSchema.post('save', function (req, next) {
  elasticsearch.save(this, 'project', this.room);
  next();
});

ProjectSchema.pre('remove', function (next) {
  elasticsearch.delete(this, 'project',this.room, next);
  next();
});

ProjectSchema.plugin(archive, 'project');

mongoose.model('Project', ProjectSchema);
<|endoftext|>


<commit_before>// see: http://stackoverflow.com/questions/1909441/jquery-keyup-delay
var delay = (function(){
  var timer = 0;
  return function(callback, ms){
    clearTimeout (timer);
    timer = setTimeout(callback, ms);
  };
})();

Meteor.startup(function () {

  Template[getTemplate('search')].helpers({
    canSearch: function () {
      return can.view(Meteor.user());
    },
    searchQuery: function () {
      return Session.get("searchQuery");
    },
    searchQueryEmpty: function () {
      return !!Session.get("searchQuery") ? '' : 'empty';
    }
  });

  Template[getTemplate('search')].events({
    'keyup, search .search-field': function(e){
      e.preventDefault();
      var val = $(e.target).val(),
          $search = $('.search');
      if (val === '') {
        // if search field is empty, just do nothing and show an empty template
        $search.addClass('empty');
        Session.set('searchQuery', '');
        Router.go('search', null, {replaceState: true});
      } else {
        $search.removeClass('empty');
        // if search field is not empty, add a delay to avoid firing new searches for every keystroke
        delay(function(){
          Session.set('searchQuery', val);

          // Update the querystring.
          var opts = {query: {q: val}};
          // if we're already on the search page, do a replaceState. Otherwise,
          // just use the pushState default.
          if(Router.current().route.getName() === 'search') {
            opts.replaceState = true;
          }
          Router.go('search', null, opts);

        }, 700 );
      }
    }
  });

});
<commit_msg>Increse specificity of `keyup` search event<commit_after>// see: http://stackoverflow.com/questions/1909441/jquery-keyup-delay
var delay = (function(){
  var timer = 0;
  return function(callback, ms){
    clearTimeout (timer);
    timer = setTimeout(callback, ms);
  };
})();

Meteor.startup(function () {

  Template[getTemplate('search')].helpers({
    canSearch: function () {
      return can.view(Meteor.user());
    },
    searchQuery: function () {
      return Session.get("searchQuery");
    },
    searchQueryEmpty: function () {
      return !!Session.get("searchQuery") ? '' : 'empty';
    }
  });

  Template[getTemplate('search')].events({
    'keyup .search-field, search .search-field': function(e){
      console.log("telescope-handler");
      e.preventDefault();
      var val = $(e.target).val(),
          $search = $('.search');
      if (val === '') {
        // if search field is empty, just do nothing and show an empty template
        $search.addClass('empty');
        Session.set('searchQuery', '');
        Router.go('search', null, {replaceState: true});
      } else {
        $search.removeClass('empty');
        // if search field is not empty, add a delay to avoid firing new searches for every keystroke
        delay(function(){
          Session.set('searchQuery', val);

          // Update the querystring.
          var opts = {query: {q: val}};
          // if we're already on the search page, do a replaceState. Otherwise,
          // just use the pushState default.
          if(Router.current().route.getName() === 'search') {
            opts.replaceState = true;
          }
          Router.go('search', null, opts);

        }, 700 );
      }
    }
  });

});
<|endoftext|>


<commit_before>Meteor.startup(function() {
	const enableQuery = {
		_id: 'AutoLinker',
		value: true
	};

	RocketChat.settings.add('AutoLinker', false, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, i18nLabel: 'Enabled'});

	RocketChat.settings.add('AutoLinker_StripPrefix', false, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, i18nDescription: 'AutoLinker_StripPrefix_Description', enableQuery});
	RocketChat.settings.add('AutoLinker_Urls_Scheme', true, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, enableQuery});
	RocketChat.settings.add('AutoLinker_Urls_www', true, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, enableQuery});
	RocketChat.settings.add('AutoLinker_Urls_TLD', true, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, enableQuery});
	RocketChat.settings.add('AutoLinker_UrlsRegExp', '(://|www\\.).+', {type: 'string', group: 'Message', section: 'AutoLinker', public: true, enableQuery});
	RocketChat.settings.add('AutoLinker_Email', true, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, enableQuery});
	RocketChat.settings.add('AutoLinker_Phone', true, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, i18nDescription: 'AutoLinker_Phone_Description', enableQuery});
});
<commit_msg>Enable AutoLinker back<commit_after>Meteor.startup(function() {
	const enableQuery = {
		_id: 'AutoLinker',
		value: true
	};

	RocketChat.settings.add('AutoLinker', true, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, i18nLabel: 'Enabled'});

	RocketChat.settings.add('AutoLinker_StripPrefix', false, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, i18nDescription: 'AutoLinker_StripPrefix_Description', enableQuery});
	RocketChat.settings.add('AutoLinker_Urls_Scheme', true, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, enableQuery});
	RocketChat.settings.add('AutoLinker_Urls_www', true, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, enableQuery});
	RocketChat.settings.add('AutoLinker_Urls_TLD', true, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, enableQuery});
	RocketChat.settings.add('AutoLinker_UrlsRegExp', '(://|www\\.).+', {type: 'string', group: 'Message', section: 'AutoLinker', public: true, enableQuery});
	RocketChat.settings.add('AutoLinker_Email', true, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, enableQuery});
	RocketChat.settings.add('AutoLinker_Phone', true, {type: 'boolean', group: 'Message', section: 'AutoLinker', public: true, i18nDescription: 'AutoLinker_Phone_Description', enableQuery});
});
<|endoftext|>


<commit_before>const assert = require('assert')
const childProcess = require('child_process')
const fs = require('fs')
const http = require('http')
const multiparty = require('multiparty')
const path = require('path')
const temp = require('temp').track()
const url = require('url')
const {closeWindow} = require('./window-helpers')

const {remote} = require('electron')
const {app, BrowserWindow, crashReporter} = remote.require('electron')

describe('crashReporter module', function () {
  if (process.mas) {
    return
  }

  var originalTempDirectory = null
  var tempDirectory = null

  before(function () {
    tempDirectory = temp.mkdirSync('electronCrashReporterSpec-')
    originalTempDirectory = app.getPath('temp')
    app.setPath('temp', tempDirectory)
  })

  after(function () {
    app.setPath('temp', originalTempDirectory)
  })

  var fixtures = path.resolve(__dirname, 'fixtures')
  const generateSpecs = (description, browserWindowOpts) => {
    describe(description, function () {
      var w = null
      var stopServer = null

      beforeEach(function () {
        stopServer = null
        w = new BrowserWindow(Object.assign({
          show: false
        }, browserWindowOpts))
      })

      afterEach(function () {
        return closeWindow(w).then(function () { w = null })
      })

      afterEach(function (done) {
        if (stopServer != null) {
          stopServer(done)
        }
      })

      it('should send minidump when renderer crashes', function (done) {
        if (process.env.APPVEYOR === 'True') return done()
        if (process.env.TRAVIS === 'true') return done()

        this.timeout(120000)

        stopServer = startServer({
          callback (port) {
            const crashUrl = url.format({
              protocol: 'file',
              pathname: path.join(fixtures, 'api', 'crash.html'),
              search: '?port=' + port
            })
            w.loadURL(crashUrl)
          },
          processType: 'renderer',
          done: done
        })
      })

      it('should send minidump when node processes crash', function (done) {
        if (process.env.APPVEYOR === 'True') return done()
        if (process.env.TRAVIS === 'true') return done()

        this.timeout(120000)

        stopServer = startServer({
          callback (port) {
            const crashesDir = path.join(app.getPath('temp'), `${app.getName()} Crashes`)
            const version = app.getVersion()
            const crashPath = path.join(fixtures, 'module', 'crash.js')
            childProcess.fork(crashPath, [port, version, crashesDir], {silent: true})
          },
          processType: 'browser',
          done: done
        })
      })

      it('should not send minidump if uploadToServer is false', function (done) {
        this.timeout(120000)

        let dumpFile
        let crashesDir = crashReporter.getCrashesDirectory()
        const existingDumpFiles = new Set()
        if (process.platform === 'darwin') {
          // crashpad puts the dump files in the "completed" subdirectory
          crashesDir = path.join(crashesDir, 'completed')
          crashReporter.setUploadToServer(false)
        }
        const testDone = (uploaded) => {
          if (uploaded) {
            return done(new Error('fail'))
          }
          if (process.platform === 'darwin') {
            crashReporter.setUploadToServer(true)
          }
          assert(fs.existsSync(dumpFile))
          done()
        }

        let pollInterval
        const pollDumpFile = () => {
          fs.readdir(crashesDir, (err, files) => {
            if (err) {
              return
            }
            const dumps = files.filter((file) => /\.dmp$/.test(file) && !existingDumpFiles.has(file))
            if (!dumps.length) {
              return
            }
            assert.equal(1, dumps.length)
            dumpFile = path.join(crashesDir, dumps[0])
            clearInterval(pollInterval)
            // dump file should not be deleted when not uploading, so we wait
            // 1s and assert it still exists in `testDone`
            setTimeout(testDone, 1000)
          })
        }

        remote.ipcMain.once('list-existing-dumps', (event) => {
          fs.readdir(crashesDir, (err, files) => {
            if (!err) {
              for (const file of files) {
                if (/\.dmp$/.test(file)) {
                  existingDumpFiles.add(file)
                }
              }
            }
            event.returnValue = null  // allow the renderer to crash
            pollInterval = setInterval(pollDumpFile, 100)
          })
        })

        stopServer = startServer({
          callback (port) {
            const crashUrl = url.format({
              protocol: 'file',
              pathname: path.join(fixtures, 'api', 'crash.html'),
              search: `?port=${port}&skipUpload=1`
            })
            w.loadURL(crashUrl)
          },
          processType: 'renderer',
          done: testDone.bind(null, true)
        })
      })

      it('should send minidump with updated extra parameters', function (done) {
        if (process.env.APPVEYOR === 'True') return done()
        if (process.env.TRAVIS === 'true') return done()

        this.timeout(120000)

        stopServer = startServer({
          callback (port) {
            const crashUrl = url.format({
              protocol: 'file',
              pathname: path.join(fixtures, 'api', 'crash-restart.html'),
              search: '?port=' + port
            })
            w.loadURL(crashUrl)
          },
          processType: 'renderer',
          done: done
        })
      })
    })
  }

  generateSpecs('without sandbox', {})
  generateSpecs('with sandbox', {
    webPreferences: {
      sandbox: true,
      preload: path.join(fixtures, 'module', 'preload-sandbox.js')
    }
  })

  describe('.start(options)', function () {
    it('requires that the companyName and submitURL options be specified', function () {
      assert.throws(function () {
        crashReporter.start({
          companyName: 'Missing submitURL'
        })
      }, /submitURL is a required option to crashReporter\.start/)
      assert.throws(function () {
        crashReporter.start({
          submitURL: 'Missing companyName'
        })
      }, /companyName is a required option to crashReporter\.start/)
    })

    it('can be called multiple times', function () {
      assert.doesNotThrow(function () {
        crashReporter.start({
          companyName: 'Umbrella Corporation',
          submitURL: 'http://127.0.0.1/crashes'
        })

        crashReporter.start({
          companyName: 'Umbrella Corporation 2',
          submitURL: 'http://127.0.0.1/more-crashes'
        })
      })
    })
  })

  describe('.get/setUploadToServer', function () {
    it('throws an error when called from the renderer process', function () {
      assert.throws(() => require('electron').crashReporter.getUploadToServer())
    })

    it('can be read/set from the main process', function () {
      if (process.platform === 'darwin') {
        crashReporter.start({
          companyName: 'Umbrella Corporation',
          submitURL: 'http://127.0.0.1/crashes',
          uploadToServer: true
        })
        assert.equal(crashReporter.getUploadToServer(), true)
        crashReporter.setUploadToServer(false)
        assert.equal(crashReporter.getUploadToServer(), false)
      } else {
        assert.equal(crashReporter.getUploadToServer(), true)
      }
    })
  })
})

const waitForCrashReport = () => {
  return new Promise((resolve, reject) => {
    let times = 0
    const checkForReport = () => {
      if (crashReporter.getLastCrashReport() != null) {
        resolve()
      } else if (times >= 10) {
        reject(new Error('No crash report available'))
      } else {
        times++
        setTimeout(checkForReport, 100)
      }
    }
    checkForReport()
  })
}

const startServer = ({callback, processType, done}) => {
  var called = false
  var server = http.createServer((req, res) => {
    var form = new multiparty.Form()
    form.parse(req, (error, fields) => {
      if (error) throw error
      if (called) return
      called = true
      assert.equal(fields.prod, 'Electron')
      assert.equal(fields.ver, process.versions.electron)
      assert.equal(fields.process_type, processType)
      assert.equal(fields.platform, process.platform)
      assert.equal(fields.extra1, 'extra1')
      assert.equal(fields.extra2, 'extra2')
      assert.equal(fields.extra3, undefined)
      assert.equal(fields._productName, 'Zombies')
      assert.equal(fields._companyName, 'Umbrella Corporation')
      assert.equal(fields._version, app.getVersion())

      const reportId = 'abc-123-def-456-abc-789-abc-123-abcd'
      res.end(reportId, () => {
        waitForCrashReport().then(() => {
          assert.equal(crashReporter.getLastCrashReport().id, reportId)
          assert.notEqual(crashReporter.getUploadedReports().length, 0)
          assert.equal(crashReporter.getUploadedReports()[0].id, reportId)
          req.socket.destroy()
          done()
        }, done)
      })
    })
  })

  const activeConnections = new Set()
  server.on('connection', (connection) => {
    activeConnections.add(connection)
    connection.once('close', () => {
      activeConnections.delete(connection)
    })
  })

  let {port} = remote.process
  server.listen(port, '127.0.0.1', () => {
    port = server.address().port
    remote.process.port = port
    if (process.platform === 'darwin') {
      crashReporter.start({
        companyName: 'Umbrella Corporation',
        submitURL: 'http://127.0.0.1:' + port
      })
    }
    callback(port)
  })

  return function stopServer (done) {
    for (const connection of activeConnections) {
      connection.destroy()
    }
    server.close(function () {
      done()
    })
  }
}
<commit_msg>Still call done when stop server function is null<commit_after>const assert = require('assert')
const childProcess = require('child_process')
const fs = require('fs')
const http = require('http')
const multiparty = require('multiparty')
const path = require('path')
const temp = require('temp').track()
const url = require('url')
const {closeWindow} = require('./window-helpers')

const {remote} = require('electron')
const {app, BrowserWindow, crashReporter} = remote.require('electron')

describe('crashReporter module', function () {
  if (process.mas) {
    return
  }

  var originalTempDirectory = null
  var tempDirectory = null

  before(function () {
    tempDirectory = temp.mkdirSync('electronCrashReporterSpec-')
    originalTempDirectory = app.getPath('temp')
    app.setPath('temp', tempDirectory)
  })

  after(function () {
    app.setPath('temp', originalTempDirectory)
  })

  var fixtures = path.resolve(__dirname, 'fixtures')
  const generateSpecs = (description, browserWindowOpts) => {
    describe(description, function () {
      var w = null
      var stopServer = null

      beforeEach(function () {
        stopServer = null
        w = new BrowserWindow(Object.assign({
          show: false
        }, browserWindowOpts))
      })

      afterEach(function () {
        return closeWindow(w).then(function () { w = null })
      })

      afterEach(function (done) {
        if (stopServer != null) {
          stopServer(done)
        } else {
          done()
        }
      })

      it('should send minidump when renderer crashes', function (done) {
        if (process.env.APPVEYOR === 'True') return done()
        if (process.env.TRAVIS === 'true') return done()

        this.timeout(120000)

        stopServer = startServer({
          callback (port) {
            const crashUrl = url.format({
              protocol: 'file',
              pathname: path.join(fixtures, 'api', 'crash.html'),
              search: '?port=' + port
            })
            w.loadURL(crashUrl)
          },
          processType: 'renderer',
          done: done
        })
      })

      it('should send minidump when node processes crash', function (done) {
        if (process.env.APPVEYOR === 'True') return done()
        if (process.env.TRAVIS === 'true') return done()

        this.timeout(120000)

        stopServer = startServer({
          callback (port) {
            const crashesDir = path.join(app.getPath('temp'), `${app.getName()} Crashes`)
            const version = app.getVersion()
            const crashPath = path.join(fixtures, 'module', 'crash.js')
            childProcess.fork(crashPath, [port, version, crashesDir], {silent: true})
          },
          processType: 'browser',
          done: done
        })
      })

      it('should not send minidump if uploadToServer is false', function (done) {
        this.timeout(120000)

        let dumpFile
        let crashesDir = crashReporter.getCrashesDirectory()
        const existingDumpFiles = new Set()
        if (process.platform === 'darwin') {
          // crashpad puts the dump files in the "completed" subdirectory
          crashesDir = path.join(crashesDir, 'completed')
          crashReporter.setUploadToServer(false)
        }
        const testDone = (uploaded) => {
          if (uploaded) {
            return done(new Error('fail'))
          }
          if (process.platform === 'darwin') {
            crashReporter.setUploadToServer(true)
          }
          assert(fs.existsSync(dumpFile))
          done()
        }

        let pollInterval
        const pollDumpFile = () => {
          fs.readdir(crashesDir, (err, files) => {
            if (err) {
              return
            }
            const dumps = files.filter((file) => /\.dmp$/.test(file) && !existingDumpFiles.has(file))
            if (!dumps.length) {
              return
            }
            assert.equal(1, dumps.length)
            dumpFile = path.join(crashesDir, dumps[0])
            clearInterval(pollInterval)
            // dump file should not be deleted when not uploading, so we wait
            // 1s and assert it still exists in `testDone`
            setTimeout(testDone, 1000)
          })
        }

        remote.ipcMain.once('list-existing-dumps', (event) => {
          fs.readdir(crashesDir, (err, files) => {
            if (!err) {
              for (const file of files) {
                if (/\.dmp$/.test(file)) {
                  existingDumpFiles.add(file)
                }
              }
            }
            event.returnValue = null  // allow the renderer to crash
            pollInterval = setInterval(pollDumpFile, 100)
          })
        })

        stopServer = startServer({
          callback (port) {
            const crashUrl = url.format({
              protocol: 'file',
              pathname: path.join(fixtures, 'api', 'crash.html'),
              search: `?port=${port}&skipUpload=1`
            })
            w.loadURL(crashUrl)
          },
          processType: 'renderer',
          done: testDone.bind(null, true)
        })
      })

      it('should send minidump with updated extra parameters', function (done) {
        if (process.env.APPVEYOR === 'True') return done()
        if (process.env.TRAVIS === 'true') return done()

        this.timeout(120000)

        stopServer = startServer({
          callback (port) {
            const crashUrl = url.format({
              protocol: 'file',
              pathname: path.join(fixtures, 'api', 'crash-restart.html'),
              search: '?port=' + port
            })
            w.loadURL(crashUrl)
          },
          processType: 'renderer',
          done: done
        })
      })
    })
  }

  generateSpecs('without sandbox', {})
  generateSpecs('with sandbox', {
    webPreferences: {
      sandbox: true,
      preload: path.join(fixtures, 'module', 'preload-sandbox.js')
    }
  })

  describe('.start(options)', function () {
    it('requires that the companyName and submitURL options be specified', function () {
      assert.throws(function () {
        crashReporter.start({
          companyName: 'Missing submitURL'
        })
      }, /submitURL is a required option to crashReporter\.start/)
      assert.throws(function () {
        crashReporter.start({
          submitURL: 'Missing companyName'
        })
      }, /companyName is a required option to crashReporter\.start/)
    })

    it('can be called multiple times', function () {
      assert.doesNotThrow(function () {
        crashReporter.start({
          companyName: 'Umbrella Corporation',
          submitURL: 'http://127.0.0.1/crashes'
        })

        crashReporter.start({
          companyName: 'Umbrella Corporation 2',
          submitURL: 'http://127.0.0.1/more-crashes'
        })
      })
    })
  })

  describe('.get/setUploadToServer', function () {
    it('throws an error when called from the renderer process', function () {
      assert.throws(() => require('electron').crashReporter.getUploadToServer())
    })

    it('can be read/set from the main process', function () {
      if (process.platform === 'darwin') {
        crashReporter.start({
          companyName: 'Umbrella Corporation',
          submitURL: 'http://127.0.0.1/crashes',
          uploadToServer: true
        })
        assert.equal(crashReporter.getUploadToServer(), true)
        crashReporter.setUploadToServer(false)
        assert.equal(crashReporter.getUploadToServer(), false)
      } else {
        assert.equal(crashReporter.getUploadToServer(), true)
      }
    })
  })
})

const waitForCrashReport = () => {
  return new Promise((resolve, reject) => {
    let times = 0
    const checkForReport = () => {
      if (crashReporter.getLastCrashReport() != null) {
        resolve()
      } else if (times >= 10) {
        reject(new Error('No crash report available'))
      } else {
        times++
        setTimeout(checkForReport, 100)
      }
    }
    checkForReport()
  })
}

const startServer = ({callback, processType, done}) => {
  var called = false
  var server = http.createServer((req, res) => {
    var form = new multiparty.Form()
    form.parse(req, (error, fields) => {
      if (error) throw error
      if (called) return
      called = true
      assert.equal(fields.prod, 'Electron')
      assert.equal(fields.ver, process.versions.electron)
      assert.equal(fields.process_type, processType)
      assert.equal(fields.platform, process.platform)
      assert.equal(fields.extra1, 'extra1')
      assert.equal(fields.extra2, 'extra2')
      assert.equal(fields.extra3, undefined)
      assert.equal(fields._productName, 'Zombies')
      assert.equal(fields._companyName, 'Umbrella Corporation')
      assert.equal(fields._version, app.getVersion())

      const reportId = 'abc-123-def-456-abc-789-abc-123-abcd'
      res.end(reportId, () => {
        waitForCrashReport().then(() => {
          assert.equal(crashReporter.getLastCrashReport().id, reportId)
          assert.notEqual(crashReporter.getUploadedReports().length, 0)
          assert.equal(crashReporter.getUploadedReports()[0].id, reportId)
          req.socket.destroy()
          done()
        }, done)
      })
    })
  })

  const activeConnections = new Set()
  server.on('connection', (connection) => {
    activeConnections.add(connection)
    connection.once('close', () => {
      activeConnections.delete(connection)
    })
  })

  let {port} = remote.process
  server.listen(port, '127.0.0.1', () => {
    port = server.address().port
    remote.process.port = port
    if (process.platform === 'darwin') {
      crashReporter.start({
        companyName: 'Umbrella Corporation',
        submitURL: 'http://127.0.0.1:' + port
      })
    }
    callback(port)
  })

  return function stopServer (done) {
    for (const connection of activeConnections) {
      connection.destroy()
    }
    server.close(function () {
      done()
    })
  }
}
<|endoftext|>


<commit_before>var Tag = Backbone.Model.extend();

var TagItemView = Backbone.View.extend({
  className: "tag-editor-tag",
  template: _.template('
<%= name %>
' +
      'x'),
  events: {
    'click .tag-editor-delete': 'deleteTag'
  },
  initialize: function() {
    this.listenTo(this.model, 'change', this.render);
    this.listenTo(this.model, 'destroy', this.remove);
  },
  render: function() {
    var html = this.template(this.model.toJSON());
    this.$el.html(html);
    return this;
  },
  deleteTag: function(e) {
    this.model.destroy();
  }
});

var Tags = Backbone.Collection.extend({
  model: Tag
});

var TagEditorView = Backbone.View.extend({
  separator: /[, ]+/,
  initialize: function(options) {
    this.width = options.width;
    this.itemViews = _.map(this.collection.models, function(model) {
      return new TagItemView({model: model});
    });
    this.tagInput = Backbone.$('<input class="tag-editor-input">').css('width', 0);
    this.tagMeasure = (new TagItemView({model: new Tag({name: ""})})).render().$el;
    this.tagMeasure.css({position: 'absolute', left: "-999px"});
    this.textMeasure = this.tagMeasure.find('.tag-editor-text');
    this.listenTo(this.collection, 'add', this.onAddModel);
    this.listenTo(this.collection, 'remove', this.onRemoveModel);
  },
  className: 'tag-editor-field',
  events: {
    click: 'onClick',
    'focus .tag-editor-input': 'onInputFocus',
    'blur .tag-editor-input': 'onInputBlur',
    'keydown .tag-editor-input': 'onInputKeydown',
    'keyup .tag-editor-input': 'onInputKeyup'
  },
  onClick: function() {
    this.tagInput.focus();
  },
  onAddModel: function(model, collection, options) {
    this.$el.children('div:nth-child(' + (options.at + 1) + ')').after(
        new TagItemView({model: model}).render().el);
  },
  onRemoveModel: function(model, collection, options) {
    this.itemViews.splice(options.index, 1);
  },
  onInputFocus: function() {
    this.tagInput.css('font', this.textMeasure.css('font'));
  },
  onInputBlur: function() {
    this.mayInsertTags();
  },
  onInputKeydown: function(e) {
    var val = this.tagInput.val(), collection = this.collection;
    if (!val && e.which == 8 /* Backspace */ && collection.length) {
      e.preventDefault();
      collection.pop().destroy();
      this.tagInput.focus();
    }
  },
  onInputKeyup: function() {
    var val = this.tagInput.val();
    if (this.separator.test(val)) {
      this.mayInsertTags();
    } else {
      this.adjustInputWidth();
    }
  },
  adjustInputWidth: function() {
    var tagInput = this.tagInput, textMeasure = this.textMeasure;
    // To avoid juggling of input widths, we measure text width
    // with two more characters.  We use 'W' here because it is
    // a wide character.
    textMeasure.text(tagInput.val() + 'WW');
    tagInput.css('width', textMeasure.width());
  },
  mayInsertTags: function() {
    var tagInput = this.tagInput, val = tagInput.val();
    tagInput.val('');
    this.adjustInputWidth();
    // We need to split tag text with separators
    // because text pasted from clipboard may contain those.
    _.each(val.split(this.separator), function(word) {
      if (word && !this.collection.where({name: word}, true)) {
        this.collection.push(new Tag({name: word}));
      }
    }, this);
  },
  render: function() {
    var $el = this.$el;
    $el.empty();
    $el.append(this.tagMeasure);
    _(this.itemViews).each(function(itemView) {
      $el.append(itemView.render().el);
    });
    $el.append(this.tagInput);
    $el.css('width', this.width);
    this.adjustInputWidth();
    return this;
  }
});
<commit_msg>Remove unnecessary code in onInputKeydown<commit_after>var Tag = Backbone.Model.extend();

var TagItemView = Backbone.View.extend({
  className: "tag-editor-tag",
  template: _.template('
<%= name %>
' +
      'x'),
  events: {
    'click .tag-editor-delete': 'deleteTag'
  },
  initialize: function() {
    this.listenTo(this.model, 'change', this.render);
    this.listenTo(this.model, 'destroy', this.remove);
  },
  render: function() {
    var html = this.template(this.model.toJSON());
    this.$el.html(html);
    return this;
  },
  deleteTag: function(e) {
    this.model.destroy();
  }
});

var Tags = Backbone.Collection.extend({
  model: Tag
});

var TagEditorView = Backbone.View.extend({
  separator: /[, ]+/,
  initialize: function(options) {
    this.width = options.width;
    this.itemViews = _.map(this.collection.models, function(model) {
      return new TagItemView({model: model});
    });
    this.tagInput = Backbone.$('<input class="tag-editor-input">').css('width', 0);
    this.tagMeasure = (new TagItemView({model: new Tag({name: ""})})).render().$el;
    this.tagMeasure.css({position: 'absolute', left: "-999px"});
    this.textMeasure = this.tagMeasure.find('.tag-editor-text');
    this.listenTo(this.collection, 'add', this.onAddModel);
    this.listenTo(this.collection, 'remove', this.onRemoveModel);
  },
  className: 'tag-editor-field',
  events: {
    click: 'onClick',
    'focus .tag-editor-input': 'onInputFocus',
    'blur .tag-editor-input': 'onInputBlur',
    'keydown .tag-editor-input': 'onInputKeydown',
    'keyup .tag-editor-input': 'onInputKeyup'
  },
  onClick: function() {
    this.tagInput.focus();
  },
  onAddModel: function(model, collection, options) {
    this.$el.children('div:nth-child(' + (options.at + 1) + ')').after(
        new TagItemView({model: model}).render().el);
  },
  onRemoveModel: function(model, collection, options) {
    this.itemViews.splice(options.index, 1);
  },
  onInputFocus: function() {
    this.tagInput.css('font', this.textMeasure.css('font'));
  },
  onInputBlur: function() {
    this.mayInsertTags();
  },
  onInputKeydown: function(e) {
    var val = this.tagInput.val(), collection = this.collection;
    if (!val && e.which == 8 /* Backspace */ && collection.length) {
      collection.pop().destroy();
    }
  },
  onInputKeyup: function() {
    var val = this.tagInput.val();
    if (this.separator.test(val)) {
      this.mayInsertTags();
    } else {
      this.adjustInputWidth();
    }
  },
  adjustInputWidth: function() {
    var tagInput = this.tagInput, textMeasure = this.textMeasure;
    // To avoid juggling of input widths, we measure text width
    // with two more characters.  We use 'W' here because it is
    // a wide character.
    textMeasure.text(tagInput.val() + 'WW');
    tagInput.css('width', textMeasure.width());
  },
  mayInsertTags: function() {
    var tagInput = this.tagInput, val = tagInput.val();
    tagInput.val('');
    this.adjustInputWidth();
    // We need to split tag text with separators
    // because text pasted from clipboard may contain those.
    _.each(val.split(this.separator), function(word) {
      if (word && !this.collection.where({name: word}, true)) {
        this.collection.push(new Tag({name: word}));
      }
    }, this);
  },
  render: function() {
    var $el = this.$el;
    $el.empty();
    $el.append(this.tagMeasure);
    _(this.itemViews).each(function(itemView) {
      $el.append(itemView.render().el);
    });
    $el.append(this.tagInput);
    $el.css('width', this.width);
    this.adjustInputWidth();
    return this;
  }
});
<|endoftext|>


<commit_before>
module.exports = publish

var npm = require("./npm.js")
  , log = require("npmlog")
  , tar = require("./utils/tar.js")
  , path = require("path")
  , readJson = require("read-package-json")
  , fs = require("graceful-fs")
  , lifecycle = require("./utils/lifecycle.js")
  , chain = require("slide").chain
  , Conf = require("npmconf").Conf
  , RegClient = require("npm-registry-client")

publish.usage = "npm publish <tarball>"
              + "\nnpm publish <folder>"
              + "\n\nPublishes '.' if no argument supplied"

publish.completion = function (opts, cb) {
  // publish can complete to a folder with a package.json
  // or a tarball, or a tarball url.
  // for now, not yet implemented.
  return cb()
}

function publish (args, isRetry, cb) {
  if (typeof cb !== "function") cb = isRetry, isRetry = false
  if (args.length === 0) args = ["."]
  if (args.length !== 1) return cb(publish.usage)

  log.verbose("publish", args)
  var arg = args[0]
  // if it's a local folder, then run the prepublish there, first.
  readJson(path.resolve(arg, "package.json"), function (er, data) {
    er = needVersion(er, data)
    if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
    // error is ok.  could be publishing a url or tarball
    // however, that means that we will not have automatically run
    // the prepublish script, since that gets run when adding a folder
    // to the cache.
    if (er) return cacheAddPublish(arg, false, isRetry, cb)
    cacheAddPublish(arg, true, isRetry, cb)
  })
}

// didPre in this case means that we already ran the prepublish script,
// and that the "dir" is an actual directory, and not something silly
// like a tarball or name@version thing.
// That means that we can run publish/postpublish in the dir, rather than
// in the cache dir.
function cacheAddPublish (dir, didPre, isRetry, cb) {
  npm.commands.cache.add(dir, function (er, data) {
    if (er) return cb(er)
    log.silly("publish", data)
    var cachedir = path.resolve( npm.cache
                               , data.name
                               , data.version
                               , "package" )
    chain
      ( [ !didPre && [lifecycle, data, "prepublish", cachedir]
        , [publish_, dir, data, isRetry, cachedir]
        , [lifecycle, data, "publish", didPre ? dir : cachedir]
        , [lifecycle, data, "postpublish", didPre ? dir : cachedir] ]
      , cb )
  })
}

function publish_ (arg, data, isRetry, cachedir, cb) {
  if (!data) return cb(new Error("no package.json file found"))

  // check for publishConfig hash
  var registry = npm.registry
  if (data.publishConfig) {
    var pubConf = new Conf(npm.config)

    // don't modify the actual publishConfig object, in case we have
    // to set a login token or some other data.
    pubConf.unshift(Object.keys(data.publishConfig).reduce(function (s, k) {
      s[k] = data.publishConfig[k]
      return s
    }, {}))
    registry = new RegClient(pubConf)
  }

  data._npmVersion = npm.version
  data._npmUser = { name: npm.config.get("username")
                  , email: npm.config.get("email") }

  delete data.modules
  if (data.private) return cb(new Error
    ("This package has been marked as private\n"
    +"Remove the 'private' field from the package.json to publish it."))

  var tarball = cachedir + ".tgz"
  registry.publish(data, tarball, function (er) {
    if (er && er.code === "EPUBLISHCONFLICT"
        && npm.config.get("force") && !isRetry) {
      log.warn("publish", "Forced publish over "+data._id)
      return npm.commands.unpublish([data._id], function (er) {
        // ignore errors.  Use the force.  Reach out with your feelings.
        publish([arg], true, cb)
      })
    }
    if (er) return cb(er)
    console.log("+ " + data._id)
    cb()
  })
}

function needVersion(er, data) {
  return er ? er
       : (data && !data.version) ? new Error("No version provided")
       : null
}
<commit_msg>publish -f: Fail with the first error if unpublish failed<commit_after>
module.exports = publish

var npm = require("./npm.js")
  , log = require("npmlog")
  , tar = require("./utils/tar.js")
  , path = require("path")
  , readJson = require("read-package-json")
  , fs = require("graceful-fs")
  , lifecycle = require("./utils/lifecycle.js")
  , chain = require("slide").chain
  , Conf = require("npmconf").Conf
  , RegClient = require("npm-registry-client")

publish.usage = "npm publish <tarball>"
              + "\nnpm publish <folder>"
              + "\n\nPublishes '.' if no argument supplied"

publish.completion = function (opts, cb) {
  // publish can complete to a folder with a package.json
  // or a tarball, or a tarball url.
  // for now, not yet implemented.
  return cb()
}

function publish (args, isRetry, cb) {
  if (typeof cb !== "function") cb = isRetry, isRetry = false
  if (args.length === 0) args = ["."]
  if (args.length !== 1) return cb(publish.usage)

  log.verbose("publish", args)
  var arg = args[0]
  // if it's a local folder, then run the prepublish there, first.
  readJson(path.resolve(arg, "package.json"), function (er, data) {
    er = needVersion(er, data)
    if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
    // error is ok.  could be publishing a url or tarball
    // however, that means that we will not have automatically run
    // the prepublish script, since that gets run when adding a folder
    // to the cache.
    if (er) return cacheAddPublish(arg, false, isRetry, cb)
    cacheAddPublish(arg, true, isRetry, cb)
  })
}

// didPre in this case means that we already ran the prepublish script,
// and that the "dir" is an actual directory, and not something silly
// like a tarball or name@version thing.
// That means that we can run publish/postpublish in the dir, rather than
// in the cache dir.
function cacheAddPublish (dir, didPre, isRetry, cb) {
  npm.commands.cache.add(dir, function (er, data) {
    if (er) return cb(er)
    log.silly("publish", data)
    var cachedir = path.resolve( npm.cache
                               , data.name
                               , data.version
                               , "package" )
    chain
      ( [ !didPre && [lifecycle, data, "prepublish", cachedir]
        , [publish_, dir, data, isRetry, cachedir]
        , [lifecycle, data, "publish", didPre ? dir : cachedir]
        , [lifecycle, data, "postpublish", didPre ? dir : cachedir] ]
      , cb )
  })
}

function publish_ (arg, data, isRetry, cachedir, cb) {
  if (!data) return cb(new Error("no package.json file found"))

  // check for publishConfig hash
  var registry = npm.registry
  if (data.publishConfig) {
    var pubConf = new Conf(npm.config)

    // don't modify the actual publishConfig object, in case we have
    // to set a login token or some other data.
    pubConf.unshift(Object.keys(data.publishConfig).reduce(function (s, k) {
      s[k] = data.publishConfig[k]
      return s
    }, {}))
    registry = new RegClient(pubConf)
  }

  data._npmVersion = npm.version
  data._npmUser = { name: npm.config.get("username")
                  , email: npm.config.get("email") }

  delete data.modules
  if (data.private) return cb(new Error
    ("This package has been marked as private\n"
    +"Remove the 'private' field from the package.json to publish it."))

  var tarball = cachedir + ".tgz"
  registry.publish(data, tarball, function (er) {
    if (er && er.code === "EPUBLISHCONFLICT"
        && npm.config.get("force") && !isRetry) {
      log.warn("publish", "Forced publish over "+data._id)
      return npm.commands.unpublish([data._id], function (er) {
        // ignore errors.  Use the force.  Reach out with your feelings.
        // but if it fails again, then report the first error.
        publish([arg], er || true, cb)
      })
    }
    // report the unpublish error if this was a retry and unpublish failed
    if (er && isRetry && isRetry !== true) return cb(isRetry)
    if (er) return cb(er)
    console.log("+ " + data._id)
    cb()
  })
}

function needVersion(er, data) {
  return er ? er
       : (data && !data.version) ? new Error("No version provided")
       : null
}
<|endoftext|>


<commit_before>'use strict'

const os = require('os')
const spawnSync = require('child_process').spawnSync
const fancyHr = require('fancy-hr')
const symbols = require('log-symbols')

function hr(text) {
	text = '  ' + text + ' '
	const char = os.platform() === 'darwin' ? '🍻' : '-'
	console.log(fancyHr(text, 15, char))
}

function spawn() {
	const command = spawnSync.apply(null, arguments)
	if (command.status === 1) {
		if (command.stderr) {
			console.log(command.stderr.toString())
		}
		console.log(`${symbols.error} Failed to publish new version.`.red)
		process.exit(1)
	} else {
		return command
	}
}

module.exports = function (type, argv) {
	hr('TEST')
	const testCommand = argv.test ? ['run', argv.test] : ['test']
	spawn('npm', testCommand, {stdio: 'inherit'})

	hr('VERSIONING')
	spawn('npm', ['version', type], {stdio: 'inherit'})

	hr('PUBLISH')
	spawn('npm', ['publish'], {stdio: 'inherit'})

	hr('PUSHING')
	var currentBranch = spawn('git', ['rev-parse', '--abbrev-ref', 'HEAD']).stdout.toString().trim()
	spawn('git', ['push', 'origin', currentBranch, '--follow-tags'], {stdio: 'inherit'})

	console.log(`${symbols.success} Everything done!`)
}
<commit_msg>shorten the heading<commit_after>'use strict'

const os = require('os')
const spawnSync = require('child_process').spawnSync
const fancyHr = require('fancy-hr')
const symbols = require('log-symbols')

function hr(text) {
	text = '  ' + text + ' '
	const char = os.platform() === 'darwin' ? '🍻' : '-'
	console.log(fancyHr(text, 15, char))
}

function spawn() {
	const command = spawnSync.apply(null, arguments)
	if (command.status === 1) {
		if (command.stderr) {
			console.log(command.stderr.toString())
		}
		console.log(`${symbols.error} Failed to publish new version.`.red)
		process.exit(1)
	} else {
		return command
	}
}

module.exports = function (type, argv) {
	hr('TEST')
	const testCommand = argv.test ? ['run', argv.test] : ['test']
	spawn('npm', testCommand, {stdio: 'inherit'})

	hr('VERSION')
	spawn('npm', ['version', type], {stdio: 'inherit'})

	hr('PUBLISH')
	spawn('npm', ['publish'], {stdio: 'inherit'})

	hr('PUSH')
	var currentBranch = spawn('git', ['rev-parse', '--abbrev-ref', 'HEAD']).stdout.toString().trim()
	spawn('git', ['push', 'origin', currentBranch, '--follow-tags'], {stdio: 'inherit'})

	console.log(`${symbols.success} Everything done!`)
}
<|endoftext|>


<commit_before>/*

	Ractive-decorators-minmaxwidth
	==============================

	Version <%= VERSION %>.

	A decorator to add min-width and max-width media queries to elements.
	It's based on https://github.com/FremyCompany/prollyfill-min-width/, but with a different css syntax (no hitch.js)

	==========================

	Troubleshooting: If you're using a module system in your app (AMD or
	something more nodey) then you may need to change the paths below,
	where it says `require( 'Ractive' )` or `define([ 'Ractive' ]...)`.

	==========================

	Usage: Include this file on your page below Ractive, e.g:

	Or, if you're using a module loader, require this module:

	    // requiring the plugin will 'activate' it - no need to use
	    // the return value
	    require( 'Ractive-decorators-minmaxwidth' );

	<< more specific instructions for this plugin go here... >>

*/

(function ( global, factory ) {

	'use strict';

	// Common JS (i.e. browserify) environment
	if ( typeof module !== 'undefined' && module.exports && typeof require === 'function' ) {
		factory( require( 'Ractive' ) );
	}

	// AMD?
	else if ( typeof define === 'function' && define.amd ) {
		define([ 'Ractive' ], factory );
	}

	// browser global
	else if ( global.Ractive ) {
		factory( global.Ractive );
	}

	else {
		throw new Error( 'Could not find Ractive! It must be loaded before the Ractive-decorators-minmaxwidth plugin' );
	}

}( typeof window !== 'undefined' ? window : this, function ( Ractive ) {

	'use strict';

    var styles_added = [],
        stylesheet;

    // IE8 polyfills
    if(!Array.isArray) {
        Array.isArray = function (vArg) {
            var isArray;

            isArray = vArg instanceof Array;

            return isArray;
        };
    }

    function addFlowListener(element, type, fn){
        var flow = type == 'over';
        element.addEventListener('OverflowEvent' in window ? 'overflowchanged' : type + 'flow', function(e){
            if (e.type == (type + 'flow') ||
                ((e.orient === 0 && e.horizontalOverflow === flow) ||
                    (e.orient === 1 && e.verticalOverflow === flow) ||
                    (e.orient === 2 && e.horizontalOverflow === flow && e.verticalOverflow === flow))) {
                e.flow = type;
                return fn.call(this, e);
            }
        }, false);
    }

    function fireEvent(element, type, data, options){
        var options = options || {};
        if( document.createEvent ) {
            var event = document.createEvent('Event');
            event.initEvent(type, 'bubbles' in options ? options.bubbles : true, 'cancelable' in options ? options.cancelable : true);
            for (var z in data) event[z] = data[z];
            element.dispatchEvent(event);
        }else if( document.createEventObject ) {
            var evObj = document.createEventObject();
            for (var z in data) evObj[z] = data[z];
            element.fireEvent( 'on' + evt, evObj );
        }
    }

    function addSensorStyles(sensorClass){
        if(!styles_added[sensorClass]){
            var style = '.'+sensorClass+', .'+sensorClass+' > div {position: absolute;top: 0;left: 0;width: 100%;height: 100%;overflow: hidden;z-index: -1;}';
            if(!stylesheet){
                stylesheet = document.createElement('style');
                stylesheet.type = 'text/css';
                stylesheet.id = 'ractive_decorator_minmaxwidth_styles';
                document.getElementsByTagName("head")[0].appendChild(stylesheet);
            }

            if (stylesheet.styleSheet) {
                stylesheet.styleSheet.cssText = style;
            }else {
                stylesheet.appendChild(document.createTextNode(style));
            }
            styles_added[sensorClass] = true;
        }
    }

    function addResizeListener(element, fn, sensorClass){
        var resize = 'onresize' in element;
        if (!resize && !element._resizeSensor) {
            var sensor = element._resizeSensor = document.createElement('div');
            sensor.className = sensorClass || 'resize-sensor';
            sensor.innerHTML = '

';
            addSensorStyles(sensorClass);

            var x = 0, y = 0,
                first = sensor.firstElementChild.firstChild,
                last = sensor.lastElementChild.firstChild,
                matchFlow = function(event){
                    var change = false,
                        width = element.offsetWidth;
                    if (x != width) {
                        first.style.width = width - 1 + 'px';
                        last.style.width = width + 1 + 'px';
                        change = true;
                        x = width;
                    }
                    var height = element.offsetHeight;
                    if (y != height) {
                        first.style.height = height - 1 + 'px';
                        last.style.height = height + 1 + 'px';
                        change = true;
                        y = height;
                    }
                    if (change && event.currentTarget != element) fireEvent(element, 'resize');
                };

            if (window.getComputedStyle(element).position == 'static'){
                element.style.position = 'relative';
                element._resizeSensor._resetPosition = true;
            }
            addFlowListener(sensor, 'over', matchFlow);
            addFlowListener(sensor, 'under', matchFlow);
            addFlowListener(sensor.firstElementChild, 'over', matchFlow);
            addFlowListener(sensor.lastElementChild, 'under', matchFlow);
            element.appendChild(sensor);
            matchFlow({});
        }
        var events = element._flowEvents || (element._flowEvents = []);
        if (events.indexOf(fn) === -1) events.push(fn);
        if (!resize) element.addEventListener('resize', fn, false);
        element.onresize = function(e){
            events.forEach(function(fn){
                fn.call(element, e);
            });
        };
    }

    function removeResizeListener(element, fn){
        var index = element._flowEvents.indexOf(fn);
        if (index > -1) element._flowEvents.splice(index, 1);
        if (!element._flowEvents.length) {
            var sensor = element._resizeSensor;
            if (sensor) {
                element.removeChild(sensor);
                if (sensor._resetPosition) element.style.position = 'static';
                delete element._resizeSensor;
            }
            if ('onresize' in element) element.onresize = null;
            delete element._flowEvents;
        }
        element.removeEventListener('resize', fn);
    }

    var minmaxwidth = function ( node, options ) {
        var min = options.min || [],
            max = options.max || [],
            key = options.key || false,
            R = node._ractive.root;

        if(!Array.isArray(min)) min = [min];
        if(!Array.isArray(max)) max = [max];

        function on_modified(){
            var minWidths = min.filter(function(width){
                    return node.offsetWidth>=parseInt(width);
                }),
                maxWidths = max.filter(function(width){
                    return node.offsetWidth<parseInt(width);
                });
            node.setAttribute('data-min-width',minWidths.join(' '));
            node.setAttribute('data-max-width',maxWidths.join(' '));
            if(key) R.set(key,node.offsetWidth);
        }

        // add pretty events
        if(!node._flowEvents || node._flowEvents.length===0) {
            addResizeListener(node, function() { fireEvent(this, "DOMAttrModified"); },minmaxwidth.sensorClass);
        }
        node.addEventListener("DOMAttrModified",on_modified);
        on_modified(); // run on initialization

        return {
            teardown: function () {
                // remove event listeners
                removeResizeListener(node);
                node.removeEventListener('DOMAttrModified',on_modified);
            }
        };
    };

    // defaults
    minmaxwidth.sensorClass = 'resize-sensor';

    Ractive.decorators.minmaxwidth = minmaxwidth;
}));<commit_msg>IE8 fixes<commit_after>/*

	Ractive-decorators-minmaxwidth
	==============================

	Version <%= VERSION %>.

	A decorator to add min-width and max-width media queries to elements.
	It's based on https://github.com/FremyCompany/prollyfill-min-width/, but with a different css syntax (no hitch.js)

	==========================

	Troubleshooting: If you're using a module system in your app (AMD or
	something more nodey) then you may need to change the paths below,
	where it says `require( 'Ractive' )` or `define([ 'Ractive' ]...)`.

	==========================

	Usage: Include this file on your page below Ractive, e.g:

	Or, if you're using a module loader, require this module:

	    // requiring the plugin will 'activate' it - no need to use
	    // the return value
	    require( 'Ractive-decorators-minmaxwidth' );

	<< more specific instructions for this plugin go here... >>

*/

(function ( global, factory ) {

	'use strict';

	// Common JS (i.e. browserify) environment
	if ( typeof module !== 'undefined' && module.exports && typeof require === 'function' ) {
		factory( require( 'Ractive' ) );
	}

	// AMD?
	else if ( typeof define === 'function' && define.amd ) {
		define([ 'Ractive' ], factory );
	}

	// browser global
	else if ( global.Ractive ) {
		factory( global.Ractive );
	}

	else {
		throw new Error( 'Could not find Ractive! It must be loaded before the Ractive-decorators-minmaxwidth plugin' );
	}

}( typeof window !== 'undefined' ? window : this, function ( Ractive ) {

	'use strict';

    var styles_added = [],
        stylesheet;

    // IE8 polyfills
    if(!Array.isArray) {
        Array.isArray = function (vArg) {
            var isArray;

            isArray = vArg instanceof Array;

            return isArray;
        };
    }

    function addFlowListener(element, type, fn){
        var flow = type == 'over';
        element.addEventListener('OverflowEvent' in window ? 'overflowchanged' : type + 'flow', function(e){
            if (e.type == (type + 'flow') ||
                ((e.orient === 0 && e.horizontalOverflow === flow) ||
                    (e.orient === 1 && e.verticalOverflow === flow) ||
                    (e.orient === 2 && e.horizontalOverflow === flow && e.verticalOverflow === flow))) {
                e.flow = type;
                return fn.call(this, e);
            }
        }, false);
    }

    function fireEvent(element, type, data, options){
        var options = options || {};
        if( document.createEvent ) {
            var event = document.createEvent('Event');
            event.initEvent(type, 'bubbles' in options ? options.bubbles : true, 'cancelable' in options ? options.cancelable : true);
            for (var z in data) event[z] = data[z];
            element.dispatchEvent(event);
        }else if( document.createEventObject ) {
            var evObj = document.createEventObject();
            for (var z in data) evObj[z] = data[z];
            element.fireEvent( 'on' + type, evObj );
        }
    }

    function addSensorStyles(sensorClass){
        if(!styles_added[sensorClass]){
            var style = '.'+sensorClass+', .'+sensorClass+' > div {position: absolute;top: 0;left: 0;width: 100%;height: 100%;overflow: hidden;z-index: -1;}';
            if(!stylesheet){
                stylesheet = document.createElement('style');
                stylesheet.type = 'text/css';
                stylesheet.id = 'ractive_decorator_minmaxwidth_styles';
                document.getElementsByTagName("head")[0].appendChild(stylesheet);
            }

            if (stylesheet.styleSheet) {
                stylesheet.styleSheet.cssText = style;
            }else {
                stylesheet.appendChild(document.createTextNode(style));
            }
            styles_added[sensorClass] = true;
        }
    }

    function addResizeListener(element, fn, sensorClass){
        var resize = 'onresize' in element;
        if (!resize && !element._resizeSensor) {
            var sensor = element._resizeSensor = document.createElement('div');
            sensor.className = sensorClass || 'resize-sensor';
            sensor.innerHTML = '

';
            addSensorStyles(sensorClass);

            var x = 0, y = 0,
                first = sensor.firstElementChild.firstChild,
                last = sensor.lastElementChild.firstChild,
                matchFlow = function(event){
                    var change = false,
                        width = element.offsetWidth;
                    if (x != width) {
                        first.style.width = width - 1 + 'px';
                        last.style.width = width + 1 + 'px';
                        change = true;
                        x = width;
                    }
                    var height = element.offsetHeight;
                    if (y != height) {
                        first.style.height = height - 1 + 'px';
                        last.style.height = height + 1 + 'px';
                        change = true;
                        y = height;
                    }
                    if (change && event.currentTarget != element) fireEvent(element, 'resize');
                };

            if (window.getComputedStyle(element).position == 'static'){
                element.style.position = 'relative';
                element._resizeSensor._resetPosition = true;
            }
            addFlowListener(sensor, 'over', matchFlow);
            addFlowListener(sensor, 'under', matchFlow);
            addFlowListener(sensor.firstElementChild, 'over', matchFlow);
            addFlowListener(sensor.lastElementChild, 'under', matchFlow);
            element.appendChild(sensor);
            matchFlow({});
        }
        var events = element._flowEvents || (element._flowEvents = []);
        if (events.indexOf(fn) === -1) events.push(fn);
        if (!resize) element.addEventListener('resize', fn, false);
        element.onresize = function(e){
            events.forEach(function(fn){
                fn.call(element, e);
            });
        };
    }

    function removeResizeListener(element, fn){
        var index = element._flowEvents.indexOf(fn);
        if (index > -1) element._flowEvents.splice(index, 1);
        if (!element._flowEvents.length) {
            var sensor = element._resizeSensor;
            if (sensor) {
                element.removeChild(sensor);
                if (sensor._resetPosition) element.style.position = 'static';
                delete element._resizeSensor;
            }
            if ('onresize' in element) element.onresize = null;
            delete element._flowEvents;
        }
        element.removeEventListener('resize', fn);
    }

    var minmaxwidth = function ( node, options ) {
        var min = options.min || [],
            max = options.max || [],
            key = options.key || false,
            R = node._ractive.root;

        if(!Array.isArray(min)) min = [min];
        if(!Array.isArray(max)) max = [max];

        function on_modified(){
            var minWidths = min.filter(function(width){
                    return node.offsetWidth>=parseInt(width);
                }),
                maxWidths = max.filter(function(width){
                    return node.offsetWidth<parseInt(width);
                });
            node.setAttribute('data-min-width',minWidths.join(' '));
            node.setAttribute('data-max-width',maxWidths.join(' '));
            if(key) R.set(key,node.offsetWidth);
        }

        // add pretty events
        if(!node._flowEvents || node._flowEvents.length===0) {
            addResizeListener(node, function() { fireEvent(this, "DOMAttrModified"); },minmaxwidth.sensorClass);
        }
        node.addEventListener("DOMAttrModified",on_modified);
        on_modified(); // run on initialization

        return {
            teardown: function () {
                // remove event listeners
                removeResizeListener(node);
                node.removeEventListener('DOMAttrModified',on_modified);
            }
        };
    };

    // defaults
    minmaxwidth.sensorClass = 'resize-sensor';

    Ractive.decorators.minmaxwidth = minmaxwidth;
}));<|endoftext|>


<commit_before>/**
 * Schedules a routine execution using `process.nextTick`
 * https://nodejs.org/api/process.html#process_process_nexttick_callback_args
 */
export default class NextTickExecutor {
  execute(routine) {
    return new Promise(resolve => {
      process.nextTick(() => resolve(routine()));
    });
  }
}
<commit_msg>make NextTickExecutor working with queue<commit_after>/**
 * Schedules a routine execution using `process.nextTick`
 * https://nodejs.org/api/process.html#process_process_nexttick_callback_args
 */
export default class NextTickExecutor {
  execute(queue) {
    return new Promise(resolveQueue => {
      process.nextTick(() => {
        const task = queue.shift();
        task.run();

        if (queue.length > 0) {
          return resolveQueue(Promise.resolve().then(() => this.execute(queue)));
        }

        resolveQueue();
      }, this.delay);
    });
  }
}
<|endoftext|>