<commit_before>'use strict';
var log = require('./lib/log');
var colors = require('./lib/colors');
var formatException = require('./lib/format-exception');
var Task = require('./lib/task');
var Step = require('./lib/step');
var version = require('./lib/local-version');
var _ = require('lodash');
var consoleUtil = require('./lib/mute-console');
var muteConsole = consoleUtil.muteConsole;
var unmuteConsole = consoleUtil.unmuteConsole;

var changed = require('./lib/changed');
var ensureDirs = require('./lib/ensure-dirs');
var mkdirp = require('mkdirp');

// Stateful variables
//
// * exitFn - holds a custom exit function, mainly used for tests
// * tasksRunning - a counter to prevent early exiting if tasks are triggered from other tasks
// * tasks - `'task-name' => TaskInstance`
// * easyb - container for the exported interface
var exitFn = null;
var tasksRunning = 0;
var tasks = {};
var easyb = {};

// `fail` is a general way to quit when a fatal error has occurred.  If
// `exitFn` hasn't been set, it will simply do a `process.exit`.
function fail(errcode) {
  if (typeof(errcode) === 'undefined') {
    errcode = 1;
  }
  if (exitFn) {
    exitFn(errcode);
  } else {
    process.exit(errcode);
  }
  return null;
}

// For detecting whether easyb.HALT has been passed to prevent moving to the
// next step.
function isHaltDirective(v) {
  return (v && (typeof(v) === 'object') && v.__IS_EASYB_HALT === true);
}

// For detecting whether easyb.HALT has been passed to prevent moving to the
// next step.
function isErrorDirective(v) {
  return (v && (typeof(v) === 'object') && v.__IS_EASYB_ERROR === true);
}

// `maybeHalt` is a composition that decreases the `tasksRunning` counter then
// sees if it is an ok time to exit
function maybeHalt() {
  taskEnding();
  maybeExit();
  return null;
}

// The primary workhorse of the task system.
//
// * `taskName` - (string) the name of the task to be run, * `initialOptions` -
// (object, optional) meant for the value you'd like to be passed to the first
// step function's second argument.
//
// `easyb#trigger` is the public interface to this function.
function runTask(taskName, initialOptions) {
  // Prevent from exiting on long running asynchronous tasks.
  var task = tasks[taskName];
  var currentStep = 0;
  if (!task) {
    log.error(colors.fatal('Non-existent task requested: ') + colors.normal(taskName));
    fail();
    return null;
  }
  var steps = task.getSteps();
  var stepDefaults = task.getStepDefaults();
  if (!steps[0]) {
    log.error(colors.fatal('Task ') + colors.normal(taskName) +
              colors.fatal(' has no steps assigned.'));
    fail();
    return null;
  }
  taskStarting();
  // `next` is the function that will be passed as the first argument to the
  // step function.  It gets it's first trigger from `runTask`, but then it is
  // up to each step function to call it (unless you never want the process to
  // exit, which may sometimes be the case, for instance when you want to
  // monitor files)
  //
  // In addition to providing next with options, it also accepts two
  // directives, `easyb.HALT` or `easyb.ERROR`.
  var next = function next(opts) {
    // Passing next the `easyb.HALT` value will result in early termination of
    // the task.
    if (isHaltDirective(opts)) {
      maybeHalt();
      return null;
    }
    // If `easyb.ERROR` has been passed, the second argument should be the
    // error.  This is a way to force an error to trigger if you aren't in a
    // position to throw an error (for example, if you get the error in an
    // async operation)
    if (isErrorDirective(opts)) {
      // We the step will have been incremented at this point, so we'll need to
      // backup to the previous step
      var errorStep = steps[currentStep - 1];
      handleNextError(errorStep, task, arguments[1]);
      return null;
    }
    // Load steps from the task and set option defaults.
    var step = steps[currentStep];
    var stepDefault = stepDefaults[currentStep];
    var options = _.defaultsDeep({}, opts, stepDefault);
    // If there are no more steps left, we're done with the task.
    if (!step) {
      log.log(colors.success('Task ') + colors.normal(taskName) +
              colors.success(' complete.'));
      maybeHalt();
      return null;
    }
    currentStep += 1;
    // This block tries to run the step, and
    try {
      step.getRunFn()(next, options);
    } catch (e) {
      handleNextError(step, task, e, currentStep);
    }
  };
  next(initialOptions);
  return null;
}

// Error handling is broken out into it's own closure, so it can be called from
// either a thrown error or from an error directive from `next`.
function handleNextError(step, task, err, currentStep) {
  var stepError = step.getErrorFn();
  var taskError = task.getErrorFn();
  if (stepError) {
    stepError(err);
  } else if (taskError) {
    taskError(err);
  } else {
    // Default error handling behavior occurs if no step level or task level error handler
    // has been assigned.
    log.warn(colors.error('Uncaught error running step ' + currentStep + ' in task ') +
             colors.normal(task.getName()));
    if (err.message) {
      log.warn(colors.error('Error Message: ') + colors.normal(err.message));
    }
  }
  maybeHalt();
  return null;
}

// Increases the state variable `tasksRunning`
function taskStarting() {
  tasksRunning += 1;
  return null;
}

// Decreases the state variable `tasksRunning`
function taskEnding() {
  tasksRunning -= 1;
  return null;
}

// Will exit if their are no tasks still running
function maybeExit() {
  if (tasksRunning > 1) {
    return null;
  }
  if (exitFn) {
    exitFn(0);
  } else {
    process.exit(0);
  }
}

// ## easyb interface

// `easyb.task` is for setting up a new task in the system. Give it a name and
// optional description, and you'll get back an instance of the `Task` data
// structure.
easyb.task = function task(name, description) {
  if (tasks[name] !== undefined) {
    log.fatal(colors.fatal('Task name ' + name + ' has already been defined.'));
    fail();
  }
  tasks[name] = new Task(name);
  if (description) {
    tasks[name].description(description);
  }
  return tasks[name];
};

easyb.Step = Step;

// `start` is the interface into easyb designed to be called by the CLI. If you
// are using easyb programatically, you probably won't need this function.
//
// If you do need to use it, three things may be set in the `options` object,
// `taskName`, `silent`, and `argv`. `taskName` (required) is the name of the
// task you want to trigger after the `configPath` has been required, and
// `argv` contains the options that will be passed to the first step of the
// specified task. `silent` mutes any console output (including from running
// tasks).
easyb.start = function start(configPath, options) {
  // Loading the config will usually modify the local state.
  try {
    require(configPath);
  } catch (e) {
    log.fatal(colors.fatal('Error reading local config file: ') + colors.file(configPath));
    log.fatal(formatException(e));
    fail();
  }
  runTask(options.task, options.argv);
};

// Setter for the private `exitFn` variable. Primarily for test
// suites or other programatic usages.
easyb.setExitFn = function setExitFn(fn) {
  exitFn = fn;
  return null;
};

// Returns just the names and descriptions from all registered tasks.
easyb.getTaskNamesAndDescriptions = function getTaskNamesAndDescriptions() {
  return (Object.keys(tasks)).map(function taskNameAndDescMap(key) {
    return {
      name: tasks[key].getName(),
      description: tasks[key].getDescription()
    };
  });
};

// Trigger a task. Acts as the interface to the private function `runTask`.
easyb.trigger = function trigger(taskName, opts) {
  runTask(taskName, opts);
};

// Resets all local state variables. Primarily added for testing.
easyb.reset = function reset() {
  exitFn = null;
  tasksRunning = 0;
  tasks = {};
  return null;
};

// Shortcut to `require('./package').version`
easyb.version = version;

// Definition of the HALT directive, used to stop a task from continuing.
easyb.HALT = {__IS_EASYB_HALT: true};

// Definition of the ERROR directive, used to trigger a step or task error when
// throwing an error isn't possible.
easyb.ERROR = {__IS_EASYB_ERROR: true};

// Utility and library access
easyb.changed = changed;
easyb.ensureDirs = ensureDirs;
easyb.mkdirp = mkdirp;
easyb.colors = colors;
easyb.log = log;
easyb.muteConsole = muteConsole;
easyb.unmuteConsole = unmuteConsole;

module.exports = easyb;
<commit_msg>prevent maybeExit from exiting early<commit_after>'use strict';
var log = require('./lib/log');
var colors = require('./lib/colors');
var formatException = require('./lib/format-exception');
var Task = require('./lib/task');
var Step = require('./lib/step');
var version = require('./lib/local-version');
var _ = require('lodash');
var consoleUtil = require('./lib/mute-console');
var muteConsole = consoleUtil.muteConsole;
var unmuteConsole = consoleUtil.unmuteConsole;

var changed = require('./lib/changed');
var ensureDirs = require('./lib/ensure-dirs');
var mkdirp = require('mkdirp');

// Stateful variables
//
// * exitFn - holds a custom exit function, mainly used for tests
// * tasksRunning - a counter to prevent early exiting if tasks are triggered from other tasks
// * tasks - `'task-name' => TaskInstance`
// * easyb - container for the exported interface
var exitFn = null;
var tasksRunning = 0;
var tasks = {};
var easyb = {};

// `fail` is a general way to quit when a fatal error has occurred.  If
// `exitFn` hasn't been set, it will simply do a `process.exit`.
function fail(errcode) {
  if (typeof(errcode) === 'undefined') {
    errcode = 1;
  }
  if (exitFn) {
    exitFn(errcode);
  } else {
    process.exit(errcode);
  }
  return null;
}

// For detecting whether easyb.HALT has been passed to prevent moving to the
// next step.
function isHaltDirective(v) {
  return (v && (typeof(v) === 'object') && v.__IS_EASYB_HALT === true);
}

// For detecting whether easyb.HALT has been passed to prevent moving to the
// next step.
function isErrorDirective(v) {
  return (v && (typeof(v) === 'object') && v.__IS_EASYB_ERROR === true);
}

// `maybeHalt` is a composition that decreases the `tasksRunning` counter then
// sees if it is an ok time to exit
function maybeHalt() {
  taskEnding();
  maybeExit();
  return null;
}

// The primary workhorse of the task system.
//
// * `taskName` - (string) the name of the task to be run, * `initialOptions` -
// (object, optional) meant for the value you'd like to be passed to the first
// step function's second argument.
//
// `easyb#trigger` is the public interface to this function.
function runTask(taskName, initialOptions) {
  var task = tasks[taskName];
  var currentStep = 0;
  if (!task) {
    log.error(colors.fatal('Non-existent task requested: ') + colors.normal(taskName));
    fail();
    return null;
  }
  var steps = task.getSteps();
  var stepDefaults = task.getStepDefaults();
  if (!steps[0]) {
    log.error(colors.fatal('Task ') + colors.normal(taskName) +
              colors.fatal(' has no steps assigned.'));
    fail();
    return null;
  }
  taskStarting();
  // `next` is the function that will be passed as the first argument to the
  // step function.  It gets it's first trigger from `runTask`, but then it is
  // up to each step function to call it (unless you never want the process to
  // exit, which may sometimes be the case, for instance when you want to
  // monitor files)
  //
  // In addition to providing next with options, it also accepts two
  // directives, `easyb.HALT` or `easyb.ERROR`.
  var next = function next(opts) {
    // Passing next the `easyb.HALT` value will result in early termination of
    // the task.
    if (isHaltDirective(opts)) {
      maybeHalt();
      return null;
    }
    // If `easyb.ERROR` has been passed, the second argument should be the
    // error.  This is a way to force an error to trigger if you aren't in a
    // position to throw an error (for example, if you get the error in an
    // async operation)
    if (isErrorDirective(opts)) {
      // We the step will have been incremented at this point, so we'll need to
      // backup to the previous step
      var errorStep = steps[currentStep - 1];
      handleNextError(errorStep, task, arguments[1]);
      return null;
    }
    // Load steps from the task and set option defaults.
    var step = steps[currentStep];
    var stepDefault = stepDefaults[currentStep];
    var options = _.defaultsDeep({}, opts, stepDefault);
    // If there are no more steps left, we're done with the task.
    if (!step) {
      log.log(colors.success('Task ') + colors.normal(taskName) +
              colors.success(' complete.'));
      maybeHalt();
      return null;
    }
    currentStep += 1;
    // This block tries to run the step, and passes it to a funciton that will
    // bubble the errors if it throws.
    try {
      step.getRunFn()(next, options);
    } catch (e) {
      handleNextError(step, task, e, currentStep);
    }
  };
  next(initialOptions);
  return null;
}

// Error handling is broken out into it's own closure, so it can be called from
// either a thrown error or from an error directive from `next`.
function handleNextError(step, task, err, currentStep) {
  var stepError = step.getErrorFn();
  var taskError = task.getErrorFn();
  if (stepError) {
    stepError(err);
  } else if (taskError) {
    taskError(err);
  } else {
    // Default error handling behavior occurs if no step level or task level error handler
    // has been assigned.
    log.warn(colors.error('Uncaught error running step ' + currentStep + ' in task ') +
             colors.normal(task.getName()));
    if (err.message) {
      log.warn(colors.error('Error Message: ') + colors.normal(err.message));
    }
  }
  maybeHalt();
  return null;
}

// Increases the state variable `tasksRunning`
function taskStarting() {
  tasksRunning += 1;
  return null;
}

// Decreases the state variable `tasksRunning`
function taskEnding() {
  tasksRunning -= 1;
  return null;
}

// Will exit if their are no tasks still running
function maybeExit() {
  if (tasksRunning > 0) {
    return null;
  }
  if (exitFn) {
    exitFn(0);
  } else {
    process.exit(0);
  }
}

// ## easyb interface

// `easyb.task` is for setting up a new task in the system. Give it a name and
// optional description, and you'll get back an instance of the `Task` data
// structure.
easyb.task = function task(name, description) {
  if (tasks[name] !== undefined) {
    log.fatal(colors.fatal('Task name ' + name + ' has already been defined.'));
    fail();
  }
  tasks[name] = new Task(name);
  if (description) {
    tasks[name].description(description);
  }
  return tasks[name];
};

easyb.Step = Step;

// `start` is the interface into easyb designed to be called by the CLI. If you
// are using easyb programatically, you probably won't need this function.
//
// If you do need to use it, three things may be set in the `options` object,
// `taskName`, `silent`, and `argv`. `taskName` (required) is the name of the
// task you want to trigger after the `configPath` has been required, and
// `argv` contains the options that will be passed to the first step of the
// specified task. `silent` mutes any console output (including from running
// tasks).
easyb.start = function start(configPath, options) {
  // Loading the config will usually modify the local state.
  try {
    require(configPath);
  } catch (e) {
    log.fatal(colors.fatal('Error reading local config file: ') + colors.file(configPath));
    log.fatal(formatException(e));
    fail();
  }
  runTask(options.task, options.argv);
};

// Setter for the private `exitFn` variable. Primarily for test
// suites or other programatic usages.
easyb.setExitFn = function setExitFn(fn) {
  exitFn = fn;
  return null;
};

// Returns just the names and descriptions from all registered tasks.
easyb.getTaskNamesAndDescriptions = function getTaskNamesAndDescriptions() {
  return (Object.keys(tasks)).map(function taskNameAndDescMap(key) {
    return {
      name: tasks[key].getName(),
      description: tasks[key].getDescription()
    };
  });
};

// Trigger a task. Acts as the interface to the private function `runTask`.
easyb.trigger = function trigger(taskName, opts) {
  runTask(taskName, opts);
};

// Resets all local state variables. Primarily added for testing.
easyb.reset = function reset() {
  exitFn = null;
  tasksRunning = 0;
  tasks = {};
  return null;
};

// Shortcut to `require('./package').version`
easyb.version = version;

// Definition of the HALT directive, used to stop a task from continuing.
easyb.HALT = {__IS_EASYB_HALT: true};

// Definition of the ERROR directive, used to trigger a step or task error when
// throwing an error isn't possible.
easyb.ERROR = {__IS_EASYB_ERROR: true};

// Utility and library access
easyb.changed = changed;
easyb.ensureDirs = ensureDirs;
easyb.mkdirp = mkdirp;
easyb.colors = colors;
easyb.log = log;
easyb.muteConsole = muteConsole;
easyb.unmuteConsole = unmuteConsole;

module.exports = easyb;
<|endoftext|>


<commit_before>var incrementalMapReduce = require("incremental-map-reduce")

snapshotReduce.reduce = reduce
snapshotReduce.map = map

module.exports = snapshotReduce

function snapshotReduce(snapshot, opts) {
    var inputCollection = opts.inputCollection
    var outputCollection = opts.outputCollection
    var outputCollectionName = opts.outputName ||
        "snapshot." + snapshot

    var result = incrementalMapReduce(inputCollection, {
        map: map
        , reduce: reduce
        , reducedCollection: outputCollection
        , options: {
            out: {
                reduce: outputCollectionName
            }
            // , jsMode: true
            , query: {
                "value.type": new RegExp("^" + snapshot)
            }
            , finalize: finalize
        }
        , timestampPath: "timestamp"
        , lastTimestampPath: "__lastTimestamp__"
    })

    return result
}

/*global emit*/
function map() {
    var _emit = typeof emit !== "undefined" ? emit : function () {}

    function handleAdd() {
        if (parts.length === 1) {
            value.__lastTimestamp__ = doc.timestamp
            _emit(value.id, value)
            return [value.id, value]
        } else if (parts.length === 2) {
            var prop = parts[1]
            var result = {
                __lastTimestamp__: doc.timestamp
            }
            var key = value.parentId[0]

            result[prop] = [value]
            _emit(key, result)
            return [key, result]
        } else if (parts.length > 2) {
            var paths = parts.slice(1)
            var result = {
                __lastTimestamp__: doc.timestamp
            }
            var keys = value.parentId.slice(1)
            var key = value.parentId[0]
            var parent = result

            for (var i = 0; i < paths.length; i++) {
                var path = paths[i]
                var item = i === paths.length - 1 ?
                    value : { id: keys[i] }
                parent[path] = [item]
                parent = item
            }

            _emit(key, result)
            return [key, result]
        }
    }

    function handleRemove() {
        if (parts.length === 1) {
            _emit(value.id, {
                id: value.id
                , __lastTimestamp__: doc.timestamp
                , __deleted__: true
            })
        } else if (parts.length === 2) {
            var prop = parts[1]
            var result = {
                __lastTimestamp__: doc.timestamp
            }
            var key = value.parentId[0]

            result[prop] = [{
                id: value.id
                , __deleted__: true
            }]
            _emit(key, result)
        }
    }

    var doc = this
    var value = doc.value
    var type = value.type
    var parts = type.split("~")
    var eventType = doc.eventType

    if (eventType === "add") {
        return handleAdd()
    } else if (eventType === "remove") {
        handleRemove()
    }
}

function reduce(_, values) {
    function clone(obj) {
        var res = {}

        for (var key in obj) {
            res[key] = obj[key]
        }

        return res
    }

    function isArray(x) {
        return x !== null &&
            x !== undefined &&
            x.constructor === Array
    }

    function find(arr, id) {
        for (var i = 0; i < arr.length; i++) {
            var item = arr[i]
            if (item.id === id) {
                return i
            }
        }

        return null
    }

    function mergeArrays(target, source) {
        source.forEach(function (value) {
            var index = find(target, value.id)

            if (index === null) {
                target.push(value)
            } else {
                target[index] = merge(target[index], value)
            }
        })

        return target
    }

    function isObject(value) {
        return typeof value === "object" && value !== null
    }

    function merge(target, source) {
        if (typeof source !== "object" || source === null) {
            return source
        }

        var res = clone(target)

        for (var key in source) {
            var sourceValue = source[key]
            var targetValue = target[key]

            res[key] = mergeValues(targetValue, sourceValue)
        }

        return res
    }

    function mergeValues(targetValue, sourceValue) {
        var result

        if (targetValue === undefined) {
            result = sourceValue
        } else if (isArray(sourceValue)) {
            if (!isArray(targetValue)) {
                targetValue = []
            }

            result = mergeArrays(targetValue.slice(), sourceValue)
        } else if (isObject(sourceValue) && isObject(targetValue)) {
            result = merge(targetValue, sourceValue)
        } else {
            result = sourceValue
        }

        return result
    }

    var result = {}
    var lastTimestamp = 0

    values.forEach(function (valueInReduce) {
        if (valueInReduce.__lastTimestamp__ > lastTimestamp) {
            lastTimestamp = valueInReduce.__lastTimestamp__
        }

        result = merge(result, valueInReduce)
    })

    result.__lastTimestamp__ = lastTimestamp

    return result
}

function finalize(key, value) {
    function isNotDeleted(v) {
        return v === null || v === undefined || !v.__deleted__
    }

    function isObject(x) {
        return typeof x === "object" && x !== null
    }

    function isArray(x) {
        return x !== null &&
            x !== undefined &&
            x.constructor === Array
    }

    function byTimestamp(a, b) {
        if (!isObject(a) || !isObject(b)) {
            return 0
        }

        if (!("timestamp" in a) && !("timestamp" in b)) {
            return 0
        }

        if (a.timestamp === b.timestamp) {
            return 0
        } else if (a.timestamp < b.timestamp) {
            return -1
        } else if (a.timestamp > b.timestamp) {
            return 1
        } else {
            return 0
        }
    }

    function cleanse(data) {
        var res = {}

        if (!isObject(data)) {
            return data
        }

        for (var key in data) {
            var value = data[key]

            if (value !== null && value !== undefined && value.__deleted__) {
                continue
            }

            if (isArray(value)) {
                res[key] = value.
                    filter(isNotDeleted).
                    map(cleanse).
                    sort(byTimestamp)
            } else if (typeof value === "object" && value !== null) {
                res[key] = cleanse(value)
            } else {
                res[key] = value
            }
        }

        return res
    }

    return cleanse(value)
}
<commit_msg>change sorting to be by createdAt, not timestamp<commit_after>var incrementalMapReduce = require("incremental-map-reduce")

snapshotReduce.reduce = reduce
snapshotReduce.map = map

module.exports = snapshotReduce

function snapshotReduce(snapshot, opts) {
    var inputCollection = opts.inputCollection
    var outputCollection = opts.outputCollection
    var outputCollectionName = opts.outputName ||
        "snapshot." + snapshot

    var result = incrementalMapReduce(inputCollection, {
        map: map
        , reduce: reduce
        , reducedCollection: outputCollection
        , options: {
            out: {
                reduce: outputCollectionName
            }
            // , jsMode: true
            , query: {
                "value.type": new RegExp("^" + snapshot)
            }
            , finalize: finalize
        }
        , timestampPath: "timestamp"
        , lastTimestampPath: "__lastTimestamp__"
    })

    return result
}

/*global emit*/
function map() {
    var _emit = typeof emit !== "undefined" ? emit : function () {}

    function handleAdd() {
        if (parts.length === 1) {
            value.__lastTimestamp__ = doc.timestamp
            _emit(value.id, value)
            return [value.id, value]
        } else if (parts.length === 2) {
            var prop = parts[1]
            var result = {
                __lastTimestamp__: doc.timestamp
            }
            var key = value.parentId[0]

            result[prop] = [value]
            _emit(key, result)
            return [key, result]
        } else if (parts.length > 2) {
            var paths = parts.slice(1)
            var result = {
                __lastTimestamp__: doc.timestamp
            }
            var keys = value.parentId.slice(1)
            var key = value.parentId[0]
            var parent = result

            for (var i = 0; i < paths.length; i++) {
                var path = paths[i]
                var item = i === paths.length - 1 ?
                    value : { id: keys[i] }
                parent[path] = [item]
                parent = item
            }

            _emit(key, result)
            return [key, result]
        }
    }

    function handleRemove() {
        if (parts.length === 1) {
            _emit(value.id, {
                id: value.id
                , __lastTimestamp__: doc.timestamp
                , __deleted__: true
            })
        } else if (parts.length === 2) {
            var prop = parts[1]
            var result = {
                __lastTimestamp__: doc.timestamp
            }
            var key = value.parentId[0]

            result[prop] = [{
                id: value.id
                , __deleted__: true
            }]
            _emit(key, result)
        }
    }

    var doc = this
    var value = doc.value
    var type = value.type
    var parts = type.split("~")
    var eventType = doc.eventType

    if (eventType === "add") {
        return handleAdd()
    } else if (eventType === "remove") {
        handleRemove()
    }
}

function reduce(_, values) {
    function clone(obj) {
        var res = {}

        for (var key in obj) {
            res[key] = obj[key]
        }

        return res
    }

    function isArray(x) {
        return x !== null &&
            x !== undefined &&
            x.constructor === Array
    }

    function find(arr, id) {
        for (var i = 0; i < arr.length; i++) {
            var item = arr[i]
            if (item.id === id) {
                return i
            }
        }

        return null
    }

    function mergeArrays(target, source) {
        source.forEach(function (value) {
            var index = find(target, value.id)

            if (index === null) {
                target.push(value)
            } else {
                target[index] = merge(target[index], value)
            }
        })

        return target
    }

    function isObject(value) {
        return typeof value === "object" && value !== null
    }

    function merge(target, source) {
        if (typeof source !== "object" || source === null) {
            return source
        }

        var res = clone(target)

        for (var key in source) {
            var sourceValue = source[key]
            var targetValue = target[key]

            res[key] = mergeValues(targetValue, sourceValue)
        }

        return res
    }

    function mergeValues(targetValue, sourceValue) {
        var result

        if (targetValue === undefined) {
            result = sourceValue
        } else if (isArray(sourceValue)) {
            if (!isArray(targetValue)) {
                targetValue = []
            }

            result = mergeArrays(targetValue.slice(), sourceValue)
        } else if (isObject(sourceValue) && isObject(targetValue)) {
            result = merge(targetValue, sourceValue)
        } else {
            result = sourceValue
        }

        return result
    }

    var result = {}
    var lastTimestamp = 0

    values.forEach(function (valueInReduce) {
        if (valueInReduce.__lastTimestamp__ > lastTimestamp) {
            lastTimestamp = valueInReduce.__lastTimestamp__
        }

        result = merge(result, valueInReduce)
    })

    result.__lastTimestamp__ = lastTimestamp

    return result
}

function finalize(key, value) {
    function isNotDeleted(v) {
        return v === null || v === undefined || !v.__deleted__
    }

    function isObject(x) {
        return typeof x === "object" && x !== null
    }

    function isArray(x) {
        return x !== null &&
            x !== undefined &&
            x.constructor === Array
    }

    function byTimestamp(a, b) {
        if (!isObject(a) || !isObject(b)) {
            return 0
        }

        if (!("createdAt" in a) && !("createdAt" in b)) {
            return 0
        }

        if (a.createdAt === b.createdAt) {
            return 0
        } else if (a.createdAt < b.createdAt) {
            return -1
        } else if (a.createdAt > b.createdAt) {
            return 1
        } else {
            return 0
        }
    }

    function cleanse(data) {
        var res = {}

        if (!isObject(data)) {
            return data
        }

        for (var key in data) {
            var value = data[key]

            if (value !== null && value !== undefined && value.__deleted__) {
                continue
            }

            if (isArray(value)) {
                res[key] = value.
                    filter(isNotDeleted).
                    map(cleanse).
                    sort(byTimestamp)
            } else if (typeof value === "object" && value !== null) {
                res[key] = cleanse(value)
            } else {
                res[key] = value
            }
        }

        return res
    }

    return cleanse(value)
}
<|endoftext|>


<commit_before><commit_msg>Create start.js<commit_after><|endoftext|>


<commit_before>let addEventsToButtons = () => {
  addDigitsListener();
  addOperationsListener();
}

let math = {
  '+': (x, y) => { return x + y },
  '-': (x, y) => { return x - y },
  '÷': (x, y) => { return x / y },
  '×': (x, y) => { return x * y },
}

let addDigitsListener = () => {
  let digitButtons = document.getElementsByClassName('digits');
  let responsePane = document.getElementById('response-pane');
  for (let elem of digitButtons) {
    elem.addEventListener('click', (e) => {
      let elemText = e.currentTarget.innerText;
      if (responsePane.dataset.processed === 'false') {
        responsePane.innerText += elemText;
      } else {
        responsePane.innerText = elemText;
      } // end if
      responsePane.dataset.processed = false;
    });
  } // end for
}

let containsMultiplication = elem => elem === '×' || elem === '÷';

let containsAddition = elem => elem === '+' || elem === '-';

let addOperationsListener = () => { // consider removing = button from this and giving it its own listener
  let operationButtons = document.getElementsByClassName('operations');
  let responsePane = document.getElementById('response-pane');
  for (let elem of operationButtons) {
    elem.addEventListener('click', (e) => {
      tape.push(Number(responsePane.innerText));
      responsePane.dataset.processed = true;

      let elemText = e.currentTarget.innerText;
      tape.push(elemText);
      let multiplicationCounter = tape.filter((operator) => operator === '×' || operator === '÷').length;
      let additionCounter = tape.filter((operator) => operator === "+" || operator === '-').length;
      // scenario: [N, m, N, m]
      if ((tape[1] === '×' || tape[1] === '÷') && (tape[3] === '×' || tape[3] === '÷')) {
        let numbersToEvaluate = tape.splice(-4, 3);
        let x = numbersToEvaluate[0];
        let y = numbersToEvaluate[2];
        let operator = numbersToEvaluate[1];
        let product = math[operator](x, y);
        tape.splice(-1, 0, product);
      }
      // scenario: [N, m, N, a]
      if ((tape[1] === '×' || tape[1] === '÷') && (tape[3] === '+' || tape[3] === '-')) {
        let numbersToEvaluate = tape.splice(-4, 3);
        let x = numbersToEvaluate[0];
        let y = numbersToEvaluate[2];
        let operator = numbersToEvaluate[1];
        let product = math[operator](x, y);
        tape.splice(-1, 0, product);
      }
      // scenario: [N, a, N, m, N, m]
      if ((tape[1] === '+' || tape[1] === '-') && (tape[3] === '×' || tape[3] === '÷') && (tape[5] === '×' || tape[5] === '÷')) {
        let numbersToEvaluate = tape.splice(-4, 3);
        let x = numbersToEvaluate[0];
        let y = numbersToEvaluate[2];
        let operator = numbersToEvaluate[1];
        let product = math[operator](x, y);
        tape.splice(-1, 0, product);
      }
      // scenario: [N, a, N, m, N, a]
      if ((tape[1] === '+' || tape[1] === '-') && (tape[3] === '×' || tape[3] === '÷') && (tape[5] === '+' || tape[5] === '-')) {
        let numbersToEvaluate = tape.splice(-4, 3);
        let x = numbersToEvaluate[0];
        let y = numbersToEvaluate[2];
        let operator = numbersToEvaluate[1];
        let product = math[operator](x, y);
        numbersToEvaluate = tape.splice(0, 2);
        x = numbersToEvaluate[0];
        operator = numbersToEvaluate[1];
        let sum = math[operator](x, product);
        tape.splice(-1, 0, sum);
      }

      // scenario: [N, a, N, a]

      responsePane.innerText = tape[tape.length - 2] || responsePane.innerText;
    })
  } // end for
}

let tape = []

document.addEventListener('DOMContentLoaded', addEventsToButtons());<commit_msg>Correctly evaluate the fifth possible math scenario. Use shorter syntax for math arrow functions<commit_after>let addEventsToButtons = () => {
  addDigitsListener();
  addOperationsListener();
}

let math = {
  '+': (x, y) => x + y,
  '-': (x, y) => x - y,
  '÷': (x, y) => x / y,
  '×': (x, y) => x * y,
}

let addDigitsListener = () => {
  let digitButtons = document.getElementsByClassName('digits');
  let responsePane = document.getElementById('response-pane');
  for (let elem of digitButtons) {
    elem.addEventListener('click', (e) => {
      let elemText = e.currentTarget.innerText;
      if (responsePane.dataset.processed === 'false') {
        responsePane.innerText += elemText;
      } else {
        responsePane.innerText = elemText;
      } // end if
      responsePane.dataset.processed = false;
    });
  } // end for
}

let containsMultiplication = elem => elem === '×' || elem === '÷';

let containsAddition = elem => elem === '+' || elem === '-';

let addOperationsListener = () => { // consider removing = button from this and giving it its own listener
  let operationButtons = document.getElementsByClassName('operations');
  let responsePane = document.getElementById('response-pane');
  for (let elem of operationButtons) {
    elem.addEventListener('click', (e) => {
      tape.push(Number(responsePane.innerText));
      responsePane.dataset.processed = true;

      let elemText = e.currentTarget.innerText;
      tape.push(elemText);
      let multiplicationCounter = tape.filter((operator) => operator === '×' || operator === '÷').length;
      let additionCounter = tape.filter((operator) => operator === "+" || operator === '-').length;
      // scenario: [N, m, N, m]
      if ((tape[1] === '×' || tape[1] === '÷') && (tape[3] === '×' || tape[3] === '÷')) {
        let numbersToEvaluate = tape.splice(-4, 3);
        let x = numbersToEvaluate[0];
        let y = numbersToEvaluate[2];
        let operator = numbersToEvaluate[1];
        let product = math[operator](x, y);
        tape.splice(-1, 0, product);
      }
      // scenario: [N, m, N, a]
      if ((tape[1] === '×' || tape[1] === '÷') && (tape[3] === '+' || tape[3] === '-')) {
        let numbersToEvaluate = tape.splice(-4, 3);
        let x = numbersToEvaluate[0];
        let y = numbersToEvaluate[2];
        let operator = numbersToEvaluate[1];
        let product = math[operator](x, y);
        tape.splice(-1, 0, product);
      }
      // scenario: [N, a, N, m, N, m]
      if ((tape[1] === '+' || tape[1] === '-') && (tape[3] === '×' || tape[3] === '÷') && (tape[5] === '×' || tape[5] === '÷')) {
        let numbersToEvaluate = tape.splice(-4, 3);
        let x = numbersToEvaluate[0];
        let y = numbersToEvaluate[2];
        let operator = numbersToEvaluate[1];
        let product = math[operator](x, y);
        tape.splice(-1, 0, product);
      }
      // scenario: [N, a, N, m, N, a]
      if ((tape[1] === '+' || tape[1] === '-') && (tape[3] === '×' || tape[3] === '÷') && (tape[5] === '+' || tape[5] === '-')) {
        let numbersToEvaluate = tape.splice(-4, 3);
        let x = numbersToEvaluate[0];
        let y = numbersToEvaluate[2];
        let operator = numbersToEvaluate[1];
        let product = math[operator](x, y);
        numbersToEvaluate = tape.splice(0, 2);
        x = numbersToEvaluate[0];
        operator = numbersToEvaluate[1];
        let sum = math[operator](x, product);
        tape.splice(-1, 0, sum);
      }

      // scenario: [N, a, N, a]
      if ((tape[1] === '+' || tape[1] === '-') && (tape[3] === '+' || tape[3] === '-')) {
        let numbersToEvaluate = tape.splice(-4, 3);
        let x = numbersToEvaluate[0];
        let y = numbersToEvaluate[2];
        let operator = numbersToEvaluate[1];
        let sum = math[operator](x, y);
        tape.splice(-1, 0, sum);
      }

      responsePane.innerText = tape[tape.length - 2] || responsePane.innerText;
    })
  } // end for
}

let tape = []

document.addEventListener('DOMContentLoaded', addEventsToButtons());<|endoftext|>


<commit_before>/* eslint-disable global-require */

'use strict';

const allRules = {
  'no-unused-styles': require('./lib/rules/no-unused-styles'),
  'no-inline-styles': require('./lib/rules/no-inline-styles'),
  'no-color-literals': require('./lib/rules/no-color-literals'),
  'split-platform-components': require('./lib/rules/split-platform-components'),
};

function configureAsError(rules) {
  const result = {};
  for (const key in rules) {
    if (!rules.hasOwnProperty(key)) {
      continue;
    }
    result['react-native/' + key] = 2;
  }
  return result;
}

const allRulesConfig = configureAsError(allRules);

module.exports = {
  deprecatedRules: {},
  rules: allRules,
  rulesConfig: {
    'no-unused-styles': 0,
    'no-inline-styles': 0,
    'no-color-literals': 0,
    'split-platform-components': 0,
  },
  configs: {
    all: {
      plugins: [
        'react-native',
      ],
      parserOptions: {
        ecmaFeatures: {
          jsx: true,
        },
      },
      rules: allRulesConfig,
    },
  },
};
<commit_msg>copy paste globals from relay .eslintrc<commit_after>/* eslint-disable global-require */

'use strict';

const allRules = {
  'no-unused-styles': require('./lib/rules/no-unused-styles'),
  'no-inline-styles': require('./lib/rules/no-inline-styles'),
  'no-color-literals': require('./lib/rules/no-color-literals'),
  'split-platform-components': require('./lib/rules/split-platform-components'),
};

function configureAsError(rules) {
  const result = {};
  for (const key in rules) {
    if (!rules.hasOwnProperty(key)) {
      continue;
    }
    result['react-native/' + key] = 2;
  }
  return result;
}

const allRulesConfig = configureAsError(allRules);

module.exports = {
  deprecatedRules: {},
  rules: allRules,
  rulesConfig: {
    'no-unused-styles': 0,
    'no-inline-styles': 0,
    'no-color-literals': 0,
    'split-platform-components': 0,
  },
  environments: {
    'react-native': {
      globals: {
        __DEV__: true,
        __dirname: false,
        __fbBatchedBridgeConfig: false,
        alert: false,
        cancelAnimationFrame: false,
        cancelIdleCallback: false,
        clearImmediate: true,
        clearInterval: false,
        clearTimeout: false,
        console: false,
        document: false,
        escape: false,
        Event: false,
        EventTarget: false,
        exports: false,
        fetch: false,
        FormData: false,
        global: false,
        jest: false,
        Map: true,
        module: false,
        navigator: false,
        process: false,
        Promise: true,
        requestAnimationFrame: true,
        requestIdleCallback: true,
        require: false,
        Set: true,
        setImmediate: true,
        setInterval: false,
        setTimeout: false,
        window: false,
        XMLHttpRequest: false,
        pit: false,
      },
    },
  },
  configs: {
    all: {
      plugins: [
        'react-native',
      ],
      parserOptions: {
        ecmaFeatures: {
          jsx: true,
        },
      },
      rules: allRulesConfig,
    },
  },
};
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash'),
    child_process = require('child_process'),
    gutil = require('gulp-util'),
    es = require('event-stream'),
    path = require('path'),
    temp = require('temp'),
    fs = require('fs');

var PLUGIN_NAME = 'gulp.dotcover.runner';
var EXECUTABLE_NAME = 'dotCover.exe';

var runner = function gulpDotcoverRunner(opts) {

    opts = opts || {};

    var files = [];

    var stream = es.through(function write(file) {
        if (_.isUndefined(file)) {
            fail(this, 'File may not be null.');
        }

        files.push(file);
        this.emit('data', file);
    }, function end() {
        run(this, files, opts);
    });

    return stream;
};

runner.getExecutable = function(options) {
    if (!options.executable)
        return EXECUTABLE_NAME;

    // trim any existing surrounding quotes and then wrap in ""
    var executable = trim(options.executable, '\\s', '"', "'");

    return !path.extname(options.executable) ? path.join(executable, EXECUTABLE_NAME) : executable;
};

function trim() {
    var args = Array.prototype.slice.call(arguments);
    var source = args[0];
    var replacements = args.slice(1).join(',');
    var regex = new RegExp("^[" + replacements + "]+|[" + replacements + "]+$", "g");

    return source.replace(regex, '');
}

runner.getArguments = function(options, assemblies) {

    var assemblyArgs = assemblies.map(function(asm) {
        var qualifier = asm.trim().indexOf(' ') > -1 ? '"' : '';

        return qualifier + asm + qualifier;
    }).reduce(function(p,c) {
        return p.concat(c);
    }, []);

    var args = [];

    args.push("cover");
    args.push("/TargetExecutable=" + options.target.executable);
    args.push("/TargetWorkingDir=" + options.target.workingDirectory);
    args.push("/TargetArguments=" + assemblyArgs.join(" "));
    args.push("/output=" + options.target.output);

    return args;
};

function fail(stream, msg) {
    stream.emit('error', new gutil.PluginError(PLUGIN_NAME, msg));
}

function run(stream, files, options) {

    var assemblies = files.map(function (file) {
        return file.path;
    });

    if (assemblies.length === 0) {
        return fail(stream, 'Some assemblies required.');
    }

    var exe = runner.getExecutable(options);
    var args = (runner.getArguments(options, assemblies));
    var opts = {
        stdio: "inherit"
    };

    var child = child_process.spawn(
        exe,
        args,
        opts);

    child.on('error', function (e) {
        fail(stream, e.code === 'ENOENT' ? 'Unable to find \'' + exe + '\'.' : e.message);
    });

    child.on('close', function (code) {

        if (options.teamcity)
            gutil.log("##teamcity[importData type='dotNetCoverage' tool='dotcover' path='" + options.target.output + "']");

        if (code !== 0) {
            gutil.log(gutil.colors.red('dotCover failed.'));
            fail(stream, 'dotCover failed.');
        }
        else {
            gutil.log(gutil.colors.cyan('dotCover finished.'));
        }

        return stream.emit('end');
    });
}

module.exports = runner;
<commit_msg>pathEscaping: inline arguments<commit_after>'use strict';

var _ = require('lodash'),
    child_process = require('child_process'),
    gutil = require('gulp-util'),
    es = require('event-stream'),
    path = require('path'),
    temp = require('temp'),
    fs = require('fs');

var PLUGIN_NAME = 'gulp.dotcover.runner';
var EXECUTABLE_NAME = 'dotCover.exe';

var runner = function gulpDotcoverRunner(opts) {

    opts = opts || {};

    var files = [];

    var stream = es.through(function write(file) {
        if (_.isUndefined(file)) {
            fail(this, 'File may not be null.');
        }

        files.push(file);
        this.emit('data', file);
    }, function end() {
        run(this, files, opts);
    });

    return stream;
};

runner.getExecutable = function(options) {
    if (!options.executable)
        return EXECUTABLE_NAME;

    // trim any existing surrounding quotes and then wrap in ""
    var executable = unquotePathsIfNeeded(options.executable);

    return !path.extname(options.executable) ? path.join(executable, EXECUTABLE_NAME) : executable;
};

function unquotePathsIfNeeded(source) {
    var args = Array.prototype.slice.call(arguments);
    var replacements = [ '\\s', '"', "'" ].join(',');
    var regex = new RegExp("^[" + replacements + "]+|[" + replacements + "]+$", "g");

    return source.replace(regex, '');
}

runner.getArguments = function(options, assemblies) {

    var assemblyArgs = assemblies.map(function(asm) {
        var qualifier = asm.trim().indexOf(' ') > -1 ? '"' : '';

        return qualifier + asm + qualifier;
    }).reduce(function(p,c) {
        return p.concat(c);
    }, []);

    var args = [];

    args.push("cover");
    args.push("/TargetExecutable=" + options.target.executable);
    args.push("/TargetWorkingDir=" + options.target.workingDirectory);
    args.push("/TargetArguments=" + assemblyArgs.join(" "));
    args.push("/output=" + options.target.output);

    return args;
};

function fail(stream, msg) {
    stream.emit('error', new gutil.PluginError(PLUGIN_NAME, msg));
}

function run(stream, files, options) {

    var assemblies = files.map(function (file) {
        return file.path;
    });

    if (assemblies.length === 0) {
        return fail(stream, 'Some assemblies required.');
    }

    var exe = runner.getExecutable(options);
    var args = (runner.getArguments(options, assemblies));
    var opts = {
        stdio: "inherit"
    };

    var child = child_process.spawn(
        exe,
        args,
        opts);

    child.on('error', function (e) {
        fail(stream, e.code === 'ENOENT' ? 'Unable to find \'' + exe + '\'.' : e.message);
    });

    child.on('close', function (code) {

        if (options.teamcity)
            gutil.log("##teamcity[importData type='dotNetCoverage' tool='dotcover' path='" + options.target.output + "']");

        if (code !== 0) {
            gutil.log(gutil.colors.red('dotCover failed.'));
            fail(stream, 'dotCover failed.');
        }
        else {
            gutil.log(gutil.colors.cyan('dotCover finished.'));
        }

        return stream.emit('end');
    });
}

module.exports = runner;
<|endoftext|>


<commit_before>module.exports = function (promises) {

  if (!Array.isArray(promises)) {
    throw new Error('First argument need to be an array of Promises');
  }

  return new Promise((resolve, reject) => {

    let count = 0;
    let results = [];

    const iterateeFunc = (previousPromise, currentPromise) => {
      return previousPromise
        .then(function (result) {
          if (count++ !== 0) results = results.concat(result);
          return currentPromise(result, results, count);
        })
        .catch((err) => {
          return reject(err);
        });
    }

    promises = promises.concat(() => Promise.resolve());

    promises
    .reduce(iterateeFunc, Promise.resolve(false))
    .then(function (res) {
      resolve(results);
    })

  });
};
<commit_msg>Update index.js<commit_after>'use strict';
module.exports = function (promises) {

  if (!Array.isArray(promises)) {
    throw new Error('First argument need to be an array of Promises');
  }

  return new Promise((resolve, reject) => {

    let count = 0;
    let results = [];

    const iterateeFunc = (previousPromise, currentPromise) => {
      return previousPromise
        .then(function (result) {
          if (count++ !== 0) results = results.concat(result);
          return currentPromise(result, results, count);
        })
        .catch((err) => {
          return reject(err);
        });
    }

    promises = promises.concat(() => Promise.resolve());

    promises
    .reduce(iterateeFunc, Promise.resolve(false))
    .then(function (res) {
      resolve(results);
    })

  });
};
<|endoftext|>


<commit_before>'use strict';

var store = new Vuex.Store({
    strict: true,
    state: {
        page: {
            isOk: false,
            message: '',
            status: '',
            loading: false,
            userSelected: false
        },
        search: {
            term: '',
            count: 0,
            users: []
        },
        user: {
            repositories: []
        },
        commits: {
            repository: '',
            branchs: [],
            commits: [],
            comments: {
                sha: '',
                comments: []
            },
            show: false
        }
    },
    mutations: {
        bindSearchResult: function(state, result) {
            state.search.users = result.items;
        },
        bindUser: function(state, user) {
            if(user.type === 'User') {
                user = $user.mapAsUser(user);
            } else if(user.type === 'Organization') {
                user = $user.mapAsOrganization(user);
            }

            state.user = user;
        },
        bindRepositories: function(state, repositories) {
            state.user.repositories = repositories;
        },
        bindCommits: function(state, data) {
            state.commits = {
                repository: data.repository.trim(),
                branchs: state.commits.branchs,
                commits: data.commits,
                comments: {
                    sha: '',
                    comments: []
                },
                show: data.commits.length > 0
            }
        },
        bindBranchs: function(state, branchs) {
            state.commits.branchs = branchs;
        },
        bindComments: function(state, comments) {
            state.commits.comments = {
                sha: comments.sha,
                comments: comments.comments
            }
        },
        increaseCount: function(state) {
            state.search.count++;
        },
        updatePage: function(state, stats) {
            state.page = {
                isOk: stats.isOk,
                status: stats.status,
                message: stats.message,
                loading: false,
                userSelected: stats.userSelected ? stats.userSelected : false
            };
        },
        isLoading: function(state) {
            state.page.loading = true;
        }
    },
    actions: {
        searchRepositories: () => {
            if(!store.state.user.login)
                return;

            $github.searchRepositories(store.state.user.login).then(response => {
                store.commit('bindRepositories', response.data);
            }).catch(response => {
                store.commit('updatePage', { isOk: response.status == 200, status: response.statusText, message: response.body.message });
            });
        },
        getBranchs: (store, repository) => {
            $github.branchs(store.state.user.login, repository).then(response => {
                store.commit('bindBranchs', response.data);
            }).catch(response => {
                store.commit('updatePage', { isOk: response.status == 200, status: response.statusText, message: response.body.message });
            });
        },
        getCommitComments: (store, sha) => {
            $github.commitComments(store.state.user.login, store.state.commits.repository, sha).then(response => {
                store.commit('bindComments', { sha: sha, comments: response.data });
            }).catch(response => {
                store.commit('updatePage', { isOk: response.status == 200, status: response.statusText, message: response.body.message });
            });
        }
    }
});<commit_msg>refactor(store): change variable type to const<commit_after>'use strict';

const store = new Vuex.Store({
    strict: true,
    state: {
        page: {
            isOk: false,
            message: '',
            status: '',
            loading: false,
            userSelected: false
        },
        search: {
            term: '',
            count: 0,
            users: []
        },
        user: {
            repositories: []
        },
        commits: {
            repository: '',
            branchs: [],
            commits: [],
            comments: {
                sha: '',
                comments: []
            },
            show: false
        }
    },
    mutations: {
        bindSearchResult: function(state, result) {
            state.search.users = result.items;
        },
        bindUser: function(state, user) {
            if(user.type === 'User') {
                user = $user.mapAsUser(user);
            } else if(user.type === 'Organization') {
                user = $user.mapAsOrganization(user);
            }

            state.user = user;
        },
        bindRepositories: function(state, repositories) {
            state.user.repositories = repositories;
        },
        bindCommits: function(state, data) {
            state.commits = {
                repository: data.repository.trim(),
                branchs: state.commits.branchs,
                commits: data.commits,
                comments: {
                    sha: '',
                    comments: []
                },
                show: data.commits.length > 0
            }
        },
        bindBranchs: function(state, branchs) {
            state.commits.branchs = branchs;
        },
        bindComments: function(state, comments) {
            state.commits.comments = {
                sha: comments.sha,
                comments: comments.comments
            }
        },
        increaseCount: function(state) {
            state.search.count++;
        },
        updatePage: function(state, stats) {
            state.page = {
                isOk: stats.isOk,
                status: stats.status,
                message: stats.message,
                loading: false,
                userSelected: stats.userSelected ? stats.userSelected : false
            };
        },
        isLoading: function(state) {
            state.page.loading = true;
        }
    },
    actions: {
        searchRepositories: () => {
            if(!store.state.user.login)
                return;

            $github.searchRepositories(store.state.user.login).then(response => {
                store.commit('bindRepositories', response.data);
            }).catch(response => {
                store.commit('updatePage', { isOk: response.status == 200, status: response.statusText, message: response.body.message });
            });
        },
        getBranchs: (store, repository) => {
            $github.branchs(store.state.user.login, repository).then(response => {
                store.commit('bindBranchs', response.data);
            }).catch(response => {
                store.commit('updatePage', { isOk: response.status == 200, status: response.statusText, message: response.body.message });
            });
        },
        getCommitComments: (store, sha) => {
            $github.commitComments(store.state.user.login, store.state.commits.repository, sha).then(response => {
                store.commit('bindComments', { sha: sha, comments: response.data });
            }).catch(response => {
                store.commit('updatePage', { isOk: response.status == 200, status: response.statusText, message: response.body.message });
            });
        }
    }
});<|endoftext|>


<commit_before>(function(Shoutbox) {
	var S, actions = [];

	Shoutbox.actions = {
		register: function(obj) {
			actions.push(obj);
		},
		initialize: function(shoutPanel) {
			for (var a in actions) {
				if (actions.hasOwnProperty(a)) {
					actions[a].register(shoutPanel);
				}
			}
		}
	};

	var DefaultActions = {
		typing: {
			register: function(shoutPanel) {
				shoutPanel.find('#shoutbox-message-input').off('keyup.typing').on('keyup.typing', this.handle);
			},
			handle: function() {
				if ($(this).val()) {
					Shoutbox.sockets.notifyStartTyping();
				} else {
					Shoutbox.sockets.notifyStopTyping();
				}
			}
		},
		send: {
			register: function(shoutPanel) {
				var sendMessage = this.handle;

				shoutPanel.find('#shoutbox-message-input').off('keypress.send').on('keypress.send', function(e) {
					if(e.which === 13 && !e.shiftKey) {
						sendMessage(shoutPanel);
					}
				});

				shoutPanel.find('#shoutbox-message-send-btn').off('click.send').on('click.send', function(e){
					sendMessage(shoutPanel);
					return false;
				});
			},
			handle: function(shoutPanel) {
				var msg = S(shoutPanel.find('#shoutbox-message-input').val()).stripTags().trim().s;

				if (msg.length) {
					Shoutbox.sockets.sendShout({ message: msg });
				}
				shoutPanel.find('#shoutbox-message-input').val('');
			}
		},
		delete: {
			register: function(shoutPanel) {
				shoutPanel.off('click.delete', '.shoutbox-shout-option-close').on('click.delete', '.shoutbox-shout-option-close', this.handle);
			},
			handle: function(e) {
				var sid = $(e.currentTarget).parents('[data-sid]').data('sid');

				Shoutbox.sockets.removeShout({ sid: sid }, function (err, result) {
					if (result === true) {
						app.alertSuccess('Successfully deleted shout!');
					} else if (err) {
						app.alertError('Error deleting shout: ' + err.message, 3000);
					}
				});

				return false;
			}
		},
		edit: {
			register: function(shoutPanel) {
				var handle = this.handle;

				function eventsOff() {
					shoutPanel.off('click.edit', '.shoutbox-shout-option-edit')
						.off('dblclick.edit', '[data-sid]')
						.find('#shoutbox-message-input').off('keyup.edit');
				}

				function eventsOn() {
					shoutPanel.on('click.edit', '.shoutbox-shout-option-edit', function(e) {
						handle(shoutPanel, $(e.currentTarget).parents('[data-sid]').data('sid'));
					}).on('dblclick.edit', '[data-sid]', function(e) {
						handle(shoutPanel, $(e.currentTarget).data('sid'));
					}).find('#shoutbox-message-input').on('keyup.edit', function(e) {
						if(e.which === 38) {
							handle(shoutPanel, shoutPanel.find('[data-uid="' + app.uid + '"] [data-sid]:last').data('sid'));
						}
					});
				}

				shoutPanel.find('#shoutbox-message-input').off('textComplete:show').on('textComplete:show', function() {
					eventsOff();
				});

				shoutPanel.find('#shoutbox-message-input').off('textComplete:hide').on('textComplete:hide', function() {
					eventsOn();
				});

				eventsOff();
				eventsOn();
			},
			handle: function(shoutPanel, sid) {
				var shout = shoutPanel.find('[data-sid="' + sid + '"]');

				if (shout.parents('[data-uid]').data('uid') === app.uid || app.isAdmin) {
					Shoutbox.vars.editing = sid;

					Shoutbox.sockets.getOriginalShout({ sid: sid }, function(err, orig) {
						shoutPanel.find('#shoutbox-message-send-btn').off('click.send').on('click.send', function(e){
							edit(orig);
						}).text('Edit');

						shoutPanel.find('#shoutbox-message-input').off('keyup.edit').off('keypress.send').on('keypress.send', function(e) {
							if (e.which === 13 && !e.shiftKey) {
								edit(orig);
							}
						}).on('keyup.edit', function(e) {
							if (e.currentTarget.value.length === 0) {
								DefaultActions.edit.finish(shoutPanel);
							}
						}).val(orig).focus().putCursorAtEnd().parents('.input-group').addClass('has-warning');
					});
				}

				function edit(orig) {
					var msg = S(shoutPanel.find('#shoutbox-message-input').val()).stripTags().s;

					if (msg === orig || msg === '' || msg === null) {
						return DefaultActions.edit.finish(shoutPanel);
					}

					Shoutbox.sockets.editShout({ sid: sid, edited: msg }, function (err, result) {
						if (result === true) {
							app.alertSuccess('Successfully edited shout!');
						} else if (err) {
							app.alertError('Error editing shout: ' + err.message, 3000);
						}
						DefaultActions.edit.finish(shoutPanel);
					});
				}

				return false;
			},
			finish: function(shoutPanel) {
				var inputGroup = shoutPanel.find('#shoutbox-message-input').val('').parents('.input-group');
				inputGroup.removeClass('has-warning').find('#shoutbox-message-send-btn').text('Send').removeClass('hide');
				DefaultActions.send.register(shoutPanel);
				DefaultActions.edit.register(shoutPanel);
				Shoutbox.vars.editing = 0;
			}
		}
	};

	require(['string'], function(String) {
		S = String;
	});

	for (var a in DefaultActions) {
		if (DefaultActions.hasOwnProperty(a))
			Shoutbox.actions.register(DefaultActions[a]);
	}

	Shoutbox.actions.finishEdit = DefaultActions.edit.finish;

})(window.Shoutbox);<commit_msg>Only allow up-arrow editing if the input is empty<commit_after>(function(Shoutbox) {
	var S, actions = [];

	Shoutbox.actions = {
		register: function(obj) {
			actions.push(obj);
		},
		initialize: function(shoutPanel) {
			for (var a in actions) {
				if (actions.hasOwnProperty(a)) {
					actions[a].register(shoutPanel);
				}
			}
		}
	};

	var DefaultActions = {
		typing: {
			register: function(shoutPanel) {
				shoutPanel.find('#shoutbox-message-input').off('keyup.typing').on('keyup.typing', this.handle);
			},
			handle: function() {
				if ($(this).val()) {
					Shoutbox.sockets.notifyStartTyping();
				} else {
					Shoutbox.sockets.notifyStopTyping();
				}
			}
		},
		send: {
			register: function(shoutPanel) {
				var sendMessage = this.handle;

				shoutPanel.find('#shoutbox-message-input').off('keypress.send').on('keypress.send', function(e) {
					if(e.which === 13 && !e.shiftKey) {
						sendMessage(shoutPanel);
					}
				});

				shoutPanel.find('#shoutbox-message-send-btn').off('click.send').on('click.send', function(e){
					sendMessage(shoutPanel);
					return false;
				});
			},
			handle: function(shoutPanel) {
				var msg = S(shoutPanel.find('#shoutbox-message-input').val()).stripTags().trim().s;

				if (msg.length) {
					Shoutbox.sockets.sendShout({ message: msg });
				}
				shoutPanel.find('#shoutbox-message-input').val('');
			}
		},
		delete: {
			register: function(shoutPanel) {
				shoutPanel.off('click.delete', '.shoutbox-shout-option-close').on('click.delete', '.shoutbox-shout-option-close', this.handle);
			},
			handle: function(e) {
				var sid = $(e.currentTarget).parents('[data-sid]').data('sid');

				Shoutbox.sockets.removeShout({ sid: sid }, function (err, result) {
					if (result === true) {
						app.alertSuccess('Successfully deleted shout!');
					} else if (err) {
						app.alertError('Error deleting shout: ' + err.message, 3000);
					}
				});

				return false;
			}
		},
		edit: {
			register: function(shoutPanel) {
				var handle = this.handle;

				function eventsOff() {
					shoutPanel.off('click.edit', '.shoutbox-shout-option-edit')
						.off('dblclick.edit', '[data-sid]')
						.find('#shoutbox-message-input').off('keyup.edit');
				}

				function eventsOn() {
					shoutPanel.on('click.edit', '.shoutbox-shout-option-edit', function(e) {
						handle(shoutPanel, $(e.currentTarget).parents('[data-sid]').data('sid'));
					}).on('dblclick.edit', '[data-sid]', function(e) {
						handle(shoutPanel, $(e.currentTarget).data('sid'));
					}).find('#shoutbox-message-input').on('keyup.edit', function(e) {
						if(e.which === 38 && !$(this).val()) {
							handle(shoutPanel, shoutPanel.find('[data-uid="' + app.uid + '"] [data-sid]:last').data('sid'));
						}
					});
				}

				shoutPanel.find('#shoutbox-message-input').off('textComplete:show').on('textComplete:show', function() {
					eventsOff();
				});

				shoutPanel.find('#shoutbox-message-input').off('textComplete:hide').on('textComplete:hide', function() {
					eventsOn();
				});

				eventsOff();
				eventsOn();
			},
			handle: function(shoutPanel, sid) {
				var shout = shoutPanel.find('[data-sid="' + sid + '"]');

				if (shout.parents('[data-uid]').data('uid') === app.uid || app.isAdmin) {
					Shoutbox.vars.editing = sid;

					Shoutbox.sockets.getOriginalShout({ sid: sid }, function(err, orig) {
						shoutPanel.find('#shoutbox-message-send-btn').off('click.send').on('click.send', function(e){
							edit(orig);
						}).text('Edit');

						shoutPanel.find('#shoutbox-message-input').off('keyup.edit').off('keypress.send').on('keypress.send', function(e) {
							if (e.which === 13 && !e.shiftKey) {
								edit(orig);
							}
						}).on('keyup.edit', function(e) {
							if (e.currentTarget.value.length === 0) {
								DefaultActions.edit.finish(shoutPanel);
							}
						}).val(orig).focus().putCursorAtEnd().parents('.input-group').addClass('has-warning');
					});
				}

				function edit(orig) {
					var msg = S(shoutPanel.find('#shoutbox-message-input').val()).stripTags().s;

					if (msg === orig || msg === '' || msg === null) {
						return DefaultActions.edit.finish(shoutPanel);
					}

					Shoutbox.sockets.editShout({ sid: sid, edited: msg }, function (err, result) {
						if (result === true) {
							app.alertSuccess('Successfully edited shout!');
						} else if (err) {
							app.alertError('Error editing shout: ' + err.message, 3000);
						}
						DefaultActions.edit.finish(shoutPanel);
					});
				}

				return false;
			},
			finish: function(shoutPanel) {
				var inputGroup = shoutPanel.find('#shoutbox-message-input').val('').parents('.input-group');
				inputGroup.removeClass('has-warning').find('#shoutbox-message-send-btn').text('Send').removeClass('hide');
				DefaultActions.send.register(shoutPanel);
				DefaultActions.edit.register(shoutPanel);
				Shoutbox.vars.editing = 0;
			}
		}
	};

	require(['string'], function(String) {
		S = String;
	});

	for (var a in DefaultActions) {
		if (DefaultActions.hasOwnProperty(a))
			Shoutbox.actions.register(DefaultActions[a]);
	}

	Shoutbox.actions.finishEdit = DefaultActions.edit.finish;

})(window.Shoutbox);<|endoftext|>


<commit_before>window.requestAnimationFrame = (function () {
    return window.requestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function (callback) {
            window.setTimeout(callback, 1000/30);
        };
})();

(function ($) {
    $.fn.PongGame = function () {
        // Aliases for PIXI
        var Sprite       = PIXI.Sprite,
            TextureCache = PIXI.utils.TextureCache,
            Container    = PIXI.Container,
            Texture      = PIXI.Texture,
            loader       = PIXI.loader,
            resources    = loader.resources;

        // Constants definition
        const HOME_ROWS    = 10,
              HOME_COLUMNS = 10,
              BRICK_WIDTH  = 40,
              BRICK_HEIGHT = 20,
              imgPath      = "img/"; // Base path for the images

        // Configure renderer
        var renderer = PIXI.autoDetectRenderer(800, 600),
            stage    = new Container();

        var state = play;

        $(this).html(renderer.view);
        renderer.view.style.border = "1px dashed black";

        // Images for sprites
        var images = [
            "brick",
            "brick_half",
            "brick_gray",
            "brick_gray_half",
            "brick_gray_border",
            "brick_gray_half_border",
            "ball"
        ].map(function (img) {
            return { name: img, url: imgPath + img + ".png" }
        });

        loader.add(images)
            .on("progress", loadProgressHandler)
            .load(setup);

        // Define variables that might be used in more than one function
        var brickLines, ball;

        function GameBrick(name, x, y, width, height) {
            if (typeof(width) === "undefined") width = BRICK_WIDTH;
            if (typeof(height) === "undefined") height = BRICK_HEIGHT;
            var normalName     = "brick" + name;
            var grayName       = "brick_gray" + name;
            var grayBorderName = "brick_gray" + name + "_border";

            var brick    = new Sprite(resources[grayName].texture);
            brick.x      = x;
            brick.y      = y;
            brick.width  = width;
            brick.height = height;

            this.sprite   = function () {
                return brick;
            };
            this.toBorder = function () {
                brick.texture = resources[grayBorderName].texture;
            };
            this.toNormal = function () {
                brick.texture = resources[normalName].texture;
            };
            this.toGray   = function () {
                brick.texture = resources[grayName].texture;
            };
        }

        function setup() {
            brickLines = [];

            for (var i = 0; i < HOME_ROWS; ++i) {
                var bLine  = [];
                var xShift = (renderer.width - HOME_COLUMNS*BRICK_WIDTH)/2;
                var yPos   = renderer.height - BRICK_HEIGHT*(i + 1);
                if (i%2 !== 0) {
                    // Create half brick now;

                    var brickHead = new GameBrick("_half", xShift, yPos, BRICK_WIDTH/2);
                    xShift += BRICK_WIDTH/2;
                    bLine.push(brickHead);
                }
                for (var j = 0; j < HOME_COLUMNS - i%2; ++j) {
                    var brick = new GameBrick("", BRICK_WIDTH*j + xShift, yPos);
                    bLine.push(brick);
                }
                if (i%2 !== 0) {
                    var xpos      = (HOME_COLUMNS - 1)*BRICK_WIDTH + xShift;
                    var brickTail = new GameBrick("_half", xpos, yPos, BRICK_WIDTH/2);
                    bLine.push(brickTail);
                }
                brickLines.push(bLine);

                gameLoop();
            }

            for (var i = 0; i < brickLines.length; ++i) {
                for (var j = 0; j < brickLines[i].length; ++j) {
                    stage.addChild(brickLines[i][j].sprite());
                }
                if (i === 0) {
                    for (var j = 0; j < brickLines[i].length; ++j) {
                        brickLines[i][j].toBorder();
                    }
                }
            }

            // Add ball to the top center of the screen
            ball = new Sprite(resources["ball"].texture);
            ball.x = renderer.width/2;
            ball.y = 10;
            ball.width = 20;
            ball.height = 20;

            stage.addChild(ball);

            renderer.render(stage);
            console.log("Setup finished");
        }

        function loadProgressHandler(loader, resource) {
            console.log("Loading : " + resource.url);
            console.log("Progress: " + loader.progress + "%");
        }

        function gameLoop() {
            // Loop this function at 60 frames per second
            requestAnimationFrame(gameLoop);

            // Update the current game state
            state();

            // Render the stage to see the animation
            renderer.render(stage);
        }

        function play() {

        }
    }
}(jQuery));

<commit_msg>Add movement to ball<commit_after>window.requestAnimationFrame = (function () {
    return window.requestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function (callback) {
            window.setTimeout(callback, 1000/30);
        };
})();

(function ($) {
    $.fn.PongGame = function () {
        // Aliases for PIXI
        var Sprite       = PIXI.Sprite,
            TextureCache = PIXI.utils.TextureCache,
            Container    = PIXI.Container,
            Texture      = PIXI.Texture,
            loader       = PIXI.loader,
            resources    = loader.resources;

        // Constants definition
        const HOME_ROWS    = 10,
              HOME_COLUMNS = 10,
              BRICK_WIDTH  = 40,
              BRICK_HEIGHT = 20,
              imgPath      = "img/"; // Base path for the images

        // Configure renderer
        var renderer = PIXI.autoDetectRenderer(800, 600),
            stage    = new Container();

        var state = play;

        $(this).html(renderer.view);
        renderer.view.style.border = "1px dashed black";

        // Images for sprites
        var images = [
            "brick",
            "brick_half",
            "brick_gray",
            "brick_gray_half",
            "brick_gray_border",
            "brick_gray_half_border",
            "ball"
        ].map(function (img) {
            return { name: img, url: imgPath + img + ".png" }
        });

        loader.add(images)
            .on("progress", loadProgressHandler)
            .load(setup);

        // Define variables that might be used in more than one function
        var brickLines, ball, counter = 1, lastTime = 0;

        function GameBall() {
            var sprite    = new Sprite(resources["ball"].texture);
            sprite.x      = renderer.width/2;
            sprite.y      = 10;
            sprite.width  = 20;
            sprite.height = 20;

            this.velocity = { x: 1, y: 2 };

            this.sprite = function () {
                return sprite;
            };

            this.update = function () {
                sprite.x += this.velocity.x;
                sprite.y += this.velocity.y;
            };
        }

        function GameBrick(name, x, y, width, height) {
            if (typeof(width) === "undefined") width = BRICK_WIDTH;
            if (typeof(height) === "undefined") height = BRICK_HEIGHT;
            var normalName     = "brick" + name;
            var grayName       = "brick_gray" + name;
            var grayBorderName = "brick_gray" + name + "_border";

            var brick    = new Sprite(resources[grayName].texture);
            brick.x      = x;
            brick.y      = y;
            brick.width  = width;
            brick.height = height;

            this.sprite   = function () {
                return brick;
            };
            this.toBorder = function () {
                brick.texture = resources[grayBorderName].texture;
            };
            this.toNormal = function () {
                brick.texture = resources[normalName].texture;
            };
            this.toGray   = function () {
                brick.texture = resources[grayName].texture;
            };
        }

        function setup() {
            brickLines = [];

            for (var i = 0; i < HOME_ROWS; ++i) {
                var bLine  = [];
                var xShift = (renderer.width - HOME_COLUMNS*BRICK_WIDTH)/2;
                var yPos   = renderer.height - BRICK_HEIGHT*(i + 1);
                if (i%2 !== 0) {
                    // Create half brick now;

                    var brickHead = new GameBrick("_half", xShift, yPos, BRICK_WIDTH/2);
                    xShift += BRICK_WIDTH/2;
                    bLine.push(brickHead);
                }
                for (var j = 0; j < HOME_COLUMNS - i%2; ++j) {
                    var brick = new GameBrick("", BRICK_WIDTH*j + xShift, yPos);
                    bLine.push(brick);
                }
                if (i%2 !== 0) {
                    var xpos      = (HOME_COLUMNS - 1)*BRICK_WIDTH + xShift;
                    var brickTail = new GameBrick("_half", xpos, yPos, BRICK_WIDTH/2);
                    bLine.push(brickTail);
                }
                brickLines.push(bLine);
            }

            for (var i = 0; i < brickLines.length; ++i) {
                for (var j = 0; j < brickLines[i].length; ++j) {
                    stage.addChild(brickLines[i][j].sprite());
                }
                if (i === 0) {
                    for (var j = 0; j < brickLines[i].length; ++j) {
                        brickLines[i][j].toBorder();
                    }
                }
            }

            // Add ball to the top center of the screen
            ball = new GameBall();
            stage.addChild(ball.sprite());

            console.log("Setup finished");
            gameLoop(0);
        }

        function loadProgressHandler(loader, resource) {
            console.log("Loading : " + resource.url);
            console.log("Progress: " + loader.progress + "%");
        }

        function gameLoop(newTime) {
            // Loop this function at 60 frames per second
            requestAnimationFrame(gameLoop);

            var deltaTime = newTime - lastTime;
            lastTime      = newTime;

            // Update the current game state
            state(deltaTime);

            // Render the stage to see the animation
            renderer.render(stage);
            ++counter;
        }

        function play(deltaTime) {
            console.log((1000/deltaTime).toFixed(2) + " fps");
            ball.update();
        }
    }
}(jQuery));

<|endoftext|>


<commit_before>let React = require('react');
let PlantCollection = require('../collections/PlantCollection');
let _ = require('backbone/node_modules/underscore');
let PlantPicker = require('./PlantPicker');
let ResizeButton = require('./ResizeButton');
let Backbone = require('backbone');

const boxLength = 30;

module.exports = React.createClass({
	getInitialState: function() {
		let width = 20;
		let height = 20;

		return {
			width: width,
			height: height,
			units: 'imperial',
			dragStart: null,
			dragCurrent: null,
			plantMatrix: this.generatePlantMatrix(width, height),
			affinityScore: 0,
			currentPlant: 1,
		};
	},

	componentWillMount: function() {
		this.plants = new PlantCollection();
		this.plants.fetch();
		this.plants.on('sync', () => {
			this.forceUpdate();
		});
		this.dispatcher = _.extend({}, Backbone.Events);
		this.dispatcher.on('currentPlantChanged', this.setCurrentPlant);
	},

	getNeighborAffinity: function(state, plantId, x, y, xOffset, yOffset) {
		let plantModel = this.plants.get(plantId);
		let neighborX = x+xOffset;
		let neighborY = y+yOffset;
		if(!plantModel) {
			return null;
		}
		if(x < 0 || y < 0 || x >= state.width || y >= state.height) {
			return null;
		}
		if(neighborX < 0 || neighborY < 0 || neighborX >= state.width || neighborY >= state.height) {
			return null;
		}

		let neighborPlantId = state.plantMatrix[neighborY][neighborX];
		let affinities = plantModel.get('affinities');
		return affinities.hasOwnProperty(neighborPlantId) ? affinities[neighborPlantId] : 0;
	},

	getAllNeighborAffinities: function(state, plantId, x, y) {
		let neighbors = [];
		let affinity = null;

		if(affinity = this.getNeighborAffinity(state, plantId, x, y, 0, -1)) {
			neighbors.push({
				xOffset: 0,
				yOffset: -1,
				descriptor: 'top',
				affinity: affinity,
			});
		}
		if(affinity = this.getNeighborAffinity(state, plantId, x, y, 1, 0)) {
			neighbors.push({
				xOffset: 1,
				yOffset: 0,
				descriptor: 'right',
				affinity: affinity,
			});
		}
		if(affinity = this.getNeighborAffinity(state, plantId, x, y, 0, 1)) {
			neighbors.push({
				xOffset: 0,
				yOffset: 1,
				descriptor: 'bottom',
				affinity: affinity,
			});
		}
		if(affinity = this.getNeighborAffinity(state, plantId, x, y, -1, 0)) {
			neighbors.push({
				xOffset: -1,
				yOffset: 0,
				descriptor: 'left',
				affinity: affinity,
			});
		}

		return neighbors;
	},

	getAffinityStyle: function(affinity) {
		switch(affinity) {
			case 1:
				return '2px solid green';
			case -1:
				return '2px solid red';
		}
		return 'auto';
	},

	getBoxStyles: function(state, plantId, x, y) {
		let styles = {};

		if(state.dragStart !== null && state.dragCurrent !== null) {
			let minX = Math.min(state.dragStart.x, state.dragCurrent.x);
			let maxX = Math.max(state.dragStart.x, state.dragCurrent.x);
			let minY = Math.min(state.dragStart.y, state.dragCurrent.y);
			let maxY = Math.max(state.dragStart.y, state.dragCurrent.y);
			let dragBorderStyle = '2px solid #000';

			if(x === minX && y >= minY && y <= maxY) {
				styles.borderLeft = dragBorderStyle;
			}

			if(x === maxX && y >= minY && y <= maxY) {
				styles.borderRight = dragBorderStyle;
			}

			if(y === minY && x >= minX && x <= maxX) {
				styles.borderTop = dragBorderStyle;
			}

			if(y === maxY && x >= minX && x <= maxX) {
				styles.borderBottom = dragBorderStyle;
			}
		}
		return styles;
	},

	render: function() {
		let plotGridStyle = {
			height: (this.state.height*boxLength)+'px',
			width: (this.state.width*boxLength)+'px',
		};

		this.state.affinityScore = 0;

		let boxElements = this.state.plantMatrix
		.map((row, y) => {
			return row.map((plantId, x) => {
				let affinities = this.getAllNeighborAffinities(this.state, plantId, x, y);
				if(affinities.length) {
					this.state.affinityScore += affinities.reduce(function(previousValue, currentValue) {
						return previousValue + currentValue.affinity;
					}, 0);
				}
				let style = affinities.reduce((style, affinity) => {
					let borderString = 'border'+affinity.descriptor.charAt(0).toUpperCase();
					borderString += affinity.descriptor.substr(1);
					style[borderString] = this.getAffinityStyle(affinity.affinity);
					return style;
				}, {});
				style = _.extend(
					style,
					this.getBoxStyles(this.state, plantId, x, y)
				);
				let innerElement = null;
				if(plantId) {
					if(this.plants.get(plantId).get('url')) {
						innerElement =
					}
					else {
						innerElement =
{this.plants.get(plantId).get('name').substr(0, 2)}
;
					}
				}
				return (

						{innerElement}

				);
			});
		})
		.reduce(function(previousArray, currentRow) {
			return previousArray.concat(currentRow);
		}, []);

		return (

				<PlantPicker plants={this.plants} dispatcher={this.dispatcher} />

							<button className={'remove' + (this.state.currentPlant ? '' : ' active')}onClick={this.setRemove}> Remove Plants</button>

						Companion Score: {this.state.affinityScore}

							<ResizeButton width={this.state.width} height={this.state.height} units={this.state.units} onChange={this.sizeChanged} />

						{boxElements}

		);
	},

	sizeChanged: function(width, height, units) {
		this.setState({
			width: width,
			height: height,
			units: units,
			plantMatrix: this.generatePlantMatrix(width, height, this.state.plantMatrix),
		});
	},

	generatePlantMatrix: function(width, height, currentPlantMatrix) {
		if(!currentPlantMatrix) {
			currentPlantMatrix = [[]];
		}

		let newMatrix = [];
		for(let y = 0; y < height; y++) {
			let row = [];
			for(let x = 0; x < width; x++) {
				if(y < currentPlantMatrix.length && x < currentPlantMatrix[y].length) {
					row.push(currentPlantMatrix[y][x]);
				}
				else {
					row.push(0);
				}
			}
			newMatrix.push(row);
		}
		return newMatrix;
	},

	boxChange: function(x, y) {
		this.state.plantMatrix[y][x] = this.state.currentPlant;
		this.setState({
			plantMatrix: this.state.plantMatrix
		});
	},

	setDragData: function(x, y, property) {
		return () => {
			if(property !== 'dragStart' && !this.state.dragStart) return;
			let stateData = {};
			stateData[property] = {
				x: x,
				y: y
			}
			this.setState(stateData);
		};
	},

	solidifyDrag: function(x, y) {
		return () => {
			if(!this.state.dragStart || !this.state.dragCurrent) {
				return;
			}
			for(let yy=Math.min(this.state.dragStart.y, y); yy<=Math.max(this.state.dragStart.y, y); yy++) {
				for(let xx=Math.min(this.state.dragStart.x, x); xx<=Math.max(this.state.dragStart.x, x); xx++) {
					this.state.plantMatrix[yy][xx] = this.state.currentPlant;
				}
			}
			this.setState({
				dragStart: null,
				dragCurrent: null,
				plantMatrix: this.state.plantMatrix
			});
		};
	},

	updatePlant: function(x, y) {
		return () => {
			this.state.plantMatrix[y][x] = this.state.currentPlant;
			this.setState({
				dragStart: null,
				dragCurrent: null,
				plantMatrix: this.state.plantMatrix
			});
		}
	},

	setCurrentPlant: function(plantId) {
		this.setState({
			currentPlant: plantId
		});
	},

	setRemove: function(e) {
		this.dispatcher.trigger('currentPlantChanged', 0);
	}
});
<commit_msg>Clean up drag problems<commit_after>let React = require('react');
let PlantCollection = require('../collections/PlantCollection');
let _ = require('backbone/node_modules/underscore');
let PlantPicker = require('./PlantPicker');
let ResizeButton = require('./ResizeButton');
let Backbone = require('backbone');

const boxLength = 30;

module.exports = React.createClass({
	getInitialState: function() {
		let width = 20;
		let height = 20;

		return {
			width: width,
			height: height,
			units: 'imperial',
			dragStart: null,
			dragCurrent: null,
			plantMatrix: this.generatePlantMatrix(width, height),
			affinityScore: 0,
			currentPlant: 1,
		};
	},

	componentWillMount: function() {
		this.plants = new PlantCollection();
		this.plants.fetch();
		this.plants.on('sync', () => {
			this.forceUpdate();
		});
		this.dispatcher = _.extend({}, Backbone.Events);
		this.dispatcher.on('currentPlantChanged', this.setCurrentPlant);
	},

	getNeighborAffinity: function(state, plantId, x, y, xOffset, yOffset) {
		let plantModel = this.plants.get(plantId);
		let neighborX = x+xOffset;
		let neighborY = y+yOffset;
		if(!plantModel) {
			return null;
		}
		if(x < 0 || y < 0 || x >= state.width || y >= state.height) {
			return null;
		}
		if(neighborX < 0 || neighborY < 0 || neighborX >= state.width || neighborY >= state.height) {
			return null;
		}

		let neighborPlantId = state.plantMatrix[neighborY][neighborX];
		let affinities = plantModel.get('affinities');
		return affinities.hasOwnProperty(neighborPlantId) ? affinities[neighborPlantId] : 0;
	},

	getAllNeighborAffinities: function(state, plantId, x, y) {
		let neighbors = [];
		let affinity = null;

		if(affinity = this.getNeighborAffinity(state, plantId, x, y, 0, -1)) {
			neighbors.push({
				xOffset: 0,
				yOffset: -1,
				descriptor: 'top',
				affinity: affinity,
			});
		}
		if(affinity = this.getNeighborAffinity(state, plantId, x, y, 1, 0)) {
			neighbors.push({
				xOffset: 1,
				yOffset: 0,
				descriptor: 'right',
				affinity: affinity,
			});
		}
		if(affinity = this.getNeighborAffinity(state, plantId, x, y, 0, 1)) {
			neighbors.push({
				xOffset: 0,
				yOffset: 1,
				descriptor: 'bottom',
				affinity: affinity,
			});
		}
		if(affinity = this.getNeighborAffinity(state, plantId, x, y, -1, 0)) {
			neighbors.push({
				xOffset: -1,
				yOffset: 0,
				descriptor: 'left',
				affinity: affinity,
			});
		}

		return neighbors;
	},

	getAffinityStyle: function(affinity) {
		switch(affinity) {
			case 1:
				return '2px solid green';
			case -1:
				return '2px solid red';
		}
		return 'auto';
	},

	getBoxStyles: function(state, plantId, x, y) {
		let styles = {};

		if(state.dragStart !== null && state.dragCurrent !== null) {
			let minX = Math.min(state.dragStart.x, state.dragCurrent.x);
			let maxX = Math.max(state.dragStart.x, state.dragCurrent.x);
			let minY = Math.min(state.dragStart.y, state.dragCurrent.y);
			let maxY = Math.max(state.dragStart.y, state.dragCurrent.y);
			let dragBorderStyle = '2px solid #000';

			if(x === minX && y >= minY && y <= maxY) {
				styles.borderLeft = dragBorderStyle;
			}

			if(x === maxX && y >= minY && y <= maxY) {
				styles.borderRight = dragBorderStyle;
			}

			if(y === minY && x >= minX && x <= maxX) {
				styles.borderTop = dragBorderStyle;
			}

			if(y === maxY && x >= minX && x <= maxX) {
				styles.borderBottom = dragBorderStyle;
			}
		}
		return styles;
	},

	render: function() {
		let plotGridStyle = {
			height: (this.state.height*boxLength)+'px',
			width: (this.state.width*boxLength)+'px',
		};

		this.state.affinityScore = 0;

		let boxElements = this.state.plantMatrix
		.map((row, y) => {
			return row.map((plantId, x) => {
				let affinities = this.getAllNeighborAffinities(this.state, plantId, x, y);
				if(affinities.length) {
					this.state.affinityScore += affinities.reduce(function(previousValue, currentValue) {
						return previousValue + currentValue.affinity;
					}, 0);
				}
				let style = affinities.reduce((style, affinity) => {
					let borderString = 'border'+affinity.descriptor.charAt(0).toUpperCase();
					borderString += affinity.descriptor.substr(1);
					style[borderString] = this.getAffinityStyle(affinity.affinity);
					return style;
				}, {});
				style = _.extend(
					style,
					this.getBoxStyles(this.state, plantId, x, y)
				);
				let innerElement = null;
				if(plantId) {
					if(this.plants.get(plantId).get('url')) {
						innerElement =
					}
					else {
						innerElement =
{this.plants.get(plantId).get('name').substr(0, 2)}
;
					}
				}
				return (

						{innerElement}

				);
			});
		})
		.reduce(function(previousArray, currentRow) {
			return previousArray.concat(currentRow);
		}, []);

		return (

				<PlantPicker plants={this.plants} dispatcher={this.dispatcher} />

							<button className={'remove' + (this.state.currentPlant ? '' : ' active')}onClick={this.setRemove}> Remove Plants</button>

						Companion Score: {this.state.affinityScore}

							<ResizeButton width={this.state.width} height={this.state.height} units={this.state.units} onChange={this.sizeChanged} />

						{boxElements}

		);
	},

	sizeChanged: function(width, height, units) {
		this.setState({
			width: width,
			height: height,
			units: units,
			plantMatrix: this.generatePlantMatrix(width, height, this.state.plantMatrix),
		});
	},

	generatePlantMatrix: function(width, height, currentPlantMatrix) {
		if(!currentPlantMatrix) {
			currentPlantMatrix = [[]];
		}

		let newMatrix = [];
		for(let y = 0; y < height; y++) {
			let row = [];
			for(let x = 0; x < width; x++) {
				if(y < currentPlantMatrix.length && x < currentPlantMatrix[y].length) {
					row.push(currentPlantMatrix[y][x]);
				}
				else {
					row.push(0);
				}
			}
			newMatrix.push(row);
		}
		return newMatrix;
	},

	boxChange: function(x, y) {
		this.state.plantMatrix[y][x] = this.state.currentPlant;
		this.setState({
			plantMatrix: this.state.plantMatrix
		});
	},

	setDragData: function(x, y, property) {
		return (e) => {
			if(property !== 'dragStart' && !this.state.dragStart) return;
			e.preventDefault();
			let stateData = {};
			stateData[property] = {
				x: x,
				y: y
			}
			this.setState(stateData);
		};
	},

	solidifyDrag: function(x, y) {
		return (e) => {
			if(!this.state.dragStart || !this.state.dragCurrent) {
				return;
			}
			e.preventDefault();
			if(_.isUndefined(x) || _.isUndefined(y)) {
				x = this.state.dragCurrent.x;
				y = this.state.dragCurrent.y;
			}
			for(let yy=Math.min(this.state.dragStart.y, y); yy<=Math.max(this.state.dragStart.y, y); yy++) {
				for(let xx=Math.min(this.state.dragStart.x, x); xx<=Math.max(this.state.dragStart.x, x); xx++) {
					this.state.plantMatrix[yy][xx] = this.state.currentPlant;
				}
			}
			this.setState({
				dragStart: null,
				dragCurrent: null,
				plantMatrix: this.state.plantMatrix
			});
		};
	},

	updatePlant: function(x, y) {
		return () => {
			this.state.plantMatrix[y][x] = this.state.currentPlant;
			this.setState({
				dragStart: null,
				dragCurrent: null,
				plantMatrix: this.state.plantMatrix
			});
		}
	},

	setCurrentPlant: function(plantId) {
		this.setState({
			currentPlant: plantId
		});
	},

	setRemove: function(e) {
		this.dispatcher.trigger('currentPlantChanged', 0);
	}
});
<|endoftext|>


<commit_before>'use strict';

(function(module) {

  var dataView = {};

  var render = function(data) {
    var template = Handlebars.compile($('#data-template').text());
    return template(data);
  };

  dataView.populateFilters = function() {
    var options;
    var template = Handlebars.compile($('#option-template').text());
    options = Data.allAuthors()
      .map(function(author) {
        return template({val: author});
      });
    $('#author-filter').append(options);

    Data.allCategories(function(rows) {
      $('#category-filter').append(
        rows.map(function(row) {
          return template({val: row.category});
        })
      );
    });
  };

  dataView.handleFilters = function() {
    $('#filters').one('change', 'select', function() {
      var resource = this.id.replace('-filter', '');
      $(this).parent().siblings().children().val('');
      page('/' + resource + '/' +
        $(this).val().replace(/\W+/g, '+')
      );
    });
  };

  dataView.index = function(data) {
    $('#data').show().siblings().hide();

    $('#data article').remove();
    data.forEach(function(a) {
      $('#data').append(render(a));
    });

    dataView.populateFilters();
    dataView.handleFilters();

  };

  module.dataView = dataView;
})(window);
<commit_msg>saving changes prior to merge<commit_after>'use strict';

(function(module) {

  var dataView = {};

  var render = function(data) {
    var template = Handlebars.compile($('#data-template').text());
    return template(data);
  };

  dataView.populateFilters = function() {
    var options;
    var template = Handlebars.compile($('#option-template').text());
    options = Data.allCountries()
      .map(function(country) {
        return template({val: country});
      });
    $('#author-filter').append(options);

    // Data.allCategories(function(rows) {
    //   $('#category-filter').append(
    //     rows.map(function(row) {
    //       return template({val: row.category});
    //     })
    //   );
    // });
  };

  dataView.handleFilters = function() {
    $('#filters').one('change', 'select', function() {
      var resource = this.id.replace('-filter', '');
      $(this).parent().siblings().children().val('');
      page('/' + resource + '/' +
        $(this).val().replace(/\W+/g, '+')
      );
    });
  };

  dataView.index = function(data) {
    $('#data').show().siblings().hide();

    $('#data article').remove();
    data.forEach(function(a) {
      $('#data').append(render(a));
    });

    dataView.populateFilters();
    dataView.handleFilters();

  };

  module.dataView = dataView;
})(window);
<|endoftext|>


<commit_before>window.SERENGETI_SPONSORED_CAMERA_TRAPS = {
  'D05': 'Daniela F. Sieff',
  'E06': 'Rafael P. Bedia',
  'F05': 'McCrea family',
  'F06': 'Turner Glynn',
  'F12': 'El_Lion',
  'G03': 'Libby Kerr',
  'G04': 'Adam Wolkon',
  'G05': 'Kristine and Bart',
  'H05': 'the Anderson Family',
  'H06': 'Kevin Boyd',
  'S09': 'Lorrne Gates',
  'I04': 'Bushtracks Expeditions (Bushtracks.com)',
  'O06': 'Hannelore Schmidt'
};
<commit_msg>Change sponsor name<commit_after>window.SERENGETI_SPONSORED_CAMERA_TRAPS = {
  'D05': 'Daniela F. Sieff',
  'E06': 'Rafael P. Bedia',
  'F05': 'McCrea family',
  'F06': 'Turner Glynn',
  'F12': 'El_Lion',
  'G03': 'Libby Kerr',
  'G04': 'Bobbie and Adam',
  'G05': 'Kristine and Bart',
  'H05': 'the Anderson Family',
  'H06': 'Kevin Boyd',
  'S09': 'Lorrne Gates',
  'I04': 'Bushtracks Expeditions (Bushtracks.com)',
  'O06': 'Hannelore Schmidt'
};
<|endoftext|>