<commit_before>/**
 * this is the query-builder
 * it basically uses mquery with a few overwrites
 */

import {
    default as mquery
} from './mquery/mquery';
import * as util from './util';
import * as RxDocument from './RxDocument';

const defaultQuery = {
    _id: {}
};

class RxQuery {
    constructor(queryObj, collection) {
        this.collection = collection;

        this.defaultQuery = false;
        if (!queryObj ||
            (
                Object.keys(queryObj).length === 0 &&
                !Array.isArray(queryObj)
            )
        ) {
            queryObj = defaultQuery;
            this.defaultQuery = true;
        }

        this.mquery = mquery(queryObj);

        // merge mquery-prototype functions to this
        const mquery_proto = Object.getPrototypeOf(this.mquery);
        Object.keys(mquery_proto).forEach(attrName => {
            if (['select', 'remove', 'update'].includes(attrName)) return;

            // only param1 is tunneled here on purpose so no callback-call can be done
            this[attrName] = param1 => {
                this.mquery[attrName](param1);
                return this;
            };
        });

        // overwrites

        /**
         * make sure it searches index because of pouchdb-find bug
         * @link https://github.com/nolanlawson/pouchdb-find/issues/204
         */
        this.sort = params => {

            // workarround because sort wont work on unused keys
            if (typeof params !== 'object')
                this.mquery.where(params).gt(null);
            else
                Object.keys(params).map(k => this.mquery.where(k).gt(null));

            this.mquery.sort(params);
            return this;
        };

        /**
         * regex cannot run on primary _id
         * @link https://docs.cloudant.com/cloudant_query.html#creating-selector-expressions
         */
        this.regex = params => {
            if (this.mquery._path == this.collection.schema.primaryPath)
                throw new Error(`You cannot use .regex() on the primary field '${this.mquery._path}'`);

            this.mquery.regex(params);
            return this;
        };

    }

    // observe the result of this query
    get $() {
        if (!this._subject) {
            this._subject = new util.Rx.BehaviorSubject(null);
            this._obsRunning = false;
            const collection$ = this.collection.$
                .filter(cEvent => ['RxCollection.insert', 'RxDocument.save', 'RxDocument.remove'].includes(cEvent.data.op))
                .startWith(1)
                .filter(x => !this._obsRunning)
                .do(x => this._obsRunning = true)
                .mergeMap(async(cEvent) => {
                    const docs = await this.collection._pouchFind(this);
                    return docs;
                })
                .do(x => this._obsRunning = false)
                .distinctUntilChanged((prev, now) => {
                    return util.fastUnsecureHash(prev) == util.fastUnsecureHash(now);
                })
                .map(docs => RxDocument.createAr(this.collection, docs, this.toJSON()))
                .do(docs => this._subject.next(docs))
                .map(x => '');

            this._observable$ = util.Rx.Observable.merge(
                    this._subject,
                    collection$
                )
                .filter(x => (typeof x != 'string' || x != ''));
        }
        return this._observable$;
    }

    toJSON() {
        const json = {
            selector: this.mquery._conditions
        };

        let options = this.mquery._optionsForExec();

        // sort
        if (options.sort) {
            const sortArray = [];
            Object.keys(options.sort).map(fieldName => {
                const dirInt = options.sort[fieldName];
                let dir = 'asc';
                if (dirInt == -1) dir = 'desc';
                const pushMe = {};
                // TODO run primary-swap somewhere else
                if (fieldName == this.collection.schema.primaryPath)
                    fieldName = '_id';

                pushMe[fieldName] = dir;
                sortArray.push(pushMe);
            });
            json.sort = sortArray;
        }

        if (options.limit) {
            if (typeof options.limit !== 'number') throw new TypeError('limit() must get a number');
            json.limit = options.limit;
        }

        if (options.skip) {
            if (typeof options.skip !== 'number') throw new TypeError('skip() must get a number');
            json.skip = options.skip;
        }

        // add not-query to _id to prevend the grabbing of '_design..' docs
        // this is not the best solution because it prevents the usage of a 'language'-field
        if (!json.selector.language) json.selector.language = {};
        json.selector.language.$ne = 'query';

        // primary swap
        if (
            this.collection.schema.primaryPath &&
            json.selector[this.collection.schema.primaryPath]
        ) {
            const primPath = this.collection.schema.primaryPath;

            // selector
            json.selector._id = json.selector[primPath];
            delete json.selector[primPath];
        }

        return json;
    };

    /**
     * get the key-compression version of this query
     * @return {{selector: {}, sort: []}} compressedQuery
     */
    keyCompress() {
        return this
            .collection
            ._keyCompressor
            .compressQuery(this.toJSON());
    }

    /**
     * deletes all found documents
     * @return {Promise(RxDocument)} promise with deleted documents
     */
    async remove() {
        const docs = await this.exec();
        if (Array.isArray(docs)) {
            await Promise.all(
                docs.map(doc => doc.remove())
            );
        } else {
            // via findOne()
            await docs.remove();
        }
        return docs;
    }

}

export function create(queryObj = defaultQuery, collection) {
    if (Array.isArray(queryObj)) // TODO should typecheck be done here ?
        throw new TypeError('query cannot be an array');

    return new RxQuery(queryObj, collection);
}
<commit_msg>FIX jsdoc<commit_after>/**
 * this is the query-builder
 * it basically uses mquery with a few overwrites
 */

import {
    default as mquery
} from './mquery/mquery';
import * as util from './util';
import * as RxDocument from './RxDocument';

const defaultQuery = {
    _id: {}
};

class RxQuery {
    constructor(queryObj, collection) {
        this.collection = collection;

        this.defaultQuery = false;
        if (!queryObj ||
            (
                Object.keys(queryObj).length === 0 &&
                !Array.isArray(queryObj)
            )
        ) {
            queryObj = defaultQuery;
            this.defaultQuery = true;
        }

        this.mquery = mquery(queryObj);

        // merge mquery-prototype functions to this
        const mquery_proto = Object.getPrototypeOf(this.mquery);
        Object.keys(mquery_proto).forEach(attrName => {
            if (['select', 'remove', 'update'].includes(attrName)) return;

            // only param1 is tunneled here on purpose so no callback-call can be done
            this[attrName] = param1 => {
                this.mquery[attrName](param1);
                return this;
            };
        });

        // overwrites

        /**
         * make sure it searches index because of pouchdb-find bug
         * @link https://github.com/nolanlawson/pouchdb-find/issues/204
         */
        this.sort = params => {

            // workarround because sort wont work on unused keys
            if (typeof params !== 'object')
                this.mquery.where(params).gt(null);
            else
                Object.keys(params).map(k => this.mquery.where(k).gt(null));

            this.mquery.sort(params);
            return this;
        };

        /**
         * regex cannot run on primary _id
         * @link https://docs.cloudant.com/cloudant_query.html#creating-selector-expressions
         */
        this.regex = params => {
            if (this.mquery._path == this.collection.schema.primaryPath)
                throw new Error(`You cannot use .regex() on the primary field '${this.mquery._path}'`);

            this.mquery.regex(params);
            return this;
        };

    }

    // observe the result of this query
    get $() {
        if (!this._subject) {
            this._subject = new util.Rx.BehaviorSubject(null);
            this._obsRunning = false;
            const collection$ = this.collection.$
                .filter(cEvent => ['RxCollection.insert', 'RxDocument.save', 'RxDocument.remove'].includes(cEvent.data.op))
                .startWith(1)
                .filter(x => !this._obsRunning)
                .do(x => this._obsRunning = true)
                .mergeMap(async(cEvent) => {
                    const docs = await this.collection._pouchFind(this);
                    return docs;
                })
                .do(x => this._obsRunning = false)
                .distinctUntilChanged((prev, now) => {
                    return util.fastUnsecureHash(prev) == util.fastUnsecureHash(now);
                })
                .map(docs => RxDocument.createAr(this.collection, docs, this.toJSON()))
                .do(docs => this._subject.next(docs))
                .map(x => '');

            this._observable$ = util.Rx.Observable.merge(
                    this._subject,
                    collection$
                )
                .filter(x => (typeof x != 'string' || x != ''));
        }
        return this._observable$;
    }

    toJSON() {
        const json = {
            selector: this.mquery._conditions
        };

        let options = this.mquery._optionsForExec();

        // sort
        if (options.sort) {
            const sortArray = [];
            Object.keys(options.sort).map(fieldName => {
                const dirInt = options.sort[fieldName];
                let dir = 'asc';
                if (dirInt == -1) dir = 'desc';
                const pushMe = {};
                // TODO run primary-swap somewhere else
                if (fieldName == this.collection.schema.primaryPath)
                    fieldName = '_id';

                pushMe[fieldName] = dir;
                sortArray.push(pushMe);
            });
            json.sort = sortArray;
        }

        if (options.limit) {
            if (typeof options.limit !== 'number') throw new TypeError('limit() must get a number');
            json.limit = options.limit;
        }

        if (options.skip) {
            if (typeof options.skip !== 'number') throw new TypeError('skip() must get a number');
            json.skip = options.skip;
        }

        // add not-query to _id to prevend the grabbing of '_design..' docs
        // this is not the best solution because it prevents the usage of a 'language'-field
        if (!json.selector.language) json.selector.language = {};
        json.selector.language.$ne = 'query';

        // primary swap
        if (
            this.collection.schema.primaryPath &&
            json.selector[this.collection.schema.primaryPath]
        ) {
            const primPath = this.collection.schema.primaryPath;

            // selector
            json.selector._id = json.selector[primPath];
            delete json.selector[primPath];
        }

        return json;
    };

    /**
     * get the key-compression version of this query
     * @return {{selector: {}, sort: []}} compressedQuery
     */
    keyCompress() {
        return this
            .collection
            ._keyCompressor
            .compressQuery(this.toJSON());
    }

    /**
     * deletes all found documents
     * @return {Promise(RxDocument|RxDocument[])} promise with deleted documents
     */
    async remove() {
        const docs = await this.exec();
        if (Array.isArray(docs)) {
            await Promise.all(
                docs.map(doc => doc.remove())
            );
        } else {
            // via findOne()
            await docs.remove();
        }
        return docs;
    }

}

export function create(queryObj = defaultQuery, collection) {
    if (Array.isArray(queryObj)) // TODO should typecheck be done here ?
        throw new TypeError('query cannot be an array');

    return new RxQuery(queryObj, collection);
}
<|endoftext|>


<commit_before>const twgl = require('twgl.js');

const Skin = require('./Skin');
const SvgRenderer = require('scratch-svg-renderer').SVGRenderer;

const MAX_TEXTURE_DIMENSION = 2048;

class SVGSkin extends Skin {
    /**
     * Create a new SVG skin.
     * @param {!int} id - The ID for this Skin.
     * @param {!RenderWebGL} renderer - The renderer which will use this skin.
     * @constructor
     * @extends Skin
     */
    constructor (id, renderer) {
        super(id);

        /** @type {RenderWebGL} */
        this._renderer = renderer;

        /** @type {SvgRenderer} */
        this._svgRenderer = new SvgRenderer();

        /** @type {WebGLTexture} */
        this._texture = null;

        /** @type {number} */
        this._textureScale = 1;

        /** @type {Number} */
        this._maxTextureScale = 0;
    }

    /**
     * Dispose of this object. Do not use it after calling this method.
     */
    dispose () {
        if (this._texture) {
            this._renderer.gl.deleteTexture(this._texture);
            this._texture = null;
        }
        super.dispose();
    }

    /**
     * @return {Array<number>} the natural size, in Scratch units, of this skin.
     */
    get size () {
        return this._svgRenderer.size;
    }

    /**
     * Set the origin, in object space, about which this Skin should rotate.
     * @param {number} x - The x coordinate of the new rotation center.
     * @param {number} y - The y coordinate of the new rotation center.
     */
    setRotationCenter (x, y) {
        const viewOffset = this._svgRenderer.viewOffset;
        super.setRotationCenter(x - viewOffset[0], y - viewOffset[1]);
    }

    /**
     * @param {Array<number>} scale - The scaling factors to be used, each in the [0,100] range.
     * @return {WebGLTexture} The GL texture representation of this skin when drawing at the given scale.
     */
    // eslint-disable-next-line no-unused-vars
    getTexture (scale) {
        // The texture only ever gets uniform scale. Take the larger of the two axes.
        const scaleMax = scale ? Math.max(Math.abs(scale[0]), Math.abs(scale[1])) : 100;
        const requestedScale = Math.min(scaleMax / 100, this._maxTextureScale);
        let newScale = this._textureScale;
        while ((newScale < this._maxTextureScale) && (requestedScale >= 1.5 * newScale)) {
            newScale *= 2;
        }
        if (this._textureScale !== newScale) {
            this._textureScale = newScale;
            this._svgRenderer._draw(this._textureScale, () => {
                if (this._textureScale === newScale) {
                    const gl = this._renderer.gl;
                    gl.bindTexture(gl.TEXTURE_2D, this._texture);
                    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._svgRenderer.canvas);
                }
            });
        }

        return this._texture;
    }

    /**
     * Set the contents of this skin to a snapshot of the provided SVG data.
     * @param {string} svgData - new SVG to use.
     * @param {Array<number>} [rotationCenter] - Optional rotation center for the SVG. If not supplied, it will be
     * calculated from the bounding box
     * @fires Skin.event:WasAltered
     */
    setSVG (svgData, rotationCenter) {
        this._svgRenderer.fromString(svgData, 1, () => {
            const gl = this._renderer.gl;
            this._textureScale = this._maxTextureScale = 1;
            if (this._texture) {
                gl.bindTexture(gl.TEXTURE_2D, this._texture);
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._svgRenderer.canvas);
                this._silhouette.update(this._svgRenderer.canvas);
            } else {
                // TODO: mipmaps?
                const textureOptions = {
                    auto: true,
                    wrap: gl.CLAMP_TO_EDGE,
                    src: this._svgRenderer.canvas
                };

                this._texture = twgl.createTexture(gl, textureOptions);
                this._silhouette.update(this._svgRenderer.canvas);
            }

            const maxDimension = Math.max(this._svgRenderer.canvas.width, this._svgRenderer.canvas.height);
            let testScale = 2;
            for (testScale; maxDimension * testScale <= MAX_TEXTURE_DIMENSION; testScale *= 2) {
                this._maxTextureScale = testScale;
            }

            if (typeof rotationCenter === 'undefined') rotationCenter = this.calculateRotationCenter();
            this.setRotationCenter.apply(this, rotationCenter);
            this.emit(Skin.Events.WasAltered);
        });
    }

}

module.exports = SVGSkin;
<commit_msg>Increase maximum texture size and back it off if GL fails to render<commit_after>const twgl = require('twgl.js');

const Skin = require('./Skin');
const SvgRenderer = require('scratch-svg-renderer').SVGRenderer;

const MAX_TEXTURE_DIMENSION = 10240;

class SVGSkin extends Skin {
    /**
     * Create a new SVG skin.
     * @param {!int} id - The ID for this Skin.
     * @param {!RenderWebGL} renderer - The renderer which will use this skin.
     * @constructor
     * @extends Skin
     */
    constructor (id, renderer) {
        super(id);

        /** @type {RenderWebGL} */
        this._renderer = renderer;

        /** @type {SvgRenderer} */
        this._svgRenderer = new SvgRenderer();

        /** @type {WebGLTexture} */
        this._texture = null;

        /** @type {number} */
        this._textureScale = 1;

        /** @type {Number} */
        this._maxTextureScale = 0;
    }

    /**
     * Dispose of this object. Do not use it after calling this method.
     */
    dispose () {
        if (this._texture) {
            this._renderer.gl.deleteTexture(this._texture);
            this._texture = null;
        }
        super.dispose();
    }

    /**
     * @return {Array<number>} the natural size, in Scratch units, of this skin.
     */
    get size () {
        return this._svgRenderer.size;
    }

    /**
     * Set the origin, in object space, about which this Skin should rotate.
     * @param {number} x - The x coordinate of the new rotation center.
     * @param {number} y - The y coordinate of the new rotation center.
     */
    setRotationCenter (x, y) {
        const viewOffset = this._svgRenderer.viewOffset;
        super.setRotationCenter(x - viewOffset[0], y - viewOffset[1]);
    }

    /**
     * @param {Array<number>} scale - The scaling factors to be used, each in the [0,100] range.
     * @return {WebGLTexture} The GL texture representation of this skin when drawing at the given scale.
     */
    // eslint-disable-next-line no-unused-vars
    getTexture (scale) {
        // The texture only ever gets uniform scale. Take the larger of the two axes.
        const scaleMax = scale ? Math.max(Math.abs(scale[0]), Math.abs(scale[1])) : 100;
        const requestedScale = scaleMax / 100;
        let newScale = this._textureScale;
        while ((newScale < this._maxTextureScale) && (requestedScale >= 1.5 * newScale)) {
            newScale *= 2;
        }

        let error;
        const callback = () => {
            if (this._textureScale === newScale) {
                const gl = this._renderer.gl;
                gl.bindTexture(gl.TEXTURE_2D, this._texture);
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._svgRenderer.canvas);
                error = gl.getError();
            }
        };
        do {
            if (this._textureScale !== newScale) {
                this._textureScale = newScale;
                this._svgRenderer._draw(this._textureScale, callback);
            }
            newScale /= 2;
        } while (error && newScale > 1);

        return this._texture;
    }

    /**
     * Set the contents of this skin to a snapshot of the provided SVG data.
     * @param {string} svgData - new SVG to use.
     * @param {Array<number>} [rotationCenter] - Optional rotation center for the SVG. If not supplied, it will be
     * calculated from the bounding box
     * @fires Skin.event:WasAltered
     */
    setSVG (svgData, rotationCenter) {
        this._svgRenderer.fromString(svgData, 1, () => {
            const gl = this._renderer.gl;
            this._textureScale = this._maxTextureScale = 1;
            if (this._texture) {
                gl.bindTexture(gl.TEXTURE_2D, this._texture);
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._svgRenderer.canvas);
                this._silhouette.update(this._svgRenderer.canvas);
            } else {
                // TODO: mipmaps?
                const textureOptions = {
                    auto: true,
                    wrap: gl.CLAMP_TO_EDGE,
                    src: this._svgRenderer.canvas
                };

                this._texture = twgl.createTexture(gl, textureOptions);
                this._silhouette.update(this._svgRenderer.canvas);
            }

            const maxDimension = Math.max(this._svgRenderer.canvas.width, this._svgRenderer.canvas.height);
            let testScale = 2;
            for (testScale; maxDimension * testScale <= MAX_TEXTURE_DIMENSION; testScale *= 2) {
                this._maxTextureScale = testScale;
            }

            if (typeof rotationCenter === 'undefined') rotationCenter = this.calculateRotationCenter();
            this.setRotationCenter.apply(this, rotationCenter);
            this.emit(Skin.Events.WasAltered);
        });
    }

}

module.exports = SVGSkin;
<|endoftext|>


<commit_before>Concrete.UI.Toolbar = Class.create({

  initialize: function(parentElement) {
    this.toolbar = this._createDomElement(parentElement);
    this.popup = this.toolbar.down(".ct_tooltip_popup");
    this.hotkeys = new Hash();
    this.tooltips = {};
  },

  handleEvent: function(event) {
    if (event.type == "keydown") {
      this.hotkeys.keys().each(function(k) {
        var match = k.match(/^(ctrl\+)?(shift\+)?(\w)$/);
        if (match) {
          var ctrl = match[1];
          var shift = match[2];
          var keyCode = match[3].charCodeAt(0);
          if ((shift && event.shiftKey || !shift && !event.shiftKey) &&
            (ctrl && event.ctrlKey || !ctrl && !event.ctrlKey) &&
            keyCode == event.keyCode) {
            this.hotkeys.get(k)();
            event.stop();
            return true;
          }
        }
      }, this);
    }
    else if (event.type == "mousemove") {
      var element = Event.element(event);
      this.popup.hide();
      if (element.hasClassName("ct_toolbar_icon")) {
        var clazz = element.className.sub("ct_toolbar_icon ","");
        var tooltip = this.tooltips[clazz];
        if (tooltip && tooltip.length > 0) {
          this.popup.innerHTML = tooltip;
          var left = event.clientX+20;
          if (left > document.viewport.getDimensions().width - this.popup.getWidth()) {
            left = document.viewport.getDimensions().width - this.popup.getWidth();
          }
          this.popup.setStyle({left: left, top: event.clientY+20});
          this.popup.show();
        }
      }
    }
  },

  addCommand: function(options, func) {
    if (options.hotkey) {
      this.hotkeys.set(options.hotkey, func);
    }
    var clazz = options.buttonClass || "";
    if (options.tooltip && clazz.length > 0) {
      this.tooltips[clazz] = options.tooltip;
    }
    Element.insert(this.toolbar, { bottom:
      ""
    });
    var icon = this.toolbar.childElements().last();
    icon.onclick = func;
  },

  _createDomElement: function(parentElement) {
    Element.insert(parentElement, { bottom:
      "
" +
        "

" +
      "
"
    });
    return parentElement.childElements().last();
  },

});
<commit_msg>bugfix: don't edit current element when invoking a toolbar command<commit_after>Concrete.UI.Toolbar = Class.create({

  initialize: function(parentElement) {
    this.toolbar = this._createDomElement(parentElement);
    this.popup = this.toolbar.down(".ct_tooltip_popup");
    this.hotkeys = new Hash();
    this.tooltips = {};
  },

  handleEvent: function(event) {
    var handeled = false;
    if (event.type == "keydown") {
      this.hotkeys.keys().each(function(k) {
        var match = k.match(/^(ctrl\+)?(shift\+)?(\w)$/);
        if (match) {
          var ctrl = match[1];
          var shift = match[2];
          var keyCode = match[3].charCodeAt(0);
          if ((shift && event.shiftKey || !shift && !event.shiftKey) &&
            (ctrl && event.ctrlKey || !ctrl && !event.ctrlKey) &&
            keyCode == event.keyCode) {
            this.hotkeys.get(k)();
            event.stop();
            handeled = true;
            throw $break;
          }
        }
      }, this);
    }
    else if (event.type == "mousemove") {
      var element = Event.element(event);
      this.popup.hide();
      if (element.hasClassName("ct_toolbar_icon")) {
        var clazz = element.className.sub("ct_toolbar_icon ","");
        var tooltip = this.tooltips[clazz];
        if (tooltip && tooltip.length > 0) {
          this.popup.innerHTML = tooltip;
          var left = event.clientX+20;
          if (left > document.viewport.getDimensions().width - this.popup.getWidth()) {
            left = document.viewport.getDimensions().width - this.popup.getWidth();
          }
          this.popup.setStyle({left: left, top: event.clientY+20});
          this.popup.show();
        }
      }
    }
    return handeled;
  },

  addCommand: function(options, func) {
    if (options.hotkey) {
      this.hotkeys.set(options.hotkey, func);
    }
    var clazz = options.buttonClass || "";
    if (options.tooltip && clazz.length > 0) {
      this.tooltips[clazz] = options.tooltip;
    }
    Element.insert(this.toolbar, { bottom:
      ""
    });
    var icon = this.toolbar.childElements().last();
    icon.onclick = func;
  },

  _createDomElement: function(parentElement) {
    Element.insert(parentElement, { bottom:
      "
" +
        "

" +
      "
"
    });
    return parentElement.childElements().last();
  },

});
<|endoftext|>


<commit_before>// @flow

import * as React from 'react';
import classNames from 'classnames';
import setDisplayName from 'recompose/setDisplayName';
import { defaultProps } from './utils';

type Props = {
  className?: string,
  classPrefix?: string
};

class Sidebar extends React.Component<Props> {
  render() {
    const { className, classPrefix, ...props } = this.props;
    const classes = classNames(classPrefix, className);

    return <div {...props} className={classes} />;
  }
}

export default setDisplayName('Sidebar')(
  defaultProps({
    classPrefix: 'sidebar'
  })(Sidebar)
);
<commit_msg>Update Sidebar<commit_after>// @flow

import * as React from 'react';
import classNames from 'classnames';
import setDisplayName from 'recompose/setDisplayName';
import { defaultProps } from './utils';

type Props = {
  className?: string,
  classPrefix?: string,
  width: number,
  style?: Object
};

class Sidebar extends React.Component<Props> {
  static defaultProps = {
    width: 260
  };
  render() {
    const { className, classPrefix, width, style, ...props } = this.props;
    const classes = classNames(classPrefix, className);

    const styles = {
      flex: `0 0 ${width}px`,
      maxWidth: `${width}px`,
      minWidth: `${width}px`,
      width: `${width}px`,
      ...style
    };
    return <div {...props} className={classes} style={styles} />;
  }
}

export default setDisplayName('Sidebar')(
  defaultProps({
    classPrefix: 'sidebar'
  })(Sidebar)
);
<|endoftext|>


<commit_before>// @flow

import * as React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import SidenavBody from './SidenavBody';
import SidenavHeader from './SidenavHeader';
import SidenavToggle from './SidenavToggle';
import createComponent from './utils/createComponent';
import prefix, { globalKey } from './utils/prefix';

type Props = {
  classPrefix?: string,
  className?: string,
  expanded: boolean,
  appearance: 'default' | 'inverse' | 'subtle'
}

const Component = createComponent('div');

class Sidenav extends React.Component<Props> {

  static defaultProps = {
    appearance: 'default',
    expanded: true,
    classPrefix: `${globalKey}sidenav`
  };

  static childContextTypes = {
    expanded: PropTypes.bool,
    sidenav: PropTypes.bool
  };

  static Header = SidenavHeader;
  static Body = SidenavBody;
  static Toggle = SidenavToggle;

  getChildContext() {
    const { expanded } = this.props;
    return {
      sidenav: true,
      expanded
    };
  }

  render() {
    const {
      className,
      classPrefix,
      appearance,
      expanded,
      ...props
    } = this.props;

    const addPrefix = prefix(classPrefix);

    const classes = classNames(classPrefix, {
      [addPrefix('expanded')]: expanded,
      [addPrefix('folded')]: !expanded
    }, addPrefix(appearance), className);

    return (
      <Component
        {...props}
        className={classes}
        role="navigation"
      />
    );
  }

}

export default Sidenav;
<commit_msg>Update Sidenav<commit_after>// @flow

import * as React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Collapse from 'rsuite-utils/lib/Animation/Collapse';
import SidenavBody from './SidenavBody';
import SidenavHeader from './SidenavHeader';
import SidenavToggle from './SidenavToggle';
import createComponent from './utils/createComponent';
import prefix, { globalKey } from './utils/prefix';

type Props = {
  classPrefix?: string,
  className?: string,
  expanded: boolean,
  appearance: 'default' | 'inverse' | 'subtle'
}

const Component = createComponent('div');

class Sidenav extends React.Component<Props> {

  static defaultProps = {
    appearance: 'default',
    expanded: true,
    classPrefix: `${globalKey}sidenav`
  };

  static childContextTypes = {
    expanded: PropTypes.bool,
    sidenav: PropTypes.bool
  };

  static Header = SidenavHeader;
  static Body = SidenavBody;
  static Toggle = SidenavToggle;

  getChildContext() {
    const { expanded } = this.props;
    return {
      sidenav: true,
      expanded
    };
  }

  render() {
    const {
      className,
      classPrefix,
      appearance,
      expanded,
      ...props
    } = this.props;

    const addPrefix = prefix(classPrefix);
    const classes = classNames(classPrefix, addPrefix(appearance), className);

    return (
      <Collapse in={expanded}>
        <Component
          {...props}
          className={classes}
          role="navigation"
        />
      </Collapse>
    );
  }

}

export default Sidenav;
<|endoftext|>


<commit_before>import JsLinQ from "jslinq";

export class TraceQueryManager{
	constructor(traceModel){
		this.filters = traceModel.traceSearchfilters;
	}

    contains(a,b){
        if(!a){
            return false;
        }
        return (a.toString().indexOf(b) > -1);
    }
    containsIgnoreCase(a,b){
        if(!a){
            return false;
        }
        return (a.toString().toLowerCase().indexOf(b) > -1);
    }

    getQuery(rawData, filterSelection, searchTerm){
        let contains = this.contains, filters = this.filters, dataSet = JsLinQ(rawData), query;

        if(searchTerm === ""){
            return dataSet;
        }

        switch(filters[filterSelection]){
        	case filters.any:
                query = dataSet.where(function(item){return contains(item.id,searchTerm)||contains(item.type,searchTerm)||
                    contains(item.text,searchTerm)||contains(item.values,searchTerm);
                    });
        		break;
        	default:
                query = dataSet.where(function(item){
                    return contains(item[filterSelection],searchTerm);
                    });
        		break;
        }
        return query;
    }

}<commit_msg>removed s from query<commit_after>import JsLinQ from "jslinq";

export class TraceQueryManager{
	constructor(traceModel){
		this.filters = traceModel.traceSearchfilters;
	}

    contains(a,b){
        if(!a){
            return false;
        }
        return (a.toString().indexOf(b) > -1);
    }
    containsIgnoreCase(a,b){
        if(!a){
            return false;
        }
        return (a.toString().toLowerCase().indexOf(b) > -1);
    }

    getQuery(rawData, filterSelection, searchTerm){
        let contains = this.contains, filters = this.filters, dataSet = JsLinQ(rawData), query;

        if(searchTerm === ""){
            return dataSet;
        }

        switch(filters[filterSelection]){
        	case filters.any:
                query = dataSet.where(function(item){return contains(item.id,searchTerm)||contains(item.type,searchTerm)||
                    contains(item.text,searchTerm)||contains(item.value,searchTerm);
                    });
        		break;
        	default:
                query = dataSet.where(function(item){
                    return contains(item[filterSelection],searchTerm);
                    });
        		break;
        }
        return query;
    }

}<|endoftext|>


<commit_before>/* global trackEvent */

window.logout = function logout() {
	firebase.auth().signOut();
};
function login(providerName) {
	var provider;
	if (providerName === 'facebook') {
		provider = new firebase.auth.FacebookAuthProvider();
	} else if (providerName === 'twitter') {
		provider = new firebase.auth.TwitterAuthProvider();
	} else if (providerName === 'google') {
		provider = new firebase.auth.GoogleAuthProvider();
		provider.addScope('https://www.googleapis.com/auth/userinfo.profile');
	} else {
		provider = new firebase.auth.GithubAuthProvider();
	}

	return firebase
		.auth()
		.signInWithPopup(provider)
		.then(function() {
			trackEvent('fn', 'loggedIn', providerName);
		})
		.catch(function(error) {
			alert(
				'You have already signed up with the same email using different social login'
			);
			utils.log(error);
		});
}
window.login = login;
<commit_msg>auth: save last successful auth provider<commit_after>/* global trackEvent */

window.logout = function logout() {
	firebase.auth().signOut();
};
function login(providerName) {
	var provider;
	if (providerName === 'facebook') {
		provider = new firebase.auth.FacebookAuthProvider();
	} else if (providerName === 'twitter') {
		provider = new firebase.auth.TwitterAuthProvider();
	} else if (providerName === 'google') {
		provider = new firebase.auth.GoogleAuthProvider();
		provider.addScope('https://www.googleapis.com/auth/userinfo.profile');
	} else {
		provider = new firebase.auth.GithubAuthProvider();
	}

	return firebase
		.auth()
		.signInWithPopup(provider)
		.then(function() {
			trackEvent('fn', 'loggedIn', providerName);
			// Save to recommend next time
			window.db.local.set({ lastAuthProvider: providerName });
		})
		.catch(function(error) {
			alert(
				'You have already signed up with the same email using different social login'
			);
			utils.log(error);
		});
}
window.login = login;
<|endoftext|>


<commit_before>import React from 'react';
import Button from '@material-ui/core/Button';
import ListItemBase from '../common/ListItemBase'
import ApiUtils from '../utils/ApiUtils';
import './TranslationListItem.css';
import AudioRecorder from '../audio/AudioRecorder';

class TranslationListItem extends ListItemBase {
  constructor(props) {
    super(props);

    const { translation, transliteration } = this.props.item;

    this.savedData = {
      translation,
      transliteration
    };

    this.state = {
      ...this.state,
      disabled: true,
      error: false,
    };
  }

  handleTranslationChange = (e) => {
    const newTranslation = e.target.value.trim();
    this.setState({
      translation: newTranslation,
      disabled: newTranslation === this.savedData.translation,
    });
  }

  handleTransliterationChange = (e) => {
    const newTransliteration = e.target.value.trim();
    this.setState({
      transliteration: newTransliteration,
      disabled: newTransliteration === this.savedData.transliteration,
    });
  }

  saveTranslation_ = async (e) => {
    try {
      const { english_word, sound_link, translation,
        transliteration } = this.state;

      if (!translation) {
        this.setState({
          // todo(parikshiv) - add visible error state, also
          // figure out if any of these can be empty?
          error: true,
        })
        return;
      }

      // TODO(smus): Upload this blob of audio to a Cloud storage and get the
      // uploaded file's URL.
      await fetch(`${ApiUtils.origin}${ApiUtils.path}addTranslations`, {
        method: 'POST',
        body: JSON.stringify({
          english_word,
          sound_link,
          translation,
          transliteration,
        }),
        headers: {
          'Content-Type': 'application/json',
        }
      });

      this.savedData = {
        translation,
        transliteration
      };

      this.setState({
        disabled: true,
      });
    } catch(err) {
      console.error(err);
    }
  }

  onSavedAudio_(blob) {
    console.log('onSavedAudio_', blob);
    this.setState({sound_blob: blob});
  }

  renderEndOfRow() {
    return [<AudioRecorder audioUrl={this.state.sound_link}
      onSavedAudio={(blob) => this.onSavedAudio_(blob)}
      key={0} />,
      <Button
        variant="contained"
        color="primary"
        onClick={() => this.saveTranslation_()}
        key={1}
      >
        Save
      </Button>
    ];
  }
}

export default TranslationListItem;
<commit_msg>restore disabled button<commit_after>import React from 'react';
import Button from '@material-ui/core/Button';
import ListItemBase from '../common/ListItemBase'
import ApiUtils from '../utils/ApiUtils';
import './TranslationListItem.css';
import AudioRecorder from '../audio/AudioRecorder';

class TranslationListItem extends ListItemBase {
  constructor(props) {
    super(props);

    const { translation, transliteration } = this.props.item;

    this.savedData = {
      translation,
      transliteration
    };

    this.state = {
      ...this.state,
      disabled: true,
      error: false,
    };
  }

  handleTranslationChange = (e) => {
    const newTranslation = e.target.value.trim();
    this.setState({
      translation: newTranslation,
      disabled: newTranslation === this.savedData.translation,
    });
  }

  handleTransliterationChange = (e) => {
    const newTransliteration = e.target.value.trim();
    this.setState({
      transliteration: newTransliteration,
      disabled: newTransliteration === this.savedData.transliteration,
    });
  }

  saveTranslation_ = async (e) => {
    try {
      const { english_word, sound_link, translation,
        transliteration } = this.state;

      if (!translation) {
        this.setState({
          // todo(parikshiv) - add visible error state, also
          // figure out if any of these can be empty?
          error: true,
        })
        return;
      }

      // TODO(smus): Upload this blob of audio to a Cloud storage and get the
      // uploaded file's URL.
      await fetch(`${ApiUtils.origin}${ApiUtils.path}addTranslations`, {
        method: 'POST',
        body: JSON.stringify({
          english_word,
          sound_link,
          translation,
          transliteration,
        }),
        headers: {
          'Content-Type': 'application/json',
        }
      });

      this.savedData = {
        translation,
        transliteration
      };

      this.setState({
        disabled: true,
      });
    } catch(err) {
      console.error(err);
    }
  }

  onSavedAudio_(blob) {
    console.log('onSavedAudio_', blob);
    this.setState({sound_blob: blob});
  }

  renderEndOfRow() {
    return [<AudioRecorder audioUrl={this.state.sound_link}
      onSavedAudio={(blob) => this.onSavedAudio_(blob)}
      key={0} />,
      <Button
        variant="contained"
        color="primary"
        disabled={this.state.disabled}
        onClick={() => this.saveTranslation_()}
        key={1}
      >
        Save
      </Button>
    ];
  }
}

export default TranslationListItem;
<|endoftext|>


<commit_before>/**
 * 提示
 * @author Brian Li
 * @email lbxxlht@163.com
 * @version 0.0.2.1
 */
define(function (require) {

    var React = require('react');
    var util = require('./core/util');
    var Layer = require('./Layer.jsx');
    var cTools = require('./core/componentTools');

    return React.createClass({
        /**
         * @properties
         * @param {Import|Properties} src\core\componentTools.js skin className style disabled
         * @param {String} title 弹出提示的标题
         * @param {String} content 弹出提示的内容，可以含有html标签
         * @param {String} icon 提示组件外部显示的图标，具体见src/css/icon/variable.less
         * @param {ReactClass} renderer Tip内部渲染的组件，如果指定，icon属性无效
         * @param {Object} renderProps Tip内部组件渲染的属性集
         * @param {String} layerLocation 浮层的定位配置，具体见src\core\layerTools.js
         * @param {Function} onOffset 浮层位置修正回调
         */
        /**
         * @fire Import src\Layer.jsx.js layer onOffset
         */
        // @override
        getDefaultProps: function () {
            return {
                // base
                skin: '',
                className: '',
                style: {},
                disabled: false,
                // self
                title: '',
                content: '',
                icon: 'font-icon-hint-question-s',
                renderer: null,
                renderProps: {},
                layerLocation: 'right left top bottom',
                onOffset: null
            };
        },
        getInitialState: function () {
            return {
                layerOpen: false
            };
        },
        offsetLayerPosition: function (result) {
            if (typeof this.props.onOffset === 'function') {
                this.props.onOffset(result);
                return;
            }
            if (typeof this.props.renderer === 'function') return;
            result.left += '1_6_'.indexOf(result.clockPosition + '_') > -1 ? 10 : -15;
            result.top += '12_1_'.indexOf(result.clockPosition + '_') > -1  ? -5 : 10;
        },
        render: function () {
            var containerProp = cTools.containerBaseProps('tip', this, {
                merge: {
                    onMouseEnter: cTools.openLayerHandlerFactory(this, 'layerOpen'),
                    onMouseLeave: cTools.closeLayerHandlerFactory(this, 'layerOpen'),
                },
                style: (this.props.title || this.props.content) ? undefined : {display: 'none'}
            });
            var layerProp = {
                isOpen: this.state.layerOpen && (this.props.title || this.props.content) && !this.props.disabled,
                anchor: this.refs.container,
                location: this.props.layerLocation,
                onOffset: this.offsetLayerPosition
            };
            var Renderer = this.props.renderer;
            containerProp.className += typeof Renderer === 'function' ? '' : ' font-icon ' + this.props.icon;
            return (

                    {typeof Renderer === 'function' ? <Renderer {...this.props.renderProps}/> : null}
                    <Layer {...layerProp}>

{this.props.title}

                    </Layer>

            );
        }
    });

});
<commit_msg>fixed Tip<commit_after>/**
 * 提示
 * @author Brian Li
 * @email lbxxlht@163.com
 * @version 0.0.2.1
 */
define(function (require) {

    var React = require('react');
    var util = require('./core/util');
    var Layer = require('./Layer.jsx');
    var cTools = require('./core/componentTools');

    return React.createClass({
        /**
         * @properties
         * @param {Import|Properties} src\core\componentTools.js skin className style disabled
         * @param {String} title 弹出提示的标题
         * @param {String} content 弹出提示的内容，可以含有html标签
         * @param {String} icon 提示组件外部显示的图标，具体见src/css/icon/variable.less
         * @param {ReactClass} renderer Tip内部渲染的组件，如果指定，icon属性无效
         * @param {Object} renderProps Tip内部组件渲染的属性集
         * @param {String} layerLocation 浮层的定位配置，具体见src\core\layerTools.js
         * @param {Function} onOffset 浮层位置修正回调
         */
        /**
         * @fire Import src\Layer.jsx.js layer onOffset
         */
        // @override
        getDefaultProps: function () {
            return {
                // base
                skin: '',
                className: '',
                style: {},
                disabled: false,
                // self
                title: '',
                content: '',
                icon: 'font-icon-hint-question-s',
                renderer: null,
                renderProps: {},
                layerLocation: 'right left top bottom',
                onOffset: null
            };
        },
        getInitialState: function () {
            return {
                layerOpen: false,
                mouseenter: false
            };
        },
        onMouseEnter: function () {
            this.setState({
                mouseenter: true,
                layerOpen: true
            });
        },
        onMouseLeave: function () {
            this.setState({mouseenter: false});
            cTools.closeLayerHandlerFactory(this, 'layerOpen')();
        },
        offsetLayerPosition: function (result) {
            if (typeof this.props.onOffset === 'function') {
                this.props.onOffset(result);
                return;
            }
            if (typeof this.props.renderer === 'function') return;
            result.left += '1_6_'.indexOf(result.clockPosition + '_') > -1 ? 10 : -15;
            result.top += '12_1_'.indexOf(result.clockPosition + '_') > -1  ? -5 : 10;
        },
        render: function () {
            var containerProp = cTools.containerBaseProps('tip', this, {
                merge: {
                    onMouseEnter: this.onMouseEnter,
                    onMouseLeave: this.onMouseLeave
                },
                style: (this.props.title || this.props.content) ? undefined : {display: 'none'}
            });
            var layerProp = {
                ref: 'layer',
                isOpen: this.state.layerOpen && (this.props.title || this.props.content) && !this.props.disabled,
                anchor: this.refs.container,
                location: this.props.layerLocation,
                onOffset: this.offsetLayerPosition,
                onMouseLeave: this.onMouseLeave
            };
            var Renderer = this.props.renderer;
            containerProp.className += typeof Renderer === 'function' ? '' : ' font-icon ' + this.props.icon;
            return (

                    {typeof Renderer === 'function' ? <Renderer {...this.props.renderProps}/> : null}
                    <Layer {...layerProp}>

{this.props.title}

                    </Layer>

            );
        }
    });

});
<|endoftext|>


<commit_before>/*#ifndef(UMD)*/
"use strict";
/*global _GPF_HOST_BROWSER*/ // gpf.HOST_BROWSER
/*global _gpfAssert*/ // Assertion method
/*global _gpfExit*/ // Exit function
/*global _gpfHost*/ // Host type
/*global _gpfIgnore*/ // Helper to remove unused parameter warning
/*global _gpfWebWindow*/ // Browser window object
/*exported _gpfExtend*/ // gpf.extend
/*exported _gpfIsArrayLike*/ // Return true if the parameter looks like an array
/*exported _gpfNodeBuffer2JsArray*/ // Converts a NodeJS buffer into an int array
/*exported _gpfObjectForEach*/ // Similar to [].forEach but for objects
/*exported _gpfStringCapitalize*/ // Capitalize the string
/*exported _gpfStringEscapeFor*/ // Make the string content compatible with lang
/*exported _gpfStringReplaceEx*/ // String replacement using dictionary map
/*exported _gpfValues*/ // Dictionary of value converters
/*#endif*/

//region _gpfIsArrayLike

var
    /**
     * Return true if the parameter looks like an array
     *
     * @param {Object} obj
     * @return {Boolean} True if array-like
     */
    _gpfIsArrayLike;

/* istanbul ignore if */ // Not tested with NodeJS
if (_GPF_HOST_BROWSER === _gpfHost && (_gpfWebWindow.HTMLCollection || _gpfWebWindow.NodeList)) {
    _gpfIsArrayLike = function (obj) {
        return obj instanceof Array
            || obj instanceof _gpfWebWindow.HTMLCollection
            || obj instanceof _gpfWebWindow.NodeList;
    };
} else {
    _gpfIsArrayLike = function (obj) {
        return obj instanceof Array;
    };
}

/**
 * Return true if the provided parameter looks like an array (i.e. it has a property length and each item can be
 * accessed with [])
 *
 * @param {Object} obj
 * @return {Boolean} True if array-like
 */
gpf.isArrayLike = _gpfIsArrayLike;

//endregion

//region gpf.forEach

/**
 * Similar to [].forEach but works on array-like
 *
 * @param {Array} array
 * @param {Function} callback Function to execute for each own property, taking three arguments:
 * - {*} currentValue The current element being processed
 * - {String} property The current index being processed
 * - {Object} array The array currently being processed
 * @param {*} [thisArg=undefined] thisArg Value to use as this when executing callback.
 */
function _gpfArrayForEach (array, callback, thisArg) {
    var index,
        length = array.length;
    for (index = 0; index < length; ++index) {
        callback.apply(thisArg, [array[index], index, array]);
    }
}

/**
 * Similar to [].forEach but for objects
 *
 * @param {Object} object
 * @param {Function} callback Function to execute for each own property, taking three arguments:
 * - {*} currentValue The current element being processed
 * - {String} property The name of the current property being processed
 * - {Object} object The object currently being processed
 * @param {*} [thisArg=undefined] thisArg Value to use as this when executing callback.
 */
function _gpfObjectForEach (object, callback, thisArg) {
    for (var property in object) {
        /* istanbul ignore else */
        if (object.hasOwnProperty(property)) {
            callback.apply(thisArg, [object[property], property, object]);
        }
    }
}

/**
 * Executes a provided function once per structure element.
 *
 * @param {Array|Object} structure
 * @param {Function} callback Function to execute for each element, taking three arguments:
 * - {*} currentValue The current element being processed
 * - {String} property The name of the current property or the index being processed
 * - {Array|Object} structure The structure currently being processed
 * @param {*} [thisArg=undefined] thisArg Value to use as this when executing callback.
 */
gpf.forEach = function (structure, callback, thisArg) {
    if (_gpfIsArrayLike(structure)) {
        _gpfArrayForEach(structure, callback, thisArg);
        return;
    }
    _gpfObjectForEach(structure, callback, thisArg); /*gpf:inline(object)*/
};

//endregion

//region String helpers (will be reused in string module)

/**
 * Capitalize the string
 *
 * @param {String} that
 * @return {String}
 */
function _gpfStringCapitalize (that) {
    return that.charAt(0).toUpperCase() + that.substr(1);
}

/**
 * String replacement using dictionary map
 *
 * @param {String} that
 * @param {Object} replacements map of strings to search and replace
 * @return {String}
 */
function _gpfStringReplaceEx (that, replacements) {
    var result = that;
    _gpfObjectForEach(replacements, function (replacement, key) {/*gpf:inline(object)*/
        result = result.split(key).join(replacement);
    });
    return result;
}

var
// Dictionary of language to escapes
    _gpfStringEscapes = {

        javascript: {
            "\\": "\\\\",
            "\"": "\\\"",
            "\n": "\\n",
            "\r": "\\r",
            "\t": "\\t"
        },

        xml: {
            "&": "&",
            "<": "<",
            ">": ">"
        }

    };

(function () {
    var escapes = _gpfStringEscapes,
        html = {};
    // Copy XML
    _gpfObjectForEach(escapes.xml, function (escape, key) {
        html[key] = escape;
    });
    // Adds accents escape
    _gpfObjectForEach({
        224: "à",
        225: "á",
        232: "è",
        233: "é",
        234: "ê"
    }, function (escape, key) {
        html[String.fromCharCode(key)] = escape;
    });
    escapes.html = html;
}());

/**
 * Make the string content compatible with lang
 *
 * @param {String} that
 * @param {String} language
 * @return {String}
 */
function _gpfStringEscapeFor (that, language) {
    that = _gpfStringReplaceEx(that, _gpfStringEscapes[language]);
    if ("javascript" === language) {
        that = "\"" + that + "\"";
    }
    return that;
}

//endregion

//region gpf.extend

/**
 * gpf.extend implementation of assign with no callback
 *
 * @param {*} value
 * @param {String} member
 */
function _gpfAssign (value, member) {
    /*jshint validthis:true*/ // gpf.extend's arguments: this[0] is dst
    this[0][member] = value;
}

/**
 * gpf.extend implementation of assign with a callback
 *
 * @param {*} value
 * @param {String} member
 */
function _gpfAssignOrCall (value, member) {
    /*jshint validthis:true*/ // gpf.extend's arguments
    var dst = this[0],
        overwriteCallback = this[2];
    // TODO: see if in is faster
    if (undefined === dst[member]) {
        dst[member] = value;
    } else {
        overwriteCallback(dst, member, value);
    }
}

/**
 * Extends the destination object dst by copying own enumerable properties from the src object(s) to dst.
 * If a conflict has to be handled (i.e. member exists on both objects), the overwriteCallback has to handle it.
 *
 * @param {Object} dst
 * @param {Object} src
 * @param {Function} [overwriteCallback=undefined] overwriteCallback
 * @return {Object} the modified dst
 * @chainable
 */
function _gpfExtend (dst, src, overwriteCallback) {
    var callbackToUse;
    if (undefined === overwriteCallback) {
        callbackToUse = _gpfAssign;
    } else {
        _gpfAssert("function" === typeof overwriteCallback, "Expected function");
        callbackToUse = _gpfAssignOrCall;
    }
    _gpfObjectForEach(src, callbackToUse, arguments); /*gpf:inline(object)*/
    return dst;
}

// @inheritdoc _gpfExtend
gpf.extend = _gpfExtend;

//endregion

//region gpf.value

var
    /**
     * gpf.value handlers per type.
     * Each handler signature is:
     * - {*} value the value to convert
     * - {String} valueType typeof value
     * - {*} defaultValue the expected default value if not convertible
     *
     * @type {Object}
     */
    _gpfValues = {
        "boolean": function (value, valueType, defaultValue) {
            _gpfIgnore(defaultValue);
            if ("string" === valueType) {
                if ("yes" === value || "true" === value) {
                    return true;
                }
                return 0 !== parseInt(value, 10);
            }
            if ("number" === valueType) {
                return 0 !== value;
            }
        },

        number:  function (value, valueType, defaultValue) {
            _gpfIgnore(defaultValue);
            if ("string" === valueType) {
                return parseFloat(value);
            }
        },

        string: function (value, valueType, defaultValue) {
            _gpfIgnore(valueType, defaultValue);
            return value.toString();
        },

        object: function (value, valueType, defaultValue) {
            _gpfIgnore(value, valueType, defaultValue);
        }
    };

/*
 * Converts the provided value to match the expectedType.
 * If not specified or impossible to do so, defaultValue is returned.
 * When expectedType is not provided, it is deduced from defaultValue.
 *
 * @param {*} value
 * @param {*} default value
 * @param {String} [expectedType=typeof defaultValue] expected type
 * @return {*}
 */
function _gpfValue (value, defaultValue, expectedType) {
    var valueType = typeof value,
        result;
    if (!expectedType) {
        expectedType = typeof defaultValue;
    }
    if (expectedType === valueType) {
        return value;
    }
    if ("undefined" === valueType) {
        return defaultValue;
    }
    result = _gpfValues[expectedType](value, valueType, defaultValue);
    if (undefined === result) {
        return defaultValue;
    }
    return result;
}

// @inheritdoc _gpfValue
gpf.value = _gpfValue;

//endregion

_gpfExtend(gpf, {

    /**
     * Shallow copy an object
     *
     * @param {Object} obj
     * @return {Object}
     */
    clone: function (obj) {
        // http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-an-object/5344074#5344074
        return JSON.parse(JSON.stringify(obj));
    },

    /*
     * Find the first member of dictionary which value equals to value.
     *
     * @param {Object/array} dictionary
     * @param {*} value
     * @return {String/number/undefined} undefined if not found
     */
    test: function (dictionary, value) {
        var idx;
        if (dictionary instanceof Array) {
            idx = dictionary.length;
            while (idx > 0) {
                if (dictionary[--idx] === value) {
                    return idx;
                }
            }
        } else {
            for (idx in dictionary) {
                if (dictionary.hasOwnProperty(idx) && dictionary[idx] === value) {
                    return idx;
                }
            }
        }
        return undefined;
    },

    /*
     * Inserts the value in the array if not already present.
     *
     * @param {Array} array
     * @param {*} value
     * @return {Array}
     * @chainable
     */
    set: function (array, value) {
        _gpfAssert(array instanceof Array, "gpf.set must be used with an Array");
        var idx = array.length;
        while (idx > 0) {
            if (array[--idx] === value) {
                return array; // Already set
            }
        }
        array.push(value);
        return array;
    },

    /*
     * Removes the member of 'dictionary' which value equals 'value'.
     * NOTE: that the object is modified.
     *
     * @param {Object/array} dictionary
     * @param {*} value
     * @return {Object/array} dictionary
     * @chainable
     */
    clear: function (dictionary, value) {
        var idx;
        if (dictionary instanceof Array) {
            idx = dictionary.length;
            while (idx > 0) {
                if (dictionary[--idx] === value) {
                    dictionary.splice(idx, 1);
                    break;
                }
            }
        } else {
            for (idx in dictionary) {
                if (dictionary.hasOwnProperty(idx) && dictionary[idx] === value) {
                    delete dictionary[idx];
                }
            }
        }
        return dictionary;
    },

    /**
     * XOR
     *
     * @param {Boolean} a
     * @param {Boolean} b
     */
    xor: function (a, b) {
        return a && !b || !a && b;
    }

});

/* istanbul ignore next */ // Not testable
/**
 * Exit function
 *
 * @paran {Number} [exitCode=0] exitCode
 */
gpf.exit = function (exitCode) {
    if (undefined === exitCode) {
        exitCode = 0;
    }
    _gpfExit(exitCode);
};

//region NodeJS helpers

/**
 * Converts a NodeJS buffer into a native array containing unsigned
 * bytes
 *
 * @param {Buffer} buffer
 * @return {Number[]}
 */
function _gpfNodeBuffer2JsArray (buffer) {
    var result = [],
        len = buffer.length,
        idx;
    for (idx = 0; idx < len; ++idx) {
        result.push(buffer.readUInt8(idx));
    }
    return result;
}

//endregion

/*#ifndef(UMD)*/

gpf.internals._gpfObjectForEach = _gpfObjectForEach;
gpf.internals._gpfStringEscapeFor = _gpfStringEscapeFor;
gpf.internals._gpfNodeBuffer2JsArray = _gpfNodeBuffer2JsArray;

/*#endif*/
<commit_msg>Date conversion<commit_after>/*#ifndef(UMD)*/
"use strict";
/*global _GPF_HOST_BROWSER*/ // gpf.HOST_BROWSER
/*global _gpfAssert*/ // Assertion method
/*global _gpfExit*/ // Exit function
/*global _gpfHost*/ // Host type
/*global _gpfIgnore*/ // Helper to remove unused parameter warning
/*global _gpfWebWindow*/ // Browser window object
/*global _gpfIsISO8601String*/ // Check if the string is an ISO 8601 representation of a date
/*exported _gpfExtend*/ // gpf.extend
/*exported _gpfIsArrayLike*/ // Return true if the parameter looks like an array
/*exported _gpfNodeBuffer2JsArray*/ // Converts a NodeJS buffer into an int array
/*exported _gpfObjectForEach*/ // Similar to [].forEach but for objects
/*exported _gpfStringCapitalize*/ // Capitalize the string
/*exported _gpfStringEscapeFor*/ // Make the string content compatible with lang
/*exported _gpfStringReplaceEx*/ // String replacement using dictionary map
/*exported _gpfValues*/ // Dictionary of value converters
/*#endif*/

//region _gpfIsArrayLike

var
    /**
     * Return true if the parameter looks like an array
     *
     * @param {Object} obj
     * @return {Boolean} True if array-like
     */
    _gpfIsArrayLike;

/* istanbul ignore if */ // Not tested with NodeJS
if (_GPF_HOST_BROWSER === _gpfHost && (_gpfWebWindow.HTMLCollection || _gpfWebWindow.NodeList)) {
    _gpfIsArrayLike = function (obj) {
        return obj instanceof Array
            || obj instanceof _gpfWebWindow.HTMLCollection
            || obj instanceof _gpfWebWindow.NodeList;
    };
} else {
    _gpfIsArrayLike = function (obj) {
        return obj instanceof Array;
    };
}

/**
 * Return true if the provided parameter looks like an array (i.e. it has a property length and each item can be
 * accessed with [])
 *
 * @param {Object} obj
 * @return {Boolean} True if array-like
 */
gpf.isArrayLike = _gpfIsArrayLike;

//endregion

//region gpf.forEach

/**
 * Similar to [].forEach but works on array-like
 *
 * @param {Array} array
 * @param {Function} callback Function to execute for each own property, taking three arguments:
 * - {*} currentValue The current element being processed
 * - {String} property The current index being processed
 * - {Object} array The array currently being processed
 * @param {*} [thisArg=undefined] thisArg Value to use as this when executing callback.
 */
function _gpfArrayForEach (array, callback, thisArg) {
    var index,
        length = array.length;
    for (index = 0; index < length; ++index) {
        callback.apply(thisArg, [array[index], index, array]);
    }
}

/**
 * Similar to [].forEach but for objects
 *
 * @param {Object} object
 * @param {Function} callback Function to execute for each own property, taking three arguments:
 * - {*} currentValue The current element being processed
 * - {String} property The name of the current property being processed
 * - {Object} object The object currently being processed
 * @param {*} [thisArg=undefined] thisArg Value to use as this when executing callback.
 */
function _gpfObjectForEach (object, callback, thisArg) {
    for (var property in object) {
        /* istanbul ignore else */
        if (object.hasOwnProperty(property)) {
            callback.apply(thisArg, [object[property], property, object]);
        }
    }
}

/**
 * Executes a provided function once per structure element.
 *
 * @param {Array|Object} structure
 * @param {Function} callback Function to execute for each element, taking three arguments:
 * - {*} currentValue The current element being processed
 * - {String} property The name of the current property or the index being processed
 * - {Array|Object} structure The structure currently being processed
 * @param {*} [thisArg=undefined] thisArg Value to use as this when executing callback.
 */
gpf.forEach = function (structure, callback, thisArg) {
    if (_gpfIsArrayLike(structure)) {
        _gpfArrayForEach(structure, callback, thisArg);
        return;
    }
    _gpfObjectForEach(structure, callback, thisArg); /*gpf:inline(object)*/
};

//endregion

//region String helpers (will be reused in string module)

/**
 * Capitalize the string
 *
 * @param {String} that
 * @return {String}
 */
function _gpfStringCapitalize (that) {
    return that.charAt(0).toUpperCase() + that.substr(1);
}

/**
 * String replacement using dictionary map
 *
 * @param {String} that
 * @param {Object} replacements map of strings to search and replace
 * @return {String}
 */
function _gpfStringReplaceEx (that, replacements) {
    var result = that;
    _gpfObjectForEach(replacements, function (replacement, key) {/*gpf:inline(object)*/
        result = result.split(key).join(replacement);
    });
    return result;
}

var
// Dictionary of language to escapes
    _gpfStringEscapes = {

        javascript: {
            "\\": "\\\\",
            "\"": "\\\"",
            "\n": "\\n",
            "\r": "\\r",
            "\t": "\\t"
        },

        xml: {
            "&": "&",
            "<": "<",
            ">": ">"
        }

    };

(function () {
    var escapes = _gpfStringEscapes,
        html = {};
    // Copy XML
    _gpfObjectForEach(escapes.xml, function (escape, key) {
        html[key] = escape;
    });
    // Adds accents escape
    _gpfObjectForEach({
        224: "à",
        225: "á",
        232: "è",
        233: "é",
        234: "ê"
    }, function (escape, key) {
        html[String.fromCharCode(key)] = escape;
    });
    escapes.html = html;
}());

/**
 * Make the string content compatible with lang
 *
 * @param {String} that
 * @param {String} language
 * @return {String}
 */
function _gpfStringEscapeFor (that, language) {
    that = _gpfStringReplaceEx(that, _gpfStringEscapes[language]);
    if ("javascript" === language) {
        that = "\"" + that + "\"";
    }
    return that;
}

//endregion

//region gpf.extend

/**
 * gpf.extend implementation of assign with no callback
 *
 * @param {*} value
 * @param {String} member
 */
function _gpfAssign (value, member) {
    /*jshint validthis:true*/ // gpf.extend's arguments: this[0] is dst
    this[0][member] = value;
}

/**
 * gpf.extend implementation of assign with a callback
 *
 * @param {*} value
 * @param {String} member
 */
function _gpfAssignOrCall (value, member) {
    /*jshint validthis:true*/ // gpf.extend's arguments
    var dst = this[0],
        overwriteCallback = this[2];
    // TODO: see if in is faster
    if (undefined === dst[member]) {
        dst[member] = value;
    } else {
        overwriteCallback(dst, member, value);
    }
}

/**
 * Extends the destination object dst by copying own enumerable properties from the src object(s) to dst.
 * If a conflict has to be handled (i.e. member exists on both objects), the overwriteCallback has to handle it.
 *
 * @param {Object} dst
 * @param {Object} src
 * @param {Function} [overwriteCallback=undefined] overwriteCallback
 * @return {Object} the modified dst
 * @chainable
 */
function _gpfExtend (dst, src, overwriteCallback) {
    var callbackToUse;
    if (undefined === overwriteCallback) {
        callbackToUse = _gpfAssign;
    } else {
        _gpfAssert("function" === typeof overwriteCallback, "Expected function");
        callbackToUse = _gpfAssignOrCall;
    }
    _gpfObjectForEach(src, callbackToUse, arguments); /*gpf:inline(object)*/
    return dst;
}

// @inheritdoc _gpfExtend
gpf.extend = _gpfExtend;

//endregion

//region gpf.value

var
    /**
     * gpf.value handlers per type.
     * Each handler signature is:
     * - {*} value the value to convert
     * - {String} valueType typeof value
     * - {*} defaultValue the expected default value if not convertible
     *
     * @type {Object}
     */
    _gpfValues = {
        "boolean": function (value, valueType, defaultValue) {
            _gpfIgnore(defaultValue);
            if ("string" === valueType) {
                if ("yes" === value || "true" === value) {
                    return true;
                }
                return 0 !== parseInt(value, 10);
            }
            if ("number" === valueType) {
                return 0 !== value;
            }
        },

        number:  function (value, valueType, defaultValue) {
            _gpfIgnore(defaultValue);
            if ("string" === valueType) {
                return parseFloat(value);
            }
        },

        string: function (value, valueType, defaultValue) {
            if (value instanceof Date) {
                return value.toISOString();
            }
            _gpfIgnore(valueType, defaultValue);
            return value.toString();
        },

        object: function (value, valueType, defaultValue) {
            if (defaultValue instanceof Date && "string" === valueType && _gpfIsISO8601String(value)) {
                return new Date(value);
            }
        }
    };

/*
 * Converts the provided value to match the expectedType.
 * If not specified or impossible to do so, defaultValue is returned.
 * When expectedType is not provided, it is deduced from defaultValue.
 *
 * @param {*} value
 * @param {*} default value
 * @param {String} [expectedType=typeof defaultValue] expected type
 * @return {*}
 */
function _gpfValue (value, defaultValue, expectedType) {
    var valueType = typeof value,
        result;
    if (!expectedType) {
        expectedType = typeof defaultValue;
    }
    if (expectedType === valueType) {
        return value;
    }
    if ("undefined" === valueType) {
        return defaultValue;
    }
    result = _gpfValues[expectedType](value, valueType, defaultValue);
    if (undefined === result) {
        return defaultValue;
    }
    return result;
}

// @inheritdoc _gpfValue
gpf.value = _gpfValue;

//endregion

_gpfExtend(gpf, {

    /**
     * Shallow copy an object
     *
     * @param {Object} obj
     * @return {Object}
     */
    clone: function (obj) {
        // http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-an-object/5344074#5344074
        return JSON.parse(JSON.stringify(obj));
    },

    /*
     * Find the first member of dictionary which value equals to value.
     *
     * @param {Object/array} dictionary
     * @param {*} value
     * @return {String/number/undefined} undefined if not found
     */
    test: function (dictionary, value) {
        var idx;
        if (dictionary instanceof Array) {
            idx = dictionary.length;
            while (idx > 0) {
                if (dictionary[--idx] === value) {
                    return idx;
                }
            }
        } else {
            for (idx in dictionary) {
                if (dictionary.hasOwnProperty(idx) && dictionary[idx] === value) {
                    return idx;
                }
            }
        }
        return undefined;
    },

    /*
     * Inserts the value in the array if not already present.
     *
     * @param {Array} array
     * @param {*} value
     * @return {Array}
     * @chainable
     */
    set: function (array, value) {
        _gpfAssert(array instanceof Array, "gpf.set must be used with an Array");
        var idx = array.length;
        while (idx > 0) {
            if (array[--idx] === value) {
                return array; // Already set
            }
        }
        array.push(value);
        return array;
    },

    /*
     * Removes the member of 'dictionary' which value equals 'value'.
     * NOTE: that the object is modified.
     *
     * @param {Object/array} dictionary
     * @param {*} value
     * @return {Object/array} dictionary
     * @chainable
     */
    clear: function (dictionary, value) {
        var idx;
        if (dictionary instanceof Array) {
            idx = dictionary.length;
            while (idx > 0) {
                if (dictionary[--idx] === value) {
                    dictionary.splice(idx, 1);
                    break;
                }
            }
        } else {
            for (idx in dictionary) {
                if (dictionary.hasOwnProperty(idx) && dictionary[idx] === value) {
                    delete dictionary[idx];
                }
            }
        }
        return dictionary;
    },

    /**
     * XOR
     *
     * @param {Boolean} a
     * @param {Boolean} b
     */
    xor: function (a, b) {
        return a && !b || !a && b;
    }

});

/* istanbul ignore next */ // Not testable
/**
 * Exit function
 *
 * @paran {Number} [exitCode=0] exitCode
 */
gpf.exit = function (exitCode) {
    if (undefined === exitCode) {
        exitCode = 0;
    }
    _gpfExit(exitCode);
};

//region NodeJS helpers

/**
 * Converts a NodeJS buffer into a native array containing unsigned
 * bytes
 *
 * @param {Buffer} buffer
 * @return {Number[]}
 */
function _gpfNodeBuffer2JsArray (buffer) {
    var result = [],
        len = buffer.length,
        idx;
    for (idx = 0; idx < len; ++idx) {
        result.push(buffer.readUInt8(idx));
    }
    return result;
}

//endregion

/*#ifndef(UMD)*/

gpf.internals._gpfObjectForEach = _gpfObjectForEach;
gpf.internals._gpfStringEscapeFor = _gpfStringEscapeFor;
gpf.internals._gpfNodeBuffer2JsArray = _gpfNodeBuffer2JsArray;

/*#endif*/
<|endoftext|>


<commit_before>

module.exports =function() {
    function PriorityQueue (arr) {
        this.heap = [];
        if (arr) {
            for (i=0; i< arr.length; i++) {
                this.pushNode(arr[i]);
            }
        }
    }

    PriorityQueue.prototype = {
        push: function (data, priority) {
            var targetIndex = this._getPriorityIndex(priority);

            if(this._comparePriorityAtIndex(targetIndex, priority)) {
                this.heap[targetIndex].push(data);
            } else {
                this.heap.splice(targetIndex, 0, (new PriorityNode(data, priority)));
            }
        },

        pushNode: function (node) {
            var targetIndex = this._getPriorityIndex(priority);

            if(this._comparePriorityAtIndex(targetIndex, priority)) {
                node.data.forEach(function (value) {
                    this.heap[targetIndex].push(value);
                });
            } else {
                this.heap.splice(targetIndex, 0, node);
            }
        },

        pop: function () {
            var result;
            var node = this.heap[0];
            if(node) {
                result = node.pop();
                if(!node.length) {
                    this.heap.splice(0, 1);
                }
            }
            return result;
        },

        _getPriorityIndex: function (priority) {
            var targetIndex = this.heap.length;

            this.heap.some(function (value, index) {
                if(value.priority >= priority) {
                    targetIndex = index;
                    return true;
                }
            });

            return targetIndex;
        },

        _comparePriorityAtIndex: function (index, priority) {
            return this.heap[targetIndex] && this.heap[targetIndex].priority === priority;
        },

        toString: function () {
            return "[object PriorityQueue]";
        },

        get length() {
            var length = 0;
            this.heap.forEach(function (node) {
                length += node.length;
            });
            return length;
        }
    };

    return PriorityQueue;
}();
<commit_msg>Fix bugs in Priority Queue and add multiPop functionality<commit_after>

module.exports =function() {
    function PriorityQueue (arr) {
        this.heap = [];
        if (arr) {
            for (i=0; i< arr.length; i++) {
                this.pushNode(arr[i]);
            }
        }
    }

    PriorityQueue.prototype = {
        push: function (data, priority) {
            var targetIndex = this._getPriorityIndex(priority);

            if(this._comparePriorityAtIndex(targetIndex, priority)) {
                this.heap[targetIndex].push(data);
            } else {
                this.heap.splice(targetIndex, 0, (new PriorityNode(data, priority)));
            }
        },

        pushNode: function (node) {
            var targetIndex = this._getPriorityIndex(node.priority);

            if(this._comparePriorityAtIndex(targetIndex, node.priority)) {
                node.data.forEach(function (value) {
                    this.heap[targetIndex].push(value);
                });
            } else {
                this.heap.splice(targetIndex, 0, node);
            }
        },

        pop: function () {
            var result;
            var node = this.heap[0];
            if(node) {
                result = node.pop();
                if(!node.length) {
                    this.heap.splice(0, 1);
                }
            }
            return result;
        },

        multiPop: function (count) {
            var result = [];
            while(count && this.length) {
                result.push(this.pop());
                count--;
            }
            return result;
        },

        _getPriorityIndex: function (priority) {
            var targetIndex = this.heap.length;

            this.heap.some(function (value, index) {
                if(value.priority >= priority) {
                    targetIndex = index;
                    return true;
                }
            });

            return targetIndex;
        },

        _comparePriorityAtIndex: function (index, priority) {
            return this.heap[index] && this.heap[index].priority === priority;
        },

        toString: function () {
            return "[object PriorityQueue]";
        },

        get length() {
            var length = 0;
            this.heap.forEach(function (node) {
                length += node.length;
            });
            return length;
        }
    };

    return PriorityQueue;
}();
<|endoftext|>


<commit_before>(function(define) {

  function Library() {
    var factories = [],
        exports = {};

    function _export(name, definition) {
      exports[name] = definition;
    };

    this.extend = function extend(factory) {
      factories = factories.concat(Array.prototype.slice.call(arguments));
    };

    this.consume = function consume() {
      var factory;
      while(factory = factories.splice(0,1)[0]) {
        factory(_export)
      }
      return exports;
    }
  }

  var libraries = {};

  function provide(requirements) {
    return {
      from: function(librayName) {
        var exports = libraries[librayName].consume();
        for(var result = [], i=0, l=requirements.length; i<l; i++) {
          var requirementName = requirements[i],
              requirement = exports[requirementName];
          if(exports.hasOwnProperty(requirementName)) {
            result.push(requirement)
          } else {
            throw "Requirement '" + requirementName + "' from '" + librayName + "' was not found";
          }
        }
        return result.length == 1 ? result[0] : result
      }
    }
  }

  function _import(requirements) {
    requirements = Array.prototype.slice.call(arguments);
    return provide(requirements);
  }

  _import.module = function _module(librayName, factory) {
    libraries[librayName] = libraries[librayName] || new Library();
    libraries[librayName].extend(factory)
  }

  define('_import', _import);

}(//amd (requirejs)
  (typeof define === 'function' && define.amd) ? define :
  //common (node)
  (typeof exports != 'undefined' || typeof module != 'undefined') ? function(n, d, f) { exports = module.exports = f || d || n } :
  //no-modules (window)
  (function(n, d, f) {this[n] = f || d})
));
<commit_msg>add error handling<commit_after>(function(define) {

  function Library() {
    var factories = [],
        exports = {};

    function _export(name, definition) {
      exports[name] = definition;
    };

    this.extend = function extend(factory) {
      factories = factories.concat(Array.prototype.slice.call(arguments));
    };

    this.consume = function consume() {
      var factory;
      while(factory = factories.splice(0,1)[0]) {
        factory(_export)
      }
      return exports;
    }
  }

  var libraries = {};

  function provide(requirements) {
    return {
      from: function(librayName) {
        var library = libraries[librayName];
        if(!library) throw new Error("'" + librayName + "' has not been defined");
        var exports = library.consume();
        for(var result = [], i=0, l=requirements.length; i<l; i++) {
          var requirementName = requirements[i],
              requirement = exports[requirementName];
          if(exports.hasOwnProperty(requirementName)) {
            result.push(requirement)
          } else {
            throw new Error("Requirement '" + requirementName + "' from '" + librayName + "' was not found");
          }
        }
        return result.length == 1 ? result[0] : result
      }
    }
  }

  function _import(requirements) {
    requirements = Array.prototype.slice.call(arguments);
    return provide(requirements);
  }

  _import.module = function _module(librayName, factory) {
    libraries[librayName] = libraries[librayName] || new Library();
    libraries[librayName].extend(factory)
  }

  define('_import', _import);

}(//amd (requirejs)
  (typeof define === 'function' && define.amd) ? define :
  //common (node)
  (typeof exports != 'undefined' || typeof module != 'undefined') ? function(n, d, f) { exports = module.exports = f || d || n } :
  //no-modules (window)
  (function(n, d, f) {this[n] = f || d})
));
<|endoftext|>


<commit_before>import getUpstreamChanges from '../helpers/getUpstreamChanges';
import notifyPatternObservers from './applyChanges/notifyPatternObservers';

export default function Viewmodel$applyChanges () {
	var self = this,
		changes,
		upstreamChanges,
		hash = {},
		bindings;

	changes = this.changes;

	if ( !changes.length ) {
		// TODO we end up here on initial render. Perhaps we shouldn't?
		return;
	}

	function cascade ( keypath ) {
		var map, computations;

		if ( self.noCascade.hasOwnProperty( keypath.str ) ) {
			return;
		}

		if ( computations = self.deps.computed[ keypath.str ] ) {
			computations.forEach( c => {
				var key = c.key;

				if ( c.viewmodel === self ) {
					self.clearCache( key.str );
					c.invalidate();

					changes.push( key );
					cascade( key );
				} else {
					c.viewmodel.mark( key );
				}
			});
		}

		if ( map = self.depsMap.computed[ keypath.str ] ) {
			map.forEach( cascade );
		}
	}

	changes.slice().forEach( cascade );

	upstreamChanges = getUpstreamChanges( changes );
	upstreamChanges.forEach( keypath => {
		var computations;

		// make sure we haven't already been down this particular keypath in this turn
		if ( changes.indexOf( keypath ) === -1 && ( computations = self.deps.computed[ keypath.str ] ) ) {
			this.changes.push( keypath );

			computations.forEach( c => {
				c.viewmodel.mark( c.key );
			});
		}
	});

	this.changes = [];

	// Pattern observers are a weird special case
	if ( this.patternObservers.length ) {
		upstreamChanges.forEach( keypath => notifyPatternObservers( this, keypath, true ) );
		changes.forEach( keypath => notifyPatternObservers( this, keypath ) );
	}

	if ( this.deps.observers ) {
		upstreamChanges.forEach( keypath => notifyUpstreamDependants( this, null, keypath, 'observers' ) );
		notifyAllDependants( this, changes, 'observers' );
	}

	if ( this.deps['default'] ) {
		bindings = [];
		upstreamChanges.forEach( keypath => notifyUpstreamDependants( this, bindings, keypath, 'default' ) );

		if( bindings.length ) {
			notifyBindings( this, bindings, changes );
		}

		notifyAllDependants( this, changes, 'default' );
	}

	// Return a hash of keypaths to updated values
	changes.forEach( keypath => {
		hash[ keypath.str ] = this.get( keypath );
	});

	this.implicitChanges = {};
	this.noCascade = {};

	return hash;
}

function notifyUpstreamDependants ( viewmodel, bindings, keypath, groupName ) {
	var dependants, value;

	if ( dependants = findDependants( viewmodel, keypath, groupName ) ) {
		value = viewmodel.get( keypath );

		dependants.forEach( d => {
			// don't "set" the parent value, refine it
			// i.e. not data = value, but data[foo] = fooValue
			if( bindings && d.refineValue ) {
				bindings.push( d );
			}
			else {
				d.setValue( value );
			}
		});
	}
}

function notifyBindings ( viewmodel, bindings, changes ) {

	bindings.forEach( binding => {
		let useSet = false, i = 0, length = changes.length, refinements = [];

		while( i < length ) {
			let keypath = changes[i];

			if ( keypath === binding.keypath ) {
				useSet = true;
				break;
			}

			if ( keypath.slice(0, binding.keypath.length) === binding.keypath ) {
				refinements.push( keypath );
			}

			i++;
		}

		if ( useSet ) {
			binding.setValue( viewmodel.get( binding.keypath ) );
		}

		if( refinements.length ) {
			binding.refineValue( refinements );
		}
	});
}

function notifyAllDependants ( viewmodel, keypaths, groupName ) {
	var queue = [];

	addKeypaths( keypaths );
	queue.forEach( dispatch );

	function addKeypaths ( keypaths ) {
		keypaths.forEach( addKeypath );
		keypaths.forEach( cascade );
	}

	function addKeypath ( keypath ) {
		var deps = findDependants( viewmodel, keypath, groupName );

		if ( deps ) {
			queue.push({
				keypath: keypath,
				deps: deps
			});
		}
	}

	function cascade ( keypath ) {
		var childDeps;

		if ( childDeps = viewmodel.depsMap[ groupName ][ keypath.str ] ) {
			addKeypaths( childDeps );
		}
	}

	function dispatch ( set ) {
		var value = viewmodel.get( set.keypath );
		set.deps.forEach( d => d.setValue( value ) );
	}
}

function findDependants ( viewmodel, keypath, groupName ) {
	var group = viewmodel.deps[ groupName ];
	return group ? group[ keypath.str ] : null;
}
<commit_msg>fixes #1747<commit_after>import getUpstreamChanges from '../helpers/getUpstreamChanges';
import notifyPatternObservers from './applyChanges/notifyPatternObservers';

export default function Viewmodel$applyChanges () {
	var self = this,
		changes,
		upstreamChanges,
		hash = {},
		bindings;

	changes = this.changes;

	if ( !changes.length ) {
		// TODO we end up here on initial render. Perhaps we shouldn't?
		return;
	}

	function invalidateComputation ( computation ) {
		var key = computation.key;

		if ( computation.viewmodel === self ) {
			self.clearCache( key.str );
			computation.invalidate();

			changes.push( key );
			cascade( key );
		} else {
			computation.viewmodel.mark( key );
		}
	}

	function cascade ( keypath ) {
		var map, computations;

		if ( self.noCascade.hasOwnProperty( keypath.str ) ) {
			return;
		}

		if ( computations = self.deps.computed[ keypath.str ] ) {
			computations.forEach( invalidateComputation );
		}

		if ( map = self.depsMap.computed[ keypath.str ] ) {
			map.forEach( cascade );
		}
	}

	changes.slice().forEach( cascade );

	upstreamChanges = getUpstreamChanges( changes );
	upstreamChanges.forEach( keypath => {
		var computations;

		// make sure we haven't already been down this particular keypath in this turn
		if ( changes.indexOf( keypath ) === -1 && ( computations = self.deps.computed[ keypath.str ] ) ) {
			computations.forEach( invalidateComputation );
		}
	});

	this.changes = [];

	// Pattern observers are a weird special case
	if ( this.patternObservers.length ) {
		upstreamChanges.forEach( keypath => notifyPatternObservers( this, keypath, true ) );
		changes.forEach( keypath => notifyPatternObservers( this, keypath ) );
	}

	if ( this.deps.observers ) {
		upstreamChanges.forEach( keypath => notifyUpstreamDependants( this, null, keypath, 'observers' ) );
		notifyAllDependants( this, changes, 'observers' );
	}

	if ( this.deps['default'] ) {
		bindings = [];
		upstreamChanges.forEach( keypath => notifyUpstreamDependants( this, bindings, keypath, 'default' ) );

		if( bindings.length ) {
			notifyBindings( this, bindings, changes );
		}

		notifyAllDependants( this, changes, 'default' );
	}

	// Return a hash of keypaths to updated values
	changes.forEach( keypath => {
		hash[ keypath.str ] = this.get( keypath );
	});

	this.implicitChanges = {};
	this.noCascade = {};

	return hash;
}

function notifyUpstreamDependants ( viewmodel, bindings, keypath, groupName ) {
	var dependants, value;

	if ( dependants = findDependants( viewmodel, keypath, groupName ) ) {
		value = viewmodel.get( keypath );

		dependants.forEach( d => {
			// don't "set" the parent value, refine it
			// i.e. not data = value, but data[foo] = fooValue
			if( bindings && d.refineValue ) {
				bindings.push( d );
			}
			else {
				d.setValue( value );
			}
		});
	}
}

function notifyBindings ( viewmodel, bindings, changes ) {

	bindings.forEach( binding => {
		let useSet = false, i = 0, length = changes.length, refinements = [];

		while( i < length ) {
			let keypath = changes[i];

			if ( keypath === binding.keypath ) {
				useSet = true;
				break;
			}

			if ( keypath.slice(0, binding.keypath.length) === binding.keypath ) {
				refinements.push( keypath );
			}

			i++;
		}

		if ( useSet ) {
			binding.setValue( viewmodel.get( binding.keypath ) );
		}

		if( refinements.length ) {
			binding.refineValue( refinements );
		}
	});
}

function notifyAllDependants ( viewmodel, keypaths, groupName ) {
	var queue = [];

	addKeypaths( keypaths );
	queue.forEach( dispatch );

	function addKeypaths ( keypaths ) {
		keypaths.forEach( addKeypath );
		keypaths.forEach( cascade );
	}

	function addKeypath ( keypath ) {
		var deps = findDependants( viewmodel, keypath, groupName );

		if ( deps ) {
			queue.push({
				keypath: keypath,
				deps: deps
			});
		}
	}

	function cascade ( keypath ) {
		var childDeps;

		if ( childDeps = viewmodel.depsMap[ groupName ][ keypath.str ] ) {
			addKeypaths( childDeps );
		}
	}

	function dispatch ( set ) {
		var value = viewmodel.get( set.keypath );
		set.deps.forEach( d => d.setValue( value ) );
	}
}

function findDependants ( viewmodel, keypath, groupName ) {
	var group = viewmodel.deps[ groupName ];
	return group ? group[ keypath.str ] : null;
}
<|endoftext|>


<commit_before>import getUpstreamChanges from 'viewmodel/helpers/getUpstreamChanges';
import notifyPatternObservers from 'viewmodel/prototype/applyChanges/notifyPatternObservers';

var dependantGroups = [ 'observers', 'default' ];

export default function Viewmodel$applyChanges () {
	var self = this,
		changes,
		upstreamChanges,
		upstreamHash,
		hash = {};

	changes = this.changes;

	if ( !changes.length ) {
		// TODO we end up here on initial render. Perhaps we shouldn't?
		return;
	}

	function cascade ( keypath ) {
		var map, dependants, keys;

		if ( self.noCascade.hasOwnProperty( keypath ) ) {
			return;
		}

		if ( dependants = self.deps.computed[ keypath ] ) {
			dependants.forEach( invalidate );

			keys = dependants.map( getKey );

			keys.forEach( mark );
			keys.forEach( cascade );
		}

		if ( map = self.depsMap.computed[ keypath ] ) {
			map.forEach( cascade );
		}
	}

	function mark ( keypath ) {
		self.mark( keypath );
	}

	changes.forEach( cascade );

	upstreamChanges = getUpstreamChanges( changes );
	upstreamChanges.forEach( keypath => {
		var dependants, keys;

		if ( dependants = self.deps.computed[ keypath ] ) {
			dependants.forEach( invalidate );

			keys = dependants.map( getKey );
			keys.forEach( mark );
		}
	});

	this.changes = [];

	// Pattern observers are a weird special case
	if ( this.patternObservers.length ) {
		upstreamChanges.forEach( keypath => notifyPatternObservers( this, keypath, true ) );
		changes.forEach( keypath => notifyPatternObservers( this, keypath ) );
	}

	upstreamHash = getUpstreamChangeHash( changes );

	dependantGroups.forEach( group => {
		if ( !this.deps[ group ] ) {
			return;
		}

		for( var changeKeypath in upstreamHash) {
			upstreamHash[ changeKeypath ].forEach( keypath => {
				notifyUpstreamDependants( this, keypath, changeKeypath, group );
			});
		}

		notifyAllDependants( this, changes, group );
	});

	// Return a hash of keypaths to updated values
	changes.forEach( keypath => {
		hash[ keypath ] = this.get( keypath );
	});

	this.implicitChanges = {};
	this.noCascade = {};

	return hash;
}

function getUpstreamChangeHash ( changes ) {

	var sortedKeys, current, next, keep = [], index = 0, upstreamHash = {};

	sortedKeys = changes.slice().sort();

	// keep "top-most" keypath changes,
	// i.e. data, data.foo, data.bar => data
	keep.push( current = sortedKeys[0] );
	while( next = sortedKeys[++index] ){
		if( next.slice(0, current.length) ){
			keep.push( current = next);
		}
	}

	// map upstream changes
	keep.forEach( change => {
		let upstream = getUpstreamChanges( [ change ] );
		if ( upstream.length ) {
			upstreamHash[ change ] = upstream;
		}
	});

	return upstreamHash;
}

function invalidate ( computation ) {
	computation.invalidate();
}

function getKey ( computation ) {
	return computation.key;
}

function notifyUpstreamDependants ( viewmodel, keypath, originalKeypath, groupName ) {
	var dependants, value;

	if ( dependants = findDependants( viewmodel, keypath, groupName ) ) {
		value = viewmodel.get( keypath );

		dependants.forEach( d => {
			// don't "set" the parent value, refine it
			// i.e. not data = value, but data[foo] = fooValue
			if( d.refineValue && keypath !== originalKeypath ) {
				d.refineValue( keypath, originalKeypath );
			}
			else {
				d.setValue( value );
			}
		});
	}
}

function notifyAllDependants ( viewmodel, keypaths, groupName ) {
	var queue = [];

	addKeypaths( keypaths );
	queue.forEach( dispatch );

	function addKeypaths ( keypaths ) {
		keypaths.forEach( addKeypath );
		keypaths.forEach( cascade );
	}

	function addKeypath ( keypath ) {
		var deps = findDependants( viewmodel, keypath, groupName );

		if ( deps ) {
			queue.push({
				keypath: keypath,
				deps: deps
			});
		}
	}

	function cascade ( keypath ) {
		var childDeps;

		if ( childDeps = viewmodel.depsMap[ groupName ][ keypath ] ) {
			addKeypaths( childDeps );
		}
	}

	function dispatch ( set ) {
		var value = viewmodel.get( set.keypath );
		set.deps.forEach( d => d.setValue( value ) );
	}
}

function findDependants ( viewmodel, keypath, groupName ) {
	var group = viewmodel.deps[ groupName ];
	return group ? group[ keypath ] : null;
}
<commit_msg>forgot not equal check in get upstream hash<commit_after>import getUpstreamChanges from 'viewmodel/helpers/getUpstreamChanges';
import notifyPatternObservers from 'viewmodel/prototype/applyChanges/notifyPatternObservers';

var dependantGroups = [ 'observers', 'default' ];

export default function Viewmodel$applyChanges () {
	var self = this,
		changes,
		upstreamChanges,
		upstreamHash,
		hash = {};

	changes = this.changes;

	if ( !changes.length ) {
		// TODO we end up here on initial render. Perhaps we shouldn't?
		return;
	}

	function cascade ( keypath ) {
		var map, dependants, keys;

		if ( self.noCascade.hasOwnProperty( keypath ) ) {
			return;
		}

		if ( dependants = self.deps.computed[ keypath ] ) {
			dependants.forEach( invalidate );

			keys = dependants.map( getKey );

			keys.forEach( mark );
			keys.forEach( cascade );
		}

		if ( map = self.depsMap.computed[ keypath ] ) {
			map.forEach( cascade );
		}
	}

	function mark ( keypath ) {
		self.mark( keypath );
	}

	changes.forEach( cascade );

	upstreamChanges = getUpstreamChanges( changes );
	upstreamChanges.forEach( keypath => {
		var dependants, keys;

		if ( dependants = self.deps.computed[ keypath ] ) {
			dependants.forEach( invalidate );

			keys = dependants.map( getKey );
			keys.forEach( mark );
		}
	});

	this.changes = [];

	// Pattern observers are a weird special case
	if ( this.patternObservers.length ) {
		upstreamChanges.forEach( keypath => notifyPatternObservers( this, keypath, true ) );
		changes.forEach( keypath => notifyPatternObservers( this, keypath ) );
	}

	upstreamHash = getUpstreamChangeHash( changes );

	dependantGroups.forEach( group => {
		if ( !this.deps[ group ] ) {
			return;
		}

		for( var changeKeypath in upstreamHash) {
			upstreamHash[ changeKeypath ].forEach( keypath => {
				notifyUpstreamDependants( this, keypath, changeKeypath, group );
			});
		}

		notifyAllDependants( this, changes, group );
	});

	// Return a hash of keypaths to updated values
	changes.forEach( keypath => {
		hash[ keypath ] = this.get( keypath );
	});

	this.implicitChanges = {};
	this.noCascade = {};

	return hash;
}

function getUpstreamChangeHash ( changes ) {

	var sortedKeys, current, next, keep = [], index = 0, upstreamHash = {};

	sortedKeys = changes.slice().sort();

	// keep "top-most" keypath changes,
	// i.e. data, data.foo, data.bar => data
	keep.push( current = sortedKeys[0] );
	while( next = sortedKeys[++index] ){
		if( next.slice(0, current.length) !== current ){
			keep.push( current = next);
		}
	}

	// map upstream changes
	keep.forEach( change => {
		let upstream = getUpstreamChanges( [ change ] );
		if ( upstream.length ) {
			upstreamHash[ change ] = upstream;
		}
	});

	return upstreamHash;
}

function invalidate ( computation ) {
	computation.invalidate();
}

function getKey ( computation ) {
	return computation.key;
}

function notifyUpstreamDependants ( viewmodel, keypath, originalKeypath, groupName ) {
	var dependants, value;

	if ( dependants = findDependants( viewmodel, keypath, groupName ) ) {
		value = viewmodel.get( keypath );

		dependants.forEach( d => {
			// don't "set" the parent value, refine it
			// i.e. not data = value, but data[foo] = fooValue
			if( d.refineValue && keypath !== originalKeypath ) {
				d.refineValue( keypath, originalKeypath );
			}
			else {
				d.setValue( value );
			}
		});
	}
}

function notifyAllDependants ( viewmodel, keypaths, groupName ) {
	var queue = [];

	addKeypaths( keypaths );
	queue.forEach( dispatch );

	function addKeypaths ( keypaths ) {
		keypaths.forEach( addKeypath );
		keypaths.forEach( cascade );
	}

	function addKeypath ( keypath ) {
		var deps = findDependants( viewmodel, keypath, groupName );

		if ( deps ) {
			queue.push({
				keypath: keypath,
				deps: deps
			});
		}
	}

	function cascade ( keypath ) {
		var childDeps;

		if ( childDeps = viewmodel.depsMap[ groupName ][ keypath ] ) {
			addKeypaths( childDeps );
		}
	}

	function dispatch ( set ) {
		var value = viewmodel.get( set.keypath );
		set.deps.forEach( d => d.setValue( value ) );
	}
}

function findDependants ( viewmodel, keypath, groupName ) {
	var group = viewmodel.deps[ groupName ];
	return group ? group[ keypath ] : null;
}
<|endoftext|>