<commit_before>'use babel';
/**
  DebuggerStateStore
  @description keeps track of current state of the Delve remote debugger,
    synchronizing our state with the debugger state
**/

import { ReduceStore } from 'flux/utils';
import Constants       from '../constants/debuggerStateConstants';

const makeBlankState = () => ({
  currentThread: null,
  currentGoroutine: null,
  threads: [],
  exited: false,
  exitStatus: null
});

export default class DebuggerStateStore extends ReduceStore {
  constructor(dispatcher) {
    super(dispatcher);
  }

  resetState() {
    this._state = this.getInitialState();
  }

  getInitialState() {
    return {
      debuggerState: makeBlankState(), stacktrace: null, goroutines: []
    };
  }

  reduce(state, action) {
    switch (action.type) {
    case Constants.DEBUGGER_CONTINUE:
      return {
        debuggerState: action.debuggerState, stacktrace: action.stacktrace,
        goroutines: action.goroutines
      };

    case Constants.DEBUGGER_NEXT:
      return {
        debuggerState: action.debuggerState, stacktrace: action.stacktrace,
        goroutines: action.goroutines
      };

    case Constants.DEBUGGER_NEXT_FAILURE:
      atom.notifications.addError(
        'Delve: Could not go to next source line',
        { dismissable: true, detail: action.error.toString() }
      ); break;

    case Constants.DEBUGGER_STEP:
      return {
        debuggerState: action.debuggerState, stacktrace: action.stacktrace,
        goroutines: action.goroutines
      };

    case Constants.DEBUGGER_STEP_FAILURE:
      atom.notifications.addError(
        'Delve: Could not step through',
        { dismissable: true, detail: action.error.toString() }
      ); break;

    case Constants.DEBUGGER_STEP_INSTR:
      return {
        debuggerState: action.debuggerState, stacktrace: action.stacktrace,
        goroutines: action.goroutines
      };

    case Constants.DEBUGGER_STEP_INSTR_FAILURE:
      atom.notifications.addError(
        'Delve: Could not step instruction',
        { dismissable: true, detail: action.error.toString() }
      ); break;

    case Constants.DEBUGGER_RESTART:
      atom.notifications.addInfo('Delve: restarted process');
      return {
        debuggerState: action.debuggerState, stacktrace: null, goroutines: []
      };

    case Constants.DEBUGGER_RESTART_FAILURE:
      atom.notifications.addError(
        'Delve: Could not restart process',
        { dismissable: true, detail: action.error.toString() }
      ); break;

    case Constants.DEBUGGER_EXITED:
      if (action.exitStatus == 0)
        atom.notifications.addInfo('Delve: Process exited normally');
      else
        atom.notifications.addError(
          `Delve: Process exited with status ${action.exitStatus}`
        );

      return this.getInitialState();

    case Constants.DEBUGGER_UNKOWN_ERROR:
      atom.notifications.addError(
        'Delve encountered an error',
        { dismissable: true, detail: action.error.toString() }
      );

      return this.getInitialState();

    default:
      return state;
    }

    return state;
  }

  getScope() {
    const thread = this.getState().currentThread;
    if (thread === null) return null;
    return {
      file: thread.file,
      line: thread.line
    };
  }

  getEvalScope() {
    const curThread = this.getState().currentThread;
    if (curThread === null) return { goroutineId: -1, frameId: 0 };
    return {
      goroutineId: curThread.goroutineID || -1,
      frameId: 0 // TODO: set to 0 until we figure out where to get it
    };
  }

  getLocals() {
    if (!this.getState().currentThread) return [];
    return this.getState().currentThread.function.locals;
  }

  getArgs() {
    if (!this.getState().currentThread) return [];
    return this.getState().currentThread.function.args;
  }

  // TODO: implement a getVars method that gets all of the locals AND
  // arguments (and if applicable any vars in scope that are not 'local')

  // TODO: for getThreads & getGoroutines inspect the current state
  // to figure which one is the current one & inject an identifier
  getThreads() {
    return this.getState().threads;
  }

  getGoroutines() {
    return this._state.goroutines;
  }

  getState() {
    return this._state.debuggerState;
  }

  getStacktrace() {
    return this._state.stacktrace;
  }
}
<commit_msg>Add 'active' prop when getting traces, threads, or goroutines<commit_after>'use babel';
/**
  DebuggerStateStore
  @description keeps track of current state of the Delve remote debugger,
    synchronizing our state with the debugger state
**/

import { ReduceStore } from 'flux/utils';
import Constants       from '../constants/debuggerStateConstants';

const makeBlankState = () => ({
  currentThread: null,
  currentGoroutine: null,
  threads: [],
  exited: false,
  exitStatus: null
});

export default class DebuggerStateStore extends ReduceStore {
  constructor(dispatcher) {
    super(dispatcher);
  }

  resetState() {
    this._state = this.getInitialState();
  }

  getInitialState() {
    return {
      debuggerState: makeBlankState(), stacktrace: null, goroutines: []
    };
  }

  reduce(state, action) {
    switch (action.type) {
    case Constants.DEBUGGER_CONTINUE:
      return {
        debuggerState: action.debuggerState, stacktrace: action.stacktrace,
        goroutines: action.goroutines
      };

    case Constants.DEBUGGER_NEXT:
      return {
        debuggerState: action.debuggerState, stacktrace: action.stacktrace,
        goroutines: action.goroutines
      };

    case Constants.DEBUGGER_NEXT_FAILURE:
      atom.notifications.addError(
        'Delve: Could not go to next source line',
        { dismissable: true, detail: action.error.toString() }
      ); break;

    case Constants.DEBUGGER_STEP:
      return {
        debuggerState: action.debuggerState, stacktrace: action.stacktrace,
        goroutines: action.goroutines
      };

    case Constants.DEBUGGER_STEP_FAILURE:
      atom.notifications.addError(
        'Delve: Could not step through',
        { dismissable: true, detail: action.error.toString() }
      ); break;

    case Constants.DEBUGGER_STEP_INSTR:
      return {
        debuggerState: action.debuggerState, stacktrace: action.stacktrace,
        goroutines: action.goroutines
      };

    case Constants.DEBUGGER_STEP_INSTR_FAILURE:
      atom.notifications.addError(
        'Delve: Could not step instruction',
        { dismissable: true, detail: action.error.toString() }
      ); break;

    case Constants.DEBUGGER_RESTART:
      atom.notifications.addInfo('Delve: restarted process');
      return {
        debuggerState: action.debuggerState, stacktrace: null, goroutines: []
      };

    case Constants.DEBUGGER_RESTART_FAILURE:
      atom.notifications.addError(
        'Delve: Could not restart process',
        { dismissable: true, detail: action.error.toString() }
      ); break;

    case Constants.DEBUGGER_EXITED:
      if (action.exitStatus == 0)
        atom.notifications.addInfo('Delve: Process exited normally');
      else
        atom.notifications.addError(
          `Delve: Process exited with status ${action.exitStatus}`
        );

      return this.getInitialState();

    case Constants.DEBUGGER_UNKOWN_ERROR:
      atom.notifications.addError(
        'Delve encountered an error',
        { dismissable: true, detail: action.error.toString() }
      );

      return this.getInitialState();

    default:
      return state;
    }

    return state;
  }

  getScope() {
    const thread = this.getState().currentThread;
    if (thread === null) return null;
    return {
      file: thread.file,
      line: thread.line
    };
  }

  getEvalScope() {
    const curThread = this.getState().currentThread;
    if (curThread === null) return { goroutineId: -1, frameId: 0 };
    return {
      goroutineId: curThread.goroutineID || -1,
      frameId: 0 // TODO: set to 0 until we figure out where to get it
    };
  }

  getLocals() {
    if (!this.getState().currentThread) return [];
    return this.getState().currentThread.function.locals;
  }

  getArgs() {
    if (!this.getState().currentThread) return [];
    return this.getState().currentThread.function.args;
  }

  // TODO: implement a getVars method that gets all of the locals AND
  // arguments (and if applicable any vars in scope that are not 'local')

  getThreads() {
    if (!this.getState() || !this.getState().threads) return [];

    const curId = this.getState().currentThread
      ? this.getState().currentThread.id
      : -1;

    return this.getState().threads.map(t => {
      t.active = t.id === curId;
      return t;
    });
  }

  getGoroutines() {
    const curId = this.getState().currentGoroutine
      ? this.getState().currentGoroutine.id
      : -1;

    return this._state.goroutines.map(g => {
      g.active = g.id === curId;
      return g;
    });
  }

  getState() {
    return this._state.debuggerState;
  }

  getStacktrace() {
    if (!this._state.stacktrace || !this.getState().currentThread) return [];

    const curPC = this.getState().currentThread.pc;
    return this._state.stacktrace.map(st => {
      st.active = st.pc === curPC;
      return st;
    });
  }
}
<|endoftext|>


<commit_before>var through = require( 'through2' );
var logger = require( 'pelias-logger' ).get( 'openaddresses' );
var peliasAdminLookup = require( 'pelias-wof-admin-lookup' );

function createAdminLookupStream(enable, peliasConfig) {
  if (enable) {
    logger.info( 'Setting up admin value lookup stream.' );
    var pipResolver = peliasAdminLookup.createWofPipResolver(peliasConfig.imports.adminLookup.url);
    return peliasAdminLookup.createLookupStream(pipResolver);
  } else {
    return through.obj(function (doc, enc, next) {
      next(null, doc);
    });
  }
}

module.exports = {
  create: createAdminLookupStream
};
<commit_msg>Use local WOF PIP service<commit_after>var through = require( 'through2' );
var logger = require( 'pelias-logger' ).get( 'openaddresses' );
var peliasAdminLookup = require( 'pelias-wof-admin-lookup' );

function createAdminLookupStream(enable) {
  if (enable) {
    logger.info( 'Setting up admin value lookup stream.' );
    var pipResolver = peliasAdminLookup.createLocalWofPipResolver();
    return peliasAdminLookup.createLookupStream(pipResolver);
  } else {
    return through.obj(function (doc, enc, next) {
      next(null, doc);
    });
  }
}

module.exports = {
  create: createAdminLookupStream
};
<|endoftext|>


<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 * Distributed under the BSD license:
 *
 * Copyright (c) 2010, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ***** END LICENSE BLOCK ***** */

define(function(require, exports, module) {
"use strict";

var Anchor = require("ace/anchor").Anchor;
var Range = require("ace/range").Range;
var comparePoints = Range.comparePoints;
var lang = require("ace/lib/lang");

var ReplCell = function(options, session) {
    this.session = session;
    this.type = options.type;
};

(function() {
    this.insert = function(pos, text) {
        if (typeof pos == "string") {
            text = pos;
            pos = this.getRange().end;
        }
        this.session.insert(pos, text);
    };
    this.setPlaceholder = function(str) {
        this.placeholder = str;

    };
    this.setMode = function() {

    };
    this.setWaiting = function(val) {
        this.waiting = val;
        this.session.repl.$updateSession();
    };
    this.prompt = "";
    this.promptType = null;
    this.setPrompt = function(str, type) {
        if (this.prompt == str)
            return;
        this.promptType = type;
        this.prompt = str || "";
        this.session.maxPromptLength = Math.max(this.session.maxPromptLength||0, this.prompt.length);
    };

    this.setValue = function(val, selection) {
        if (!this.session)
            return;
        if (val == null)
            return this.remove();
        if (this.lineWidget && val.trim())
            this.removeWidget();
        this.$updateRange();
        var pos = this.session.doc.replace(this.range, val);
        this.range.setEnd(pos);
        if (selection == 1)
            this.session.selection.setRange({start: this.range.end, end: this.range.end});
        else if (selection == -1)
            this.session.selection.setRange({start: this.range.start, end: this.range.start});
    };
    this.getValue = function() {
        if (!this.session)
            return "";
        return this.session.doc.getTextRange(this.range);
    };
    this.getRange = function() {
        this.$updateRange();
        return this.range;
    };
    this.$updateRange = function(row) {
        var cells = this.session.replCells
        if (row == null)
            row = cells.indexOf(this);

        for (i = row; i > 0; i--) {
            if (cells[i])
                break;
        }
        var cell = cells[i];
        if (!cell)
            return;
        cell.row = i;
        for (var i = row+1; i < this.session.getLength(); i++) {
            if (cells[i])
                break;
        }
        cell.endRow = i-1;
        cell.range = new Range(cell.row, 0, cell.endRow, Number.MAX_VALUE);

        return this.range;
    };

    this.removeWidget = function() {
        if (this.lineWidget) {
            var w = this.lineWidget;
            this.lineWidget = null;
            this.session.repl.removeLineWidget(w);
        }
    };

    this.addWidget = function(options) {
        if (this.lineWidget)
            this.removeWidget();

        this.setValue("")
        options.row = this.range.end.row;
        this.lineWidget = options;
        this.session.repl.addLineWidget(this.lineWidget);
    };

    this.destroy = function() {
        this.removeWidget();
        this.session = null;
    }

    this.remove = function() {
        this.session.repl.removeCell(this);
    }

}).call(ReplCell.prototype);

exports.ReplCell = ReplCell;

});<commit_msg>fix restore/cancel causes spinning wheel in the gutter<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 * Distributed under the BSD license:
 *
 * Copyright (c) 2010, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ***** END LICENSE BLOCK ***** */

define(function(require, exports, module) {
"use strict";

var Anchor = require("ace/anchor").Anchor;
var Range = require("ace/range").Range;
var comparePoints = Range.comparePoints;
var lang = require("ace/lib/lang");

var ReplCell = function(options, session) {
    this.session = session;
    this.type = options.type;
};

(function() {
    this.insert = function(pos, text) {
        if (typeof pos == "string") {
            text = pos;
            pos = this.getRange().end;
        }
        this.session.insert(pos, text);
    };
    this.setPlaceholder = function(str) {
        this.placeholder = str;

    };
    this.setMode = function() {

    };
    this.setWaiting = function(val) {
        this.waiting = val;
        this.session.repl.$updateSession();
    };
    this.prompt = "";
    this.promptType = null;
    this.setPrompt = function(str, type) {
        if (this.prompt == str)
            return;
        this.promptType = type;
        this.prompt = (str || "") + "  ";
        this.session.maxPromptLength = Math.max(this.session.maxPromptLength||0, this.prompt.length);
    };

    this.setValue = function(val, selection) {
        if (!this.session)
            return;
        if (val == null)
            return this.remove();
        if (this.lineWidget && val.trim())
            this.removeWidget();
        this.$updateRange();
        var pos = this.session.doc.replace(this.range, val);
        this.range.setEnd(pos);
        if (selection == 1)
            this.session.selection.setRange({start: this.range.end, end: this.range.end});
        else if (selection == -1)
            this.session.selection.setRange({start: this.range.start, end: this.range.start});
    };
    this.getValue = function() {
        if (!this.session)
            return "";
        return this.session.doc.getTextRange(this.range);
    };
    this.getRange = function() {
        this.$updateRange();
        return this.range;
    };
    this.$updateRange = function(row) {
        var cells = this.session.replCells;
        if (row == null)
            row = cells.indexOf(this);

        for (i = row; i > 0; i--) {
            if (cells[i])
                break;
        }
        var cell = cells[i];
        if (!cell)
            return;
        cell.row = i;
        for (var i = row+1; i < this.session.getLength(); i++) {
            if (cells[i])
                break;
        }
        cell.endRow = i-1;
        cell.range = new Range(cell.row, 0, cell.endRow, Number.MAX_VALUE);

        return this.range;
    };

    this.removeWidget = function() {
        if (this.lineWidget) {
            var w = this.lineWidget;
            this.lineWidget = null;
            this.session.repl.removeLineWidget(w);
        }
    };

    this.addWidget = function(options) {
        if (this.lineWidget)
            this.removeWidget();

        this.setValue("");
        options.row = this.range.end.row;
        this.lineWidget = options;
        this.session.repl.addLineWidget(this.lineWidget);
    };

    this.destroy = function() {
        this.removeWidget();
        this.session = null;
    };

    this.remove = function() {
        if (this.session)
            this.session.repl.removeCell(this);
    };

}).call(ReplCell.prototype);

exports.ReplCell = ReplCell;

});<|endoftext|>


<commit_before>var _ = require('underscore');
var util = require('./helpers');

var normalize = module.exports = {

  // Normalize the different ways of specifying criteria into a uniform object
  criteria: function(origCriteria) {
    var criteria = _.clone(origCriteria);

    if(!criteria) return {
      where: null
    };

    // Empty undefined values from criteria object
    _.each(criteria, function(val, key) {
      if(_.isUndefined(val)) delete criteria[key];
    });

    // Convert non-objects (ids) into a criteria
    // TODO: use customizable primary key attribute
    if(!_.isObject(criteria)) {
      criteria = {
        id: +criteria || criteria
      };
    }

    // Return string to indicate an error
    if(!_.isObject(criteria)) throw new Error('Invalid options/criteria :: ' + criteria);

    // If criteria doesn't seem to contain operational keys, assume all the keys are criteria
    if(!criteria.where && !criteria.limit && !criteria.skip && !criteria.sort && !criteria.sum && !criteria.average) {

      // Delete any residuals and then use the remaining keys as attributes in a criteria query
      delete criteria.where;
      delete criteria.limit;
      delete criteria.skip;
      delete criteria.sort;
      criteria = {
        where: criteria
      };
    }
    // If where is null, turn it into an object
    else if(_.isNull(criteria.where)) criteria.where = {};

    // If WHERE is {}, always change it back to null
    if(criteria.where && _.keys(criteria.where).length === 0) {
      criteria.where = null;
    }

    // If a LIKE was specified, normalize it
    if(criteria.where && criteria.where.like) {
      _.each(criteria.where.like, function(criterion, attrName) {
        criteria.where.like[attrName] = normalizePercentSigns(criterion);
      });
    }

    // Normalize sort criteria
    if(criteria.sort) {
      // Split string into attr and sortDirection parts (default to 'asc')
      if(_.isString(criteria.sort)) {
        var parts = criteria.sort.split(' ');

        // make criteria an object
        criteria.sort = {};
        criteria.sort[parts[0]] = parts[1] ? parts[1].toLowerCase() : 'asc';
        if(parts.length !== 2 || (parts[1].toLowerCase() !== 'asc' && parts[1].toLowerCase() !== 'desc')) {
          throw new Error('Invalid sort criteria :: ' + criteria.sort);
        }
      }

      // normalize ASC/DESC notation
      Object.keys(criteria.sort).forEach(function(attr) {
        if(criteria.sort[attr] === 'asc') criteria.sort[attr] = 1;
        if(criteria.sort[attr] === 'desc') criteria.sort[attr] = -1;
      });

      // normalize binary sorting criteria
      Object.keys(criteria.sort).forEach(function(attr) {
        if(criteria.sort[attr] === 0) criteria.sort[attr] = -1;
      });

      // Verify that user either specified a proper object
      // or provided explicit comparator function
      if(!_.isObject(criteria.sort) && !_.isFunction(criteria.sort)) {
        throw new Error('Invalid sort criteria for ' + attrName + ' :: ' + direction);
      }
    }

    return criteria;
  },

  // Normalize the capitalization and % wildcards in a like query
  // Returns false if criteria is invalid,
  // otherwise returns normalized criteria obj.
  // Enhancer is an optional function to run on each criterion to preprocess the string
  likeCriteria: function(criteria, attributes, enhancer) {

    // Only accept criteria as an object
    if(criteria !== Object(criteria)) return false;

    criteria = _.clone(criteria);

    if(!criteria.where) criteria = { where: criteria };

    // Apply enhancer to each
    if (enhancer) criteria.where = util.objMap(criteria.where, enhancer);

    criteria.where = { like: criteria.where };

    // Look for and handle % signs
    _.each(criteria.where.like, function(criterion, attrName) {
      criteria.where.like[attrName] = normalizePercentSigns(criterion);
    });

    return criteria;
  },

  // Normalize a result set from an adapter
  resultSet: function (resultSet) {

    // Ensure that any numbers that can be parsed have been
    return util.pluralize(resultSet, numberizeModel);
  }
};

// If any attribute looks like a number, but it's a string
// cast it to a number
function numberizeModel (model) {
  return util.objMap(model, numberize);
}

// If specified attr looks like a number, but it's a string, cast it to a number
function numberize (attr) {
  if (_.isString(attr) && isNumbery(attr) && parseInt(attr,10) < Math.pow(2, 53)) return +attr;
  else return attr;
}

// Returns whether this value can be successfully parsed as a finite number
function isNumbery (value) {
  return Math.pow(+value, 2) > 0;
}

// Given a criteria string inside of a "LIKE" criteria object,
// support the use of % signs to add startsWith and endsWith functionality
function normalizePercentSigns(likeCriterion) {
  // If no % signs are specified, wrap it in %
  if(!likeCriterion.match(/%/)) {
    return '%' + likeCriterion + '%';
  } else return likeCriterion;
}

// Replace % with %%%
function escapeLikeQuery(likeCriterion) {
  return likeCriterion.replace(/[^%]%[^%]/g, '%%%');
}

// Replace %%% with %

function unescapeLikeQuery(likeCriterion) {
  return likeCriterion.replace(/%%%/g, '%');
}
<commit_msg>added groupBy to normalization<commit_after>var _ = require('underscore');
var util = require('./helpers');

var normalize = module.exports = {

  // Normalize the different ways of specifying criteria into a uniform object
  criteria: function(origCriteria) {
    var criteria = _.clone(origCriteria);

    if(!criteria) return {
      where: null
    };

    // Empty undefined values from criteria object
    _.each(criteria, function(val, key) {
      if(_.isUndefined(val)) delete criteria[key];
    });

    // Convert non-objects (ids) into a criteria
    // TODO: use customizable primary key attribute
    if(!_.isObject(criteria)) {
      criteria = {
        id: +criteria || criteria
      };
    }

    // Return string to indicate an error
    if(!_.isObject(criteria)) throw new Error('Invalid options/criteria :: ' + criteria);

    // If criteria doesn't seem to contain operational keys, assume all the keys are criteria
    if(!criteria.where && !criteria.limit && !criteria.skip && !criteria.sort && !criteria.sum && !criteria.average && !criteria.groupBy) {

      // Delete any residuals and then use the remaining keys as attributes in a criteria query
      delete criteria.where;
      delete criteria.limit;
      delete criteria.skip;
      delete criteria.sort;
      criteria = {
        where: criteria
      };
    }
    // If where is null, turn it into an object
    else if(_.isNull(criteria.where)) criteria.where = {};

    // If WHERE is {}, always change it back to null
    if(criteria.where && _.keys(criteria.where).length === 0) {
      criteria.where = null;
    }

    // If a LIKE was specified, normalize it
    if(criteria.where && criteria.where.like) {
      _.each(criteria.where.like, function(criterion, attrName) {
        criteria.where.like[attrName] = normalizePercentSigns(criterion);
      });
    }

    // Normalize sort criteria
    if(criteria.sort) {
      // Split string into attr and sortDirection parts (default to 'asc')
      if(_.isString(criteria.sort)) {
        var parts = criteria.sort.split(' ');

        // make criteria an object
        criteria.sort = {};
        criteria.sort[parts[0]] = parts[1] ? parts[1].toLowerCase() : 'asc';
        if(parts.length !== 2 || (parts[1].toLowerCase() !== 'asc' && parts[1].toLowerCase() !== 'desc')) {
          throw new Error('Invalid sort criteria :: ' + criteria.sort);
        }
      }

      // normalize ASC/DESC notation
      Object.keys(criteria.sort).forEach(function(attr) {
        if(criteria.sort[attr] === 'asc') criteria.sort[attr] = 1;
        if(criteria.sort[attr] === 'desc') criteria.sort[attr] = -1;
      });

      // normalize binary sorting criteria
      Object.keys(criteria.sort).forEach(function(attr) {
        if(criteria.sort[attr] === 0) criteria.sort[attr] = -1;
      });

      // Verify that user either specified a proper object
      // or provided explicit comparator function
      if(!_.isObject(criteria.sort) && !_.isFunction(criteria.sort)) {
        throw new Error('Invalid sort criteria for ' + attrName + ' :: ' + direction);
      }
    }

    return criteria;
  },

  // Normalize the capitalization and % wildcards in a like query
  // Returns false if criteria is invalid,
  // otherwise returns normalized criteria obj.
  // Enhancer is an optional function to run on each criterion to preprocess the string
  likeCriteria: function(criteria, attributes, enhancer) {

    // Only accept criteria as an object
    if(criteria !== Object(criteria)) return false;

    criteria = _.clone(criteria);

    if(!criteria.where) criteria = { where: criteria };

    // Apply enhancer to each
    if (enhancer) criteria.where = util.objMap(criteria.where, enhancer);

    criteria.where = { like: criteria.where };

    // Look for and handle % signs
    _.each(criteria.where.like, function(criterion, attrName) {
      criteria.where.like[attrName] = normalizePercentSigns(criterion);
    });

    return criteria;
  },

  // Normalize a result set from an adapter
  resultSet: function (resultSet) {

    // Ensure that any numbers that can be parsed have been
    return util.pluralize(resultSet, numberizeModel);
  }
};

// If any attribute looks like a number, but it's a string
// cast it to a number
function numberizeModel (model) {
  return util.objMap(model, numberize);
}

// If specified attr looks like a number, but it's a string, cast it to a number
function numberize (attr) {
  if (_.isString(attr) && isNumbery(attr) && parseInt(attr,10) < Math.pow(2, 53)) return +attr;
  else return attr;
}

// Returns whether this value can be successfully parsed as a finite number
function isNumbery (value) {
  return Math.pow(+value, 2) > 0;
}

// Given a criteria string inside of a "LIKE" criteria object,
// support the use of % signs to add startsWith and endsWith functionality
function normalizePercentSigns(likeCriterion) {
  // If no % signs are specified, wrap it in %
  if(!likeCriterion.match(/%/)) {
    return '%' + likeCriterion + '%';
  } else return likeCriterion;
}

// Replace % with %%%
function escapeLikeQuery(likeCriterion) {
  return likeCriterion.replace(/[^%]%[^%]/g, '%%%');
}

// Replace %%% with %

function unescapeLikeQuery(likeCriterion) {
  return likeCriterion.replace(/%%%/g, '%');
}
<|endoftext|>


<commit_before>var _ = require('lodash');
var util = require('./helpers');
var hop = util.object.hasOwnProperty;
var switchback = require('switchback');
var errorify = require('../error');
var WLUsageError = require('../error/WLUsageError');

var normalize = module.exports = {

  // Expand Primary Key criteria into objects
  expandPK: function(context, options) {

    // Default to id as primary key
    var pk = 'id';

    // If autoPK is not used, attempt to find a primary key
    if (!context.autoPK) {
      // Check which attribute is used as primary key
      for (var key in context.attributes) {
        if (!util.object.hasOwnProperty(context.attributes[key], 'primaryKey')) continue;

        // Check if custom primaryKey value is falsy
        if (!context.attributes[key].primaryKey) continue;

        // If a custom primary key is defined, use it
        pk = key;
        break;
      }
    }

    // Check if options is an integer or string and normalize criteria
    // to object, using the specified primary key field.
    if (_.isNumber(options) || _.isString(options) || Array.isArray(options)) {
      // Temporary store the given criteria
      var pkCriteria = _.clone(options);

      // Make the criteria object, with the primary key
      options = {};
      options[pk] = pkCriteria;
    }

    // If we're querying by primary key, create a coercion function for it
    // depending on the data type of the key
    if (options && options[pk]) {

      var coercePK;
      if (context.attributes[pk].type == 'integer') {
        coercePK = function(pk) {return +pk;};
      } else if (context.attributes[pk].type == 'string') {
        coercePK = function(pk) {return String(pk).toString();};

      // If the data type is unspecified, return the key as-is
      } else {
        coercePK = function(pk) {return pk;};
      }

      // If the criteria is an array of PKs, coerce them all
      if (Array.isArray(options[pk])) {
        options[pk] = options[pk].map(coercePK);

      // Otherwise just coerce the one
      } else {
        if (!_.isObject(options[pk])) {
          options[pk] = coercePK(options[pk]);
        }
      }

    }

    return options;

  },

  // Normalize the different ways of specifying criteria into a uniform object
  criteria: function(origCriteria) {
    var criteria = _.cloneDeep(origCriteria);

    // If original criteria is already false, keep it that way.
    if (criteria === false) return criteria;

    if (!criteria) {
      return {
        where: null
      };
    }

    // Let the calling method normalize array criteria. It could be an IN query
    // where we need the PK of the collection or a .findOrCreateEach
    if (Array.isArray(criteria)) return criteria;

    // Empty undefined values from criteria object
    _.each(criteria, function(val, key) {
      if (_.isUndefined(val)) criteria[key] = null;
    });

    // Convert non-objects (ids) into a criteria
    // TODO: use customizable primary key attribute
    if (!_.isObject(criteria)) {
      criteria = {
        id: +criteria || criteria
      };
    }

    if (_.isObject(criteria) && !criteria.where && criteria.where !== null) {
      criteria = { where: criteria };
    }

    // Return string to indicate an error
    if (!_.isObject(criteria)) throw new WLUsageError('Invalid options/criteria :: ' + criteria);

    // If criteria doesn't seem to contain operational keys, assume all the keys are criteria
    if (!criteria.where && !criteria.joins && !criteria.join && !criteria.limit && !criteria.skip &&
      !criteria.sort && !criteria.sum && !criteria.average &&
      !criteria.groupBy && !criteria.min && !criteria.max && !criteria.select) {

      // Delete any residuals and then use the remaining keys as attributes in a criteria query
      delete criteria.where;
      delete criteria.joins;
      delete criteria.join;
      delete criteria.limit;
      delete criteria.skip;
      delete criteria.sort;
      criteria = {
        where: criteria
      };

    // If where is null, turn it into an object
    } else if (_.isNull(criteria.where)) criteria.where = {};

    // Move Limit, Skip, sort outside the where criteria
    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'limit')) {
      criteria.limit = parseInt(_.clone(criteria.where.limit), 10);
      if (criteria.limit < 0) criteria.limit = 0;
      delete criteria.where.limit;
    } else if (hop(criteria, 'limit')) {
      criteria.limit = parseInt(criteria.limit, 10);
      if (criteria.limit < 0) criteria.limit = 0;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'skip')) {
      criteria.skip = parseInt(_.clone(criteria.where.skip), 10);
      if (criteria.skip < 0) criteria.skip = 0;
      delete criteria.where.skip;
    } else if (hop(criteria, 'skip')) {
      criteria.skip = parseInt(criteria.skip, 10);
      if (criteria.skip < 0) criteria.skip = 0;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'sort')) {
      criteria.sort = _.clone(criteria.where.sort);
      delete criteria.where.sort;
    }

    // Pull out aggregation keys from where key
    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'sum')) {
      criteria.sum = _.clone(criteria.where.sum);
      delete criteria.where.sum;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'average')) {
      criteria.average = _.clone(criteria.where.average);
      delete criteria.where.average;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'groupBy')) {
      criteria.groupBy = _.clone(criteria.where.groupBy);
      delete criteria.where.groupBy;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'min')) {
      criteria.min = _.clone(criteria.where.min);
      delete criteria.where.min;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'max')) {
      criteria.max = _.clone(criteria.where.max);
      delete criteria.where.max;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'select')) {
      criteria.select = _.clone(criteria.where.select);
      delete criteria.where.select;
    }

    // If WHERE is {}, always change it back to null
    if (criteria.where && _.keys(criteria.where).length === 0) {
      criteria.where = null;
    }

    // If an IN was specified in the top level query and is an empty array, we can return an
    // empty object without running the query because nothing will match anyway. Let's return
    // false from here so the query knows to exit out.
    if (criteria.where) {
      var falsy = false;
      Object.keys(criteria.where).forEach(function(key) {
        if (Array.isArray(criteria.where[key]) && criteria.where[key].length === 0) {
          falsy = true;
        }
      });

      if (falsy) return false;
    }

    // If an IN was specified inside an OR clause and is an empty array, remove it because nothing will
    // match it anyway and it can prevent errors in the adapters
    if (criteria.where && hop(criteria.where, 'or')) {

      // Ensure `or` is an array
      if (!_.isArray(criteria.where.or)) {
        throw new WLUsageError('An `or` clause in a query should be specified as an array of subcriteria');
      }

      var _clone = _.cloneDeep(criteria.where.or);
      criteria.where.or.forEach(function(clause, i) {
        Object.keys(clause).forEach(function(key) {
          if (Array.isArray(clause[key]) && clause[key].length === 0) {
            _clone.splice(i, 1);
          }
        });
      });

      criteria.where.or = _clone;
    }

    // Normalize sort criteria
    if (hop(criteria, 'sort') && criteria.sort !== null) {

      // Split string into attr and sortDirection parts (default to 'asc')
      if (_.isString(criteria.sort)) {
        var parts = criteria.sort.split(' ');

        // Set default sort to asc
        parts[1] = parts[1] ? parts[1].toLowerCase() : 'asc';

        // Expand criteria.sort into object
        criteria.sort = {};
        criteria.sort[parts[0]] = parts[1];
      }

      // normalize ASC/DESC notation
      Object.keys(criteria.sort).forEach(function(attr) {

        if (_.isString(criteria.sort[attr])) {
          criteria.sort[attr] = criteria.sort[attr].toLowerCase();

          // Throw error on invalid sort order
          if (criteria.sort[attr] !== 'asc' && criteria.sort[attr] !== 'desc') {
            throw new WLUsageError('Invalid sort criteria :: ' + criteria.sort);
          }
        }

        if (criteria.sort[attr] === 'asc') criteria.sort[attr] = 1;
        if (criteria.sort[attr] === 'desc') criteria.sort[attr] = -1;
      });

      // normalize binary sorting criteria
      Object.keys(criteria.sort).forEach(function(attr) {
        if (criteria.sort[attr] === 0) criteria.sort[attr] = -1;
      });

      // Verify that user either specified a proper object
      // or provided explicit comparator function
      if (!_.isObject(criteria.sort) && !_.isFunction(criteria.sort)) {
        throw new WLUsageError('Invalid sort criteria for ' + attrName + ' :: ' + direction);
      }
    }

    return criteria;
  },

  // Normalize the capitalization and % wildcards in a like query
  // Returns false if criteria is invalid,
  // otherwise returns normalized criteria obj.
  // Enhancer is an optional function to run on each criterion to preprocess the string
  likeCriteria: function(criteria, attributes, enhancer) {

    // Only accept criteria as an object
    if (criteria !== Object(criteria)) return false;

    criteria = _.clone(criteria);

    if (!criteria.where) criteria = { where: criteria };

    // Apply enhancer to each
    if (enhancer) criteria.where = util.objMap(criteria.where, enhancer);

    criteria.where = { like: criteria.where };

    return criteria;
  },

  // Normalize a result set from an adapter
  resultSet: function(resultSet) {

    // Ensure that any numbers that can be parsed have been
    return util.pluralize(resultSet, numberizeModel);
  },

  /**
   * Normalize the different ways of specifying callbacks in built-in Waterline methods.
   * Switchbacks vs. Callbacks (but not deferred objects/promises)
   *
   * @param  {Function|Handlers} cb
   * @return {Handlers}
   */
  callback: function(cb) {

    // Build modified callback:
    // (only works for functions currently)
    var wrappedCallback;
    if (_.isFunction(cb)) {
      wrappedCallback = function(err) {

        // If no error occurred, immediately trigger the original callback
        // without messing up the context or arguments:
        if (!err) {
          return applyInOriginalCtx(cb, arguments);
        }

        // If an error argument is present, upgrade it to a WLError
        // (if it isn't one already)
        err = errorify(err);

        var modifiedArgs = Array.prototype.slice.call(arguments, 1);
        modifiedArgs.unshift(err);

        // Trigger callback without messing up the context or arguments:
        return applyInOriginalCtx(cb, modifiedArgs);
      };
    }

    //
    // TODO: Make it clear that switchback support it experimental.
    //
    // Push switchback support off until >= v0.11
    // or at least add a warning about it being a `stage 1: experimental`
    // feature.
    //

    if (!_.isFunction(cb)) wrappedCallback = cb;
    return switchback(wrappedCallback, {
      invalid: 'error', // Redirect 'invalid' handler to 'error' handler
      error: function _defaultErrorHandler() {
        console.error.apply(console, Array.prototype.slice.call(arguments));
      }
    });

    // ????
    // TODO: determine support target for 2-way switchback usage
    // ????

    // Allow callback to be -HANDLED- in different ways
    // at the app-level.
    // `cb` may be passed in (at app-level) as either:
    //    => an object of handlers
    //    => or a callback function
    //
    // If a callback function was provided, it will be
    // automatically upgraded to a simplerhandler object.
    // var cb_fromApp = switchback(cb);

    // Allow callback to be -INVOKED- in different ways.
    // (adapter def)
    // var cb_fromAdapter = cb_fromApp;

  }
};

// If any attribute looks like a number, but it's a string
// cast it to a number
function numberizeModel(model) {
  return util.objMap(model, numberize);
}

// If specified attr looks like a number, but it's a string, cast it to a number
function numberize(attr) {
  if (_.isString(attr) && isNumbery(attr) && parseInt(attr, 10) < Math.pow(2, 53)) return +attr;
  else return attr;
}

// Returns whether this value can be successfully parsed as a finite number
function isNumbery(value) {
  return Math.pow(+value, 2) > 0;
}

// Replace % with %%%
function escapeLikeQuery(likeCriterion) {
  return likeCriterion.replace(/[^%]%[^%]/g, '%%%');
}

// Replace %%% with %
function unescapeLikeQuery(likeCriterion) {
  return likeCriterion.replace(/%%%/g, '%');
}

/**
 * Like _.partial, but accepts an array of arguments instead of
 * comma-seperated args (if _.partial is `call`, this is `apply`.)
 * The biggest difference from `_.partial`, other than the usage,
 * is that this helper actually CALLS the partially applied function.
 *
 * This helper is mainly useful for callbacks.
 *
 * @param  {Function} fn   [description]
 * @param  {[type]}   args [description]
 * @return {[type]}        [description]
 */

function applyInOriginalCtx(fn, args) {
  return (_.partial.apply(null, [fn].concat(Array.prototype.slice.call(args))))();
}
<commit_msg>normalize select in criteria<commit_after>var _ = require('lodash');
var util = require('./helpers');
var hop = util.object.hasOwnProperty;
var switchback = require('switchback');
var errorify = require('../error');
var WLUsageError = require('../error/WLUsageError');

module.exports = {

  // Expand Primary Key criteria into objects
  expandPK: function(context, options) {

    // Default to id as primary key
    var pk = 'id';

    // If autoPK is not used, attempt to find a primary key
    if (!context.autoPK) {
      // Check which attribute is used as primary key
      for (var key in context.attributes) {
        if (!util.object.hasOwnProperty(context.attributes[key], 'primaryKey')) continue;

        // Check if custom primaryKey value is falsy
        if (!context.attributes[key].primaryKey) continue;

        // If a custom primary key is defined, use it
        pk = key;
        break;
      }
    }

    // Check if options is an integer or string and normalize criteria
    // to object, using the specified primary key field.
    if (_.isNumber(options) || _.isString(options) || Array.isArray(options)) {
      // Temporary store the given criteria
      var pkCriteria = _.clone(options);

      // Make the criteria object, with the primary key
      options = {};
      options[pk] = pkCriteria;
    }

    // If we're querying by primary key, create a coercion function for it
    // depending on the data type of the key
    if (options && options[pk]) {

      var coercePK;
      if (context.attributes[pk].type == 'integer') {
        coercePK = function(pk) {return +pk;};
      } else if (context.attributes[pk].type == 'string') {
        coercePK = function(pk) {return String(pk).toString();};

      // If the data type is unspecified, return the key as-is
      } else {
        coercePK = function(pk) {return pk;};
      }

      // If the criteria is an array of PKs, coerce them all
      if (Array.isArray(options[pk])) {
        options[pk] = options[pk].map(coercePK);

      // Otherwise just coerce the one
      } else {
        if (!_.isObject(options[pk])) {
          options[pk] = coercePK(options[pk]);
        }
      }

    }

    return options;

  },

  // Normalize the different ways of specifying criteria into a uniform object
  criteria: function(origCriteria) {
    var criteria = _.cloneDeep(origCriteria);

    // If original criteria is already false, keep it that way.
    if (criteria === false) return criteria;

    if (!criteria) {
      return {
        where: null
      };
    }

    // Let the calling method normalize array criteria. It could be an IN query
    // where we need the PK of the collection or a .findOrCreateEach
    if (Array.isArray(criteria)) return criteria;

    // Empty undefined values from criteria object
    _.each(criteria, function(val, key) {
      if (_.isUndefined(val)) criteria[key] = null;
    });

    // Convert non-objects (ids) into a criteria
    // TODO: use customizable primary key attribute
    if (!_.isObject(criteria)) {
      criteria = {
        id: +criteria || criteria
      };
    }

    if (_.isObject(criteria) && !criteria.where && criteria.where !== null) {
      criteria = { where: criteria };
    }

    // Return string to indicate an error
    if (!_.isObject(criteria)) throw new WLUsageError('Invalid options/criteria :: ' + criteria);

    // If criteria doesn't seem to contain operational keys, assume all the keys are criteria
    if (!criteria.where && !criteria.joins && !criteria.join && !criteria.limit && !criteria.skip &&
      !criteria.sort && !criteria.sum && !criteria.average &&
      !criteria.groupBy && !criteria.min && !criteria.max && !criteria.select) {

      // Delete any residuals and then use the remaining keys as attributes in a criteria query
      delete criteria.where;
      delete criteria.joins;
      delete criteria.join;
      delete criteria.limit;
      delete criteria.skip;
      delete criteria.sort;
      criteria = {
        where: criteria
      };

    // If where is null, turn it into an object
    } else if (_.isNull(criteria.where)) criteria.where = {};

    // Move Limit, Skip, sort outside the where criteria
    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'limit')) {
      criteria.limit = parseInt(_.clone(criteria.where.limit), 10);
      if (criteria.limit < 0) criteria.limit = 0;
      delete criteria.where.limit;
    } else if (hop(criteria, 'limit')) {
      criteria.limit = parseInt(criteria.limit, 10);
      if (criteria.limit < 0) criteria.limit = 0;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'skip')) {
      criteria.skip = parseInt(_.clone(criteria.where.skip), 10);
      if (criteria.skip < 0) criteria.skip = 0;
      delete criteria.where.skip;
    } else if (hop(criteria, 'skip')) {
      criteria.skip = parseInt(criteria.skip, 10);
      if (criteria.skip < 0) criteria.skip = 0;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'sort')) {
      criteria.sort = _.clone(criteria.where.sort);
      delete criteria.where.sort;
    }

    // Pull out aggregation keys from where key
    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'sum')) {
      criteria.sum = _.clone(criteria.where.sum);
      delete criteria.where.sum;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'average')) {
      criteria.average = _.clone(criteria.where.average);
      delete criteria.where.average;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'groupBy')) {
      criteria.groupBy = _.clone(criteria.where.groupBy);
      delete criteria.where.groupBy;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'min')) {
      criteria.min = _.clone(criteria.where.min);
      delete criteria.where.min;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'max')) {
      criteria.max = _.clone(criteria.where.max);
      delete criteria.where.max;
    }

    if (hop(criteria, 'where') && criteria.where !== null && hop(criteria.where, 'select') || hop(criteria, 'select')) {

      if(criteria.where.select) {
        criteria.select = _.clone(criteria.where.select);
      }

      // If the select contains a '*' then remove the whole projection, a '*'
      // will always return all records.
      if(!_.isArray(criteria.select)) {
        criteria.select = [criteria.select];
      }

      if(_.includes(criteria.select, '*')) {
        delete criteria.select;
      }

      delete criteria.where.select;
    }

    // If WHERE is {}, always change it back to null
    if (criteria.where && _.keys(criteria.where).length === 0) {
      criteria.where = null;
    }

    // If an IN was specified in the top level query and is an empty array, we can return an
    // empty object without running the query because nothing will match anyway. Let's return
    // false from here so the query knows to exit out.
    if (criteria.where) {
      var falsy = false;
      Object.keys(criteria.where).forEach(function(key) {
        if (Array.isArray(criteria.where[key]) && criteria.where[key].length === 0) {
          falsy = true;
        }
      });

      if (falsy) return false;
    }

    // If an IN was specified inside an OR clause and is an empty array, remove it because nothing will
    // match it anyway and it can prevent errors in the adapters
    if (criteria.where && hop(criteria.where, 'or')) {

      // Ensure `or` is an array
      if (!_.isArray(criteria.where.or)) {
        throw new WLUsageError('An `or` clause in a query should be specified as an array of subcriteria');
      }

      var _clone = _.cloneDeep(criteria.where.or);
      criteria.where.or.forEach(function(clause, i) {
        Object.keys(clause).forEach(function(key) {
          if (Array.isArray(clause[key]) && clause[key].length === 0) {
            _clone.splice(i, 1);
          }
        });
      });

      criteria.where.or = _clone;
    }

    // Normalize sort criteria
    if (hop(criteria, 'sort') && criteria.sort !== null) {

      // Split string into attr and sortDirection parts (default to 'asc')
      if (_.isString(criteria.sort)) {
        var parts = criteria.sort.split(' ');

        // Set default sort to asc
        parts[1] = parts[1] ? parts[1].toLowerCase() : 'asc';

        // Expand criteria.sort into object
        criteria.sort = {};
        criteria.sort[parts[0]] = parts[1];
      }

      // normalize ASC/DESC notation
      Object.keys(criteria.sort).forEach(function(attr) {

        if (_.isString(criteria.sort[attr])) {
          criteria.sort[attr] = criteria.sort[attr].toLowerCase();

          // Throw error on invalid sort order
          if (criteria.sort[attr] !== 'asc' && criteria.sort[attr] !== 'desc') {
            throw new WLUsageError('Invalid sort criteria :: ' + criteria.sort);
          }
        }

        if (criteria.sort[attr] === 'asc') criteria.sort[attr] = 1;
        if (criteria.sort[attr] === 'desc') criteria.sort[attr] = -1;
      });

      // normalize binary sorting criteria
      Object.keys(criteria.sort).forEach(function(attr) {
        if (criteria.sort[attr] === 0) criteria.sort[attr] = -1;
      });

      // Verify that user either specified a proper object
      // or provided explicit comparator function
      if (!_.isObject(criteria.sort) && !_.isFunction(criteria.sort)) {
        throw new WLUsageError('Invalid sort criteria for ' + attrName + ' :: ' + direction);
      }
    }

    return criteria;
  },

  // Normalize the capitalization and % wildcards in a like query
  // Returns false if criteria is invalid,
  // otherwise returns normalized criteria obj.
  // Enhancer is an optional function to run on each criterion to preprocess the string
  likeCriteria: function(criteria, attributes, enhancer) {

    // Only accept criteria as an object
    if (criteria !== Object(criteria)) return false;

    criteria = _.clone(criteria);

    if (!criteria.where) criteria = { where: criteria };

    // Apply enhancer to each
    if (enhancer) criteria.where = util.objMap(criteria.where, enhancer);

    criteria.where = { like: criteria.where };

    return criteria;
  },

  // Normalize a result set from an adapter
  resultSet: function(resultSet) {

    // Ensure that any numbers that can be parsed have been
    return util.pluralize(resultSet, numberizeModel);
  },

  /**
   * Normalize the different ways of specifying callbacks in built-in Waterline methods.
   * Switchbacks vs. Callbacks (but not deferred objects/promises)
   *
   * @param  {Function|Handlers} cb
   * @return {Handlers}
   */
  callback: function(cb) {

    // Build modified callback:
    // (only works for functions currently)
    var wrappedCallback;
    if (_.isFunction(cb)) {
      wrappedCallback = function(err) {

        // If no error occurred, immediately trigger the original callback
        // without messing up the context or arguments:
        if (!err) {
          return applyInOriginalCtx(cb, arguments);
        }

        // If an error argument is present, upgrade it to a WLError
        // (if it isn't one already)
        err = errorify(err);

        var modifiedArgs = Array.prototype.slice.call(arguments, 1);
        modifiedArgs.unshift(err);

        // Trigger callback without messing up the context or arguments:
        return applyInOriginalCtx(cb, modifiedArgs);
      };
    }

    //
    // TODO: Make it clear that switchback support it experimental.
    //
    // Push switchback support off until >= v0.11
    // or at least add a warning about it being a `stage 1: experimental`
    // feature.
    //

    if (!_.isFunction(cb)) wrappedCallback = cb;
    return switchback(wrappedCallback, {
      invalid: 'error', // Redirect 'invalid' handler to 'error' handler
      error: function _defaultErrorHandler() {
        console.error.apply(console, Array.prototype.slice.call(arguments));
      }
    });

    // ????
    // TODO: determine support target for 2-way switchback usage
    // ????

    // Allow callback to be -HANDLED- in different ways
    // at the app-level.
    // `cb` may be passed in (at app-level) as either:
    //    => an object of handlers
    //    => or a callback function
    //
    // If a callback function was provided, it will be
    // automatically upgraded to a simplerhandler object.
    // var cb_fromApp = switchback(cb);

    // Allow callback to be -INVOKED- in different ways.
    // (adapter def)
    // var cb_fromAdapter = cb_fromApp;

  }
};

// If any attribute looks like a number, but it's a string
// cast it to a number
function numberizeModel(model) {
  return util.objMap(model, numberize);
}

// If specified attr looks like a number, but it's a string, cast it to a number
function numberize(attr) {
  if (_.isString(attr) && isNumbery(attr) && parseInt(attr, 10) < Math.pow(2, 53)) return +attr;
  else return attr;
}

// Returns whether this value can be successfully parsed as a finite number
function isNumbery(value) {
  return Math.pow(+value, 2) > 0;
}

// Replace % with %%%
function escapeLikeQuery(likeCriterion) {
  return likeCriterion.replace(/[^%]%[^%]/g, '%%%');
}

// Replace %%% with %
function unescapeLikeQuery(likeCriterion) {
  return likeCriterion.replace(/%%%/g, '%');
}

/**
 * Like _.partial, but accepts an array of arguments instead of
 * comma-seperated args (if _.partial is `call`, this is `apply`.)
 * The biggest difference from `_.partial`, other than the usage,
 * is that this helper actually CALLS the partially applied function.
 *
 * This helper is mainly useful for callbacks.
 *
 * @param  {Function} fn   [description]
 * @param  {[type]}   args [description]
 * @return {[type]}        [description]
 */

function applyInOriginalCtx(fn, args) {
  return (_.partial.apply(null, [fn].concat(Array.prototype.slice.call(args))))();
}
<|endoftext|>


<commit_before>/**
 * @fileoverview Scene.js - Set up the scene
 * @author Ben Brooks (beb12@aber.ac.uk)
 * @version 1.0
 */

var objects = new Array();

function initScene() {

  projMatrix = mat4.create();
  mat4.perspective(projMatrix, settings['fov'], canvas.width/canvas.height, 0.01, 10000);

  theta = 0,
  phi   = 0;

  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.enable(gl.DEPTH_TEST);
  gl.depthFunc(gl.LEQUAL);
  gl.clearDepth(1.0);

  // Semi-accurate data taken from http://en.wikipedia.org/wiki/List_of_gravitationally_rounded_objects_of_the_Solar_System#Planets
  // Spin speed, Axial Tilt, Orbit radius, Orbit speed, Orbit inclination
  objects.push(new Planet(   0.000,   0.00,   0.00,   0.000, 0.00));
  objects.push(new Planet(  58.640,   0.00,   3.87,  47.873, 7.00));
  objects.push(new Planet(-243.018, 177.30,   7.23,  35.021, 3.39));
  objects.push(new Planet(   0.997,  23.44,  10.00,  29.786, 0.00));
  objects.push(new Planet(   1.026,  25.19,  15.24,  24.131, 1.85));
  objects.push(new Planet(   0.414,   3.12,  52.03,  13.070, 1.31));
  objects.push(new Planet(   0.444,  26.73,  95.37,   9.672, 2.48));
  objects.push(new Planet(  -0.718,  97.86, 191.91,   6.835, 0.76));
  objects.push(new Planet(   0.671,  29.58, 300.69,   5.478, 1.77));

  // objects.push(new Planet(0, 0, 0, 0, 0)); // Sun
  // objects.push(new Planet(1, 20, 10, 1, 0)); // Earth
  // objects.push(new Moon(objects[1]));

  initShaders();

  update();
  draw();

}

/**
 *
 */
function update() {

  // Loop through objects in scene and run update function
  for (var i = objects.length - 1; i >= 0; i--) {
    objects[i].update();
  };

  viewMatrix = mat4.create();
  mat4.translate(viewMatrix, viewMatrix, [0, 0, settings['zoom']]);
  mat4.rotateY(viewMatrix, viewMatrix, theta);
  mat4.rotateX(viewMatrix, viewMatrix, phi);
  mat4.rotateX(viewMatrix, viewMatrix, 45*(Math.PI/180));

  // Loop update function every 16.667ms if possible
  setTimeout(update, 1000 / 60);
}

/**
 *
 */
function draw() {

  gl.viewport(0.0, 0.0, canvas.width, canvas.height);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  // Loop through objects in scene and run draw function
  for (var i = objects.length - 1; i >= 0; i--) {
    objects[i].draw();
  };

  gl.flush();

  // Request animation frame from browser
  // (typical target 16.667ms/frame)
  requestAnimationFrame(draw);
}
<commit_msg>Add sun rotation<commit_after>/**
 * @fileoverview Scene.js - Set up the scene
 * @author Ben Brooks (beb12@aber.ac.uk)
 * @version 1.0
 */

var objects = new Array();

function initScene() {

  projMatrix = mat4.create();
  mat4.perspective(projMatrix, settings['fov'], canvas.width/canvas.height, 0.01, 10000);

  theta = 0,
  phi   = 0;

  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.enable(gl.DEPTH_TEST);
  gl.depthFunc(gl.LEQUAL);
  gl.clearDepth(1.0);

  // Semi-accurate data taken from http://en.wikipedia.org/wiki/List_of_gravitationally_rounded_objects_of_the_Solar_System#Planets
  // Spin speed, Axial Tilt, Orbit radius, Orbit speed, Orbit inclination
  objects.push(new Planet(  25.050,   0.00,   0.00,   0.000, 0.00));
  objects.push(new Planet(  58.640,   0.00,   3.87,  47.873, 7.00));
  objects.push(new Planet(-243.018, 177.30,   7.23,  35.021, 3.39));
  objects.push(new Planet(   0.997,  23.44,  10.00,  29.786, 0.00));
  objects.push(new Planet(   1.026,  25.19,  15.24,  24.131, 1.85));
  objects.push(new Planet(   0.414,   3.12,  52.03,  13.070, 1.31));
  objects.push(new Planet(   0.444,  26.73,  95.37,   9.672, 2.48));
  objects.push(new Planet(  -0.718,  97.86, 191.91,   6.835, 0.76));
  objects.push(new Planet(   0.671,  29.58, 300.69,   5.478, 1.77));

  // objects.push(new Planet(0, 0, 0, 0, 0)); // Sun
  // objects.push(new Planet(1, 20, 10, 1, 0)); // Earth
  // objects.push(new Moon(objects[1]));

  initShaders();

  update();
  draw();

}

/**
 *
 */
function update() {

  // Loop through objects in scene and run update function
  for (var i = objects.length - 1; i >= 0; i--) {
    objects[i].update();
  };

  viewMatrix = mat4.create();
  mat4.translate(viewMatrix, viewMatrix, [0, 0, settings['zoom']]);
  mat4.rotateY(viewMatrix, viewMatrix, theta);
  mat4.rotateX(viewMatrix, viewMatrix, phi);
  mat4.rotateX(viewMatrix, viewMatrix, 45*(Math.PI/180));

  // Loop update function every 16.667ms if possible
  setTimeout(update, 1000 / 60);
}

/**
 *
 */
function draw() {

  gl.viewport(0.0, 0.0, canvas.width, canvas.height);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  // Loop through objects in scene and run draw function
  for (var i = objects.length - 1; i >= 0; i--) {
    objects[i].draw();
  };

  gl.flush();

  // Request animation frame from browser
  // (typical target 16.667ms/frame)
  requestAnimationFrame(draw);
}
<|endoftext|>


<commit_before>$(function() {
  // The link to colorScheme.js is hidden by default
  // to not confuse users who don't have JavaScript
  // enabled. Make it visible now
  $('li a[href="colorScheme.html"]').css("display", "inline");

  // UI elements in colorScheme.html
  // these vars will not select anything if we are in a
  // different page
  var headerSelect = $("#headerSelect");
  var titleSelect = $("#titleSelect");
  var mainBodySelect = $("#mainBodySelect");
  var navSelect = $("#navSelect");
  var backgroundSelect = $("#backgroundSelect");

  // read the options for the selects into an array to use for
  // the random color button
  var selectOptions = [];
  $('#headerSelect > option').each(function(i, selected) {
    selectOptions[i] = $(selected).val();
  });

  function ColorSet(headerHex, titleHex, mainHex, sideHex, bgHex) {
    // Constructor for an object that stores a set of the hexcodes
    // for a specified color scheme
    this.headerHex = headerHex;
    this.titleHex = titleHex;
    this.mainHex = mainHex;
    this.sideHex = sideHex;
    this.bgHex = bgHex;
  }

  function defaultColorSet() {
    return new ColorSet('#0099FF', '#FFCC00', '#FFFFFF',
        '#808080', '#B0C4DE');
  }

  function changeColor(selector, color) {
    // changes the background-color of the elements covered
    // by selector to color
    $(selector).css("background-color", color);
  }

  function animateColor(selector, color) {
    // like changeColor, but does the change with an
    // animation, using jquery.colors.js
    // we only animate the initial change of color when the
    // user first picks the new color, all other changes of
    // the css value are done instantly with changeColor
    $(selector).animate({backgroundColor: color}, 'slow');
  }

  function save() {
    var newColors = new ColorSet(headerSelect.val(),
        titleSelect.val(),
        mainBodySelect.val(),
        navSelect.val(),
        backgroundSelect.val());
    $.cookie("color", JSON.stringify(newColors),{expires: 7});
  }

  function selectChangeEvent(selector, color)
  {
    // event that is called when one of the selects changes.
    // The elements specified by selector animate a color
    // change to color, and the cookie is updated
    // accordingly
    animateColor(selector, color);
    save();
  }

  headerSelect.change(function() {
    selectChangeEvent("header", headerSelect.val());
  });

  titleSelect.change(function() {
    selectChangeEvent("h1", titleSelect.val());
  });

  mainBodySelect.change(function() {
    selectChangeEvent("#mainText", mainBodySelect.val());
  });

  navSelect.change(function() {
    // In case the user highlighted nav li's via
    // highlightNav.js, change them too
    selectChangeEvent("nav, nav li", navSelect.val());
  });

  backgroundSelect.change(function() {
    selectChangeEvent("body", backgroundSelect.val());
  });

  function set(colSet, shouldAnimate) {
    // sets the selects' names and the background colors as
    // specified by colSet, animates if shouldAnimate is
    // true, else just changes the colors
    colSet = $.extend(defaultColorSet(), colSet);//remove null values just in case
    headerSelect.val(colSet.headerHex);
    titleSelect.val(colSet.titleHex);
    mainBodySelect.val(colSet.mainHex);
    navSelect.val(colSet.sideHex);
    backgroundSelect.val(colSet.bgHex);

    var colorFun = shouldAnimate ? animateColor : changeColor;

    colorFun("header", colSet.headerHex);
    colorFun("h1", colSet.titleHex);
    colorFun("#mainText", colSet.mainHex);
    colorFun("nav, nav li", colSet.sideHex);
    colorFun("body", colSet.bgHex);
    return true;
  }

  function resetCookie() {
    $.cookie("color", null);
  }

  $("#resetButton").click(function() {
    set(defaultColorSet(), true);
    resetCookie();
  });

  function randomNum(maxVal) {
    return Math.floor(Math.random() * maxVal);
  }

  $("#listRandom").click(function() {
    var randomColors = [];
    var numOptions = selectOptions.length;
    for (var i = 0; i < numOptions; i++) {
      randomColors[i] = selectOptions[randomNum(numOptions)];
    }
    var randCols = new ColorSet(randomColors[0], randomColors[1],
      randomColors[2], randomColors[3],
      randomColors[4]);
    set(randCols, true);
    save();
  });

  $("#expRandom").click(function() {

    function randRGBVal() {
      // FF in hex:
      var maxVal = 255;
      var colHex = randomNum(maxVal).toString(16);
      // pad it with leading 0's if needed
      while (colHex.length < 2) {
        colHex = "0" + colHex;
      }
      return colHex;
    }

    function getColorHex() {
      var red = randRGBVal();
      var green = randRGBVal();
      var blue = randRGBVal();
      return "#" + red + green + blue;
    }
    var newCols = [];
    $("select").each(function(index) {
      var col = getColorHex().toUpperCase();
      var self = $(this);
      var newColOption = $("<option>", {
        value : col,
          html : col});
      self.append(newColOption);
      self.val(col);
      newCols[index] = col;
    });
    set(new ColorSet(newCols[0], newCols[1],
          newCols[2], newCols[3],
          newCols[4]), true);
    save();
  });

  function setColorsFromCookie() {
    // reads color and sets the colors accordingly
    // does NOT animate the color change, as the page should
    // load with the changed colors, and the user should not
    // see the original ones (they have already seen an
    // animation)
    set(JSON.parse($.cookie("color")), false);
  }

  setColorsFromCookie();

});
<commit_msg>Changed function foo(..) to var foo = function(...)<commit_after>$(function() {
  // The link to colorScheme.js is hidden by default
  // to not confuse users who don't have JavaScript
  // enabled. Make it visible now
  $('li a[href="colorScheme.html"]').css("display", "inline");

  // UI elements in colorScheme.html
  // these vars will not select anything if we are in a
  // different page
  var headerSelect = $("#headerSelect");
  var titleSelect = $("#titleSelect");
  var mainBodySelect = $("#mainBodySelect");
  var navSelect = $("#navSelect");
  var backgroundSelect = $("#backgroundSelect");

  // read the options for the selects into an array to use for
  // the random color button
  var selectOptions = [];
  $('#headerSelect > option').each(function(i, selected) {
    selectOptions[i] = $(selected).val();
  });

  var ColorSet = function(headerHex, titleHex, mainHex, sideHex, bgHex) {
    // Constructor for an object that stores a set of the hexcodes
    // for a specified color scheme
    this.headerHex = headerHex;
    this.titleHex = titleHex;
    this.mainHex = mainHex;
    this.sideHex = sideHex;
    this.bgHex = bgHex;
  };

  var defaultColorSet = function() {
    return new ColorSet('#0099FF', '#FFCC00', '#FFFFFF',
        '#808080', '#B0C4DE');
  };

  var changeColor = function(selector, color) {
    // changes the background-color of the elements covered
    // by selector to color
    $(selector).css("background-color", color);
  };

  var animateColor = function(selector, color) {
    // like changeColor, but does the change with an
    // animation, using jquery.colors.js
    // we only animate the initial change of color when the
    // user first picks the new color, all other changes of
    // the css value are done instantly with changeColor
    $(selector).animate({backgroundColor: color}, 'slow');
  };

  var save = function() {
    var newColors = new ColorSet(headerSelect.val(),
        titleSelect.val(),
        mainBodySelect.val(),
        navSelect.val(),
        backgroundSelect.val());
    $.cookie("color", JSON.stringify(newColors),{expires: 7});
  };

  var selectChangeEvent = function(selector, color) {
    // event that is called when one of the selects changes.
    // The elements specified by selector animate a color
    // change to color, and the cookie is updated
    // accordingly
    animateColor(selector, color);
    save();
  };

  headerSelect.change(function() {
    selectChangeEvent("header", headerSelect.val());
  });

  titleSelect.change(function() {
    selectChangeEvent("h1", titleSelect.val());
  });

  mainBodySelect.change(function() {
    selectChangeEvent("#mainText", mainBodySelect.val());
  });

  navSelect.change(function() {
    // In case the user highlighted nav li's via
    // highlightNav.js, change them too
    selectChangeEvent("nav, nav li", navSelect.val());
  });

  backgroundSelect.change(function() {
    selectChangeEvent("body", backgroundSelect.val());
  });

  var set = function(colSet, shouldAnimate) {
    // sets the selects' names and the background colors as
    // specified by colSet, animates if shouldAnimate is
    // true, else just changes the colors
    colSet = $.extend(defaultColorSet(), colSet);//remove null values just in case
    headerSelect.val(colSet.headerHex);
    titleSelect.val(colSet.titleHex);
    mainBodySelect.val(colSet.mainHex);
    navSelect.val(colSet.sideHex);
    backgroundSelect.val(colSet.bgHex);

    var colorFun = shouldAnimate ? animateColor : changeColor;

    colorFun("header", colSet.headerHex);
    colorFun("h1", colSet.titleHex);
    colorFun("#mainText", colSet.mainHex);
    colorFun("nav, nav li", colSet.sideHex);
    colorFun("body", colSet.bgHex);
    return true;
  };

  var resetCookie = function() {
    $.cookie("color", null);
  };

  $("#resetButton").click(function() {
    set(defaultColorSet(), true);
    resetCookie();
  });

  var randomNum = function(maxVal) {
    return Math.floor(Math.random() * maxVal);
  };

  $("#listRandom").click(function() {
    var randomColors = [];
    var numOptions = selectOptions.length;
    for (var i = 0; i < numOptions; i++) {
      randomColors[i] = selectOptions[randomNum(numOptions)];
    }
    var randCols = new ColorSet(randomColors[0], randomColors[1],
      randomColors[2], randomColors[3],
      randomColors[4]);
    set(randCols, true);
    save();
  });

  $("#expRandom").click(function() {

    var randRGBVal = function() {
      // FF in hex:
      var maxVal = 255;
      var colHex = randomNum(maxVal).toString(16);
      // pad it with leading 0's if needed
      while (colHex.length < 2) {
        colHex = "0" + colHex;
      }
      return colHex;
    };

    var getColorHex = function() {
      var red = randRGBVal();
      var green = randRGBVal();
      var blue = randRGBVal();
      return "#" + red + green + blue;
    };
    var newCols = [];
    $("select").each(function(index) {
      var col = getColorHex().toUpperCase();
      var self = $(this);
      var newColOption = $("<option>", {
        value : col,
          html : col});
      self.append(newColOption);
      self.val(col);
      newCols[index] = col;
    });
    set(new ColorSet(newCols[0], newCols[1],
          newCols[2], newCols[3],
          newCols[4]), true);
    save();
  });

  var setColorsFromCookie = function() {
    // reads color and sets the colors accordingly
    // does NOT animate the color change, as the page should
    // load with the changed colors, and the user should not
    // see the original ones (they have already seen an
    // animation)
    set(JSON.parse($.cookie("color")), false);
  };

  setColorsFromCookie();

});
<|endoftext|>


<commit_before>/**
 * @class CM_FormField_Textarea
 * @extends CM_FormField_Text
 */
var CM_FormField_Textarea = CM_FormField_Text.extend({
  _class: 'CM_FormField_Textarea',

  events: {
    'blur [contenteditable]': function() {
      this.trigger('blur');
    },
    'focus [contenteditable]': function() {
      this.trigger('focus');
    },
    'input [contenteditable]': function() {
      this.triggerChange();
    },
    'change [contenteditable]': function() {
      this.triggerChange();
    },
    'keydown [contenteditable]': function(event) {
      if (this.getOptions().lengthMax > 0) {
        var isRemovalKey = _.contains([cm.keyCode.DELETE, cm.keyCode.BACKSPACE, cm.keyCode.INSERT], event.which);
        var isControl = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
        var isExceeded = this.getValue().length > this.getOptions().lengthMax;
        if (!isRemovalKey && !isControl && isExceeded) {
          event.preventDefault();
        }
        this._checkLengthMax();
      }
    },
    'paste [contenteditable]': function(event) {
      var $input = this.getInput();
      if ('plaintext-only' !== $input.attr('contenteditable')) {
        event.stopPropagation();
        event.preventDefault();
        var clipboardData = (event.originalEvent || event).clipboardData || window.clipboardData;
        var text = clipboardData.getData('text/plain');
        var html = this._convertTextToHtml(text);
        document.execCommand('insertHTML', false, html);
        this._checkLengthMax();
      }
    }
  },

  ready: function() {
    CM_FormField_SuggestOne.prototype.ready.call(this);

    this.on('change', function() {
      this._cleanEmptyWhiteSpace();
    });

    if (Modernizr.plaintextonly) {
      /**
       * Use "plaintext-only" attribute where available.
       * It's currently not available on Firefox (see https://bugzilla.mozilla.org/show_bug.cgi?id=1291467).
       * For iOS this is needed to prevent "styling" options to be displayed in the context menu.
       */
      this.getInput().attr('contenteditable', 'plaintext-only');
    }
  },

  getInput: function() {
    return this.$('[contenteditable]');
  },

  getValue: function() {
    var input = this.getInput().get(0);
    var value = input.innerText;

    // Browsers add an additional newline to the end of "contenteditable" content
    value = value.replace(/\r?\n$/, '');

    return value;
  },

  setValue: function(value) {
    var html = this._convertTextToHtml(value);
    this.getInput().html(html);
  },

  getEnabled: function() {
    return true;
  },

  reset: function() {
    this.setValue('');
  },

  /**
   * @param {String} text
   * @returns {string}
   * @private
   */
  _convertTextToHtml: function(text) {
    var html = _.escape(text);
    html = html.replace(/\r?\n/g, '
');
    return '
' + html + '
';
  },

  _cleanEmptyWhiteSpace: function() {
    if ('' === this.getValue()) {
      // Getting rid of the extra newline added by browsers to the end of the "contenteditable"
      this.getInput().empty();
    }
  },

  _checkLengthMax: function() {
    if (this.getOptions().lengthMax && this.getValue().length > this.getOptions().lengthMax) {
      this.error(cm.language.get('Too long'));
    } else {
      this.error(null);
    }
  }
});
<commit_msg>Clean selection on contenteditable blur - selection contains the caret otherwise<commit_after>/**
 * @class CM_FormField_Textarea
 * @extends CM_FormField_Text
 */
var CM_FormField_Textarea = CM_FormField_Text.extend({
  _class: 'CM_FormField_Textarea',

  events: {
    'blur [contenteditable]': function() {
      window.getSelection().removeAllRanges();
      this.trigger('blur');
    },
    'focus [contenteditable]': function() {
      this.trigger('focus');
    },
    'input [contenteditable]': function() {
      this.triggerChange();
    },
    'change [contenteditable]': function() {
      this.triggerChange();
    },
    'keydown [contenteditable]': function(event) {
      if (this.getOptions().lengthMax > 0) {
        var isRemovalKey = _.contains([cm.keyCode.DELETE, cm.keyCode.BACKSPACE, cm.keyCode.INSERT], event.which);
        var isControl = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
        var isExceeded = this.getValue().length > this.getOptions().lengthMax;
        if (!isRemovalKey && !isControl && isExceeded) {
          event.preventDefault();
        }
        this._checkLengthMax();
      }
    },
    'paste [contenteditable]': function(event) {
      var $input = this.getInput();
      if ('plaintext-only' !== $input.attr('contenteditable')) {
        event.stopPropagation();
        event.preventDefault();
        var clipboardData = (event.originalEvent || event).clipboardData || window.clipboardData;
        var text = clipboardData.getData('text/plain');
        var html = this._convertTextToHtml(text);
        document.execCommand('insertHTML', false, html);
        this._checkLengthMax();
      }
    }
  },

  ready: function() {
    CM_FormField_SuggestOne.prototype.ready.call(this);

    this.on('change', function() {
      this._cleanEmptyWhiteSpace();
    });

    if (Modernizr.plaintextonly) {
      /**
       * Use "plaintext-only" attribute where available.
       * It's currently not available on Firefox (see https://bugzilla.mozilla.org/show_bug.cgi?id=1291467).
       * For iOS this is needed to prevent "styling" options to be displayed in the context menu.
       */
      this.getInput().attr('contenteditable', 'plaintext-only');
    }
  },

  getInput: function() {
    return this.$('[contenteditable]');
  },

  getValue: function() {
    var input = this.getInput().get(0);
    var value = input.innerText;

    // Browsers add an additional newline to the end of "contenteditable" content
    value = value.replace(/\r?\n$/, '');

    return value;
  },

  setValue: function(value) {
    var html = this._convertTextToHtml(value);
    this.getInput().html(html);
  },

  getEnabled: function() {
    return true;
  },

  reset: function() {
    this.setValue('');
  },

  /**
   * @param {String} text
   * @returns {string}
   * @private
   */
  _convertTextToHtml: function(text) {
    var html = _.escape(text);
    html = html.replace(/\r?\n/g, '
');
    return '
' + html + '
';
  },

  _cleanEmptyWhiteSpace: function() {
    if ('' === this.getValue()) {
      // Getting rid of the extra newline added by browsers to the end of the "contenteditable"
      this.getInput().empty();
    }
  },

  _checkLengthMax: function() {
    if (this.getOptions().lengthMax && this.getValue().length > this.getOptions().lengthMax) {
      this.error(cm.language.get('Too long'));
    } else {
      this.error(null);
    }
  }
});
<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv<commit_msg>Update character<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: %s", length)
    try {
      child_process.execFileSync('/usr/bin/git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var args = ['commit', outFile, '-m', 'Update character']
    for (var counter = 0; counter < length; counter++)
    {
      fs.writeSync(outFD, data.slice(counter, counter+1), 0, 1)
      sleep(Math.random() * max_sleep)
      child_process.execFileSync('/usr/bin/git', args)
    }
  })
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

process.on('exit<commit_msg>Update character<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: %s", length)
    try {
      child_process.execFileSync('/usr/bin/git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var args = ['commit', outFile, '-m', 'Update character']
    for (var counter = 0; counter < length; counter++)
    {
      fs.writeSync(outFD, data.slice(counter, counter+1), 0, 1)
      sleep(Math.random() * max_sleep)
      child_process.execFileSync('/usr/bin/git', args)
    }
  })
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

process.on('exit'<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: <commit_msg>Update character<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: %<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that<commit_msg>Fixed memory parsing error #1337<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that <|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re<commit_msg>Fixed memory parsing error #1337<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: %s", length)
    try {
      child_process.execFileSync('/usr/bin/git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    for (var counter = 0; counter < length; counter++)
    {
      var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
      var args = ['commit', outFile, '-m', message]
      fs.writeSync(outFD, data.slice(counter, counter+1), 0, 1)
      sleep(Math.random() * max_sleep)
      child_process.execFileSync('/usr/bin/git', args)
    }
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [time in seconds]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

process.on('exit', function () {
  var args = ['push']
  child_process.execFileSync('/usr/bin/git', args)
})

function randomIntFromInterval(min,max)
{
   retu<commit_msg>Someone poisoned the waterhole!<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: %s", length)
    try {
      child_process.execFileSync('/usr/bin/git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    for (var counter = 0; counter < length; counter++)
    {
      var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
      var args = ['commit', outFile, '-m', message]
      fs.writeSync(outFD, data.slice(counter, counter+1), 0, 1)
      sleep(Math.random() * max_sleep)
      child_process.execFileSync('/usr/bin/git', args)
    }
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [time in seconds]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

process.on('exit', function () {
  var args = ['push']
  child_process.execFileSync('/usr/bin/git', args)
})

function randomIntFromInterval(min,max)
{
   retur<|endoftext|>


<commit_before>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes",
  "Merging in private branch",
  "Time machines are real man!"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var <commit_msg>Ooops!<commit_after>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes",
  "Merging in private branch",
  "Time machines are real man!"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length<|endoftext|>