<commit_before>/*global jQuery: false, alert: false, obviel: false, _: false */
/*jshint white: false, browser: true, onevar: false, undef: true,
eqeqeq: true, plusplus: false, bitwise: true, regexp: true, newcap: true,
immed: true, strict: false, maxlen: 80, maxerr: 9999 */

if (typeof obviel === "undefined") {
    var obviel = {};
}

obviel.sync = {};

(function($, module) {
    module.ConnectionError = function(message) {
        this.name = 'ConnectionError';
        this.message = message;
    };

    var mappings = {};

    // var defaults = {
    //     source: {
    //         update: {
    //             finder: getById
    //         }

    //     },
    //     target: {
    //         update: {
    //             http: {
    //                 method: 'POST',
    //                 url: function(m) { return m.obj.updateUrl; }
    //             },
    //             socket: {
    //                 type: function(m) { return m.obj.updateType; }
    //             }
    //         },
    //         refresh: {
    //             http: {
    //                 method: 'GET',
    //                 url: function(m) { return m.obj['refreshUrl']; },
    //                 response: obviel.sync.multiUpdater
    //             }
    //         },
    //         add: {
    //             http: {
    //                 method: 'POST',
    //                 url: function(m) { return m.container.addUrl; },
    //                 response: obviel.sync.multiUpdater
    //             }
    //         }
    //     }
    // };

    module.mapping = function(m) {
        // XXX should use cleverer iface storage aware of inheritance?
        mappings[m.iface] = m;
    };

    var ObjectMutator = function(session, obj) {
        this.session = session;
        this.obj = obj;
    };

    ObjectMutator.prototype.get = function(name) {
        var value = this.obj[name];
        // XXX special case for non-obj attributes, and array attributes
        if ($.isObject(value)) {
            return ObjectMutator(this.session, value);
        } else if ($.isArray(value)) {
            return ArrayMutator(this.session, this.obj, name);
        } else {
            return value;
        }
    };

    ObjectMutator.prototype.set = function(name, value) {
        this.obj[name] = value;
        this.session.update(this.obj);
    };

    var ArrayMutator = function(session, obj, arrayName) {
        this.session = session;
        this.obj = obj;
        this.arrayName = arrayName;
    };

    ArrayMutator.prototype.push = function(value) {
        this.obj[this.arrayName].push(value);
        this.session.add(this.obj, this.arrayName, value);
    };

    module.registerSessionFunc = function(name, argNames) {
        Session.prototype[name] = function() {
            var d = {},
                i = 0,
                argName;
            d['name'] = name;
            for (i = 0; i < argNames.length; i++) {
                d[argNames[i]] = arguments[i];
            }
            this.actions.push(d);
        };
    };

    var Session = function(connection) {
        this.connection = connection;
        this.actions = [];
    };

    module.registerSessionFunc('add', ['container', 'propertyName', 'obj']);
    module.registerSessionFunc('update', ['obj']);
    module.registerSessionFunc('refresh', ['obj']);

    Session.prototype.commit = function() {
        var i, action,
            conn = this.connection,
            promises = [];

        for (i = 0; i < this.actions.length; i++) {
            action = this.actions[i];
            promises.push(conn[action.name](action));

            // if (action.name === 'add') {
            //     promises.push(conn.add(action));
            // } else if (action.name === 'update') {
            //     promises.push(conn.update(action));
            // } else if (action.name === 'refresh') {
            //     promises.push(conn.refresh(action));
            // }
        }

        this.connection.complete();
        return $.when.apply(null, promises);
    };

    module.multiUpdater = function(connection, entries) {
        var i, finder, entry;
        if (!$.isArray(entries)) {
            entries = [entries];
        }
        for (i = 0; i < entries.length; i++) {
            entry = entries[i];
            finder = connection.getSource(entry.iface).update.finder;
            if (!finder) {
                // XXX is this an error?
                continue;
            }
            objectUpdater(finder(entry), entry);
        }
    };

    Session.prototype.processSource = function(obj) {
        var entries=obj.obvielsync,
            source, i, entry, info;
        for (i = 0; i < entries.length; i++) {
            entry = entries[i];
            if (entry.action === 'update') {
                source = this.connection.getSource(entry.obj.iface);
                objectUpdater(source.update.finder(entry.obj), entry.obj);
            } else if (entry.action === 'add') {
                source = this.connection.getSource(entry.obj.iface);
                info = source.add.finder(entry.obj);
                info.container[info.propertyName].push(entry.obj);
            }
        }
    };

    Session.prototype.mutator = function(obj) {
        return new Mutator(obj);
    };

    // Session.prototype.remove = function(container, propertyName, obj) {

    // };

    module.Connection = function() {
        return this;
    };

    module.Connection.prototype.getTarget = function(iface) {
        var target = mappings[iface].target;
        if (target === undefined) {
            throw new module.ConnectionError("No target defined");
        }
        return target;
    };

    module.Connection.prototype.getSource = function(iface) {
        var source = mappings[iface].source;
        if (source === undefined) {
            throw new module.ConnectionError("No source defined");
        }
        return source;
    };

    module.Connection.prototype.getPropertiesFunc = function(context) {
        throw new module.ConnectionError("Not implemented");
    };

    module.Connection.prototype.add = function(m) {
        var target = this.getTarget(m.container.iface),
            add = target.add;
        if (add === undefined) {
            throw new module.ConnectionError("No add defined for target");
        }
        return this.processTarget(this.getPropertiesFunc(add)(m), m.obj);
    };

    module.Connection.prototype.update = function(m) {
        var target = this.getTarget(m.obj.iface),
            update = target.update;
        if (update === undefined) {
            throw new module.ConnectionError("No update defined for target");
        }
        return this.processTarget(this.getPropertiesFunc(update)(m), m.obj);
    };

    module.Connection.prototype.refresh = function(m) {
        var target = this.getTarget(m.obj.iface),
            refresh = target.refresh;
        if (refresh === undefined) {
            throw new module.ConnectionError("No refresh defined for source");
        }
        return this.processTarget(this.getPropertiesFunc(refresh)(m), m.obj);
    };

    module.Connection.prototype.complete = function() {

    };

    module.Connection.prototype.session = function() {
        return new Session(this);
    };

    module.HttpConnection = function() {
    };

    module.HttpConnection.prototype = new module.Connection();

    module.HttpConnection.prototype.getPropertiesFunc = function(m) {
        return m.httpProperties;
    };

    module.HttpConnection.prototype.processTarget = function(properties, obj) {
        var self = this,
            data,
            method = properties.method || 'POST';

        if (method === 'POST') {
            data = JSON.stringify(obj);
        } else {
            data = null;
        }
        return $.ajax({
            type: method,
            url: properties.url,
            processData: false,
            contentType: 'application/json',
            dataType: 'json',
            data: data
        }).done(function(responseObj) {
            var response = properties.response;
            if (!response) {
                return;
            }
            response(self, responseObj);
        });
    };

    // module.HttpConnection.prototype.processSource = function(properties, obj) {
    //     return $.ajax({
    //         type: properties.method || 'GET',
    //         url: properties.url,
    //         processData: false,
    //         contentType: 'application/json',
    //         dataType: 'json'
    //     }).done(function(newObj) {
    //         objectUpdater(obj, newObj);
    //     });
    // };

    module.SocketIoConnection = function(io) {
        this.io = io;
    };

    module.SocketIoConnection.prototype = new module.Connection();

    module.SocketIoConnection.prototype.getPropertiesFunc = function(m) {
        return m.socketProperties;
    };

    module.SocketIoConnection.prototype.processTarget = function(properties, obj) {
        this.io.emit(properties.type, obj);
    };

    var rules = {};

    var handlers = {};

    module.clear = function () {
        rules = {};
        handlers = {};
    };

    var objectUpdater = function (target, source) {
        var seen = {};
        for (var key in source) {
            var value = source[key];
            target[key] = value;
            seen[key] = true;
        }
        // XXX not safe in the face of model inheritance
        for (key in target) {
            if (key.substring(0, 6) === 'jQuery') {
                continue;
            }
            var found = seen[key];
            // XXX this is sometimes the right thing to do, but sometimes
            // isn't. model deletions explicitly?
            //if (!found) {
            //    delete target[key];
            //}
        }
    };

    module.objectUpdateRule = function (eventName, transformer, finder) {
        rules[eventName] = function (obj) {
            var source = transformer(eventName, obj);
            var target = finder(source);
            objectUpdater(target, source);
            $(target).triggerHandler(
                'objectUpdate',
                [{obj: target}]);
        };
    };

    module.objectAddRule = function(eventName, transformer, finder, getName) {
        rules[eventName] = function (obj) {
            obj = transformer(eventName, obj);
            var container = finder(obj);
            var name = getName(container, obj);
            container[name] = obj;
            $(container).triggerHandler(
                'objectAdd',
                [{container: container,
                  obj: obj,
                  name: name}]);
        };
    };

    module.arrayAddRule = function(eventName, transformer, finder) {
        rules[eventName] = function (obj) {
            obj = transformer(eventName, obj);
            var found = finder(obj);
            var container = found.container;
            var array = container[found.arrayName];
            var index = array.length;
            array.push(obj);
            $(container).triggerHandler(
                'arrayAdd',
                [{container: container,
                  obj: obj,
                  arrayName: found.arrayName,
                  array: array,
                  index: index}]);
        };
    };

    module.objectDeleteRule = function(eventName, transformer, finder,
                                       getName) {
        rules[eventName] = function (obj) {
            obj = transformer(eventName, obj);
            var container = finder(obj);
            var name = getName(container, obj);
            delete container[name];
            $(container).triggerHandler(
                'objectDelete',
                {container: container,
                 name: name,
                 obj: obj});
        };
    };

    module.arrayDeleteRule = function(eventName, transformer, finder,
                                      getIndex) {
        rules[eventName] = function (obj) {
            obj = transformer(eventName, obj);
            var found = finder(obj);
            var container = found.container;
            var array = container[found.arrayName];
            var index = getIndex(array, obj);
            if (index === -1) {
                return;
            }
            array.splice(index, 1);
            $(container).triggerHandler(
                'arrayDelete',
                [{container: container,
                  obj: obj,
                  arrayName: found.arrayName,
                  array: array,
                  index: index}]);
        };
    };

    module.triggerRule = function (eventName, obj) {
        var rule = rules[eventName];
        if (rule === undefined) {
            return;
        }
        rule(obj);
    };

}(jQuery, obviel.sync));
<commit_msg>Make more code generic.<commit_after>/*global jQuery: false, alert: false, obviel: false, _: false */
/*jshint white: false, browser: true, onevar: false, undef: true,
eqeqeq: true, plusplus: false, bitwise: true, regexp: true, newcap: true,
immed: true, strict: false, maxlen: 80, maxerr: 9999 */

if (typeof obviel === "undefined") {
    var obviel = {};
}

obviel.sync = {};

(function($, module) {
    module.ConnectionError = function(message) {
        this.name = 'ConnectionError';
        this.message = message;
    };

    var mappings = {};

    // var defaults = {
    //     source: {
    //         update: {
    //             finder: getById
    //         }

    //     },
    //     target: {
    //         update: {
    //             http: {
    //                 method: 'POST',
    //                 url: function(m) { return m.obj.updateUrl; }
    //             },
    //             socket: {
    //                 type: function(m) { return m.obj.updateType; }
    //             }
    //         },
    //         refresh: {
    //             http: {
    //                 method: 'GET',
    //                 url: function(m) { return m.obj['refreshUrl']; },
    //                 response: obviel.sync.multiUpdater
    //             }
    //         },
    //         add: {
    //             http: {
    //                 method: 'POST',
    //                 url: function(m) { return m.container.addUrl; },
    //                 response: obviel.sync.multiUpdater
    //             }
    //         }
    //     }
    // };

    module.mapping = function(m) {
        // XXX should use cleverer iface storage aware of inheritance?
        mappings[m.iface] = m;
    };

    var ObjectMutator = function(session, obj) {
        this.session = session;
        this.obj = obj;
    };

    ObjectMutator.prototype.get = function(name) {
        var value = this.obj[name];
        // XXX special case for non-obj attributes, and array attributes
        if ($.isObject(value)) {
            return ObjectMutator(this.session, value);
        } else if ($.isArray(value)) {
            return ArrayMutator(this.session, this.obj, name);
        } else {
            return value;
        }
    };

    ObjectMutator.prototype.set = function(name, value) {
        this.obj[name] = value;
        this.session.update(this.obj);
    };

    var ArrayMutator = function(session, obj, arrayName) {
        this.session = session;
        this.obj = obj;
        this.arrayName = arrayName;
    };

    ArrayMutator.prototype.push = function(value) {
        this.obj[this.arrayName].push(value);
        this.session.add(this.obj, this.arrayName, value);
    };

    module.registerSessionFunc = function(name, argNames, ifaceObj) {
        Session.prototype[name] = function() {
            var d = {},
                i = 0,
                argName;
            d.name = name;
            for (i = 0; i < argNames.length; i++) {
                d[argNames[i]] = arguments[i];
            }
            d.iface = d[ifaceObj].iface;
            this.actions.push(d);
        };
    };

    var Session = function(connection) {
        this.connection = connection;
        this.actions = [];
    };

    module.registerSessionFunc('add', ['container', 'propertyName', 'obj'],
                              'container');
    module.registerSessionFunc('update', ['obj'], 'obj');
    module.registerSessionFunc('refresh', ['obj'], 'obj');

    Session.prototype.commit = function() {
        var i, action,
            conn = this.connection,
            promises = [],
            iface;

        for (i = 0; i < this.actions.length; i++) {
            action = this.actions[i];
            promises.push(conn.processAction(action, action.iface));
        }

        this.connection.complete();
        return $.when.apply(null, promises);
    };

    module.multiUpdater = function(connection, entries) {
        var i, finder, entry;
        if (!$.isArray(entries)) {
            entries = [entries];
        }
        for (i = 0; i < entries.length; i++) {
            entry = entries[i];
            finder = connection.getSource(entry.iface).update.finder;
            if (!finder) {
                // XXX is this an error?
                continue;
            }
            objectUpdater(finder(entry), entry);
        }
    };

    Session.prototype.processSource = function(obj) {
        var entries=obj.obvielsync,
            source, i, entry, info;
        for (i = 0; i < entries.length; i++) {
            entry = entries[i];
            if (entry.action === 'update') {
                source = this.connection.getSource(entry.obj.iface);
                objectUpdater(source.update.finder(entry.obj), entry.obj);
            } else if (entry.action === 'add') {
                source = this.connection.getSource(entry.obj.iface);
                info = source.add.finder(entry.obj);
                info.container[info.propertyName].push(entry.obj);
            }
        }
    };

    Session.prototype.mutator = function(obj) {
        return new Mutator(obj);
    };

    // Session.prototype.remove = function(container, propertyName, obj) {

    // };

    module.Connection = function() {
        return this;
    };

    module.Connection.prototype.getTarget = function(iface) {
        var target = mappings[iface].target;
        if (target === undefined) {
            throw new module.ConnectionError("No target defined");
        }
        return target;
    };

    module.Connection.prototype.getSource = function(iface) {
        var source = mappings[iface].source;
        if (source === undefined) {
            throw new module.ConnectionError("No source defined");
        }
        return source;
    };

    module.Connection.prototype.getPropertiesFunc = function(context) {
        throw new module.ConnectionError("Not implemented");
    };

    module.Connection.prototype.processAction = function(m, iface) {
        var target = this.getTarget(iface),
            config = target[m.name];
        if (config === undefined) {
            throw new module.ConnectionError(
                "No " + m.name + " defined for target");
        }
        return this.processTarget(this.getPropertiesFunc(config)(m), m.obj);
    };

    module.Connection.prototype.add = function(m) {
        var target = this.getTarget(m.container.iface),
            add = target.add;
        if (add === undefined) {
            throw new module.ConnectionError("No add defined for target");
        }
        return this.processTarget(this.getPropertiesFunc(add)(m), m.obj);
    };

    module.Connection.prototype.update = function(m) {
        var target = this.getTarget(m.obj.iface),
            update = target.update;
        if (update === undefined) {
            throw new module.ConnectionError("No update defined for target");
        }
        return this.processTarget(this.getPropertiesFunc(update)(m), m.obj);
    };

    module.Connection.prototype.refresh = function(m) {
        var target = this.getTarget(m.obj.iface),
            refresh = target.refresh;
        if (refresh === undefined) {
            throw new module.ConnectionError("No refresh defined for source");
        }
        return this.processTarget(this.getPropertiesFunc(refresh)(m), m.obj);
    };

    module.Connection.prototype.complete = function() {

    };

    module.Connection.prototype.session = function() {
        return new Session(this);
    };

    module.HttpConnection = function() {
    };

    module.HttpConnection.prototype = new module.Connection();

    module.HttpConnection.prototype.getPropertiesFunc = function(m) {
        return m.httpProperties;
    };

    module.HttpConnection.prototype.processTarget = function(properties, obj) {
        var self = this,
            data,
            method = properties.method || 'POST';

        if (method === 'POST') {
            data = JSON.stringify(obj);
        } else {
            data = null;
        }
        return $.ajax({
            type: method,
            url: properties.url,
            processData: false,
            contentType: 'application/json',
            dataType: 'json',
            data: data
        }).done(function(responseObj) {
            var response = properties.response;
            if (!response) {
                return;
            }
            response(self, responseObj);
        });
    };

    // module.HttpConnection.prototype.processSource = function(properties, obj) {
    //     return $.ajax({
    //         type: properties.method || 'GET',
    //         url: properties.url,
    //         processData: false,
    //         contentType: 'application/json',
    //         dataType: 'json'
    //     }).done(function(newObj) {
    //         objectUpdater(obj, newObj);
    //     });
    // };

    module.SocketIoConnection = function(io) {
        this.io = io;
    };

    module.SocketIoConnection.prototype = new module.Connection();

    module.SocketIoConnection.prototype.getPropertiesFunc = function(m) {
        return m.socketProperties;
    };

    module.SocketIoConnection.prototype.processTarget = function(properties, obj) {
        this.io.emit(properties.type, obj);
    };

    var rules = {};

    var handlers = {};

    module.clear = function () {
        rules = {};
        handlers = {};
    };

    var objectUpdater = function (target, source) {
        var seen = {};
        for (var key in source) {
            var value = source[key];
            target[key] = value;
            seen[key] = true;
        }
        // XXX not safe in the face of model inheritance
        for (key in target) {
            if (key.substring(0, 6) === 'jQuery') {
                continue;
            }
            var found = seen[key];
            // XXX this is sometimes the right thing to do, but sometimes
            // isn't. model deletions explicitly?
            //if (!found) {
            //    delete target[key];
            //}
        }
    };

    module.objectUpdateRule = function (eventName, transformer, finder) {
        rules[eventName] = function (obj) {
            var source = transformer(eventName, obj);
            var target = finder(source);
            objectUpdater(target, source);
            $(target).triggerHandler(
                'objectUpdate',
                [{obj: target}]);
        };
    };

    module.objectAddRule = function(eventName, transformer, finder, getName) {
        rules[eventName] = function (obj) {
            obj = transformer(eventName, obj);
            var container = finder(obj);
            var name = getName(container, obj);
            container[name] = obj;
            $(container).triggerHandler(
                'objectAdd',
                [{container: container,
                  obj: obj,
                  name: name}]);
        };
    };

    module.arrayAddRule = function(eventName, transformer, finder) {
        rules[eventName] = function (obj) {
            obj = transformer(eventName, obj);
            var found = finder(obj);
            var container = found.container;
            var array = container[found.arrayName];
            var index = array.length;
            array.push(obj);
            $(container).triggerHandler(
                'arrayAdd',
                [{container: container,
                  obj: obj,
                  arrayName: found.arrayName,
                  array: array,
                  index: index}]);
        };
    };

    module.objectDeleteRule = function(eventName, transformer, finder,
                                       getName) {
        rules[eventName] = function (obj) {
            obj = transformer(eventName, obj);
            var container = finder(obj);
            var name = getName(container, obj);
            delete container[name];
            $(container).triggerHandler(
                'objectDelete',
                {container: container,
                 name: name,
                 obj: obj});
        };
    };

    module.arrayDeleteRule = function(eventName, transformer, finder,
                                      getIndex) {
        rules[eventName] = function (obj) {
            obj = transformer(eventName, obj);
            var found = finder(obj);
            var container = found.container;
            var array = container[found.arrayName];
            var index = getIndex(array, obj);
            if (index === -1) {
                return;
            }
            array.splice(index, 1);
            $(container).triggerHandler(
                'arrayDelete',
                [{container: container,
                  obj: obj,
                  arrayName: found.arrayName,
                  array: array,
                  index: index}]);
        };
    };

    module.triggerRule = function (eventName, obj) {
        var rule = rules[eventName];
        if (rule === undefined) {
            return;
        }
        rule(obj);
    };

}(jQuery, obviel.sync));
<|endoftext|>


<commit_before>goog.provide('ol.control.DragBox');

goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.style');
goog.require('ol.Size');
goog.require('ol.control.Control');

/**
 * @constructor
 * @extends {ol.control.Control}
 * @param {ol.Map} map Map.
 * @param {ol.Coordinate=} opt_startCoordinate start coordinate of the box.
 *     If not provided, call {@link startBox} to start the box.
 */
ol.control.DragBox = function(map, opt_startCoordinate) {

  goog.base(this, map);

  /**
   * @type {Element}
   * @private
   */
  this.divElement_ = goog.dom.createDom(goog.dom.TagName.DIV, 'ol-dragbox');

  /**
   * @type {ol.Pixel|undefined}
   * @private
   */
  this.startPixel_ = null;

  if (goog.isDef(opt_startCoordinate)) {
    this.startBox(opt_startCoordinate);
  }

};
goog.inherits(ol.control.DragBox, ol.control.Control);

/**
 * @inheritDoc
 */
ol.control.DragBox.prototype.getElement = function() {
  return this.divElement_;
};

/**
 * Adds a box to the map, at the specified coordinate. Dragging will change
 * the size of the box.
 * @param {ol.Coordinate} startCoordinate The coordinate to start the box at.
 */
ol.control.DragBox.prototype.startBox = function(startCoordinate) {
  var map = this.getMap();
  this.startPixel_ = map.getPixelFromCoordinate(startCoordinate);
  goog.asserts.assert(goog.isDef(this.startPixel_));
  goog.style.setPosition(this.divElement_, this.startPixel_);
  goog.style.setBorderBoxSize(this.divElement_, new ol.Size(0, 0));
  goog.dom.append(/** @type {!Node} */ (map.getViewport()), this.divElement_);
  goog.events.listen(
      map, ol.MapBrowserEvent.EventType.DRAG,
      this.updateBox_, false, this);
  goog.events.listen(
      map, ol.MapBrowserEvent.EventType.DRAGEND,
      this.finalizeBox_, false, this);
};

/**
 * @param {ol.MapBrowserEvent} mapBrowserEvent The event to handle.
 * @private
 */
ol.control.DragBox.prototype.updateBox_ = function(mapBrowserEvent) {
  var map = this.getMap();
  var coordinate = mapBrowserEvent.getCoordinate();
  goog.asserts.assert(goog.isDef(coordinate));
  var currentPixel = map.getPixelFromCoordinate(coordinate);
  goog.style.setPosition(this.divElement_, new ol.Pixel(
      Math.min(currentPixel.x, this.startPixel_.x),
      Math.min(currentPixel.y, this.startPixel_.y)));
  goog.style.setBorderBoxSize(this.divElement_, new ol.Size(
      Math.abs(currentPixel.x - this.startPixel_.x),
      Math.abs(currentPixel.y - this.startPixel_.y)));
};

/**
 * @private
 */
ol.control.DragBox.prototype.finalizeBox_ = function() {
  var map = this.getMap();
  goog.events.unlisten(
      map, ol.MapBrowserEvent.EventType.DRAG,
      this.updateBox_, false, this);
  goog.events.unlisten(
      map, ol.MapBrowserEvent.EventType.DRAGEND,
      this.finalizeBox_, false, this);
};

/**
 * Removes the box from the map.
 */
ol.control.DragBox.prototype.removeBox = function() {
  goog.dom.removeNode(this.divElement_);
};

/**
 * @inheritDoc
 */
ol.control.DragBox.prototype.disposeInternal = function() {
  this.finalizeBox_();
  this.removeBox();
  delete this.divElement_;
  delete this.startPixel_;
  goog.base(this, 'disposeInternal');
};
<commit_msg>Remove ol.control.DragBox temporarily<commit_after><|endoftext|>


<commit_before>'use strict';

const acorn = require('acorn-jsx');
const esrecurse = require('esrecurse');
const escodegen = require('escodegen');

const htmlElements = require('./constants.js').htmlElements;
const reactMethods = require('./constants.js').reactMethods;

/**
 * Recursively walks AST and extracts ES5 React component names, child components, props and state
 * @param {ast} ast
 * @returns {Object} Nested object containing name, children, props and state properties of components
 */
function getES5ReactComponents(ast) {
  let output = {
    name: '',
    state: [],
    props: [],
    methods: [],
    children: [],
  },
  topJsxComponent;
  esrecurse.visit(ast, {
    VariableDeclarator: function (node) {
      topJsxComponent = node.id.name;
      this.visitChildren(node);
    },
    MemberExpression: function (node) {
      if (node.property && node.property.name === "createClass") {
        output.name = topJsxComponent;
      }
    },
    ObjectExpression: function (node) {
      node.properties.forEach(prop => {
        switch (prop.key.name) {
          case "getInitialState":
            output.state = getReactStates(prop.value.body.body[0].argument);
            break;
          default:
            if (reactMethods.indexOf(prop.key.name) < 0
                && prop.value.type === 'FunctionExpression') {
              output.methods.push(prop.key.name);
            }
            break;
        }
      });
      this.visitChildren(node);
    },
    JSXElement: function (node) {
      output.children = getChildJSXElements(node);
      output.props = getReactProps(node);
    },
  });
  return output;
}

function getReactStates (node) {
  const stateStr = escodegen.generate(node);
  let states;
  eval('states = ' + stateStr);

  let output = [];
  for (let state in states) {
    output.push({
      name: state,
      value: states[state]
    });
  }

  return output;
}

/**
 * Returns array of props from React component passed to input
 * @param {Node} node
 * @returns {Array} Array of all JSX props on React component
 */
function getReactProps (node) {
  if (node.openingElement.attributes.length === 0) return [];
  return node.openingElement.attributes
    .map(attribute => { return { name: attribute.name.name }; });
}

/**
 * Returns array of children components of React component passed to input
 * @param {Node} node
 * @returns {Array} Array of (nested) children of React component passed in
 */
function getChildJSXElements (node) {
  if (node.children.length === 0) return [];
  var childJsxComponentsArr = node
    .children
    .filter(jsx => jsx.type === "JSXElement"
    && htmlElements.indexOf(jsx.openingElement.name.name) < 0);
  return childJsxComponentsArr
    .map(child => {
      return {
        name: child.openingElement.name.name,
        children: getChildJSXElements(child),
        props: getReactProps(child),
        state: [],
        methods: [],
      };
    })
}

/**
 * Returns if AST node is an ES6 React component
 * @param {Node} node
 * @return {Boolean} Determines if AST node is a React component node
 */
function isES6ReactComponent (node) {
  return (node.superClass.property && node.superClass.property.name === "Component")
    || node.superClass.name === "Component"
}

/**
 * Helper function to convert Javascript stringified code to an AST using acorn-jsx library
 * @param js
 */
function jsToAst(js) {
  const ast = acorn.parse(js, {
    plugins: { jsx: true }
  });
  if (ast.body.length === 0) throw new Error('Empty AST input');
  return ast;
}

function componentChecker(ast) {
  for (let i = 0; i < ast.body.length; i++) {
    if (ast.body[i].type === 'ClassDeclaration' || ast.body[i].type === 'ExportDefaultDeclaration') return true;
  }
  return false;
}

/**
 * Recursively walks AST and extracts ES5 React component names, child components, props and state
 * @param {ast} ast
 * @returns {Object} Nested object containing name, children, props and state properties of components
 */
function getES5ReactComponents(ast) {
  let output = {
    name: '',
    state: [],
    props: [],
    methods: [],
    children: [],
  },
  topJsxComponent;
  esrecurse.visit(ast, {
    VariableDeclarator: function (node) {
      topJsxComponent = node.id.name;
      this.visitChildren(node);
    },
    MemberExpression: function (node) {
      if (node.property && node.property.name === "createClass") {
        output.name = topJsxComponent;
      }
      this.visitChildren(node);
    },
    ObjectExpression: function (node) {
      node.properties.forEach(prop => {
        switch (prop.key.name) {
          case "getInitialState":
            output.state = getReactStates(prop.value.body.body[0].argument);
            break;
          default:
            if (reactMethods.indexOf(prop.key.name) < 0
                && prop.value.type === 'FunctionExpression') {
              output.methods.push(prop.key.name);
            }
            break;
        }
      });
      this.visitChildren(node);
    },
    JSXElement: function (node) {
      output.children = getChildJSXElements(node);
      output.props = getReactProps(node);
    },
  });
  return output;
}

/**
 * Recursively walks AST and extracts ES6 React component names, child components, props and state
 * @param {ast} ast
 * @returns {Object} Nested object containing name, children, props and state properties of components
 */
function getES6ReactComponents(ast) {
  let output = {
    name: '',
    props: [],
    state: [],
    methods: [],
    children: [],
  };
  esrecurse.visit(ast, {
    ClassDeclaration: function (node) {
      if (isES6ReactComponent(node)) {
        output.name = node.id.name;
        this.visitChildren(node);
      }
    },
    MethodDefinition: function (node) {
      if (reactMethods.indexOf(node.key.name) < 0)
        output.methods.push(node.key.name);
      this.visitChildren(node);
    },
    ExpressionStatement: function (node) {
      if  (node.expression.left && node.expression.left.property && node.expression.left.property.name === 'state') {
        output.state = getReactStates(node.expression.right)
      }
      this.visitChildren(node);
    },
    JSXElement: function (node) {
      output.children = getChildJSXElements(node);
      output.props = getReactProps(node);
    },
  });

  return output;
}

/**
 * Recursively walks AST extracts name, child component, and props for a stateless functional component
 * Still a WIP - no way to tell if it is actually a component or just a function
 * @param {ast} ast
 * @returns {Object} Nested object containing name, children, and props properties of components
 */
function getStatelessFunctionalComponents(ast) {
  let output = {
    name: '',
    props: [],
    state: [],
    methods: [],
    children: [],
  },
  topJsxComponent;
  esrecurse.visit(ast, {
    VariableDeclarator: function (node) {
      if (output.name === '') output.name = topJsxComponent = node.id.name;
      this.visitChildren(node);
    },

    JSXElement: function (node) {
      output.children = getChildJSXElements(node);
      output.props = getReactProps(node);
    },
  })
  return output;
}

/**
 * Helper function to convert Javascript stringified code to an AST using acorn-jsx library
 * @param js
 */
function jsToAst(js) {
  const ast = acorn.parse(js, {
    plugins: { jsx: true }
  });
  if (ast.body.length === 0) throw new Error('Empty AST input');
  return ast;
}

function componentChecker(ast) {
  for (let i = 0; i < ast.body.length; i++) {
    if (ast.body[i].type === 'ClassDeclaration') return true;
    if (ast.body[i].type === 'ExportDefaultDeclaration' && ast.body[i].declaration.type === 'ClassDeclaration') return true;
  }
  return false;
}

module.exports = {
  jsToAst,
  componentChecker,
  getES5ReactComponents,
  getES6ReactComponents,
  getStatelessFunctionalComponents
};<commit_msg>remove duplicate function definition for getES5ReactComponents<commit_after>'use strict';

const acorn = require('acorn-jsx');
const esrecurse = require('esrecurse');
const escodegen = require('escodegen');

const htmlElements = require('./constants.js').htmlElements;
const reactMethods = require('./constants.js').reactMethods;

function getReactStates (node) {
  const stateStr = escodegen.generate(node);
  let states;
  eval('states = ' + stateStr);

  let output = [];
  for (let state in states) {
    output.push({
      name: state,
      value: states[state]
    });
  }

  return output;
}

/**
 * Returns array of props from React component passed to input
 * @param {Node} node
 * @returns {Array} Array of all JSX props on React component
 */
function getReactProps (node) {
  if (node.openingElement.attributes.length === 0) return [];
  return node.openingElement.attributes
    .map(attribute => { return { name: attribute.name.name }; });
}

/**
 * Returns array of children components of React component passed to input
 * @param {Node} node
 * @returns {Array} Array of (nested) children of React component passed in
 */
function getChildJSXElements (node) {
  if (node.children.length === 0) return [];
  var childJsxComponentsArr = node
    .children
    .filter(jsx => jsx.type === "JSXElement"
    && htmlElements.indexOf(jsx.openingElement.name.name) < 0);
  return childJsxComponentsArr
    .map(child => {
      return {
        name: child.openingElement.name.name,
        children: getChildJSXElements(child),
        props: getReactProps(child),
        state: [],
        methods: [],
      };
    })
}

/**
 * Returns if AST node is an ES6 React component
 * @param {Node} node
 * @return {Boolean} Determines if AST node is a React component node
 */
function isES6ReactComponent (node) {
  return (node.superClass.property && node.superClass.property.name === "Component")
    || node.superClass.name === "Component"
}

/**
 * Helper function to convert Javascript stringified code to an AST using acorn-jsx library
 * @param js
 */
function jsToAst(js) {
  const ast = acorn.parse(js, {
    plugins: { jsx: true }
  });
  if (ast.body.length === 0) throw new Error('Empty AST input');
  return ast;
}

function componentChecker(ast) {
  for (let i = 0; i < ast.body.length; i++) {
    if (ast.body[i].type === 'ClassDeclaration' || ast.body[i].type === 'ExportDefaultDeclaration') return true;
  }
  return false;
}

/**
 * Recursively walks AST and extracts ES5 React component names, child components, props and state
 * @param {ast} ast
 * @returns {Object} Nested object containing name, children, props and state properties of components
 */
function getES5ReactComponents(ast) {
  let output = {
    name: '',
    state: [],
    props: [],
    methods: [],
    children: [],
  },
  topJsxComponent;
  esrecurse.visit(ast, {
    VariableDeclarator: function (node) {
      topJsxComponent = node.id.name;
      this.visitChildren(node);
    },
    MemberExpression: function (node) {
      if (node.property && node.property.name === "createClass") {
        output.name = topJsxComponent;
      }
      this.visitChildren(node);
    },
    ObjectExpression: function (node) {
      node.properties.forEach(prop => {
        switch (prop.key.name) {
          case "getInitialState":
            output.state = getReactStates(prop.value.body.body[0].argument);
            break;
          default:
            if (reactMethods.indexOf(prop.key.name) < 0
                && prop.value.type === 'FunctionExpression') {
              output.methods.push(prop.key.name);
            }
            break;
        }
      });
      this.visitChildren(node);
    },
    JSXElement: function (node) {
      output.children = getChildJSXElements(node);
      output.props = getReactProps(node);
    },
  });
  return output;
}

/**
 * Recursively walks AST and extracts ES6 React component names, child components, props and state
 * @param {ast} ast
 * @returns {Object} Nested object containing name, children, props and state properties of components
 */
function getES6ReactComponents(ast) {
  let output = {
    name: '',
    props: [],
    state: [],
    methods: [],
    children: [],
  };
  esrecurse.visit(ast, {
    ClassDeclaration: function (node) {
      if (isES6ReactComponent(node)) {
        output.name = node.id.name;
        this.visitChildren(node);
      }
    },
    MethodDefinition: function (node) {
      if (reactMethods.indexOf(node.key.name) < 0)
        output.methods.push(node.key.name);
      this.visitChildren(node);
    },
    ExpressionStatement: function (node) {
      if  (node.expression.left && node.expression.left.property && node.expression.left.property.name === 'state') {
        output.state = getReactStates(node.expression.right)
      }
      this.visitChildren(node);
    },
    JSXElement: function (node) {
      output.children = getChildJSXElements(node);
      output.props = getReactProps(node);
    },
  });

  return output;
}

/**
 * Recursively walks AST extracts name, child component, and props for a stateless functional component
 * Still a WIP - no way to tell if it is actually a component or just a function
 * @param {ast} ast
 * @returns {Object} Nested object containing name, children, and props properties of components
 */
function getStatelessFunctionalComponents(ast) {
  let output = {
    name: '',
    props: [],
    state: [],
    methods: [],
    children: [],
  },
  topJsxComponent;
  esrecurse.visit(ast, {
    VariableDeclarator: function (node) {
      if (output.name === '') output.name = topJsxComponent = node.id.name;
      this.visitChildren(node);
    },

    JSXElement: function (node) {
      output.children = getChildJSXElements(node);
      output.props = getReactProps(node);
    },
  })
  return output;
}

/**
 * Helper function to convert Javascript stringified code to an AST using acorn-jsx library
 * @param js
 */
function jsToAst(js) {
  const ast = acorn.parse(js, {
    plugins: { jsx: true }
  });
  if (ast.body.length === 0) throw new Error('Empty AST input');
  return ast;
}

function componentChecker(ast) {
  for (let i = 0; i < ast.body.length; i++) {
    if (ast.body[i].type === 'ClassDeclaration') return true;
    if (ast.body[i].type === 'ExportDefaultDeclaration' && ast.body[i].declaration.type === 'ClassDeclaration') return true;
  }
  return false;
}

module.exports = {
  jsToAst,
  componentChecker,
  getES5ReactComponents,
  getES6ReactComponents,
  getStatelessFunctionalComponents
};<|endoftext|>


<commit_before>(function() {

var ƒ = Rpd.unit;

    // inlets/outlets are at the left/right sides of a node body
var QUARTZ_MODE = 'quartz',
    // inlets/outlets are at the top/bottom sides of a node body
    PD_MODE = 'pd';

var defaultConfig = {
    mode: QUARTZ_MODE,
    // show inlet/outlet value only when user hovers over its connector
    // (always showing, by default)
    valuesOnHover: false,
    // show inlets/outlets and node types for debugging purposes
    showTypes: false,
    // show node containers for debugging purposes
    showBoxes: false,
    // are nodes allowed to be dragged
    nodesMovingAllowed: true,
    // show the list of nodes
    renderNodeList: true,
    // is node list collapsed by default, if shown
    nodeListCollapsed: true,
    // dimensions of the box used to measure everything
    boxSize: [ 100, 40 ],
    // width of a link, sometimes it's hard to catch so could be increased
    linkWidth: null, // null means use the value from CSS
    // a time for value update or error effects on inlets/outlets
    effectTime: 1000
};

// either use the full d3.js library or the super-tiny version provided with RPD
var d3 = d3_tiny || d3;

var tree = {
    patches: {},
    nodes: {},
    inlets: {},
    outlets: {},
    links: {}
};

function HtmlRenderer(patch) {

return function(networkRoot, userConfig) {

    var config = mergeConfig(userConfig, defaultConfig);

    return {

        // the object below reacts on every Patch event and constructs corresponding
        // HTML structures in response, or modifies them;

        'patch/is-ready': function(update) {

            var docElm = d3.select(document.documentElement);

            root = d3.select(document.createElement('div'))
                     .attr('class', function() {
                         var classes = [ 'rpd-patch' ];
                         classes.push('rpd-layout-' + config.mode);
                         classes.push('rpd-values-' + (config.valuesOnHover ? 'on-hover' : 'always-shown'));
                         if (config.showBoxes) classes.push('rpd-show-boxes');
                         return classes.join(' ');
                     })
                     .style('height', docElm.property('clientHeight') + 'px')
                     .data(update.patch);

            tree.patches[patch.id] = root;

            Kefir.fromEvents(docElm.node(), 'resize').onValue(function() {
                root.style('height', docElm.property('clientHeight') + 'px');
            });

        }

    }

} // function(target, config)

} // function(patch)

// =============================================================================
// =========================== registration ====================================
// =============================================================================

Rpd.HtmlRenderer = HtmlRenderer;

Rpd.renderer('html', HtmlRenderer);

})();
<commit_msg>patch/is-ready, patch/enter<commit_after>(function() {

var ƒ = Rpd.unit;

    // inlets/outlets are at the left/right sides of a node body
var QUARTZ_MODE = 'quartz',
    // inlets/outlets are at the top/bottom sides of a node body
    PD_MODE = 'pd';

var defaultConfig = {
    mode: QUARTZ_MODE,
    // show inlet/outlet value only when user hovers over its connector
    // (always showing, by default)
    valuesOnHover: false,
    // show inlets/outlets and node types for debugging purposes
    showTypes: false,
    // show node containers for debugging purposes
    showBoxes: false,
    // are nodes allowed to be dragged
    nodesMovingAllowed: true,
    // show the list of nodes
    renderNodeList: true,
    // is node list collapsed by default, if shown
    nodeListCollapsed: true,
    // dimensions of the box used to measure everything
    boxSize: [ 100, 40 ],
    // width of a link, sometimes it's hard to catch so could be increased
    linkWidth: null, // null means use the value from CSS
    // a time for value update or error effects on inlets/outlets
    effectTime: 1000
};

// either use the full d3.js library or the super-tiny version provided with RPD
var d3 = d3_tiny || d3;

var tree = {
    patches: {},
    nodes: {},
    inlets: {},
    outlets: {},
    links: {}
};

function HtmlRenderer(patch) {

return function(networkRoot, userConfig) {

    var config = mergeConfig(userConfig, defaultConfig);

    networkRoot = d3.select(networkRoot)
                    .classed('rpd-network', true);

    return {

        // the object below reacts on every Patch event and constructs corresponding
        // HTML structures in response, or modifies them;

        'patch/is-ready': function(update) {

            var docElm = d3.select(document.documentElement);

            var root = d3.select(document.createElement('div'))
                         .property('className', function() {
                             var classes = [ 'rpd-patch' ];
                             classes.push('rpd-layout-' + config.mode);
                             classes.push('rpd-values-' + (config.valuesOnHover ? 'on-hover' : 'always-shown'));
                             if (config.showBoxes) classes.push('rpd-show-boxes');
                             return classes.join(' ');
                         })
                         .style('height', docElm.property('clientHeight') + 'px')
                         .data(update.patch);

            tree.patches[patch.id] = root;

            Kefir.fromEvents(docElm.node(), 'resize').onValue(function() {
                root.style('height', docElm.property('clientHeight') + 'px');
            });

        },

        'patch/enter': function(update) {
            networkRoot.append(tree.patches[update.patch.id].node());
        }

    }

} // function(target, config)

} // function(patch)

// =============================================================================
// =========================== registration ====================================
// =============================================================================

Rpd.HtmlRenderer = HtmlRenderer;

Rpd.renderer('html', HtmlRenderer);

})();
<|endoftext|>


<commit_before>'use strict'

const MetaRole = require('roles_meta')
const CONTROLLER_MESSAGE = '* Self Managed Code * quorum.tedivm.com * #quorum in Slack *'

class Spook extends MetaRole {
  getBuild (room, options) {
    return [MOVE]
  }

  manageCreep (creep) {
    // Disable notifications of attack since this creep will head into hostile rooms.
    if (!creep.memory.dn) {
      creep.memory.dn = true
      creep.notifyWhenAttacked(false)
    }

    // Delete current target if it is currently visible.
    if (creep.memory.starget && Game.rooms[creep.memory.starget]) {
      delete creep.memory.starget
    }

    // Harass current room by signing controller and stomping contruction sites.
    if (!creep.room.controller || !creep.room.controller.my) {
      if (!creep.memory.stomproom || creep.memory.stomproom !== creep.room.name) {
        creep.memory.stomproom = creep.room.name
        creep.memory.stomptime = Game.time
      }

      if (Game.time - creep.memory.stomptime < 70) {
        // Find and destroy any hostile construction sites
        if (this.stompConstruction(creep)) {
          return
        }
        // Tag the controller
        if (this.signController(creep)) {
          return
        }
      }
    }

    // Move on to the next room
    this.migrateRooms(creep)
  }

  stompConstruction (creep) {
    // Use cached construction site
    if (creep.memory.stomp) {
      let construction = Game.getObjectById(creep.memory.stomp)
      if (construction) {
        creep.travelTo(construction)
        return true
      } else {
        delete creep.memory.stomp
      }
    }
    // Find a new site to stomp, excluding any being stood on.
    const construction = creep.pos.findClosestByRange(FIND_HOSTILE_CONSTRUCTION_SITES, {filter: function (site) {
      return site.pos.getRangeTo(creep) > 0
    }})
    if (!construction) {
      return false
    }
    creep.memory.stomp = construction.id
    creep.travelTo(construction)
    return true
  }

  signController (creep) {
    if (!creep.room.controller) {
      return false
    }
    if (creep.room.controller.sign && creep.room.controller.sign.text === CONTROLLER_MESSAGE) {
      return false
    }
    if (creep.pos.isNearTo(creep.room.controller)) {
      creep.signController(creep.room.controller, CONTROLLER_MESSAGE)
    } else {
      creep.travelTo(creep.room.controller)
    }
    return true
  }

  migrateRooms (creep) {
    let target
    if (creep.memory.starget && creep.memory.starget !== creep.room.name) {
      target = creep.memory.starget
    } else {
      target = Room.getScoutTarget(creep)
      creep.memory.starget = target
    }
    if (creep.travelTo(new RoomPosition(25, 25, target), {range: 23}) === ERR_NO_PATH) {
      delete creep.memory.starget
    }
  }
}

module.exports = Spook
<commit_msg>Different controller message for public account<commit_after>'use strict'

const MetaRole = require('roles_meta')
let CONTROLLER_MESSAGE
if (PUBLIC_ACCOUNT) {
  CONTROLLER_MESSAGE = 'Self Managed Code * quorum.tedivm.com * github.com/ScreepsQuorum/screeps-quorum * #quorum in Slack'
} else {
  CONTROLLER_MESSAGE = 'Fully Autonomous Open Source Bot * github.com/ScreepsQuorum/screeps-quorum * #quorum in Slack'
}

class Spook extends MetaRole {
  getBuild (room, options) {
    return [MOVE]
  }

  manageCreep (creep) {
    // Disable notifications of attack since this creep will head into hostile rooms.
    if (!creep.memory.dn) {
      creep.memory.dn = true
      creep.notifyWhenAttacked(false)
    }

    // Delete current target if it is currently visible.
    if (creep.memory.starget && Game.rooms[creep.memory.starget]) {
      delete creep.memory.starget
    }

    // Harass current room by signing controller and stomping contruction sites.
    if (!creep.room.controller || !creep.room.controller.my) {
      if (!creep.memory.stomproom || creep.memory.stomproom !== creep.room.name) {
        creep.memory.stomproom = creep.room.name
        creep.memory.stomptime = Game.time
      }

      if (Game.time - creep.memory.stomptime < 70) {
        // Find and destroy any hostile construction sites
        if (this.stompConstruction(creep)) {
          return
        }
        // Tag the controller
        if (this.signController(creep)) {
          return
        }
      }
    }

    // Move on to the next room
    this.migrateRooms(creep)
  }

  stompConstruction (creep) {
    // Use cached construction site
    if (creep.memory.stomp) {
      let construction = Game.getObjectById(creep.memory.stomp)
      if (construction) {
        creep.travelTo(construction)
        return true
      } else {
        delete creep.memory.stomp
      }
    }
    // Find a new site to stomp, excluding any being stood on.
    const construction = creep.pos.findClosestByRange(FIND_HOSTILE_CONSTRUCTION_SITES, {filter: function (site) {
      return site.pos.getRangeTo(creep) > 0
    }})
    if (!construction) {
      return false
    }
    creep.memory.stomp = construction.id
    creep.travelTo(construction)
    return true
  }

  signController (creep) {
    if (!creep.room.controller) {
      return false
    }
    if (creep.room.controller.sign && creep.room.controller.sign.username === USERNAME) {
      return false
    }
    if (creep.pos.isNearTo(creep.room.controller)) {
      creep.signController(creep.room.controller, CONTROLLER_MESSAGE)
    } else {
      creep.travelTo(creep.room.controller)
    }
    return true
  }

  migrateRooms (creep) {
    let target
    if (creep.memory.starget && creep.memory.starget !== creep.room.name) {
      target = creep.memory.starget
    } else {
      target = Room.getScoutTarget(creep)
      creep.memory.starget = target
    }
    if (creep.travelTo(new RoomPosition(25, 25, target), {range: 23}) === ERR_NO_PATH) {
      delete creep.memory.starget
    }
  }
}

module.exports = Spook
<|endoftext|>


<commit_before>import { createSelector } from 'reselect'
import get from 'lodash/fp/get'

import * as constants from './constants'

/**
 * Given an augmented page doc, attempts to calculate its approx. freeze dry page size in MB.
 * @param {any} pageDoc The augmented page doc from search results.
 * @returns {string} Approx. size in MB of freeze-dry attachment. 0 if not found.
 */
function calcFreezeDrySize(pageDoc) {
    const pageSize = get(['_attachments', 'frozen-page.html', 'length'])(pageDoc)
    const sizeInMB = pageSize !== undefined
        ? Math.round(pageSize / 1024**2 * 10) / 10
        : 0

    return sizeInMB.toString()
}

/**
 * Either set display title to be the top-level title field, else look in content. Fallback is the URL.
 * @param {any} pageDoc The augmented page doc from search results.
 * @returns {string} Title string to display from page title, or URL in case of bad data..
 */
function decideTitle(pageDoc) {
    if (pageDoc.title) return pageDoc.title

    return (pageDoc.content && pageDoc.content.title) ? pageDoc.content.title : pageDoc.url
}

export const overview = state => state.overview
const searchResult = createSelector(overview, state => state.searchResult)
const resultDocs = createSelector(searchResult, results => results.docs)
export const currentQueryParams = createSelector(overview, state => state.currentQueryParams)
export const isLoading = createSelector(overview, state => state.isLoading)
export const noResults = createSelector(resultDocs, isLoading, (docs, isLoading) => docs.length === 0 && !isLoading)
export const currentPage = createSelector(overview, state => state.currentPage)
export const resultsSkip = createSelector(currentPage, page => page * constants.PAGE_SIZE)
export const deleteConfirmProps = createSelector(overview, state => state.deleteConfirmProps)
export const isDeleteConfShown = createSelector(deleteConfirmProps, state => state.isShown)
export const urlToDelete = createSelector(deleteConfirmProps, state => state.url)

export const results = createSelector(
    resultDocs,
    docs => docs.map(pageDoc => ({
        ...pageDoc,
        freezeDrySize: calcFreezeDrySize(pageDoc),
        title: decideTitle(pageDoc),
    })),
)

const resultsExhausted = createSelector(searchResult, results => results.resultsExhausted)
export const needsPagWaypoint = createSelector(
    resultsExhausted, isLoading,
    (isExhausted, isLoading) => !isLoading && !isExhausted,
)
<commit_msg>Move skip state derivation to results state length<commit_after>import { createSelector } from 'reselect'
import get from 'lodash/fp/get'

import * as constants from './constants'

/**
 * Given an augmented page doc, attempts to calculate its approx. freeze dry page size in MB.
 * @param {any} pageDoc The augmented page doc from search results.
 * @returns {string} Approx. size in MB of freeze-dry attachment. 0 if not found.
 */
function calcFreezeDrySize(pageDoc) {
    const pageSize = get(['_attachments', 'frozen-page.html', 'length'])(pageDoc)
    const sizeInMB = pageSize !== undefined
        ? Math.round(pageSize / 1024**2 * 10) / 10
        : 0

    return sizeInMB.toString()
}

/**
 * Either set display title to be the top-level title field, else look in content. Fallback is the URL.
 * @param {any} pageDoc The augmented page doc from search results.
 * @returns {string} Title string to display from page title, or URL in case of bad data..
 */
function decideTitle(pageDoc) {
    if (pageDoc.title) return pageDoc.title

    return (pageDoc.content && pageDoc.content.title) ? pageDoc.content.title : pageDoc.url
}

export const overview = state => state.overview
const searchResult = createSelector(overview, state => state.searchResult)
const resultDocs = createSelector(searchResult, results => results.docs)
export const currentQueryParams = createSelector(overview, state => state.currentQueryParams)
export const isLoading = createSelector(overview, state => state.isLoading)
export const noResults = createSelector(resultDocs, isLoading, (docs, isLoading) => docs.length === 0 && !isLoading)
export const currentPage = createSelector(overview, state => state.currentPage)
export const resultsSkip = createSelector(resultDocs, results => results.length)
export const deleteConfirmProps = createSelector(overview, state => state.deleteConfirmProps)
export const isDeleteConfShown = createSelector(deleteConfirmProps, state => state.isShown)
export const urlToDelete = createSelector(deleteConfirmProps, state => state.url)

export const results = createSelector(
    resultDocs,
    docs => docs.map(pageDoc => ({
        ...pageDoc,
        freezeDrySize: calcFreezeDrySize(pageDoc),
        title: decideTitle(pageDoc),
    })),
)

const resultsExhausted = createSelector(searchResult, results => results.resultsExhausted)
export const needsPagWaypoint = createSelector(
    resultsExhausted, isLoading,
    (isExhausted, isLoading) => !isLoading && !isExhausted,
)
<|endoftext|>


<commit_before>/**
 * Copied from Node-Google-Text-To-Speech module
 * https://github.com/ashafir20/node-google-text-to-speech
 *
 * Altered to not change output to Base64 String, and since I'm
 * modifying it for my own purposes, I'll make it more directly tied in
 * as a VO creation script
 */

var request = require('request');
var fs = require('fs');
var File = require('../utils/File')
var http = require('http');
var path = require('path');

/**
 * Escape special characters in the given string of html.
 *
 * @param  {String} languageLocale = the target locale language (example : en)
 * @param  {String} word = the word to translate to speech
 * @param  {function({'audio' : String, 'message' : String })} callback = function invoked on translate completed with two
 * arguments : audio data as base64 and success true for translated ok and false otherwise
 */
var VOCreation = function(config) {
    var self = this;

    /** voice cache to avoid duplicate requests */
    this.voiceCache = {};

    /** max chars in each network request */
    this.maxChars = 80;

    /** response speech data */
    this.data = [''];

    /** url for TTS request */
    this.url = 'http://translate.google.com/translate_tts?tl=';

    /** language locale */
    this.locale = '';

    /**
     * c-tor
     */
    this.init = function() {
        if ( !fs.existsSync(config.mediaDirectory + '/vosegments')) {
            fs.mkdirSync(config.mediaDirectory + '/vosegments');
        }
    };

    /**
     * create VO
     * @param languageLocale
     * @param words
     * @param callback
     */
    this.create = function(languageLocale, words, callback) {
        config.log('VOCreation', 'Creating VO: ' + words, { date: new Date(), level: "verbose" });
        this.callback = callback;
        this.locale = languageLocale;
        //words = words.replace('*', 'o');
        var chunked = words.split(' ');
        this.requests = [''];

        // separate network requests by words vs character limits
        for (var chunk in chunked) {
            this.appendWord(chunked[chunk]);
        }

        // clean the list
        this.requests = this.requests.filter(function(value) {
            return value !== '';
        });

        this.requests.reverse();
        this.nextRequest();
    };

    /**
     * append word to requests
     * @param txt
     */
    this.appendWord = function(txt) {
        if (txt === '' || txt === ' ') {
            return;
        }

        // handle speech breaks
        if (txt.indexOf(VOCreation.SPEECHBREAK) > -1) {
            var wrds = txt.split(VOCreation.SPEECHBREAK);
            for (var c in wrds) {
                if ( self.requests[self.requests.length-1] !== '') {
                    self.appendWord(wrds[c]);
                    self.requests[self.requests.length-1] = self.requests[self.requests.length-1].trim();
                    self.requests.push('');
                } else {
                    self.appendWord(wrds[c]);
                }
            }
            return;
        }

        // make new request if over max char limit
        if (self.requests[self.requests.length-1].length + txt.length >= self.maxChars) {
            self.requests[self.requests.length-1] = self.requests[self.requests.length-1].trim();
            self.requests.push(txt);
        } else {
            self.requests[self.requests.length-1] += txt + ' ';
        }
    };

    /**
     * make request
     */
    this.nextRequest = function() {
        var txt = self.requests.pop();

        // can we use a cached response?

        if ( fs.existsSync(config.mediaDirectory + path.sep + 'vosegments'  + path.sep + escape(txt) + '.mp3')) {
            var data = fs.readFileSync(config.mediaDirectory + path.sep + 'vosegments' + path.sep + File.prototype.safeFilename(txt) + '.mp3', 'base64');
            self.data[self.data.length-1] += data;
            config.log('VOCreation', 'Using previously created VO segment: ' + txt, { date: new Date(), level: "verbose" });
            self.onRequestComplete(txt);
            return;
        }

        http.get(self.url + self.locale + '&q=' + txt, function(response) {
            response.setEncoding('base64');
            response.on('data', function (chunk) {
                self.data[self.data.length-1] += chunk;
            });

            response.on('end', function () {
                config.log('VOCreation', 'Created VO Segment: ' + txt, { date: new Date(), level: "verbose" });
                self.onRequestComplete(txt);
            });
        });
    };

    /**
     * on request complete - finish or do next
     */
    this.onRequestComplete = function(txt) {
        if (self.requests.length > 0 ) {
            config.log('VOCreation', 'Caching VO Segment: ' + txt, { date: new Date(), level: "verbose" });
            fs.writeFileSync(config.mediaDirectory + path.sep + 'vosegments' + path.sep + File.prototype.safeFilename(txt) + '.mp3', self.data[self.data.length-1], 'base64');
            self.data.push('');
            self.nextRequest();
        } else {
            var result = {'audio': self.data.join(), 'success': true};
            self.callback(result);
            self.data = [];
        }
    };

    this.init();
};

VOCreation.SPEECHBREAK = '<speechbreak>';

exports = module.exports = VOCreation;<commit_msg>updated VO creation to sneak past Googles new TTS restrictions<commit_after>/**
 * Copied from Node-Google-Text-To-Speech module
 * https://github.com/ashafir20/node-google-text-to-speech
 *
 * Altered to not change output to Base64 String, and since I'm
 * modifying it for my own purposes, I'll make it more directly tied in
 * as a VO creation script
 */

var request = require('request');
var fs = require('fs');
var File = require('../utils/File')
var http = require('http');
var path = require('path');

/**
 * Escape special characters in the given string of html.
 *
 * @param  {String} languageLocale = the target locale language (example : en)
 * @param  {String} word = the word to translate to speech
 * @param  {function({'audio' : String, 'message' : String })} callback = function invoked on translate completed with two
 * arguments : audio data as base64 and success true for translated ok and false otherwise
 */
var VOCreation = function(config) {
    var self = this;

    /** voice cache to avoid duplicate requests */
    this.voiceCache = {};

    /** max chars in each network request */
    this.maxChars = 80;

    /** response speech data */
    this.data = [''];

    /** language locale */
    this.locale = '';

    /**
     * c-tor
     */
    this.init = function() {
        if ( !fs.existsSync(config.mediaDirectory + '/vosegments')) {
            fs.mkdirSync(config.mediaDirectory + '/vosegments');
        }
    };

    /**
     * create VO
     * @param languageLocale
     * @param words
     * @param callback
     */
    this.create = function(languageLocale, words, callback) {
        config.log('VOCreation', 'Creating VO: ' + words, { date: new Date(), level: "verbose" });
        this.callback = callback;
        this.locale = languageLocale;
        //words = words.replace('*', 'o');
        var chunked = words.split(' ');
        this.requests = [''];

        // separate network requests by words vs character limits
        for (var chunk in chunked) {
            this.appendWord(chunked[chunk]);
        }

        // clean the list
        this.requests = this.requests.filter(function(value) {
            return value !== '';
        });

        this.requests.reverse();
        this.nextRequest();
    };

    /**
     * append word to requests
     * @param txt
     */
    this.appendWord = function(txt) {
        if (txt === '' || txt === ' ') {
            return;
        }

        // handle speech breaks
        if (txt.indexOf(VOCreation.SPEECHBREAK) > -1) {
            var wrds = txt.split(VOCreation.SPEECHBREAK);
            for (var c in wrds) {
                if ( self.requests[self.requests.length-1] !== '') {
                    self.appendWord(wrds[c]);
                    self.requests[self.requests.length-1] = self.requests[self.requests.length-1].trim();
                    self.requests.push('');
                } else {
                    self.appendWord(wrds[c]);
                }
            }
            return;
        }

        // make new request if over max char limit
        if (self.requests[self.requests.length-1].length + txt.length >= self.maxChars) {
            self.requests[self.requests.length-1] = self.requests[self.requests.length-1].trim();
            self.requests.push(txt);
        } else {
            self.requests[self.requests.length-1] += txt + ' ';
        }
    };

    /**
     * make request
     */
    this.nextRequest = function() {
        var txt = self.requests.pop();

        // can we use a cached response?

        if ( fs.existsSync(config.mediaDirectory + path.sep + 'vosegments'  + path.sep + escape(txt) + '.mp3')) {
            var data = fs.readFileSync(config.mediaDirectory + path.sep + 'vosegments' + path.sep + File.prototype.safeFilename(txt) + '.mp3', 'base64');
            self.data[self.data.length-1] += data;
            config.log('VOCreation', 'Using previously created VO segment: ' + txt, { date: new Date(), level: "verbose" });
            self.onRequestComplete(txt);
            return;
        }

        var options = {
            host: 'translate.google.com',
            path: '/translate_tts?tl=' +self.locale + '&q=' + encodeURI(txt) + '&client=t',
            method: 'GET',
            headers: {
                'User-Agent': 'stagefright/1.2 (Linux;Android 5.0)',
                'Referer': 'http://translate.google.com/'
            }
        };

        http.request(options, function(response) {
            response.setEncoding('base64');
            response.on('data', function (chunk) {
                self.data[self.data.length-1] += chunk;
            });

            response.on('end', function () {
                config.log('VOCreation', 'Created VO Segment: ' + txt, { date: new Date(), level: "verbose" });
                self.onRequestComplete(txt);
            });
        });
    };

    /**
     * on request complete - finish or do next
     */
    this.onRequestComplete = function(txt) {
        if (self.requests.length > 0 ) {
            config.log('VOCreation', 'Caching VO Segment: ' + txt, { date: new Date(), level: "verbose" });
            fs.writeFileSync(config.mediaDirectory + path.sep + 'vosegments' + path.sep + File.prototype.safeFilename(txt) + '.mp3', self.data[self.data.length-1], 'base64');
            self.data.push('');
            self.nextRequest();
        } else {
            var result = {'audio': self.data.join(), 'success': true};
            self.callback(result);
            self.data = [];
        }
    };

    this.init();
};

VOCreation.SPEECHBREAK = '<speechbreak>';

exports = module.exports = VOCreation;<|endoftext|>


<commit_before>import Fuse from 'fuse.js';
import { deletedTabsCache } from './caches';
import {
  TAB_TYPE,
  OTHER_WINDOW_TAB_TYPE,
  SESSION_TYPE,
} from './constants';
import {
  identity,
  isOfWindow,
  isOfType,
  annotateTypeConditionally,
  annotateType,
  doubleFilterAndMerge,
} from './utils/array';

export default function filterResult(
  query,
  options,
  {
    showRecentlyClosed,
    recentlyClosedLimit,
    alwaysShowRecentlyClosedAtTheBottom: recentAtBottom,
  },
  currentWindowId,
) {
  const { enableFuzzySearch, keys } = options;
  return function promiseSearchResults(loadedTabs) {
    const isQueryEmpty = query.length === 0;
    const isTabType = isOfType(TAB_TYPE);
    const tabFilter = ({ id }) => !deletedTabsCache().includes(id);
    // First filter any unwanted results
    const annotatedTabs = loadedTabs.filter(tabFilter).map(
      annotateTypeConditionally(
        isOfWindow(currentWindowId),
        TAB_TYPE,
        OTHER_WINDOW_TAB_TYPE,
      ),
    );

    // If we want to move the closed tabs to the botttom filter it
    const shouldMoveClosedToBottom = showRecentlyClosed && recentAtBottom;
    const arrayToSearch = showRecentlyClosed
      ? Promise.all([
        annotatedTabs,
        getRecentlyClosed(recentlyClosedLimit),
      ]).then(([tabs, sessions]) => [...tabs, ...sessions])
      : Promise.resolve(annotatedTabs);
    const doFinalOperation = shouldMoveClosedToBottom
      ? doubleFilterAndMerge(isTabType)
      : identity;
    let search;
    if (isQueryEmpty) {
      search = identity;
    } else if (enableFuzzySearch) {
      search = arr => new Fuse(arr, options).search(query);
    } else {
      search = arr => arr.filter(tab =>
        keys.reduce((acc, key) => tab[key].includes(query)),
      );
    }
    return arrayToSearch
      .then(search)
      .then(doFinalOperation);
  };
}

function getRecentlyClosed(maxResults) {
  const tab = ({ tab: _tab }) => _tab;
  // Don't want to show new tab pages
  const isNewTabPage = ({ url }) => url !== 'about:newtab';
  const getTabsAndAnnotate = objects => objects
    .filter(tab)
    .map(tab)
    .filter(isNewTabPage)
    .map(annotateType(SESSION_TYPE));
  return browser.sessions.getRecentlyClosed({ maxResults })
    .then(getTabsAndAnnotate);
}
<commit_msg>Fix issue where search wasn't filtering properly when enableFuzzySearch and searchByUrls were both false<commit_after>import Fuse from 'fuse.js';
import { deletedTabsCache } from './caches';
import {
  TAB_TYPE,
  OTHER_WINDOW_TAB_TYPE,
  SESSION_TYPE,
} from './constants';
import {
  identity,
  isOfWindow,
  isOfType,
  annotateTypeConditionally,
  annotateType,
  doubleFilterAndMerge,
} from './utils/array';

export default function filterResult(
  query,
  options,
  {
    showRecentlyClosed,
    recentlyClosedLimit,
    alwaysShowRecentlyClosedAtTheBottom: recentAtBottom,
  },
  currentWindowId,
) {
  const { enableFuzzySearch, keys } = options;
  return function promiseSearchResults(loadedTabs) {
    const isQueryEmpty = query.length === 0;
    const isTabType = isOfType(TAB_TYPE);
    const tabFilter = ({ id }) => !deletedTabsCache().includes(id);
    // First filter any unwanted results
    const annotatedTabs = loadedTabs.filter(tabFilter).map(
      annotateTypeConditionally(
        isOfWindow(currentWindowId),
        TAB_TYPE,
        OTHER_WINDOW_TAB_TYPE,
      ),
    );

    // If we want to move the closed tabs to the botttom filter it
    const shouldMoveClosedToBottom = showRecentlyClosed && recentAtBottom;
    const arrayToSearch = showRecentlyClosed
      ? Promise.all([
        annotatedTabs,
        getRecentlyClosed(recentlyClosedLimit),
      ]).then(([tabs, sessions]) => [...tabs, ...sessions])
      : Promise.resolve(annotatedTabs);
    const doFinalOperation = shouldMoveClosedToBottom
      ? doubleFilterAndMerge(isTabType)
      : identity;
    let search;
    if (isQueryEmpty) {
      search = identity;
    } else if (enableFuzzySearch) {
      search = arr => new Fuse(arr, options).search(query);
    } else {
      // If enableFuzzySearch is off
      search = arr => arr.filter(tab => keys.some(key => tab[key].includes(query)));
    }
    return arrayToSearch
      .then(search)
      .then(doFinalOperation);
  };
}

function getRecentlyClosed(maxResults) {
  const tab = ({ tab: _tab }) => _tab;
  // Don't want to show new tab pages
  const isNewTabPage = ({ url }) => url !== 'about:newtab';
  const getTabsAndAnnotate = objects => objects
    .filter(tab)
    .map(tab)
    .filter(isNewTabPage)
    .map(annotateType(SESSION_TYPE));
  return browser.sessions.getRecentlyClosed({ maxResults })
    .then(getTabsAndAnnotate);
}
<|endoftext|>


<commit_before>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name CurveLocation
 *
 * @class CurveLocation objects describe a location on {@link Curve}
 * objects, as defined by the curve {@link #parameter}, a value between
 * {@code 0} (beginning of the curve) and {@code 1} (end of the curve). If
 * the curve is part of a {@link Path} item, its {@link #index} inside the
 * {@link Path#curves} array is also provided.
 *
 * The class is in use in many places, such as
 * {@link Path#getLocationAt(offset, isParameter)},
 * {@link Path#getLocationOf(point)},
 * {@link Path#getNearestLocation(point),
 * {@link PathItem#getIntersections(path)},
 * etc.
 */
var CurveLocation = Base.extend(/** @lends CurveLocation# */{
	_class: 'CurveLocation',
	// Enforce creation of beans, as bean getters have hidden parameters.
	// See #getSegment() below.
	beans: true,

	// DOCS: CurveLocation class description: add these back when the  mentioned
	// functioned have been added: {@link Path#split(location)}
	/**
	 * Creates a new CurveLocation object.
	 *
	 * @param {Curve} curve
	 * @param {Number} parameter
	 * @param {Point} point
	 */
	initialize: function CurveLocation(curve, parameter, point, _curve2,
			_parameter2, _point2, _distance) {
		// Define this CurveLocation's unique id.
		this._id = CurveLocation._id = (CurveLocation._id || 0) + 1;
		this._curve = curve;
		// Also store references to segment1 and segment2, in case path
		// splitting / dividing is going to happen, in which case the segments
		// can be used to determine the new curves, see #getCurve(true)
		this._segment1 = curve._segment1;
		this._segment2 = curve._segment2;
		this._parameter = parameter;
		this._point = point;
		this._curve2 = _curve2;
		this._parameter2 = _parameter2;
		this._point2 = _point2;
		this._distance = _distance;
	},

	/**
	 * The segment of the curve which is closer to the described location.
	 *
	 * @type Segment
	 * @bean
	 */
	getSegment: function(_preferFirst) {
		if (!this._segment) {
			var curve = this.getCurve(),
				parameter = this.getParameter();
			if (parameter === 1) {
				this._segment = curve._segment2;
			} else if (parameter === 0 || _preferFirst) {
				this._segment = curve._segment1;
			} else if (parameter == null) {
				return null;
			} else {
				// Determine the closest segment by comparing curve lengths
				this._segment = curve.getPartLength(0, parameter)
					< curve.getPartLength(parameter, 1)
						? curve._segment1
						: curve._segment2;
			}
		}
		return this._segment;
	},

	/**
	 * The curve that this location belongs to.
	 *
	 * @type Curve
	 * @bean
	 */
	getCurve: function(_uncached) {
		if (!this._curve || _uncached) {
			// If we're asked to get the curve uncached, access current curve
			// objects through segment1 / segment2. Since path splitting or
			// dividing might have happened in the meantime, try segment1's
			// curve, and see if _point lies on it still, otherwise assume it's
			// the curve before segment2.
			this._curve = this._segment1.getCurve();
			if (this._curve.getParameterOf(this._point) == null)
				this._curve = this._segment2.getPrevious().getCurve();
		}
		return this._curve;
	},

	/**
	 * The curve location on the intersecting curve, if this location is the
	 * result of a call to {@link PathItem#getIntersections(path)} /
	 * {@link Curve#getIntersections(curve)}.
	 *
	 * @type CurveLocation
	 * @bean
	 */
	getIntersection: function() {
		var intersection = this._intersection;
		if (!intersection && this._curve2) {
			var param = this._parameter2;
			// If we have the parameter on the other curve use that for
			// intersection rather than the point.
			this._intersection = intersection = new CurveLocation(
					this._curve2, param, this._point2 || this._point, this);
			intersection._intersection = this;
		}
		return intersection;
	},

	/**
	 * The path this curve belongs to, if any.
	 *
	 * @type Item
	 * @bean
	 */
	getPath: function() {
		var curve = this.getCurve();
		return curve && curve._path;
	},

	/**
	 * The index of the curve within the {@link Path#curves} list, if the
	 * curve is part of a {@link Path} item.
	 *
	 * @type Index
	 * @bean
	 */
	getIndex: function() {
		var curve = this.getCurve();
		return curve && curve.getIndex();
	},

	/**
	 * The length of the path from its beginning up to the location described
	 * by this object.
	 *
	 * @type Number
	 * @bean
	 */
	getOffset: function() {
		var path = this.getPath();
		return path && path._getOffset(this);
	},

	/**
	 * The length of the curve from its beginning up to the location described
	 * by this object.
	 *
	 * @type Number
	 * @bean
	 */
	getCurveOffset: function() {
		var curve = this.getCurve(),
			parameter = this.getParameter();
		return parameter != null && curve && curve.getPartLength(0, parameter);
	},

	/**
	 * The curve parameter, as used by various bezier curve calculations. It is
	 * value between {@code 0} (beginning of the curve) and {@code 1} (end of
	 * the curve).
	 *
	 * @type Number
	 * @bean
	 */
	getParameter: function(_uncached) {
		if ((this._parameter == null || _uncached) && this._point) {
			var curve = this.getCurve(_uncached && this._point);
			this._parameter = curve && curve.getParameterOf(this._point);
		}
		return this._parameter;
	},

	/**
	 * The point which is defined by the {@link #curve} and
	 * {@link #parameter}.
	 *
	 * @type Point
	 * @bean
	 */
	getPoint: function(_uncached) {
		if ((!this._point || _uncached) && this._parameter != null) {
			var curve = this.getCurve();
			this._point = curve && curve.getPointAt(this._parameter, true);
		}
		return this._point;
	},

	/**
	 * The tangential vector to the {@link #curve} at the given location.
	 *
	 * @type Point
	 * @bean
	 */
	getTangent: function() {
		var parameter = this.getParameter(),
			curve = this.getCurve();
		return parameter != null && curve && curve.getTangentAt(parameter, true);
	},

	/**
	 * The normal vector to the {@link #curve} at the given location.
	 *
	 * @type Point
	 * @bean
	 */
	getNormal: function() {
		var parameter = this.getParameter(),
			curve = this.getCurve();
		return parameter != null && curve && curve.getNormalAt(parameter, true);
	},

	/**
	 * The distance from the queried point to the returned location.
	 *
	 * @type Number
	 * @bean
	 */
	getDistance: function() {
		return this._distance;
	},

	divide: function() {
		var curve = this.getCurve(true);
		return curve && curve.divide(this.getParameter(true), true);
	},

	split: function() {
		var curve = this.getCurve(true);
		return curve && curve.split(this.getParameter(true), true);
	},

	/**
	 * Checks whether tow CurveLocation objects are describing the same location
	 * on a path, by applying the same tolerances as elsewhere when dealing with
	 * curve time parameters.
	 *
	 * @param {CurveLocation} location
	 * @return {Boolean} {@true if the locations are equal}
	 */
	equals: function(loc) {
		var isZero = Numerical.isZero;
		return this === loc
				|| loc
					&& this._curve === loc._curve
					&& this._curve2 === loc._curve2
					&& isZero(this._parameter - loc._parameter)
					&& isZero(this._parameter2 - loc._parameter2)
				|| false;
	},

	/**
	 * @return {String} a string representation of the curve location
	 */
	toString: function() {
		var parts = [],
			point = this.getPoint(),
			f = Formatter.instance;
		if (point)
			parts.push('point: ' + point);
		var index = this.getIndex();
		if (index != null)
			parts.push('index: ' + index);
		var parameter = this.getParameter();
		if (parameter != null)
			parts.push('parameter: ' + f.number(parameter));
		if (this._distance != null)
			parts.push('distance: ' + f.number(this._distance));
		return '{ ' + parts.join(', ') + ' }';
	}
});
<commit_msg>Use loop to produce CurveLocation getters, and add CurveLocation#curvature.<commit_after>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name CurveLocation
 *
 * @class CurveLocation objects describe a location on {@link Curve}
 * objects, as defined by the curve {@link #parameter}, a value between
 * {@code 0} (beginning of the curve) and {@code 1} (end of the curve). If
 * the curve is part of a {@link Path} item, its {@link #index} inside the
 * {@link Path#curves} array is also provided.
 *
 * The class is in use in many places, such as
 * {@link Path#getLocationAt(offset, isParameter)},
 * {@link Path#getLocationOf(point)},
 * {@link Path#getNearestLocation(point),
 * {@link PathItem#getIntersections(path)},
 * etc.
 */
var CurveLocation = Base.extend(/** @lends CurveLocation# */{
	_class: 'CurveLocation',
	// Enforce creation of beans, as bean getters have hidden parameters.
	// See #getSegment() below.
	beans: true,

	// DOCS: CurveLocation class description: add these back when the  mentioned
	// functioned have been added: {@link Path#split(location)}
	/**
	 * Creates a new CurveLocation object.
	 *
	 * @param {Curve} curve
	 * @param {Number} parameter
	 * @param {Point} point
	 */
	initialize: function CurveLocation(curve, parameter, point, _curve2,
			_parameter2, _point2, _distance) {
		// Define this CurveLocation's unique id.
		this._id = CurveLocation._id = (CurveLocation._id || 0) + 1;
		this._curve = curve;
		// Also store references to segment1 and segment2, in case path
		// splitting / dividing is going to happen, in which case the segments
		// can be used to determine the new curves, see #getCurve(true)
		this._segment1 = curve._segment1;
		this._segment2 = curve._segment2;
		this._parameter = parameter;
		this._point = point;
		this._curve2 = _curve2;
		this._parameter2 = _parameter2;
		this._point2 = _point2;
		this._distance = _distance;
	},

	/**
	 * The segment of the curve which is closer to the described location.
	 *
	 * @type Segment
	 * @bean
	 */
	getSegment: function(_preferFirst) {
		if (!this._segment) {
			var curve = this.getCurve(),
				parameter = this.getParameter();
			if (parameter === 1) {
				this._segment = curve._segment2;
			} else if (parameter === 0 || _preferFirst) {
				this._segment = curve._segment1;
			} else if (parameter == null) {
				return null;
			} else {
				// Determine the closest segment by comparing curve lengths
				this._segment = curve.getPartLength(0, parameter)
					< curve.getPartLength(parameter, 1)
						? curve._segment1
						: curve._segment2;
			}
		}
		return this._segment;
	},

	/**
	 * The curve that this location belongs to.
	 *
	 * @type Curve
	 * @bean
	 */
	getCurve: function(_uncached) {
		if (!this._curve || _uncached) {
			// If we're asked to get the curve uncached, access current curve
			// objects through segment1 / segment2. Since path splitting or
			// dividing might have happened in the meantime, try segment1's
			// curve, and see if _point lies on it still, otherwise assume it's
			// the curve before segment2.
			this._curve = this._segment1.getCurve();
			if (this._curve.getParameterOf(this._point) == null)
				this._curve = this._segment2.getPrevious().getCurve();
		}
		return this._curve;
	},

	/**
	 * The curve location on the intersecting curve, if this location is the
	 * result of a call to {@link PathItem#getIntersections(path)} /
	 * {@link Curve#getIntersections(curve)}.
	 *
	 * @type CurveLocation
	 * @bean
	 */
	getIntersection: function() {
		var intersection = this._intersection;
		if (!intersection && this._curve2) {
			var param = this._parameter2;
			// If we have the parameter on the other curve use that for
			// intersection rather than the point.
			this._intersection = intersection = new CurveLocation(
					this._curve2, param, this._point2 || this._point, this);
			intersection._intersection = this;
		}
		return intersection;
	},

	/**
	 * The path this curve belongs to, if any.
	 *
	 * @type Item
	 * @bean
	 */
	getPath: function() {
		var curve = this.getCurve();
		return curve && curve._path;
	},

	/**
	 * The index of the curve within the {@link Path#curves} list, if the
	 * curve is part of a {@link Path} item.
	 *
	 * @type Index
	 * @bean
	 */
	getIndex: function() {
		var curve = this.getCurve();
		return curve && curve.getIndex();
	},

	/**
	 * The length of the path from its beginning up to the location described
	 * by this object.
	 *
	 * @type Number
	 * @bean
	 */
	getOffset: function() {
		var path = this.getPath();
		return path && path._getOffset(this);
	},

	/**
	 * The length of the curve from its beginning up to the location described
	 * by this object.
	 *
	 * @type Number
	 * @bean
	 */
	getCurveOffset: function() {
		var curve = this.getCurve(),
			parameter = this.getParameter();
		return parameter != null && curve && curve.getPartLength(0, parameter);
	},

	/**
	 * The curve parameter, as used by various bezier curve calculations. It is
	 * value between {@code 0} (beginning of the curve) and {@code 1} (end of
	 * the curve).
	 *
	 * @type Number
	 * @bean
	 */
	getParameter: function(_uncached) {
		if ((this._parameter == null || _uncached) && this._point) {
			var curve = this.getCurve(_uncached && this._point);
			this._parameter = curve && curve.getParameterOf(this._point);
		}
		return this._parameter;
	},

	/**
	 * The point which is defined by the {@link #curve} and
	 * {@link #parameter}.
	 *
	 * @type Point
	 * @bean
	 */
	getPoint: function(_uncached) {
		if ((!this._point || _uncached) && this._parameter != null) {
			var curve = this.getCurve();
			this._point = curve && curve.getPointAt(this._parameter, true);
		}
		return this._point;
	},

	/**
	 * The tangential vector to the {@link #curve} at the given location.
	 *
	 * @name Item#getTangent
	 * @type Point
	 * @bean
	 */

	/**
	 * The normal vector to the {@link #curve} at the given location.
	 *
	 * @name Item#getNormal
	 * @type Point
	 * @bean
	 */

	/**
	 * The curvature of the {@link #curve} at the given location.
	 *
	 * @name Item#getCurvature
	 * @type Number
	 * @bean
	 */

	/**
	 * The distance from the queried point to the returned location.
	 *
	 * @type Number
	 * @bean
	 */
	getDistance: function() {
		return this._distance;
	},

	divide: function() {
		var curve = this.getCurve(true);
		return curve && curve.divide(this.getParameter(true), true);
	},

	split: function() {
		var curve = this.getCurve(true);
		return curve && curve.split(this.getParameter(true), true);
	},

	/**
	 * Checks whether tow CurveLocation objects are describing the same location
	 * on a path, by applying the same tolerances as elsewhere when dealing with
	 * curve time parameters.
	 *
	 * @param {CurveLocation} location
	 * @return {Boolean} {@true if the locations are equal}
	 */
	equals: function(loc) {
		var isZero = Numerical.isZero;
		return this === loc
				|| loc
					&& this._curve === loc._curve
					&& this._curve2 === loc._curve2
					&& isZero(this._parameter - loc._parameter)
					&& isZero(this._parameter2 - loc._parameter2)
				|| false;
	},

	/**
	 * @return {String} a string representation of the curve location
	 */
	toString: function() {
		var parts = [],
			point = this.getPoint(),
			f = Formatter.instance;
		if (point)
			parts.push('point: ' + point);
		var index = this.getIndex();
		if (index != null)
			parts.push('index: ' + index);
		var parameter = this.getParameter();
		if (parameter != null)
			parts.push('parameter: ' + f.number(parameter));
		if (this._distance != null)
			parts.push('distance: ' + f.number(this._distance));
		return '{ ' + parts.join(', ') + ' }';
	}
}, Base.each(['Tangent', 'Normal', 'Curvature'],
	// Produce getters for #getTangent() / #getNormal() / #getCurvature()
	function(name) {
		var get = 'get' + name + 'At';
		this['get' + name] = function() {
			var parameter = this.getParameter(),
				curve = this.getCurve();
			return parameter != null && curve && curve[get](parameter, true);
		};
	}, {}
));
<|endoftext|>


<commit_before>define([
    "jquery",
    "../registry"
], function($, registry) {
    var _ = {
        name: "autoscale",
        trigger: ".pat-auto-scale",
        transform: true,

        init: function($el, options) {
            // initialize the elements
            $el.each(_.resizeElement);
        },

        resizeElement: function() {
            var $this = $(this),
                scale;

            if ($this.tagName.toLowerCase() == 'body') {
                scale = $(window).width()/$this.outerWidth();
            } else {
                scale = $this.parent().outerWidth()/$this.outerWidth();
            }

            if (_.transform) {
                $this.css('transform', 'scale(' + scale + ')');
            } else {
                $this.css('zoom', scale);
            }
        },

        resizeEvent: function() {
            $(_.trigger).each(_.resizeElement);
        }
    };

    _.transform = $('html').hasClass('csstransforms');
    $(window).resize(_.resizeEvent);

    registry.register(_);

    return _;
});
<commit_msg>Fixed small typo bug<commit_after>define([
    "jquery",
    "../registry"
], function($, registry) {
    var _ = {
        name: "autoscale",
        trigger: ".pat-auto-scale",
        transform: true,

        init: function($el, options) {
            // initialize the elements
            $el.each(_.resizeElement);
        },

        resizeElement: function() {
            var $this = $(this),
                scale;

            if (this.tagName.toLowerCase() == 'body') {
                scale = $(window).width()/$this.outerWidth();
            } else {
                scale = $this.parent().outerWidth()/$this.outerWidth();
            }

            if (_.transform) {
                $this.css('transform', 'scale(' + scale + ')');
            } else {
                $this.css('zoom', scale);
            }
        },

        resizeEvent: function() {
            $(_.trigger).each(_.resizeElement);
        }
    };

    _.transform = $('html').hasClass('csstransforms');
    $(window).resize(_.resizeEvent);

    registry.register(_);

    return _;
});
<|endoftext|>


<commit_before>// @flow

export default (paths: Object, useBabelrc: boolean, dev: boolean) => ({
  moduleRules: [
    // Disable require.ensure as it's not a standard language feature.
    {parser: {requireEnsure: false}},

    // Process JS with Babel.
    {
      test: /\.(js|jsx)$/,
      include: paths.appRoot,
      exclude: /node_modules/,
      loader: 'babel-loader',
      options: {
        babelrc: useBabelrc,
        presets: useBabelrc ? [] : [require.resolve('next/babel'), require.resolve('../../../lib/babel/preset')],
        // TODO check if this is an issue when this plugin is already included
        plugins: useBabelrc ? [] : [require.resolve('babel-plugin-syntax-dynamic-import')],
        cacheDirectory: true
      }
    }
  ],
  plugins: []
});
<commit_msg>Fix next.js babel preset<commit_after>// @flow

export default (paths: Object, useBabelrc: boolean, dev: boolean) => ({
  moduleRules: [
    // Disable require.ensure as it's not a standard language feature.
    {parser: {requireEnsure: false}},

    // Process JS with Babel.
    {
      test: /\.(js|jsx)$/,
      include: paths.appRoot,
      exclude: /node_modules/,
      loader: 'babel-loader',
      options: {
        babelrc: useBabelrc,
        presets: useBabelrc ? [] : [require.resolve('next/babel'), require.resolve('../../../babel')],
        // TODO check if this is an issue when this plugin is already included
        plugins: useBabelrc ? [] : [require.resolve('babel-plugin-syntax-dynamic-import')],
        cacheDirectory: true
      }
    }
  ],
  plugins: []
});
<|endoftext|>