<commit_before>// Qoogr Core

define(function (require) {
  var $ = require('jquery');
  var _ = require('underscore');
  var Backbone = require('backbone');
  var Handlebars = require('handlebars');

  // A Controller is really just a generic base class.
  var Controller = function(options) {
    this.initialize.apply(this, arguments);
  }

  // Extend Controller with Backbone Events
  _.extend(Controller.prototype, Backbone.Events, {

    // Default initialize is a no-op.
    initialize: function(){},

  });

  // Function to proxy an event on one object to another.
  var proxy = function(object, event) {
    var t = this;
    object.on(event, function() {
      t.trigger(event);
    });
  }

  // Give Controllers and Views proxy.
  Controller.prototype.proxy = Backbone.View.prototype.proxy = proxy;

  // Makes Controllers extendable like all other Backbone classes.
  Controller.extend = Backbone.View.extend;

  var QoogrView = Backbone.View.extend({

    el: $('#qoogr-box'),

    initialize: function(options) {
      var t = this;
      _.bindAll(t, 'load_graph', 'update_graph');
      t.array_map = t.options.array_map;
      t.graph_config_map = t.options.graph_config_map;
      t.qexec = t.options.qexec;

      // Selector class is optional.
      t.sel_class = t.options.selector_class;

      // If a selector class is provided, initialize it and
      // bind graph loading to it.
      if (t.sel) {
        t.sel = new t.sel_class();
        t.sel.on('load_graph', t.load_graph);
      }
    },

    resize_graph: function() {
      // Resize graph area to fit viewport.
      // Override with your custom resize logic.
      this.$('#qoogr-graph').css({
        height: $(window).height() - this.$('#qoogr-controls').height()
      });
    },

    load_graph: function(graph) {

      var t = this;

      t.resize_graph();

      // Set the graph config to that of newly-selected graph.
      t.graph_config = t.graph_config_map[graph];

      // Dynamically load the new graph module, if not yet loaded.
      require([t.graph_config.graph], function(graph) {

        // Teardown old graph.
        t.teardown_graph();

        // Get the Query Mapper and ControlsView from the graph config.
        t.qmapper_class = t.graph_config.qmapper || QueryMapper;
        t.controls_class = t.graph_config.controls || ControlsView;

        // Initialize new Query Mapper and ControlsView
        t.controls = new t.controls_class({
          container: t.$('#qoogr-controls')
        });

        t.qmapper = new t.qmapper_class({
          controls: t.controls
        });

        t.qmapper.on('change', t.update_graph);

        var raw_data = t.get_raw_data();

        t.graph = new graph({
          container: t.$('#qoogr-graph')[0],
          graph_config: t.graph_config,
          raw_data: raw_data
        });
      });
    },

    teardown_graph: function() {
      if (this.controls) {
        this.controls.teardown();
      }
      if (this.graph) {
        this.graph.remove();
      }
    },

    update_graph: function() {
      this.graph.update(this.get_raw_data());
    },

    get_raw_data: function() {
      var t = this;
      var qtree = t.qmapper.qtree;
      qtree.select.from = t.graph_config.from;

      return t.qexec.execute_query(
        t.array_map,
        t.qmapper.qtree
      );
    }

  });

  var SelectorView = Backbone.View.extend({

    el: $('#qoogr-selector'),

    events: {
      'click li': 'load_view',
    },

    // Subclasses should define a template, ala:
    // $tmpl: $(Handlebars.compile(selector_tmpl)()),

    initialize: function() {
      this.render();
    },

    render: function() {
      console.log('rendering graphselectorview');
      this.$el.html( this.$tmpl );
    },

    load_view: function(e) {
      e.stopImmediatePropagation();
      // Get the view associated with the li by the data attr.
      graph = e.currentTarget.dataset.graph;

      // The selector should not handle graph loading... leave it up to the
      // listening controller to handle it by triggering an event.
      this.trigger('load_graph', graph);
    }

  });

  var ControlsView = Backbone.View.extend({

    // Subclasses shoud define a template here, ala:
    // $tmpl: $(Handlebars.compile(controls_tmpl)()),

    initialize: function(options) {
      var t = this;
      t.container = t.options.container;
      t.render();

      // Maintain an array of filter data objects to iterate over.
      t.filter_collections = []

      // Set up individual control widgets here.
      // Don't forget to add the filter data objects to the array.

    },

    render: function() {
      console.log('rendering graphcontrolsview');
      this.$el.html( this.$tmpl );
      this.container.append(this.$el);
    },

    teardown: function() {
      // Call teardown on individual controls here.
    }

  });

  var QueryMapper = Controller.extend({

    initialize: function(options) {
      _.bindAll(this, 'map_controls');
      this.controls = options.controls;
      this.controls.on('change', this.map_controls);
      this.map_controls();
    },

    get_qtree_base: function() {
      // The following is a stub for a basic filter qtree.
      return {
        select: {
          where: {
            and: [] // We are going to insert filter clauses here.
          }
        }
      }
    },

    map_controls: function() {
      var t = this;

      // Build a new qtree by reading each control's data model.
      t.qtree = t.get_qtree_base()

      // Alias the toplevel and subclause for brevity.
      var and = t.qtree.select.where.and;

      // Push subclauses from filter data objects into query tree.
      _.each(t.controls.filter_collections, function(control_col) {
        and.push(control_col.get_subtree());
      });

      // Fire change event to alert listeners qtree has changed.
      t.trigger('change');
    }

  });

  // Return exports.
  return {
    Controller: Controller,
    QoogrView: QoogrView,
    SelectorView: SelectorView,
    ControlsView: ControlsView,
    QueryMapper: QueryMapper,
  };

});

<commit_msg>Create default graph argument to QoogrView<commit_after>// Qoogr Core

define(function (require) {
  var $ = require('jquery');
  var _ = require('underscore');
  var Backbone = require('backbone');
  var Handlebars = require('handlebars');

  // A Controller is really just a generic base class.
  var Controller = function(options) {
    this.initialize.apply(this, arguments);
  }

  // Extend Controller with Backbone Events
  _.extend(Controller.prototype, Backbone.Events, {

    // Default initialize is a no-op.
    initialize: function(){},

  });

  // Function to proxy an event on one object to another.
  var proxy = function(object, event) {
    var t = this;
    object.on(event, function() {
      t.trigger(event);
    });
  }

  // Give Controllers and Views proxy.
  Controller.prototype.proxy = Backbone.View.prototype.proxy = proxy;

  // Makes Controllers extendable like all other Backbone classes.
  Controller.extend = Backbone.View.extend;

  var QoogrView = Backbone.View.extend({

    el: $('#qoogr-box'),

    initialize: function(options) {
      var t = this;
      _.bindAll(t, 'load_graph', 'update_graph');
      t.array_map = t.options.array_map;
      t.graph_config_map = t.options.graph_config_map;
      t.default_graph = t.options.default_graph;
      t.qexec = t.options.qexec;

      // Selector class is optional.
      t.sel_class = t.options.selector_class;

      // If a selector class is provided, initialize it and
      // bind graph loading to it.
      if (t.sel) {
        t.sel = new t.sel_class();
        t.sel.on('load_graph', t.load_graph);
      }

      // Load default graph, if provided.
      if (t.default_graph) {
        t.load_graph(t.default_graph);
      }
    },

    resize_graph: function() {
      // Resize graph area to fit viewport.
      // Override with your custom resize logic.
      this.$('#qoogr-graph').css({
        height: $(window).height() - this.$('#qoogr-controls').height()
      });
    },

    load_graph: function(graph) {

      var t = this;

      t.resize_graph();

      // Set the graph config to that of newly-selected graph.
      t.graph_config = t.graph_config_map[graph];

      // Dynamically load the new graph module, if not yet loaded.
      require([t.graph_config.graph], function(graph) {

        // Teardown old graph.
        t.teardown_graph();

        // Get the Query Mapper and ControlsView from the graph config.
        t.qmapper_class = t.graph_config.qmapper || QueryMapper;
        t.controls_class = t.graph_config.controls || ControlsView;

        // Initialize new Query Mapper and ControlsView
        t.controls = new t.controls_class({
          container: t.$('#qoogr-controls')
        });

        t.qmapper = new t.qmapper_class({
          controls: t.controls
        });

        t.qmapper.on('change', t.update_graph);

        var raw_data = t.get_raw_data();

        t.graph = new graph({
          container: t.$('#qoogr-graph')[0],
          graph_config: t.graph_config,
          raw_data: raw_data
        });
      });
    },

    teardown_graph: function() {
      if (this.controls) {
        this.controls.teardown();
      }
      if (this.graph) {
        this.graph.remove();
      }
    },

    update_graph: function() {
      this.graph.update(this.get_raw_data());
    },

    get_raw_data: function() {
      var t = this;
      var qtree = t.qmapper.qtree;
      qtree.select.from = t.graph_config.from;

      return t.qexec.execute_query(
        t.array_map,
        t.qmapper.qtree
      );
    }

  });

  var SelectorView = Backbone.View.extend({

    el: $('#qoogr-selector'),

    events: {
      'click li': 'load_view',
    },

    // Subclasses should define a template, ala:
    // $tmpl: $(Handlebars.compile(selector_tmpl)()),

    initialize: function() {
      this.render();
    },

    render: function() {
      console.log('rendering graphselectorview');
      this.$el.html( this.$tmpl );
    },

    load_view: function(e) {
      e.stopImmediatePropagation();
      // Get the view associated with the li by the data attr.
      graph = e.currentTarget.dataset.graph;

      // The selector should not handle graph loading... leave it up to the
      // listening controller to handle it by triggering an event.
      this.trigger('load_graph', graph);
    }

  });

  var ControlsView = Backbone.View.extend({

    // Subclasses shoud define a template here, ala:
    // $tmpl: $(Handlebars.compile(controls_tmpl)()),

    initialize: function(options) {
      var t = this;
      t.container = t.options.container;
      t.render();

      // Maintain an array of filter data objects to iterate over.
      t.filter_collections = []

      // Set up individual control widgets here.
      // Don't forget to add the filter data objects to the array.

    },

    render: function() {
      console.log('rendering graphcontrolsview');
      this.$el.html( this.$tmpl );
      this.container.append(this.$el);
    },

    teardown: function() {
      // Call teardown on individual controls here.
    }

  });

  var QueryMapper = Controller.extend({

    initialize: function(options) {
      _.bindAll(this, 'map_controls');
      this.controls = options.controls;
      this.controls.on('change', this.map_controls);
      this.map_controls();
    },

    get_qtree_base: function() {
      // The following is a stub for a basic filter qtree.
      return {
        select: {
          where: {
            and: [] // We are going to insert filter clauses here.
          }
        }
      }
    },

    map_controls: function() {
      var t = this;

      // Build a new qtree by reading each control's data model.
      t.qtree = t.get_qtree_base()

      // Alias the toplevel and subclause for brevity.
      var and = t.qtree.select.where.and;

      // Push subclauses from filter data objects into query tree.
      _.each(t.controls.filter_collections, function(control_col) {
        and.push(control_col.get_subtree());
      });

      // Fire change event to alert listeners qtree has changed.
      t.trigger('change');
    }

  });

  // Return exports.
  return {
    Controller: Controller,
    QoogrView: QoogrView,
    SelectorView: SelectorView,
    ControlsView: ControlsView,
    QueryMapper: QueryMapper,
  };

});

<|endoftext|>


<commit_before>var slice = [].slice,
    running = {};

function noop() {}

export default function(parallelism) {
  var q,
      tasks = [],
      started = 0, // number of tasks that have been started (and perhaps finished)
      active = 0, // number of tasks currently being executed (started but not finished)
      remaining = 0, // number of tasks not yet finished
      popping, // inside a synchronous task callback?
      error = null,
      callback = noop,
      all;

  parallelism = arguments.length ? +parallelism : Infinity;

  function pop() {
    while (popping = started < tasks.length && active < parallelism) {
      var i = started++,
          t = tasks[i],
          j = t.length - 1,
          c = t[j];
      tasks[i] = running;
      ++active;
      t[j] = finished(i);
      c.apply(null, t);
    }
  }

  function finished(i) {
    return function(e, r) {
      if (tasks[i] !== running) throw new Error;
      tasks[i] = null;
      --active;
      if (error != null) return;
      if (e != null) {
        error = e; // ignore new tasks and squelch active callbacks
        started = remaining = NaN; // stop queued tasks from starting
        notify();
      } else {
        tasks[i] = r;
        if (--remaining) popping || pop();
        else notify();
      }
    };
  }

  function check() {
    if (callback !== noop) throw new Error;
  }

  function notify() {
    if (error != null) callback(error);
    else if (all) callback(error, tasks);
    else callback.apply(null, [error].concat(tasks));
  }

  return q = {
    defer: function(f) {
      check();
      if (!error) {
        var t = slice.call(arguments, 1);
        t.push(f);
        tasks.push(t);
        ++remaining;
        pop();
      }
      return q;
    },
    await: function(f) {
      check();
      callback = f, all = false;
      if (!remaining) notify();
      return q;
    },
    awaitAll: function(f) {
      check();
      callback = f, all = true;
      if (!remaining) notify();
      return q;
    }
  };
}
<commit_msg>Rename variable for clarity.<commit_after>var slice = [].slice,
    running = {};

function noop() {}

export default function(parallelism) {
  var q,
      tasks = [],
      started = 0, // number of tasks that have been started (and perhaps finished)
      active = 0, // number of tasks currently being executed (started but not finished)
      remaining = 0, // number of tasks not yet finished
      popping, // inside a synchronous task callback?
      error = null,
      callback = noop,
      callbackAll;

  parallelism = arguments.length ? +parallelism : Infinity;

  function pop() {
    while (popping = started < tasks.length && active < parallelism) {
      var i = started++,
          t = tasks[i],
          j = t.length - 1,
          c = t[j];
      tasks[i] = running;
      ++active;
      t[j] = finished(i);
      c.apply(null, t);
    }
  }

  function finished(i) {
    return function(e, r) {
      if (tasks[i] !== running) throw new Error;
      tasks[i] = null;
      --active;
      if (error != null) return;
      if (e != null) {
        error = e; // ignore new tasks and squelch active callbacks
        started = remaining = NaN; // stop queued tasks from starting
        notify();
      } else {
        tasks[i] = r;
        if (--remaining) popping || pop();
        else notify();
      }
    };
  }

  function check() {
    if (callback !== noop) throw new Error;
  }

  function notify() {
    if (error != null) callback(error);
    else if (callbackAll) callback(error, tasks);
    else callback.apply(null, [error].concat(tasks));
  }

  return q = {
    defer: function(f) {
      check();
      if (!error) {
        var t = slice.call(arguments, 1);
        t.push(f);
        tasks.push(t);
        ++remaining;
        pop();
      }
      return q;
    },
    await: function(f) {
      check();
      callback = f, callbackAll = false;
      if (!remaining) notify();
      return q;
    },
    awaitAll: function(f) {
      check();
      callback = f, callbackAll = true;
      if (!remaining) notify();
      return q;
    }
  };
}
<|endoftext|>


<commit_before>import assign from 'object-assign'
import PropTypes from 'prop-types'
import React from 'react'
import { isLikeRule, style, merge } from './index.js'

if(process.env.NODE_ENV === 'development' || !process.env.NODE_ENV) {
  console.warn('[Deprecation] In glamor v3 this file will be published as a standalone package: "glamor-react". See https://github.com/threepointone/glamor/issues/204 for more information.') // eslint-disable-line no-console
}

export * from './index.js' // convenience

// allows for elements to have a 'css' prop
export function createElement(tag, allProps, ...children) {
  // todo - pull ids from className as well?
  if(allProps && allProps.css) {
    let { css, className, ...props } = allProps
    let rule = Array.isArray(css) ? merge(...css) :
        isLikeRule(css) ? css :
        style(css)
    className = className ? className + ' ' + rule : rule
    props.className = className
    return React.createElement(tag, props, ...children)
  }
  return React.createElement(tag, allProps, ...children)
}

export const dom = createElement

// css vars, done right
// see examples/vars for usage
export function vars(value = {}) {
  return function (Target) {
    return class Vars extends React.Component {
      static childContextTypes = {
        glamorCssVars: PropTypes.object
      }
      static contextTypes = {
        glamorCssVars: PropTypes.object
      }
      getChildContext() {
        return {
          glamorCssVars: {
            ...this.context.glamorCssVars,
            ...((typeof value === 'function' ? value(this.props) : value))
          }
        }
      }
      render() {
        return React.createElement(Target,
          { ...this.props, vars: this.context.glamorCssVars || (typeof value === 'function' ? value(this.props) : value)  },
          this.props.children
        )
      }
    }
  }
}

let themeIndex = 0

export function makeTheme() {

  let key = `data-glamor-theme-${themeIndex++}`

  let fn = (_default) => {
    return Target => {
      return class Theme extends React.Component {
        static contextTypes = {
          [key]: PropTypes.arrayOf(PropTypes.object)
        }
        render() {
          return React.createElement(Target, {
            ...this.props,
            [key]: merge( typeof _default === 'function' ?
                _default(this.props) :
                _default,
              ...(this.context[key] || []) )
          })
        }
      }
    }
  }

  fn.key = key
  fn.add = (_style) => {
    return Target => {
      return class ThemeOverride extends React.Component {
        static contextTypes = {
          [key]: PropTypes.arrayOf(PropTypes.object)
        }
        static childContextTypes = {
          [key]: PropTypes.arrayOf(PropTypes.object)
        }
        getChildContext() {
          return {
            [key]: [ typeof _style === 'function' ?
              _style(this.props) :
              _style,
              ...(this.context[key] || []) ]
          }
        }
        render() {
          return React.createElement(Target, this.props)
        }
      }
    }
  }
  return fn

}

function toStyle(s) {
  return s!= null && isLikeRule(s) ? s : style(s)
}

// propMerge will take an arbitrary object "props", filter out glamor data-css-* styles and merge it with "mergeStyle"
// use it for react components composing
export function propMerge(mergeStyle, props) {
  const glamorStyleKeys = Object.keys(props).filter(x => !!/data\-css\-([a-zA-Z0-9]+)/.exec(x))

  // no glamor styles in obj
  if (glamorStyleKeys.length === 0) {
    return {
      ...props,
      ...toStyle(mergeStyle)
    }
  }

  if (glamorStyleKeys.length > 1) {
    console.warn('[glamor] detected multiple data attributes on an element. This may lead to unexpected style because of css insertion order.') // eslint-disable-line no-console

    // just append "mergeStyle" to props, because we dunno in which order glamor styles were added to props
    return {
      ...props,
      ...toStyle(mergeStyle)
    }
  }

  const dataCssKey= glamorStyleKeys[0]
  const cssData = props[dataCssKey]

  const mergedStyles = merge(mergeStyle, { [dataCssKey]: cssData })

  const restProps = assign({}, props)
  delete restProps[dataCssKey]

  return {
    ...restProps,
    ...mergedStyles
  }
}
<commit_msg>Revert unwanted changes introduced by react-codemod transform.<commit_after>import assign from 'object-assign'
import PropTypes from 'prop-types'
import React from 'react'
import { isLikeRule, style, merge } from './index.js'

if(process.env.NODE_ENV === 'development' || !process.env.NODE_ENV) {
  console.warn('[Deprecation] In glamor v3 this file will be published as a standalone package: "glamor-react". See https://github.com/threepointone/glamor/issues/204 for more information.') // eslint-disable-line no-console
}

export * from './index.js' // convenience

// allows for elements to have a 'css' prop
export function createElement(tag, allProps, ...children) {
  // todo - pull ids from className as well?
  if(allProps && allProps.css) {
    let { css, className, ...props } = allProps
    let rule = Array.isArray(css) ? merge(...css) :
        isLikeRule(css) ? css :
        style(css)
    className = className ? className + ' ' + rule : rule
    props.className = className
    return React.createElement(tag, props, ...children)
  }
  return React.createElement(tag, allProps, ...children)
}

export const dom = createElement

// css vars, done right
// see examples/vars for usage
export function vars(value = {}) {
  return function (Target) {
    return class Vars extends React.Component {
      static childContextTypes = {
        glamorCssVars: PropTypes.object
      }
      static contextTypes = {
        glamorCssVars: PropTypes.object
      }
      getChildContext() {
        return {
          glamorCssVars: {
            ...this.context.glamorCssVars,
            ...typeof value === 'function' ? value(this.props) : value
          }
        }
      }
      render() {
        return React.createElement(Target,
          { ...this.props, vars: this.context.glamorCssVars || (typeof value === 'function' ? value(this.props) : value)  },
          this.props.children
        )
      }
    }
  }
}

let themeIndex = 0

export function makeTheme() {

  let key = `data-glamor-theme-${themeIndex++}`

  let fn = (_default) => {
    return Target => {
      return class Theme extends React.Component {
        static contextTypes = {
          [key]: PropTypes.arrayOf(PropTypes.object)
        }
        render() {
          return React.createElement(Target, {
            ...this.props,
            [key]: merge( typeof _default === 'function' ?
                _default(this.props) :
                _default,
              ...(this.context[key] || []) )
          })
        }
      }
    }
  }

  fn.key = key
  fn.add = (_style) => {
    return Target => {
      return class ThemeOverride extends React.Component {
        static contextTypes = {
          [key]: PropTypes.arrayOf(PropTypes.object)
        }
        static childContextTypes = {
          [key]: PropTypes.arrayOf(PropTypes.object)
        }
        getChildContext() {
          return {
            [key]: [ typeof _style === 'function' ?
              _style(this.props) :
              _style,
              ...this.context[key] || [] ]
          }
        }
        render() {
          return React.createElement(Target, this.props)
        }
      }
    }
  }
  return fn

}

function toStyle(s) {
  return s!= null && isLikeRule(s) ? s : style(s)
}

// propMerge will take an arbitrary object "props", filter out glamor data-css-* styles and merge it with "mergeStyle"
// use it for react components composing
export function propMerge(mergeStyle, props) {
  const glamorStyleKeys = Object.keys(props).filter(x => !!/data\-css\-([a-zA-Z0-9]+)/.exec(x))

  // no glamor styles in obj
  if (glamorStyleKeys.length === 0) {
    return {
      ...props,
      ...toStyle(mergeStyle)
    }
  }

  if (glamorStyleKeys.length > 1) {
    console.warn('[glamor] detected multiple data attributes on an element. This may lead to unexpected style because of css insertion order.') // eslint-disable-line no-console

    // just append "mergeStyle" to props, because we dunno in which order glamor styles were added to props
    return {
      ...props,
      ...toStyle(mergeStyle)
    }
  }

  const dataCssKey= glamorStyleKeys[0]
  const cssData = props[dataCssKey]

  const mergedStyles = merge(mergeStyle, { [dataCssKey]: cssData })

  const restProps = assign({}, props)
  delete restProps[dataCssKey]

  return {
    ...restProps,
    ...mergedStyles
  }
}
<|endoftext|>


<commit_before>import createResourcesFromReducers from './createResourcesFromReducers';
import dispatch from './dispatch';
import getConsensus from './getConsensus';
import connectActionSets from './connectActionSets';
import { FLAMBEAU_ACTION_TYPE } from './types';

export function createRootReducer({ reducers, idToProps }) {
  const { resources, states } = createResourcesFromReducers({ reducers, idToProps });
  const initialState = Object.assign(states, {
    _resources: resources
  });

  return (state = initialState, action) => {
    if (action.type === FLAMBEAU_ACTION_TYPE && action.actionSetID && action.actionID && action.payload) {
      const changedStates = dispatch({ resources, states: state })(action);

      return Object.assign({}, state, changedStates);
    }

    return state;
  };
}

export function connectActionSetsToStore({ actionSets, store: { dispatch, getState } }) {
  return connectActionSets({
    actionSets,
    dispatch,
    getConsensusForActionSet: (actionSetID) => {
      return getConsensus({
        resources: getState()._resources,
        getStates: getState
      })(actionSetID);
    }
  });
}
<commit_msg>Refactor Redux functionality to combine reducers<commit_after>import createResourcesFromReducers from './createResourcesFromReducers';
import combineReducers from './combineReducers';
import callAction from './callAction';
import getConsensus from './getConsensus';
import connectActionSets from './connectActionSets';
import { ACTION_TYPE, INTROSPECTION_TYPE } from './types';

const GET_CONSENSUS_TYPE = 'flambeau-consensus';
let latestConsensus;

export function createRootReducer({ reducers, idToProps }) {
  const reducer = combineReducers(reducers, { getPropsByID: () => idToProps });

  return (state = reducer.getInitialState(), action) => {
    if (action.type === ACTION_TYPE) {
      return callAction({
        responder: reducer,
        type: ACTION_TYPE,
        initialState: state,
        notFoundValue: state,
        payload: action.payload,
        actionSetID: action.actionSetID,
        actionID: action.actionID
      });
    }
    else if (action.type === GET_CONSENSUS_TYPE) {
      latestConsensus = getConsensus({
        responder: reducer,
        props: {},
        state: action.state,
        actionSetID: action.actionSetID,
        introspectionID: action.introspectionID,
        payload: action.payload
      });
    }

    return state;
  };
}

export function connectActionSetsToStore({ actionSets, store: { dispatch, getState } }) {
  return connectActionSets({
    actionSets,
    dispatch,
    getConsensusForActionSet: (actionSetID) => (introspectionID) => (payload = {}) => {
      dispatch({ type: GET_CONSENSUS_TYPE, actionSetID, introspectionID, payload, state: getState() });
      return latestConsensus;
      //return getState()._consensus;
    }
  });
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
/**
 * Exposed Node script to spawn Nodemon process.
 */

'use strict';

var argv = require( '../lib/cli' );
var nodemon = require( 'nodemon' );
var path = require( 'path' );
var spawn = require( '../lib/spawn' );

var nodemonCmd = [];
var nodemonScript = path.resolve( path.join( __dirname, 'compose.js' ) );

if ( argv.ext ) {
  nodemonCmd.push( '--ext' );
  nodemonCmd.push( argv.ext );
}

if ( argv.watch ) {
  nodemonCmd.push( '--watch' );
  nodemonCmd.push( argv.watch );
}

nodemonCmd.push( nodemonScript );
nodemonCmd = nodemonCmd.concat( process.argv.slice( 2 ) ).join( ' ' );
nodemon( nodemonCmd );

function kill( code ) {
  process.stdout.write( '\n' );
  process.exit( code || 0 );
}

process.on( 'SIGINT', function () {
  spawn( 'docker-compose', [ 'down' ].concat( argv._ ) )
  .then( kill )
  .catch( kill );
} );
<commit_msg>refactor: use compose() not spawn() on SIGINT<commit_after>#!/usr/bin/env node
/**
 * Exposed Node script to spawn Nodemon process.
 */

'use strict';

var argv = require( '../lib/cli' );
var compose = require( '../lib/compose' );
var nodemon = require( 'nodemon' );
var path = require( 'path' );

var nodemonCmd = [];
var nodemonScript = path.resolve( path.join( __dirname, 'compose.js' ) );

if ( argv.ext ) {
  nodemonCmd.push( '--ext' );
  nodemonCmd.push( argv.ext );
}

if ( argv.watch ) {
  nodemonCmd.push( '--watch' );
  nodemonCmd.push( argv.watch );
}

nodemonCmd.push( nodemonScript );
nodemonCmd = nodemonCmd.concat( process.argv.slice( 2 ) ).join( ' ' );
nodemon( nodemonCmd );

function kill( code ) {
  process.stdout.write( '\n' );
  process.exit( code || 0 );
}

nodemon.on( 'crash', kill );
process.on( 'SIGINT', function () {
  compose( 'stop', '--timeout', '0' )
  .then( compose.then( 'rm', '--force' ) )
  .then( kill )
  .catch( kill )
  ;
} );
<|endoftext|>


<commit_before>export class Scene {
  #tweenables = [];

  /**
   * The {@link shifty.Scene} class provides a way to control groups of {@link
   * shifty.Tweenable}s. It is lightweight and minimalistic and meant to
   * provide performant {@link shifty.Tweenable} batch control that users of
   * Shifty might otherwise have to implement themselves. It is **not** a
   * robust timeline solution, and it does **not** provide utilities for
   * sophisticated animation sequencing or orchestration. If that is what you
   * need for your project, consider using a more robust tool such as
   * [Rekapi](http://jeremyckahn.github.io/rekapi/doc/) (a timeline layer built
   * on top of Shifty).
   *
   * Please be aware that {@link shifty.Scene} does **not** perform any
   * automatic cleanup. If you want to remove a {@link shifty.Tweenable} from a
   * {@link shifty.Scene}, you must do so explicitly with either {@link
   * shifty.Scene#remove} or {@link shifty.Scene#empty}.
   *
   *

   * See the Pen
   * Shifty Scene Demo by Jeremy Kahn (@jeremyckahn)
   * on CodePen.
   *

   *
   * @param {...shifty.Tweenable} tweenables
   * @see https://codepen.io/jeremyckahn/pen/qvZKbe
   * @constructs shifty.Scene
   */
  constructor(...tweenables) {
    tweenables.forEach(this.add.bind(this));
  }

  /**
   * A copy of the internal {@link shifty.Tweenable}s array.
   * @member shifty.Scene#tweenables
   * @type {Array.<shifty.Tweenable>}
   * @readonly
   */
  get tweenables() {
    return [...this.#tweenables];
  }

  /**
   * The {@link external:Promise}s for all {@link shifty.Tweenable}s in this
   * {@link shifty.Scene} that have been configured with {@link
   * shifty.Tweenable#setConfig}. Note that each call of {@link
   * shifty.Scene#play} or {@link shifty.Scene#pause} creates new {@link
   * external:Promise}s:
   *
   *     const scene = new Scene(new Tweenable());
   *     scene.play();
   *
   *     Promise.all(scene.promises).then(() =>
   *       // Plays the scene again upon completion, but a new promise is
   *       // created so this line only runs once.
   *       scene.play()
   *     );
   *
   * @member shifty.Scene#promises
   * @type {Array.<external:Promise>}
   * @readonly
   */
  get promises() {
    return this.#tweenables.map(({ _promise }) => _promise);
  }

  /**
   * Add a {@link shifty.Tweenable} to be controlled by this {@link
   * shifty.Scene}.
   * @method shifty.Scene#add
   * @param {shifty.Tweenable} tweenable
   * @return {shifty.Tweenable} The {@link shifty.Tweenable} that was added.
   */
  add(tweenable) {
    this.#tweenables.push(tweenable);

    return tweenable;
  }

  /**
   * Remove a {@link shifty.Tweenable} that is controlled by this {@link
   * shifty.Scene}.
   * @method shifty.Scene#remove
   * @param {shifty.Tweenable} tweenable
   * @return {shifty.Tweenable} The {@link shifty.Tweenable} that was removed.
   */
  remove(tweenable) {
    const index = this.#tweenables.indexOf(tweenable);

    if (~index) {
      this.#tweenables.splice(index, 1);
    }

    return tweenable;
  }

  /**
   * [Remove]{@link shifty.Scene#remove} all {@link shifty.Tweenable}s in this {@link
   * shifty.Scene}.
   * @method shifty.Scene#empty
   * @return {Array.<shifty.Tweenable>}
   */
  empty() {
    // Deliberate of the tweenables getter here to create a temporary array
    return this.tweenables.map(this.remove.bind(this));
  }

  /**
   * Is `true` if any {@link shifty.Tweenable} in this {@link shifty.Scene} is
   * playing.
   * @method shifty.Scene#isPlaying
   * @return {boolean}
   */
  isPlaying() {
    return this.#tweenables.some(tweenable => tweenable.isPlaying());
  }

  /**
   * Play all {@link shifty.Tweenable}s from their beginning.
   * @method shifty.Scene#play
   * @return {shifty.Scene}
   */
  play() {
    this.#tweenables.forEach(tweenable => tweenable.tween());

    return this;
  }

  /**
   * {@link shifty.Tweenable#pause} all {@link shifty.Tweenable}s in this
   * {@link shifty.Scene}.
   * @method shifty.Scene#pause
   * @return {shifty.Scene}
   */
  pause() {
    this.#tweenables.forEach(tweenable => tweenable.pause());
    return this;
  }

  /**
   * {@link shifty.Tweenable#resume} all paused {@link shifty.Tweenable}s.
   * @method shifty.Scene#resume
   * @return {shifty.Scene}
   */
  resume() {
    this.#tweenables.forEach(tweenable => tweenable.resume());

    return this;
  }

  /**
   * {@link shifty.Tweenable#stop} all {@link shifty.Tweenable}s in this {@link
   * shifty.Scene}.
   * @method shifty.Scene#stop
   * @param {boolean} [gotoEnd]
   * @return {shifty.Scene}
   */
  stop(gotoEnd) {
    this.#tweenables.forEach(tweenable => tweenable.stop(gotoEnd));
    return this;
  }
}
<commit_msg>Small documentation tweaks<commit_after>export class Scene {
  #tweenables = [];

  /**
   * The {@link shifty.Scene} class provides a way to control groups of {@link
   * shifty.Tweenable}s. It is lightweight, minimalistic, and meant to provide
   * performant {@link shifty.Tweenable} batch control that users of Shifty
   * might otherwise have to implement themselves. It is **not** a robust
   * timeline solution, and it does **not** provide utilities for sophisticated
   * animation sequencing or orchestration. If that is what you need for your
   * project, consider using a more robust tool such as
   * [Rekapi](http://jeremyckahn.github.io/rekapi/doc/) (a timeline layer built
   * on top of Shifty).
   *
   * Please be aware that {@link shifty.Scene} does **not** perform any
   * automatic cleanup. If you want to remove a {@link shifty.Tweenable} from a
   * {@link shifty.Scene}, you must do so explicitly with either {@link
   * shifty.Scene#remove} or {@link shifty.Scene#empty}.
   *
   *

   * See the Pen
   * Shifty Scene Demo by Jeremy Kahn (@jeremyckahn)
   * on CodePen.
   *

   *
   * @param {...shifty.Tweenable} tweenables
   * @see https://codepen.io/jeremyckahn/pen/qvZKbe
   * @constructs shifty.Scene
   */
  constructor(...tweenables) {
    tweenables.forEach(this.add.bind(this));
  }

  /**
   * A copy of the internal {@link shifty.Tweenable}s array.
   * @member shifty.Scene#tweenables
   * @type {Array.<shifty.Tweenable>}
   * @readonly
   */
  get tweenables() {
    return [...this.#tweenables];
  }

  /**
   * The {@link external:Promise}s for all {@link shifty.Tweenable}s in this
   * {@link shifty.Scene} that have been configured with {@link
   * shifty.Tweenable#setConfig}. Note that each call of {@link
   * shifty.Scene#play} or {@link shifty.Scene#pause} creates new {@link
   * external:Promise}s:
   *
   *     const scene = new Scene(new Tweenable());
   *     scene.play();
   *
   *     Promise.all(scene.promises).then(() =>
   *       // Plays the scene again upon completion, but a new promise is
   *       // created so this line only runs once.
   *       scene.play()
   *     );
   *
   * @member shifty.Scene#promises
   * @type {Array.<external:Promise>}
   * @readonly
   */
  get promises() {
    return this.#tweenables.map(({ _promise }) => _promise);
  }

  /**
   * Add a {@link shifty.Tweenable} to be controlled by this {@link
   * shifty.Scene}.
   * @method shifty.Scene#add
   * @param {shifty.Tweenable} tweenable
   * @return {shifty.Tweenable} The {@link shifty.Tweenable} that was added.
   */
  add(tweenable) {
    this.#tweenables.push(tweenable);

    return tweenable;
  }

  /**
   * Remove a {@link shifty.Tweenable} that is controlled by this {@link
   * shifty.Scene}.
   * @method shifty.Scene#remove
   * @param {shifty.Tweenable} tweenable
   * @return {shifty.Tweenable} The {@link shifty.Tweenable} that was removed.
   */
  remove(tweenable) {
    const index = this.#tweenables.indexOf(tweenable);

    if (~index) {
      this.#tweenables.splice(index, 1);
    }

    return tweenable;
  }

  /**
   * [Remove]{@link shifty.Scene#remove} all {@link shifty.Tweenable}s in this {@link
   * shifty.Scene}.
   * @method shifty.Scene#empty
   * @return {Array.<shifty.Tweenable>} The {@link shifty.Tweenable}s that were
   * removed.
   */
  empty() {
    // Deliberate of the tweenables getter here to create a temporary array
    return this.tweenables.map(this.remove.bind(this));
  }

  /**
   * Is `true` if any {@link shifty.Tweenable} in this {@link shifty.Scene} is
   * playing.
   * @method shifty.Scene#isPlaying
   * @return {boolean}
   */
  isPlaying() {
    return this.#tweenables.some(tweenable => tweenable.isPlaying());
  }

  /**
   * Play all {@link shifty.Tweenable}s from their beginning.
   * @method shifty.Scene#play
   * @return {shifty.Scene}
   */
  play() {
    this.#tweenables.forEach(tweenable => tweenable.tween());

    return this;
  }

  /**
   * {@link shifty.Tweenable#pause} all {@link shifty.Tweenable}s in this
   * {@link shifty.Scene}.
   * @method shifty.Scene#pause
   * @return {shifty.Scene}
   */
  pause() {
    this.#tweenables.forEach(tweenable => tweenable.pause());
    return this;
  }

  /**
   * {@link shifty.Tweenable#resume} all paused {@link shifty.Tweenable}s.
   * @method shifty.Scene#resume
   * @return {shifty.Scene}
   */
  resume() {
    this.#tweenables.forEach(tweenable => tweenable.resume());

    return this;
  }

  /**
   * {@link shifty.Tweenable#stop} all {@link shifty.Tweenable}s in this {@link
   * shifty.Scene}.
   * @method shifty.Scene#stop
   * @param {boolean} [gotoEnd]
   * @return {shifty.Scene}
   */
  stop(gotoEnd) {
    this.#tweenables.forEach(tweenable => tweenable.stop(gotoEnd));
    return this;
  }
}
<|endoftext|>


<commit_before>'use strict';

/**
 * For general instructions, see: https://www.npmjs.com/package/flightplan
 *
 * To configure, first set the "plan.target" sections below.
 * Then, set: DIRECTORY_NAME appropriately.
 * Then, to run, do:
 *   ssh-add [path-to-your-private-key]
 *   fly prod
 *
 * Also, make sure your user is setup correctly on the remote server. Scenario:
 * 'example' is the user for connecting to the host and 'www-data' is the user
 * under which you want to execute commands with sudo.
 *
 * 1. 'example' has to be in the sudo group:
 * $ groups example
 * example : example sudo
 *
 * 2. 'example' needs to be able to run sudo -u 'www-data' without a password.
 * In order to do this, add the following line to /etc/sudoers via the `visudo` command.
 * (Make sure it's at the bottom of the file.)
 * example ALL=(www-data) NOPASSWD: ALL
 *
 * 3. user 'www-data' needs to have a login shell (e.g. bash, sh, zsh, ...)
 * $ cat /etc/passwd | grep www-data
 * www-data:x:33:33::/var/www-data:/bin/bash           # GOOD
 * www-data:x:33:33::/var/www-data:/usr/sbin/no-login  # BAD
 */

const plan = require('flightplan');

plan.target('prod', [
  {
    host: 'nite-lite.net',
    username: 'mime',
    agent: process.env.SSH_AUTH_SOCK
  }
], {
  user: 'www-data',
});

const DIRECTORY_NAME = 'helloworld';

const time = new Date().getTime();
const tmpDir = `${DIRECTORY_NAME}-${time}`;
const remoteTmpDir = `/tmp/${tmpDir}`;

// run commands on localhost
plan.local(function(local) {
  local.log('Copying files to remote hosts...');
  local.with(`cd ..`, () => {
    const filesToCopy = local.exec(`git ls-files`, { silent: true });

    // rsync git files to all the target's remote hosts
    local.transfer(filesToCopy, remoteTmpDir);
  });
});

// run commands on the target's remote hosts
plan.remote(function(remote) {
  const user = plan.runtime.options.user;
  const varTmpDir = `/var/www/${tmpDir}`;
  const destDir = `/var/www/${DIRECTORY_NAME}`;

  remote.log('Moving folder to web root...');
  remote.sudo(`cp -R ${remoteTmpDir} /var/www`, { user });
  remote.rm(`-rf ${remoteTmpDir}`);

  remote.log('Copying .env file over...');
  remote.sudo(`cp ${destDir}/.env ${varTmpDir}/`, { user, failsafe: true });

  remote.log('Seeing if we can just reuse the previous node_modules folder...');
  const isNPMUnchanged = remote.sudo(`cmp ${destDir}/package.json ${varTmpDir}/package.json`, { user, failsafe: true });

  if (isNPMUnchanged.code === 0 || (isNPMUnchanged.stderr && isNPMUnchanged.stderr.indexOf('cmp: EOF') === 0 /* ignore NOEOL false positive */)) {
    remote.log('package.json is unchanged. Reusing previous node_modules folder...');
    remote.sudo(`mv ${destDir}/node_modules ${varTmpDir}`, { user });
  } else {
    remote.log('package.json has changed. Installing dependencies...');
    remote.sudo(`npm --production --prefix ${varTmpDir} install ${varTmpDir}`, { user });
  }

  remote.log('Reloading application...');
  remote.sudo(`ln -snf /var/www/resource ${varTmpDir}/resource`, { user });
  remote.sudo(`ln -snf ${varTmpDir} ${destDir}`, { user });

  // XXX(mime) :-/ sucks but getCSSModuleLocalIdent gives hashes based on filepaths... need to look for workaround
  remote.log('Building production files...');
  remote.sudo(`cd ${varTmpDir}; npm run build`, { user });

  // Copy over sessions.
  remote.sudo(`cp -R ${destDir}/sessions ${varTmpDir}`, { user, failsafe: true });

  // TODO(mime); doing `pm2 kill` is less than ideal - but pm2 doesn't know how to switch out symlinked directories :-/
  // This is done here for the sake of keeping all-the-things as zero-config as possible.
  // For a cleaner deploy take a look at this doc: http://pm2.keymetrics.io/docs/tutorials/capistrano-like-deployments
  remote.sudo(`cd ${destDir}; pm2 kill; pm2 startOrReload ecosystem.config.js`, { user });
});
<commit_msg>flightplan: copy over sessions with new build, take 2<commit_after>'use strict';

/**
 * For general instructions, see: https://www.npmjs.com/package/flightplan
 *
 * To configure, first set the "plan.target" sections below.
 * Then, set: DIRECTORY_NAME appropriately.
 * Then, to run, do:
 *   ssh-add [path-to-your-private-key]
 *   fly prod
 *
 * Also, make sure your user is setup correctly on the remote server. Scenario:
 * 'example' is the user for connecting to the host and 'www-data' is the user
 * under which you want to execute commands with sudo.
 *
 * 1. 'example' has to be in the sudo group:
 * $ groups example
 * example : example sudo
 *
 * 2. 'example' needs to be able to run sudo -u 'www-data' without a password.
 * In order to do this, add the following line to /etc/sudoers via the `visudo` command.
 * (Make sure it's at the bottom of the file.)
 * example ALL=(www-data) NOPASSWD: ALL
 *
 * 3. user 'www-data' needs to have a login shell (e.g. bash, sh, zsh, ...)
 * $ cat /etc/passwd | grep www-data
 * www-data:x:33:33::/var/www-data:/bin/bash           # GOOD
 * www-data:x:33:33::/var/www-data:/usr/sbin/no-login  # BAD
 */

const plan = require('flightplan');

plan.target('prod', [
  {
    host: 'nite-lite.net',
    username: 'mime',
    agent: process.env.SSH_AUTH_SOCK
  }
], {
  user: 'www-data',
});

const DIRECTORY_NAME = 'helloworld';

const time = new Date().getTime();
const tmpDir = `${DIRECTORY_NAME}-${time}`;
const remoteTmpDir = `/tmp/${tmpDir}`;

// run commands on localhost
plan.local(function(local) {
  local.log('Copying files to remote hosts...');
  local.with(`cd ..`, () => {
    const filesToCopy = local.exec(`git ls-files`, { silent: true });

    // rsync git files to all the target's remote hosts
    local.transfer(filesToCopy, remoteTmpDir);
  });
});

// run commands on the target's remote hosts
plan.remote(function(remote) {
  const user = plan.runtime.options.user;
  const varTmpDir = `/var/www/${tmpDir}`;
  const destDir = `/var/www/${DIRECTORY_NAME}`;

  remote.log('Moving folder to web root...');
  remote.sudo(`cp -R ${remoteTmpDir} /var/www`, { user });
  remote.rm(`-rf ${remoteTmpDir}`);

  remote.log('Copying .env file over...');
  remote.sudo(`cp ${destDir}/.env ${varTmpDir}/`, { user, failsafe: true });

  remote.log('Seeing if we can just reuse the previous node_modules folder...');
  const isNPMUnchanged = remote.sudo(`cmp ${destDir}/package.json ${varTmpDir}/package.json`, { user, failsafe: true });

  if (isNPMUnchanged.code === 0 || (isNPMUnchanged.stderr && isNPMUnchanged.stderr.indexOf('cmp: EOF') === 0 /* ignore NOEOL false positive */)) {
    remote.log('package.json is unchanged. Reusing previous node_modules folder...');
    remote.sudo(`mv ${destDir}/node_modules ${varTmpDir}`, { user });
  } else {
    remote.log('package.json has changed. Installing dependencies...');
    remote.sudo(`npm --production --prefix ${varTmpDir} install ${varTmpDir}`, { user });
  }

  // Copy over sessions.
  remote.sudo(`cp -R ${destDir}/sessions ${varTmpDir}`, { user, failsafe: true });

  remote.log('Reloading application...');
  remote.sudo(`ln -snf /var/www/resource ${varTmpDir}/resource`, { user });
  remote.sudo(`ln -snf ${varTmpDir} ${destDir}`, { user });

  // XXX(mime) :-/ sucks but getCSSModuleLocalIdent gives hashes based on filepaths... need to look for workaround
  remote.log('Building production files...');
  remote.sudo(`cd ${varTmpDir}; npm run build`, { user });

  // TODO(mime); doing `pm2 kill` is less than ideal - but pm2 doesn't know how to switch out symlinked directories :-/
  // This is done here for the sake of keeping all-the-things as zero-config as possible.
  // For a cleaner deploy take a look at this doc: http://pm2.keymetrics.io/docs/tutorials/capistrano-like-deployments
  remote.sudo(`cd ${destDir}; pm2 kill; pm2 startOrReload ecosystem.config.js`, { user });
});
<|endoftext|>


<commit_before>"use strict";
<commit_msg>Add guh update note<commit_after>"use strict";

console.log(`"guh update" isn't implemented yet. Come back later!`);<|endoftext|>


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

/*
       Licensed to the Apache Software Foundation (ASF) under one
       or more contributor license agreements.  See the NOTICE file
       distributed with this work for additional information
       regarding copyright ownership.  The ASF licenses this file
       to you under the Apache License, Version 2.0 (the
       "License"); you may not use this file except in compliance
       with the License.  You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

       Unless required by applicable law or agreed to in writing,
       software distributed under the License is distributed on an
       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
       KIND, either express or implied.  See the License for the
       specific language governing permissions and limitations
       under the License.
*/
var shell = require('shelljs'),
    child_process = require('child_process'),
    Q     = require('q'),
    path  = require('path'),
    fs    = require('fs'),
    check_reqs = require('./check_reqs'),
    ROOT    = path.join(__dirname, '..', '..');

// Returns a promise.
function exec(command, opt_cwd) {
    var d = Q.defer();
    console.log('Running: ' + command);
    child_process.exec(command, { cwd: opt_cwd }, function(err, stdout, stderr) {
        stdout && console.log(stdout);
        stderr && console.error(stderr);
        if (err) d.reject(err);
        else d.resolve(stdout);
    });
    return d.promise;
}

function setShellFatal(value, func) {
    var oldVal = shell.config.fatal;
    shell.config.fatal = value;
    func();
    shell.config.fatal = oldVal;
}

function getFrameworkDir(projectPath, shared) {
    return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib');
}

function copyJsAndLibrary(projectPath, shared, projectName) {
    var nestedCordovaLibPath = getFrameworkDir(projectPath, false);
    shell.cp('-f', path.join(ROOT, 'framework', 'assets', 'www', 'cordova.js'), path.join(projectPath, 'assets', 'www', 'cordova.js'));
    // Don't fail if there are no old jars.
    setShellFatal(false, function() {
        shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function(oldJar) {
            console.log("Deleting " + oldJar);
            shell.rm('-f', oldJar);
        });
        // Delete old library project if it existed.
        if (shared) {
            shell.rm('-rf', nestedCordovaLibPath);
        } else {
            // Delete only the src, since eclipse can't handle its .project file being deleted.
            shell.rm('-rf', path.join(nestedCordovaLibPath, 'src'));
        }
    });
    if (!shared) {
        shell.mkdir('-p', nestedCordovaLibPath);
        shell.cp('-f', path.join(ROOT, 'framework', 'AndroidManifest.xml'), nestedCordovaLibPath);
        shell.cp('-f', path.join(ROOT, 'framework', 'project.properties'), nestedCordovaLibPath);
        shell.cp('-r', path.join(ROOT, 'framework', 'src'), nestedCordovaLibPath);
        // Create an eclipse project file and set the name of it to something unique.
        // Without this, you can't import multiple CordovaLib projects into the same workspace.
        var eclipseProjectFilePath = path.join(nestedCordovaLibPath, '.project');
        if (!fs.existsSync(eclipseProjectFilePath)) {
            var data = '<?xml version="1.0" encoding="UTF-8"?><projectDescription><name>' + projectName + '-' + 'CordovaLib</name></projectDescription>';
            fs.writeFileSync(eclipseProjectFilePath, data, 'utf8');
        }
    }
}

function runAndroidUpdate(projectPath, target_api, shared) {
    var targetFrameworkDir = getFrameworkDir(projectPath, shared);
    return exec('android update project --subprojects --path "' + projectPath + '" --target ' + target_api + ' --library "' + path.relative(projectPath, targetFrameworkDir) + '"');
}

function copyAntRules(projectPath) {
    var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
    shell.cp('-f', path.join(srcDir, 'custom_rules.xml'), projectPath);
}

function copyScripts(projectPath) {
    var srcScriptsDir = path.join(ROOT, 'bin', 'templates', 'cordova');
    var destScriptsDir = path.join(projectPath, 'cordova');
    // Delete old scripts directory if this is an update.
    shell.rm('-rf', destScriptsDir);
    // Copy in the new ones.
    shell.cp('-r', srcScriptsDir, projectPath);
    shell.cp('-r', path.join(ROOT, 'bin', 'node_modules'), destScriptsDir);
    shell.cp(path.join(ROOT, 'bin', 'check_reqs'), path.join(destScriptsDir, 'check_reqs'));
    shell.cp(path.join(ROOT, 'bin', 'lib', 'check_reqs.js'), path.join(projectPath, 'cordova', 'lib', 'check_reqs.js'));
    shell.cp(path.join(ROOT, 'bin', 'android_sdk_version'), path.join(destScriptsDir, 'android_sdk_version'));
    shell.cp(path.join(ROOT, 'bin', 'lib', 'android_sdk_version.js'), path.join(projectPath, 'cordova', 'lib', 'android_sdk_version.js'));
}

/**
 * $ create [options]
 *
 * Creates an android application with the given options.
 *
 * Options:
 *
 *   - `project_path` 	{String} Path to the new Cordova android project.
 *   - `package_name`{String} Package name, following reverse-domain style convention.
 *   - `project_name` 	{String} Project name.
 *   - 'project_template_dir' {String} Path to project template (override).
 *
 * Returns a promise.
 */

exports.createProject = function(project_path, package_name, project_name, project_template_dir, use_shared_project, use_cli_template) {
    var VERSION = fs.readFileSync(path.join(ROOT, 'VERSION'), 'utf-8').trim();

    // Set default values for path, package and name
    project_path = typeof project_path !== 'undefined' ? project_path : "CordovaExample";
    project_path = path.relative(process.cwd(), project_path);
    package_name = typeof package_name !== 'undefined' ? package_name : 'my.cordova.project';
    project_name = typeof project_name !== 'undefined' ? project_name : 'CordovaExample';
    project_template_dir = typeof project_template_dir !== 'undefined' ?
                           project_template_dir :
                           path.join(ROOT, 'bin', 'templates', 'project');

    var safe_activity_name = project_name.replace(/\W/g, '');
    var package_as_path = package_name.replace(/\./g, path.sep);
    var activity_dir    = path.join(project_path, 'src', package_as_path);
    var activity_path   = path.join(activity_dir, safe_activity_name + '.java');
    var target_api      = check_reqs.get_target();
    var manifest_path   = path.join(project_path, 'AndroidManifest.xml');

    // Check if project already exists
    if(fs.existsSync(project_path)) {
        return Q.reject('Project already exists! Delete and recreate');
    }

    if (!/[a-zA-Z0-9_]+\.[a-zA-Z0-9_](.[a-zA-Z0-9_])*/.test(package_name)) {
        return Q.reject('Package name must look like: com.company.Name');
    }

    // Check that requirements are met and proper targets are installed
    return check_reqs.run()
    .then(function() {
        // Log the given values for the project
        console.log('Creating Cordova project for the Android platform:');
        console.log('\tPath: ' + project_path);
        console.log('\tPackage: ' + package_name);
        console.log('\tName: ' + project_name);
        console.log('\tAndroid target: ' + target_api);

        console.log('Copying template files...');

        setShellFatal(true, function() {
            // copy project template
            shell.cp('-r', path.join(project_template_dir, 'assets'), project_path);
            shell.cp('-r', path.join(project_template_dir, 'res'), project_path);
            // Manually create directories that would be empty within the template (since git doesn't track directories).
            shell.mkdir(path.join(project_path, 'libs'));
            // Add in the proper eclipse project file.
            if (use_cli_template) {
                shell.cp(path.join(project_template_dir, 'eclipse-project-CLI'), path.join(project_path, '.project'));
            } else {
                shell.cp(path.join(project_template_dir, 'eclipse-project'), path.join(project_path, '.project'));
            }

            // copy cordova.js, cordova.jar and res/xml
            shell.cp('-r', path.join(ROOT, 'framework', 'res', 'xml'), path.join(project_path, 'res'));
            copyJsAndLibrary(project_path, use_shared_project, safe_activity_name);

            // interpolate the activity name and package
            shell.mkdir('-p', activity_dir);
            shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
            shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path);
            shell.sed('-i', /__NAME__/, project_name, path.join(project_path, 'res', 'values', 'strings.xml'));
            shell.sed('-i', /__NAME__/, project_name, path.join(project_path, '.project'));
            shell.sed('-i', /__ID__/, package_name, activity_path);

            shell.cp('-f', path.join(project_template_dir, 'AndroidManifest.xml'), manifest_path);
            shell.sed('-i', /__ACTIVITY__/, safe_activity_name, manifest_path);
            shell.sed('-i', /__PACKAGE__/, package_name, manifest_path);
            shell.sed('-i', /__APILEVEL__/, target_api.split('-')[1], manifest_path);
            copyScripts(project_path);
            copyAntRules(project_path);
        });
        // Link it to local android install.
        return runAndroidUpdate(project_path, target_api, use_shared_project);
    }).then(function() {
        console.log('Project successfully created.');
    });
}

// Attribute removed in Cordova 4.4 (CB-5447).
function removeDebuggableFromManifest(projectPath) {
    var manifestPath   = path.join(projectPath, 'AndroidManifest.xml');
    shell.sed('-i', /\s*android:debuggable="true"/, '', manifestPath);
}

// Returns a promise.
exports.updateProject = function(projectPath) {
    var version = fs.readFileSync(path.join(ROOT, 'VERSION'), 'utf-8').trim();
    // Check that requirements are met and proper targets are installed
    return check_reqs.run()
    .then(function() {
        var target_api = check_reqs.get_target();
        copyJsAndLibrary(projectPath, false, null);
        copyScripts(projectPath);
        copyAntRules(projectPath);
        removeDebuggableFromManifest(projectPath);
        return runAndroidUpdate(projectPath, target_api, false)
        .then(function() {
            console.log('Android project is now at version ' + version);
            console.log('If you updated from a pre-3.2.0 version and use an IDE, we now require that you import the "CordovaLib" library project.');
        });
    });
};

<commit_msg>CB-5889 Make update script find project name instead of using "null" for CordovaLib<commit_after>#!/usr/bin/env node

/*
       Licensed to the Apache Software Foundation (ASF) under one
       or more contributor license agreements.  See the NOTICE file
       distributed with this work for additional information
       regarding copyright ownership.  The ASF licenses this file
       to you under the Apache License, Version 2.0 (the
       "License"); you may not use this file except in compliance
       with the License.  You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

       Unless required by applicable law or agreed to in writing,
       software distributed under the License is distributed on an
       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
       KIND, either express or implied.  See the License for the
       specific language governing permissions and limitations
       under the License.
*/
var shell = require('shelljs'),
    child_process = require('child_process'),
    Q     = require('q'),
    path  = require('path'),
    fs    = require('fs'),
    check_reqs = require('./check_reqs'),
    ROOT    = path.join(__dirname, '..', '..');

// Returns a promise.
function exec(command, opt_cwd) {
    var d = Q.defer();
    console.log('Running: ' + command);
    child_process.exec(command, { cwd: opt_cwd }, function(err, stdout, stderr) {
        stdout && console.log(stdout);
        stderr && console.error(stderr);
        if (err) d.reject(err);
        else d.resolve(stdout);
    });
    return d.promise;
}

function setShellFatal(value, func) {
    var oldVal = shell.config.fatal;
    shell.config.fatal = value;
    func();
    shell.config.fatal = oldVal;
}

function getFrameworkDir(projectPath, shared) {
    return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib');
}

function copyJsAndLibrary(projectPath, shared, projectName) {
    var nestedCordovaLibPath = getFrameworkDir(projectPath, false);
    shell.cp('-f', path.join(ROOT, 'framework', 'assets', 'www', 'cordova.js'), path.join(projectPath, 'assets', 'www', 'cordova.js'));
    // Don't fail if there are no old jars.
    setShellFatal(false, function() {
        shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function(oldJar) {
            console.log("Deleting " + oldJar);
            shell.rm('-f', oldJar);
        });
        // Delete old library project if it existed.
        if (shared) {
            shell.rm('-rf', nestedCordovaLibPath);
        } else {
            // Delete only the src, since eclipse can't handle its .project file being deleted.
            shell.rm('-rf', path.join(nestedCordovaLibPath, 'src'));
        }
    });
    if (!shared) {
        shell.mkdir('-p', nestedCordovaLibPath);
        shell.cp('-f', path.join(ROOT, 'framework', 'AndroidManifest.xml'), nestedCordovaLibPath);
        shell.cp('-f', path.join(ROOT, 'framework', 'project.properties'), nestedCordovaLibPath);
        shell.cp('-r', path.join(ROOT, 'framework', 'src'), nestedCordovaLibPath);
        // Create an eclipse project file and set the name of it to something unique.
        // Without this, you can't import multiple CordovaLib projects into the same workspace.
        var eclipseProjectFilePath = path.join(nestedCordovaLibPath, '.project');
        if (!fs.existsSync(eclipseProjectFilePath)) {
            var data = '<?xml version="1.0" encoding="UTF-8"?><projectDescription><name>' + projectName + '-' + 'CordovaLib</name></projectDescription>';
            fs.writeFileSync(eclipseProjectFilePath, data, 'utf8');
        }
    }
}

function runAndroidUpdate(projectPath, target_api, shared) {
    var targetFrameworkDir = getFrameworkDir(projectPath, shared);
    return exec('android update project --subprojects --path "' + projectPath + '" --target ' + target_api + ' --library "' + path.relative(projectPath, targetFrameworkDir) + '"');
}

function copyAntRules(projectPath) {
    var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
    shell.cp('-f', path.join(srcDir, 'custom_rules.xml'), projectPath);
}

function copyScripts(projectPath) {
    var srcScriptsDir = path.join(ROOT, 'bin', 'templates', 'cordova');
    var destScriptsDir = path.join(projectPath, 'cordova');
    // Delete old scripts directory if this is an update.
    shell.rm('-rf', destScriptsDir);
    // Copy in the new ones.
    shell.cp('-r', srcScriptsDir, projectPath);
    shell.cp('-r', path.join(ROOT, 'bin', 'node_modules'), destScriptsDir);
    shell.cp(path.join(ROOT, 'bin', 'check_reqs'), path.join(destScriptsDir, 'check_reqs'));
    shell.cp(path.join(ROOT, 'bin', 'lib', 'check_reqs.js'), path.join(projectPath, 'cordova', 'lib', 'check_reqs.js'));
    shell.cp(path.join(ROOT, 'bin', 'android_sdk_version'), path.join(destScriptsDir, 'android_sdk_version'));
    shell.cp(path.join(ROOT, 'bin', 'lib', 'android_sdk_version.js'), path.join(projectPath, 'cordova', 'lib', 'android_sdk_version.js'));
}

/**
 * $ create [options]
 *
 * Creates an android application with the given options.
 *
 * Options:
 *
 *   - `project_path` 	{String} Path to the new Cordova android project.
 *   - `package_name`{String} Package name, following reverse-domain style convention.
 *   - `project_name` 	{String} Project name.
 *   - 'project_template_dir' {String} Path to project template (override).
 *
 * Returns a promise.
 */

exports.createProject = function(project_path, package_name, project_name, project_template_dir, use_shared_project, use_cli_template) {
    var VERSION = fs.readFileSync(path.join(ROOT, 'VERSION'), 'utf-8').trim();

    // Set default values for path, package and name
    project_path = typeof project_path !== 'undefined' ? project_path : "CordovaExample";
    project_path = path.relative(process.cwd(), project_path);
    package_name = typeof package_name !== 'undefined' ? package_name : 'my.cordova.project';
    project_name = typeof project_name !== 'undefined' ? project_name : 'CordovaExample';
    project_template_dir = typeof project_template_dir !== 'undefined' ?
                           project_template_dir :
                           path.join(ROOT, 'bin', 'templates', 'project');

    var safe_activity_name = project_name.replace(/\W/g, '');
    var package_as_path = package_name.replace(/\./g, path.sep);
    var activity_dir    = path.join(project_path, 'src', package_as_path);
    var activity_path   = path.join(activity_dir, safe_activity_name + '.java');
    var target_api      = check_reqs.get_target();
    var manifest_path   = path.join(project_path, 'AndroidManifest.xml');

    // Check if project already exists
    if(fs.existsSync(project_path)) {
        return Q.reject('Project already exists! Delete and recreate');
    }

    if (!/[a-zA-Z0-9_]+\.[a-zA-Z0-9_](.[a-zA-Z0-9_])*/.test(package_name)) {
        return Q.reject('Package name must look like: com.company.Name');
    }

    // Check that requirements are met and proper targets are installed
    return check_reqs.run()
    .then(function() {
        // Log the given values for the project
        console.log('Creating Cordova project for the Android platform:');
        console.log('\tPath: ' + project_path);
        console.log('\tPackage: ' + package_name);
        console.log('\tName: ' + project_name);
        console.log('\tAndroid target: ' + target_api);

        console.log('Copying template files...');

        setShellFatal(true, function() {
            // copy project template
            shell.cp('-r', path.join(project_template_dir, 'assets'), project_path);
            shell.cp('-r', path.join(project_template_dir, 'res'), project_path);
            // Manually create directories that would be empty within the template (since git doesn't track directories).
            shell.mkdir(path.join(project_path, 'libs'));
            // Add in the proper eclipse project file.
            if (use_cli_template) {
                shell.cp(path.join(project_template_dir, 'eclipse-project-CLI'), path.join(project_path, '.project'));
            } else {
                shell.cp(path.join(project_template_dir, 'eclipse-project'), path.join(project_path, '.project'));
            }

            // copy cordova.js, cordova.jar and res/xml
            shell.cp('-r', path.join(ROOT, 'framework', 'res', 'xml'), path.join(project_path, 'res'));
            copyJsAndLibrary(project_path, use_shared_project, safe_activity_name);

            // interpolate the activity name and package
            shell.mkdir('-p', activity_dir);
            shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
            shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path);
            shell.sed('-i', /__NAME__/, project_name, path.join(project_path, 'res', 'values', 'strings.xml'));
            shell.sed('-i', /__NAME__/, project_name, path.join(project_path, '.project'));
            shell.sed('-i', /__ID__/, package_name, activity_path);

            shell.cp('-f', path.join(project_template_dir, 'AndroidManifest.xml'), manifest_path);
            shell.sed('-i', /__ACTIVITY__/, safe_activity_name, manifest_path);
            shell.sed('-i', /__PACKAGE__/, package_name, manifest_path);
            shell.sed('-i', /__APILEVEL__/, target_api.split('-')[1], manifest_path);
            copyScripts(project_path);
            copyAntRules(project_path);
        });
        // Link it to local android install.
        return runAndroidUpdate(project_path, target_api, use_shared_project);
    }).then(function() {
        console.log('Project successfully created.');
    });
}

// Attribute removed in Cordova 4.4 (CB-5447).
function removeDebuggableFromManifest(projectPath) {
    var manifestPath = path.join(projectPath, 'AndroidManifest.xml');
    shell.sed('-i', /\s*android:debuggable="true"/, '', manifestPath);
}

function extractProjectNameFromManifest(projectPath) {
    var manifestPath = path.join(projectPath, 'AndroidManifest.xml');
    var manifestData = fs.readFileSync(manifestPath, 'utf8');
    var m = /<activity[\s\S]*?android:name\s*=\s*"(.*?)"/i.exec(manifestData);
    if (!m) {
      throw new Error('Could not find activity name in ' + manifestPath);
    }
    return m[1];
}

// Returns a promise.
exports.updateProject = function(projectPath) {
    var version = fs.readFileSync(path.join(ROOT, 'VERSION'), 'utf-8').trim();
    // Check that requirements are met and proper targets are installed
    return check_reqs.run()
    .then(function() {
        var projectName = extractProjectNameFromManifest(projectPath);
        var target_api = check_reqs.get_target();
        copyJsAndLibrary(projectPath, false, projectName);
        copyScripts(projectPath);
        copyAntRules(projectPath);
        removeDebuggableFromManifest(projectPath);
        return runAndroidUpdate(projectPath, target_api, false)
        .then(function() {
            console.log('Android project is now at version ' + version);
            console.log('If you updated from a pre-3.2.0 version and use an IDE, we now require that you import the "CordovaLib" library project.');
        });
    });
};

<|endoftext|>


<commit_before>var base        = require('taskcluster-base');
var debug       = require('debug')('hooks:data');
var assert      = require('assert');
var Promise     = require('promise');
var taskcluster = require('taskcluster-client');
var _           = require('lodash');

/** Entity for tracking hooks and associated state **/
var Hook = base.Entity.configure({
  version:              1,
  partitionKey:         base.Entity.keys.StringKey('hookGroupId'),
  rowKey:               base.Entity.keys.StringKey('hookId'),
  signEntities:         true,
  properties:           {
    hookGroupId:        base.Entity.types.String,
    hookId:             base.Entity.types.String,
    metadata:           base.Entity.types.JSON,
    // task template
    task:               base.Entity.types.JSON,
    // pulse bindings (TODO; empty for now)
    bindings:           base.Entity.types.JSON,
    // timings for the task (in fromNow format, e.g., "1 day")
    deadline:           base.Entity.types.String,
    expires:            base.Entity.types.String,
    // schedule for this task (see schemas/schedule.yml)
    schedule:           base.Entity.types.JSON,
    // access token used to trigger this task via webhook
    triggerToken:       base.Entity.types.EncryptedText,
    // the taskId that will be used next time this hook is scheduled;
    // this allows scheduling to be idempotent
    nextTaskId:         base.Entity.types.EncryptedText,
    // next date at which this task is scheduled to run
    nextScheduledDate:  base.Entity.types.Date,
  }
}).configure({
  version:              2,
  signEntities:         true,
  properties:           {
    hookGroupId:        base.Entity.types.String,
    hookId:             base.Entity.types.String,
    metadata:           base.Entity.types.JSON,
    // task template
    task:               base.Entity.types.JSON,
    // pulse bindings (TODO; empty for now)
    bindings:           base.Entity.types.JSON,
    // timings for the task (in fromNow format, e.g., "1 day")
    deadline:           base.Entity.types.String,
    expires:            base.Entity.types.String,
    // schedule for this task (see schemas/schedule.yml)
    schedule:           base.Entity.types.JSON,
    // access token used to trigger this task via webhook
    triggerToken:       base.Entity.types.EncryptedText,
    // the taskId that will be used next time this hook is scheduled;
    // this allows scheduling to be idempotent
    nextTaskId:         base.Entity.types.EncryptedText,
    // next date at which this task is scheduled to run
    nextScheduledDate:  base.Entity.types.Date,
  },
  migrate: function(item) {
    // remove the task timestamps, as they are overwritten when the hook fires
    // (bug 1225234)
    delete item.task.created;
    delete item.task.expires;
    delete item.task.deadline;
    return item;
  }
});

/** Return promise for hook definition */
Hook.prototype.definition = function() {
  // temporary
  let task = _.cloneDeep(this.task);
  delete task.created;
  delete task.expires;
  delete task.deadline;

  return Promise.resolve({
    hookId:       this.hookId,
    hookGroupId:  this.hookGroupId,
    metadata:     _.cloneDeep(this.metadata),
    task:         task,
    schedule:     _.cloneDeep(this.schedule),
    deadline:     this.deadline,
    expires:      this.expires
  });
};

// export Hook
exports.Hook = Hook;
<commit_msg>Revert "temporarily strip datestamps while creating JSON"<commit_after>var base        = require('taskcluster-base');
var debug       = require('debug')('hooks:data');
var assert      = require('assert');
var Promise     = require('promise');
var taskcluster = require('taskcluster-client');
var _           = require('lodash');

/** Entity for tracking hooks and associated state **/
var Hook = base.Entity.configure({
  version:              1,
  partitionKey:         base.Entity.keys.StringKey('hookGroupId'),
  rowKey:               base.Entity.keys.StringKey('hookId'),
  signEntities:         true,
  properties:           {
    hookGroupId:        base.Entity.types.String,
    hookId:             base.Entity.types.String,
    metadata:           base.Entity.types.JSON,
    // task template
    task:               base.Entity.types.JSON,
    // pulse bindings (TODO; empty for now)
    bindings:           base.Entity.types.JSON,
    // timings for the task (in fromNow format, e.g., "1 day")
    deadline:           base.Entity.types.String,
    expires:            base.Entity.types.String,
    // schedule for this task (see schemas/schedule.yml)
    schedule:           base.Entity.types.JSON,
    // access token used to trigger this task via webhook
    triggerToken:       base.Entity.types.EncryptedText,
    // the taskId that will be used next time this hook is scheduled;
    // this allows scheduling to be idempotent
    nextTaskId:         base.Entity.types.EncryptedText,
    // next date at which this task is scheduled to run
    nextScheduledDate:  base.Entity.types.Date,
  }
}).configure({
  version:              2,
  signEntities:         true,
  properties:           {
    hookGroupId:        base.Entity.types.String,
    hookId:             base.Entity.types.String,
    metadata:           base.Entity.types.JSON,
    // task template
    task:               base.Entity.types.JSON,
    // pulse bindings (TODO; empty for now)
    bindings:           base.Entity.types.JSON,
    // timings for the task (in fromNow format, e.g., "1 day")
    deadline:           base.Entity.types.String,
    expires:            base.Entity.types.String,
    // schedule for this task (see schemas/schedule.yml)
    schedule:           base.Entity.types.JSON,
    // access token used to trigger this task via webhook
    triggerToken:       base.Entity.types.EncryptedText,
    // the taskId that will be used next time this hook is scheduled;
    // this allows scheduling to be idempotent
    nextTaskId:         base.Entity.types.EncryptedText,
    // next date at which this task is scheduled to run
    nextScheduledDate:  base.Entity.types.Date,
  },
  migrate: function(item) {
    // remove the task timestamps, as they are overwritten when the hook fires
    // (bug 1225234)
    delete item.task.created;
    delete item.task.expires;
    delete item.task.deadline;
    return item;
  }
});

/** Return promise for hook definition */
Hook.prototype.definition = function() {
  return Promise.resolve({
    hookId:       this.hookId,
    hookGroupId:  this.hookGroupId,
    metadata:     _.cloneDeep(this.metadata),
    task:         _.cloneDeep(this.task),
    schedule:     _.cloneDeep(this.schedule),
    deadline:     this.deadline,
    expires:      this.expires
  });
};

// export Hook
exports.Hook = Hook;
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Clemens Buchacher
 *
 * Much inspired by Alexey Lebedev's answer in
 * http://stackoverflow.com/questions/12445579/javascript-window-find-does-not-select-search-term.
 */

function visibleTextNodeWalker(topNode) {
	function acceptNode(node) {
		if (node.nodeType == Node.TEXT_NODE)
			return NodeFilter.FILTER_ACCEPT;
		else if (node.offsetWidth && node.offsetHeight && node.style.visibility != 'hidden')
			return NodeFilter.FILTER_SKIP;
		else
			return NodeFilter.FILTER_REJECT;
	}
	return document.createTreeWalker(topNode, NodeFilter.SHOW_ALL, acceptNode, false);
}

function makeNodeArray(walker) {
	var nodeArray = [];
	while (walker.nextNode()) {
		nodeArray.push(walker.currentNode);
	}

	return nodeArray;
}

function visibleTextNodes(topNode) {
	return makeNodeArray(visibleTextNodeWalker(topNode));
}

function nodeValues(nodes) {
	var values = [];
	for (var i = 0; i < nodes.length; i++) {
		values.push(nodes[i].nodeValue);
	}
	return values;
}

function visibleText(nodes) {
	return nodeValues(nodes).join("");
}

function nodeAt(nodeArray, index) {
	var pos = 0;
	for (var i = 0; i < nodeArray.length; i++) {
		var node = nodeArray[i];
		var next_pos = pos + node.nodeValue.length;
		if (index < next_pos) {
			return [node, index - pos];
		}

		pos = next_pos;
	}

	return null;
}

function indexAt(textNodes, range, forward) {
	var node, offset;

	if (forward) {
		node = range.endContainer;
		offset = range.endOffset;
	} else {
		node = range.startContainer;
		offset = range.startOffset;
	}

	var index = textNodes.indexOf(node);
	if (index < 0) {
		return 0;
	}

	return visibleText(textNodes.slice(0, index)).length + offset;
}

function find_substring_1(text, pattern, forward, startOffset) {
	if (forward) {
		return text.indexOf(pattern, startOffset);
	} else {
		var offset = startOffset - pattern.length;
		if (offset < 0) {
			return -1;
		}
		return text.lastIndexOf(pattern, offset);
	}
}

function find_substring(text, pattern, forward, startOffset) {
	var wraparound = false;
	var index = find_substring_1(text, pattern, forward, startOffset);
	if (index < 0) {
		wraparound = true;
		startOffset = 0;
		if (!forward) {
			startOffset = text.length+1;
		}
		index = find_substring_1(text, pattern, forward, startOffset);
	}

	if (index < 0)
		return null;

	return { "index": index, "wraparound": wraparound };
}

function find_regex(text, pattern, forward, startOffset) {
	var index = -1;
	var wraparound = false;

	var re = new RegExp(pattern, "g");
	re.lastIndex = startOffset;
	while (true) {
		/* If an empty string matches, lastIndex is not incremented. */
		var prevLastIndex;
		if (prevLastIndex !== null && re.lastIndex == prevLastIndex) {
			re.lastIndex += 1;
		}
		prevLastIndex = re.lastIndex;

		var match = re.exec(text);

		if (match == null && startOffset > 0 && !wraparound) {
			wraparound = true;
			match = re.exec(text);
		}
		if (match == null) {
			break;
		}

		if (forward) {
			/* Done with the first match. */
			index = match.index;
			break;
		} else if (wraparound && match.index >= startOffset) {
			/*
			 * We wrapped around and passed startOffset. We
			 * already found the first backward match in the
			 * previous iteration.
			 */
			break;
		} else {
			/* Keep track of the last match until we pass
			 * startOffset. */
			index = match.index;
		}
	}

	return { "index": index, "wraparound": wraparound };
}

function find_match(text, regex, pattern, forward, startOffset) {
	if (regex) {
		return find_regex(text, pattern, forward, startOffset);
	} else {
		return find_substring(text, pattern, forward, startOffset);
	}
}

function search(regex, pattern, forward, startAt) {
	if (forward == null) {
		forward = true;
	}
	var textNodes = visibleTextNodes(document.body);
	var startOffset = 0;
	if (startAt !== null) {
		startOffset = indexAt(textNodes, startAt, forward);
	}

	var text = visibleText(textNodes);
	var match = find_match(text, regex, pattern, forward, startOffset);
	if (match == null) {
		return null;
	}

	var range = document.createRange();
	range.setStart.apply(range, nodeAt(textNodes, match.index));
	range.setEnd.apply(range, nodeAt(textNodes, match.index + pattern.length));

	return { "range": range, "wraparound": match.wraparound };
}

function select(range) {
	window.getSelection().removeAllRanges();
	window.getSelection().addRange(range);
}

function select_match(regex, pattern, forward) {
	var selection = window.getSelection();
	var startAt = null;
	if (selection.type != "None") {
		startAt = selection.getRangeAt(0);
	}

	var match = search(regex, pattern, forward, startAt);
	if (match !== null) {
		select(match.range)
	}

	return match;
}
<commit_msg>handle invalid regular expressions<commit_after>/*
 * Copyright (C) 2013 Clemens Buchacher
 *
 * Much inspired by Alexey Lebedev's answer in
 * http://stackoverflow.com/questions/12445579/javascript-window-find-does-not-select-search-term.
 */

function visibleTextNodeWalker(topNode) {
	function acceptNode(node) {
		if (node.nodeType == Node.TEXT_NODE)
			return NodeFilter.FILTER_ACCEPT;
		else if (node.offsetWidth && node.offsetHeight && node.style.visibility != 'hidden')
			return NodeFilter.FILTER_SKIP;
		else
			return NodeFilter.FILTER_REJECT;
	}
	return document.createTreeWalker(topNode, NodeFilter.SHOW_ALL, acceptNode, false);
}

function makeNodeArray(walker) {
	var nodeArray = [];
	while (walker.nextNode()) {
		nodeArray.push(walker.currentNode);
	}

	return nodeArray;
}

function visibleTextNodes(topNode) {
	return makeNodeArray(visibleTextNodeWalker(topNode));
}

function nodeValues(nodes) {
	var values = [];
	for (var i = 0; i < nodes.length; i++) {
		values.push(nodes[i].nodeValue);
	}
	return values;
}

function visibleText(nodes) {
	return nodeValues(nodes).join("");
}

function nodeAt(nodeArray, index) {
	var pos = 0;
	for (var i = 0; i < nodeArray.length; i++) {
		var node = nodeArray[i];
		var next_pos = pos + node.nodeValue.length;
		if (index < next_pos) {
			return [node, index - pos];
		}

		pos = next_pos;
	}

	return null;
}

function indexAt(textNodes, range, forward) {
	var node, offset;

	if (forward) {
		node = range.endContainer;
		offset = range.endOffset;
	} else {
		node = range.startContainer;
		offset = range.startOffset;
	}

	var index = textNodes.indexOf(node);
	if (index < 0) {
		return 0;
	}

	return visibleText(textNodes.slice(0, index)).length + offset;
}

function find_substring_1(text, pattern, forward, startOffset) {
	if (forward) {
		return text.indexOf(pattern, startOffset);
	} else {
		var offset = startOffset - pattern.length;
		if (offset < 0) {
			return -1;
		}
		return text.lastIndexOf(pattern, offset);
	}
}

function find_substring(text, pattern, forward, startOffset) {
	var wraparound = false;
	var index = find_substring_1(text, pattern, forward, startOffset);
	if (index < 0) {
		wraparound = true;
		startOffset = 0;
		if (!forward) {
			startOffset = text.length+1;
		}
		index = find_substring_1(text, pattern, forward, startOffset);
	}

	if (index < 0)
		return null;

	return { "index": index, "wraparound": wraparound };
}

function find_regex(text, pattern, forward, startOffset) {
	var index = -1;
	var wraparound = false;

	try {
		var re = new RegExp(pattern, "g");
	} catch (error) {
		return null;
	}
	re.lastIndex = startOffset;
	while (true) {
		/* If an empty string matches, lastIndex is not incremented. */
		var prevLastIndex;
		if (prevLastIndex !== null && re.lastIndex == prevLastIndex) {
			re.lastIndex += 1;
		}
		prevLastIndex = re.lastIndex;

		var match = re.exec(text);

		if (match == null && startOffset > 0 && !wraparound) {
			wraparound = true;
			match = re.exec(text);
		}
		if (match == null) {
			break;
		}

		if (forward) {
			/* Done with the first match. */
			index = match.index;
			break;
		} else if (wraparound && match.index >= startOffset) {
			/*
			 * We wrapped around and passed startOffset. We
			 * already found the first backward match in the
			 * previous iteration.
			 */
			break;
		} else {
			/* Keep track of the last match until we pass
			 * startOffset. */
			index = match.index;
		}
	}

	return { "index": index, "wraparound": wraparound };
}

function find_match(text, regex, pattern, forward, startOffset) {
	if (regex) {
		return find_regex(text, pattern, forward, startOffset);
	} else {
		return find_substring(text, pattern, forward, startOffset);
	}
}

function search(regex, pattern, forward, startAt) {
	if (forward == null) {
		forward = true;
	}
	var textNodes = visibleTextNodes(document.body);
	var startOffset = 0;
	if (startAt !== null) {
		startOffset = indexAt(textNodes, startAt, forward);
	}

	var text = visibleText(textNodes);
	var match = find_match(text, regex, pattern, forward, startOffset);
	if (match == null) {
		return null;
	}

	var range = document.createRange();
	range.setStart.apply(range, nodeAt(textNodes, match.index));
	range.setEnd.apply(range, nodeAt(textNodes, match.index + pattern.length));

	return { "range": range, "wraparound": match.wraparound };
}

function select(range) {
	window.getSelection().removeAllRanges();
	window.getSelection().addRange(range);
}

function select_match(regex, pattern, forward) {
	var selection = window.getSelection();
	var startAt = null;
	if (selection.type != "None") {
		startAt = selection.getRangeAt(0);
	}

	var match = search(regex, pattern, forward, startAt);
	if (match !== null) {
		select(match.range)
	}

	return match;
}
<|endoftext|>