<commit_before>/**
 * Path 代理，可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中
 * 可以用于 isInsidePath 判断以及获取boundingRect
 *
 * @module zrender/core/PathProxy
 * @author pissang (http://www.github.com/pissang)
 *
 * TODO lineDash
 */
define(function (require) {

    var curve = require('./curve');
    var vec2 = require('./vector');

    var CMD = {
        M: 1,
        L: 2,
        C: 3,
        Q: 4,
        A: 5,
        Z: 6
    };

    var min = [];
    var max = [];
    var v = [];
    var mathMin = Math.min;
    var mathMax = Math.max;
    var mathSqrt = Math.sqrt;

    /**
     * @alias module:zrender/core/PathProxy
     * @constructor
     */
    var PathProxy = function () {

        /**
         * Path data. Stored as flat array
         * @type {Array.<Object>}
         */
        this.data = [];

        this._len = 0;

        this._ctx = null;

        this._xi = 0;
        this._yi = 0;

        this._x0 = 0;
        this._y0 = 0;
    };

    /**
     * 快速计算Path包围盒（并不是最小包围盒）
     * @return {Object}
     */
    PathProxy.prototype = {

        constructor: PathProxy,

        _lineDash: null,

        _dashOffset: 0,

        _dashIdx: 0,

        _dashSum: 0,

        /**
         * @param  {CanvasRenderingContext2D} ctx
         * @return {module:zrender/core/PathProxy}
         */
        beginPath: function (ctx) {
            this._ctx = ctx;

            ctx && ctx.beginPath();

            // Reset
            this._len = 0;

            if (this._lineDash) {
                this._lineDash = null;

                this._dashOffset = 0;
            }

            return this;
        },

        /**
         * @param  {number} x
         * @param  {number} y
         * @return {module:zrender/core/PathProxy}
         */
        moveTo: function (x, y) {
            this._pushData(CMD.M, x, y);
            this._ctx && this._ctx.moveTo(x, y);

            // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用
            // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。
            // 有可能在 beginPath 之后直接调用 lineTo，这时候 x0, y0 需要
            // 在 lineTo 方法中记录，这里先不考虑这种情况，dashed line 也只在 IE10- 中不支持
            this._x0 = x;
            this._y0 = y;

            this._xi = x;
            this._yi = y;

            return this;
        },

        /**
         * @param  {number} x
         * @param  {number} y
         * @return {module:zrender/core/PathProxy}
         */
        lineTo: function (x, y) {
            this._pushData(CMD.L, x, y);
            if (this._ctx) {
                this._needsDash() ? this._dashedLineTo(x, y)
                    : this._ctx.lineTo(x, y);
            }
            this._xi = x;
            this._yi = y;
            return this;
        },

        /**
         * @param  {number} x1
         * @param  {number} y1
         * @param  {number} x2
         * @param  {number} y2
         * @param  {number} x3
         * @param  {number} y3
         * @return {module:zrender/core/PathProxy}
         */
        bezierCurveTo: function (x1, y1, x2, y2, x3, y3) {
            this._pushData(CMD.C, x1, y1, x2, y2, x3, y3);
            if (this._ctx) {
                this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)
                    : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
            }
            this._xi = x3;
            this._yi = y3;
            return this;
        },

        /**
         * @param  {number} x1
         * @param  {number} y1
         * @param  {number} x2
         * @param  {number} y2
         * @return {module:zrender/core/PathProxy}
         */
        quadraticCurveTo: function (x1, y1, x2, y2) {
            this._pushData(CMD.Q, x1, y1, x2, y2);
            if (this._ctx) {
                this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2)
                    : this._ctx.quadraticCurveTo(x1, y1, x2, y2);
            }
            this._xi = x2;
            this._yi = y2;
            return this;
        },

        /**
         * @param  {number} cx
         * @param  {number} cy
         * @param  {number} r
         * @param  {number} startAngle
         * @param  {number} endAngle
         * @param  {boolean} anticlockwise
         * @return {module:zrender/core/PathProxy}
         */
        arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) {
            this._pushData(
                CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 0, anticlockwise ? 0 : 1
            );
            this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);

            this._xi = Math.cos(endAngle) * rx + cx;
            this._xi = Math.sin(endAngle) * rx + cx;
            return this;
        },

        // TODO
        arcTo: function (x1, y1, x2, y2, radius) {
            if (this._ctx) {
                this._ctx.arcTo(x1, y1, x2, y2, radius);
            }
            return this;
        },

        // TODO
        rect: function (x, y, w, h) {
            this._ctx && this._ctx.rect(x, y, w, h);
            return this;
        },

        /**
         * @return {module:zrender/core/PathProxy}
         */
        closePath: function () {
            this._pushData(CMD.Z);
            this._ctx && this._ctx.closePath();

            this._xi = this._x0;
            this._yi = this._y0;
            return this;
        },

        /**
         * @return {module:zrender/core/PathProxy}
         */
        fill: function () {
            this._ctx && this._ctx.fill();
            this.toStatic();
        },

        /**
         * @return {module:zrender/core/PathProxy}
         */
        stroke: function () {
            var ctx = this._ctx;
            if (ctx) {
                if (this._lineDash) {
                    ctx.setLineDash && ctx.setLineDash(this._lineDash);
                    ctx.lineDashOffset = this._dashOffset;
                }
                ctx.stroke();
            }

            this.toStatic();
        },

        /**
         * 必须在其它绘制命令前调用
         * Must be invoked before all other path drawing methods
         * @return {module:zrender/core/PathProxy}
         */
        setLineDash: function (lineDash) {
            if (lineDash instanceof Array) {
                this._lineDash = lineDash;

                this._dashIdx = 0;

                var lineDashSum = 0;
                for (var i = 0; i < lineDash.length; i++) {
                    lineDashSum += lineDash[i];
                }
                this._dashSum = lineDashSum;
            }
            return this;
        },

        /**
         * 必须在其它绘制命令前调用
         * Must be invoked before all other path drawing methods
         * @return {module:zrender/core/PathProxy}
         */
        setLineDashOffset: function (offset) {
            this._dashOffset = offset;
            return this;
        },

        /**
         *
         * @return {boolean}
         */
        len: function () {
            return this._len;
        },

        /**
         * 填充 Path 数据。
         * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。
         */
        _pushData: function (cmd) {
            var data = this.data;
            if (this._len + arguments.length > data.length) {
                // 因为之前的数组已经转换成静态的 Float32Array
                // 所以不够用时需要扩展一个新的动态数组
                this._expandData();
                data = this.data;
            }
            for (var i = 0; i < arguments.length; i++) {
                data[this._len++] = arguments[i];
            }

            this._prevCmd = cmd;
        },

        _expandData: function () {
            // Only if data is Float32Array
            if (! (this.data instanceof Array)) {
                var newData = [];
                for (var i = 0; i < this._len; i++) {
                    newData[i] = this.data[i];
                }
                this.data = newData;
            }
        },

        /**
         * If needs js implemented dashed line
         * @return {boolean}
         * @private
         */
        _needsDash: function () {
            return this._lineDash && !this._ctx.setLineDash;
            // return this._lineDash;
        },

        _dashedLineTo: function (x1, y1) {
            var offset = this._dashOffset % this._dashSum;
            var lineDash = this._lineDash;
            var ctx = this._ctx;

            var xi = this._xi;
            var yi = this._yi;
            var dx = x1 - xi;
            var dy = y1 - yi;
            var dist = mathSqrt(dx * dx + dy * dy);
            var x = xi;
            var y = yi;
            var dash;
            var len = lineDash.length;
            var idx;
            dx /= dist;
            dy /= dist;
            x -= offset * dx;
            y -= offset * dy;

            while ((dx >= 0 && x <= x1) || (dx < 0 && x > x1)) {
                idx = this._dashIdx;
                dash = lineDash[idx];
                x += dx * dash;
                y += dy * dash;
                this._dashIdx = (idx + 1) % len;
                // Skip positive offset
                if ((dx > 0 && x < xi) || (dx < 0 && x > xi)) {
                    continue;
                }
                ctx[idx % 2 ? 'moveTo' : 'lineTo'](
                    dx >= 0 ? mathMin(x, x1) : mathMax(x, x1),
                    dy >= 0 ? mathMin(y, y1) : mathMax(y, y1)
                );
            }
            // Offset for next lineTo
            dx = x - x1;
            dy = y - y1;
            this._dashOffset = -mathSqrt(dx * dx + dy * dy);
        },

        _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) {
        },

        _dashedQuadraticTo: function (x1, y1, x2, y2) {
        },

        /**
         * 转成静态的 Float32Array 减少堆内存占用
         * Convert dynamic array to static Float32Array
         * @return {[type]} [description]
         */
        toStatic: function () {
            if (typeof Float32Array != 'undefined'
                && (this.data instanceof Array)
            ) {
                this.data.length = this._len;
                this.data = new Float32Array(this.data);
            };
        },

        fastBoundingRect: function () {
            var data = this.data;
            min[0] = min[1] = Infinity;
            max[0] = max[1] = -Infinity;
            for (var i = 0; i < this._len;) {
                var cmd = data[i++];
                var nPoint = 0;
                switch (cmd) {
                    case CMD.M:
                        nPoint = 1;
                        break;
                    case CMD.L:
                        nPoint = 1;
                        break;
                    case CMD.C:
                        nPoint = 3;
                        break;
                    case CMD.Q:
                        nPoint = 2;
                        break;
                    case CMD.A:
                        var cx = data[i];
                        var cy = data[i + 1];
                        var rx = data[i + 2];
                        var ry = data[i + 3];
                        min[0] = mathMin(min[0], min[0], cx - rx);
                        min[1] = mathMin(min[1], min[1], cy - ry);
                        max[0] = mathMax(max[0], max[0], cx + rx);
                        max[1] = mathMax(max[1], max[1], cy + ry);
                        i += 8;
                        break;
                }
                for (var j = 0; j < nPoint; j++) {
                    min[0] = mathMin(min[0], min[0], data[i]);
                    max[0] = mathMax(max[0], max[0], data[i++]);
                    min[1] = mathMin(min[1], min[1], data[i]);
                    max[1] = mathMax(max[1], max[1], data[i++]);
                }
            }

            return {
                x: min[0],
                y: min[1],
                width: max[0] - min[0],
                height: max[1] - min[1]
            };
        },

        /**
         * Rebuild path from current data
         * Rebuild path will not consider javascript implemented line dash.
         * @param {CanvasRenderingContext} ctx
         */
        rebuildPath: function (ctx) {
            var d = this.data;
            for (var i = 0; i < this._len;) {
                var cmd = d[i++];
                switch (cmd) {
                    case CMD.M:
                        ctx.moveTo(d[i++], d[i++]);
                        break;
                    case CMD.L:
                        ctx.lineTo(d[i++], d[i++]);
                        break;
                    case CMD.C:
                        ctx.bezierCurveTo(
                            d[i++], d[i++], d[i++], d[i++], d[i++], d[i++]
                        );
                        break;
                    case CMD.Q:
                        ctx.bezierCurveTo(d[i++], d[i++], d[i++], d[i++]);
                        break;
                    case CMD.A:
                        var cx = d[i++];
                        var cy = d[i++];
                        var rx = d[i++];
                        var ry = d[i++];
                        var theta = d[i++];
                        var dTheta = d[i++];
                        var psi = d[i++];
                        var fs = d[i++];
                        var r = (rx > ry) ? rx : ry;
                        var scaleX = (rx > ry) ? 1 : rx / ry;
                        var scaleY = (rx > ry) ? ry / rx : 1;
                        var isEllipse = Math.abs(rx - ry) < 1e-3;
                        if (isEllipse) {
                            ctx.translate(cx, cy);
                            ctx.rotate(psi);
                            ctx.scale(scaleX, scaleY);
                            ctx.arc(0, 0, r, theta, theta + dTheta, 1 - fs);
                            ctx.scale(1 / scaleX, 1 / scaleY);
                            ctx.rotate(-psi);
                            ctx.translate(-cx, -cy);
                        }
                        else {
                            ctx.arc(cx, cy, r, theta, theta + dTheta, 1 - fs);
                        }
                        break;
                    case CMD.Z:
                        ctx.closePath();
                }
            }
        }
    };

    PathProxy.CMD = CMD;

    return PathProxy;
});<commit_msg>Negative dash offset bugfix<commit_after>/**
 * Path 代理，可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中
 * 可以用于 isInsidePath 判断以及获取boundingRect
 *
 * @module zrender/core/PathProxy
 * @author pissang (http://www.github.com/pissang)
 *
 * TODO lineDash
 */
define(function (require) {

    var curve = require('./curve');
    var vec2 = require('./vector');

    var CMD = {
        M: 1,
        L: 2,
        C: 3,
        Q: 4,
        A: 5,
        Z: 6
    };

    var min = [];
    var max = [];
    var v = [];
    var mathMin = Math.min;
    var mathMax = Math.max;
    var mathSqrt = Math.sqrt;

    /**
     * @alias module:zrender/core/PathProxy
     * @constructor
     */
    var PathProxy = function () {

        /**
         * Path data. Stored as flat array
         * @type {Array.<Object>}
         */
        this.data = [];

        this._len = 0;

        this._ctx = null;

        this._xi = 0;
        this._yi = 0;

        this._x0 = 0;
        this._y0 = 0;
    };

    /**
     * 快速计算Path包围盒（并不是最小包围盒）
     * @return {Object}
     */
    PathProxy.prototype = {

        constructor: PathProxy,

        _lineDash: null,

        _dashOffset: 0,

        _dashIdx: 0,

        _dashSum: 0,

        /**
         * @param  {CanvasRenderingContext2D} ctx
         * @return {module:zrender/core/PathProxy}
         */
        beginPath: function (ctx) {
            this._ctx = ctx;

            ctx && ctx.beginPath();

            // Reset
            this._len = 0;

            if (this._lineDash) {
                this._lineDash = null;

                this._dashOffset = 0;
            }

            return this;
        },

        /**
         * @param  {number} x
         * @param  {number} y
         * @return {module:zrender/core/PathProxy}
         */
        moveTo: function (x, y) {
            this._pushData(CMD.M, x, y);
            this._ctx && this._ctx.moveTo(x, y);

            // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用
            // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。
            // 有可能在 beginPath 之后直接调用 lineTo，这时候 x0, y0 需要
            // 在 lineTo 方法中记录，这里先不考虑这种情况，dashed line 也只在 IE10- 中不支持
            this._x0 = x;
            this._y0 = y;

            this._xi = x;
            this._yi = y;

            return this;
        },

        /**
         * @param  {number} x
         * @param  {number} y
         * @return {module:zrender/core/PathProxy}
         */
        lineTo: function (x, y) {
            this._pushData(CMD.L, x, y);
            if (this._ctx) {
                this._needsDash() ? this._dashedLineTo(x, y)
                    : this._ctx.lineTo(x, y);
            }
            this._xi = x;
            this._yi = y;
            return this;
        },

        /**
         * @param  {number} x1
         * @param  {number} y1
         * @param  {number} x2
         * @param  {number} y2
         * @param  {number} x3
         * @param  {number} y3
         * @return {module:zrender/core/PathProxy}
         */
        bezierCurveTo: function (x1, y1, x2, y2, x3, y3) {
            this._pushData(CMD.C, x1, y1, x2, y2, x3, y3);
            if (this._ctx) {
                this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)
                    : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
            }
            this._xi = x3;
            this._yi = y3;
            return this;
        },

        /**
         * @param  {number} x1
         * @param  {number} y1
         * @param  {number} x2
         * @param  {number} y2
         * @return {module:zrender/core/PathProxy}
         */
        quadraticCurveTo: function (x1, y1, x2, y2) {
            this._pushData(CMD.Q, x1, y1, x2, y2);
            if (this._ctx) {
                this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2)
                    : this._ctx.quadraticCurveTo(x1, y1, x2, y2);
            }
            this._xi = x2;
            this._yi = y2;
            return this;
        },

        /**
         * @param  {number} cx
         * @param  {number} cy
         * @param  {number} r
         * @param  {number} startAngle
         * @param  {number} endAngle
         * @param  {boolean} anticlockwise
         * @return {module:zrender/core/PathProxy}
         */
        arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) {
            this._pushData(
                CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 0, anticlockwise ? 0 : 1
            );
            this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);

            this._xi = Math.cos(endAngle) * rx + cx;
            this._xi = Math.sin(endAngle) * rx + cx;
            return this;
        },

        // TODO
        arcTo: function (x1, y1, x2, y2, radius) {
            if (this._ctx) {
                this._ctx.arcTo(x1, y1, x2, y2, radius);
            }
            return this;
        },

        // TODO
        rect: function (x, y, w, h) {
            this._ctx && this._ctx.rect(x, y, w, h);
            return this;
        },

        /**
         * @return {module:zrender/core/PathProxy}
         */
        closePath: function () {
            this._pushData(CMD.Z);
            this._ctx && this._ctx.closePath();

            this._xi = this._x0;
            this._yi = this._y0;
            return this;
        },

        /**
         * @return {module:zrender/core/PathProxy}
         */
        fill: function () {
            this._ctx && this._ctx.fill();
            this.toStatic();
        },

        /**
         * @return {module:zrender/core/PathProxy}
         */
        stroke: function () {
            var ctx = this._ctx;
            if (ctx) {
                if (this._lineDash) {
                    // ctx.setLineDash && ctx.setLineDash(this._lineDash);
                    ctx.lineDashOffset = this._dashOffset;
                }
                ctx.stroke();
            }

            this.toStatic();
        },

        /**
         * 必须在其它绘制命令前调用
         * Must be invoked before all other path drawing methods
         * @return {module:zrender/core/PathProxy}
         */
        setLineDash: function (lineDash) {
            if (lineDash instanceof Array) {
                this._lineDash = lineDash;

                this._dashIdx = 0;

                var lineDashSum = 0;
                for (var i = 0; i < lineDash.length; i++) {
                    lineDashSum += lineDash[i];
                }
                this._dashSum = lineDashSum;
            }
            return this;
        },

        /**
         * 必须在其它绘制命令前调用
         * Must be invoked before all other path drawing methods
         * @return {module:zrender/core/PathProxy}
         */
        setLineDashOffset: function (offset) {
            this._dashOffset = offset;
            return this;
        },

        /**
         *
         * @return {boolean}
         */
        len: function () {
            return this._len;
        },

        /**
         * 填充 Path 数据。
         * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。
         */
        _pushData: function (cmd) {
            var data = this.data;
            if (this._len + arguments.length > data.length) {
                // 因为之前的数组已经转换成静态的 Float32Array
                // 所以不够用时需要扩展一个新的动态数组
                this._expandData();
                data = this.data;
            }
            for (var i = 0; i < arguments.length; i++) {
                data[this._len++] = arguments[i];
            }

            this._prevCmd = cmd;
        },

        _expandData: function () {
            // Only if data is Float32Array
            if (! (this.data instanceof Array)) {
                var newData = [];
                for (var i = 0; i < this._len; i++) {
                    newData[i] = this.data[i];
                }
                this.data = newData;
            }
        },

        /**
         * If needs js implemented dashed line
         * @return {boolean}
         * @private
         */
        _needsDash: function () {
            // return this._lineDash && !this._ctx.setLineDash;
            return this._lineDash;
        },

        _dashedLineTo: function (x1, y1) {
            var dashSum = this._dashSum;
            var offset = this._dashOffset;
            var lineDash = this._lineDash;
            var ctx = this._ctx;

            var xi = this._xi;
            var yi = this._yi;
            var dx = x1 - xi;
            var dy = y1 - yi;
            var dist = mathSqrt(dx * dx + dy * dy);
            var x = xi;
            var y = yi;
            var dash;
            var len = lineDash.length;
            var idx;
            dx /= dist;
            dy /= dist;

            if (offset < 0) {
                // Convert to positive offset
                offset = dashSum + offset;
            }
            offset %= dashSum;
            x -= offset * dx;
            y -= offset * dy;

            while ((dx >= 0 && x <= x1) || (dx < 0 && x > x1)) {
                idx = this._dashIdx;
                dash = lineDash[idx];
                x += dx * dash;
                y += dy * dash;
                this._dashIdx = (idx + 1) % len;
                // Skip positive offset
                if ((dx > 0 && x < xi) || (dx < 0 && x > xi)) {
                    continue;
                }
                ctx[idx % 2 ? 'moveTo' : 'lineTo'](
                    dx >= 0 ? mathMin(x, x1) : mathMax(x, x1),
                    dy >= 0 ? mathMin(y, y1) : mathMax(y, y1)
                );
            }
            // Offset for next lineTo
            dx = x - x1;
            dy = y - y1;
            this._dashOffset = -mathSqrt(dx * dx + dy * dy);
        },

        _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) {
        },

        _dashedQuadraticTo: function (x1, y1, x2, y2) {
        },

        /**
         * 转成静态的 Float32Array 减少堆内存占用
         * Convert dynamic array to static Float32Array
         * @return {[type]} [description]
         */
        toStatic: function () {
            if (typeof Float32Array != 'undefined'
                && (this.data instanceof Array)
            ) {
                this.data.length = this._len;
                this.data = new Float32Array(this.data);
            };
        },

        fastBoundingRect: function () {
            var data = this.data;
            min[0] = min[1] = Infinity;
            max[0] = max[1] = -Infinity;
            for (var i = 0; i < this._len;) {
                var cmd = data[i++];
                var nPoint = 0;
                switch (cmd) {
                    case CMD.M:
                        nPoint = 1;
                        break;
                    case CMD.L:
                        nPoint = 1;
                        break;
                    case CMD.C:
                        nPoint = 3;
                        break;
                    case CMD.Q:
                        nPoint = 2;
                        break;
                    case CMD.A:
                        var cx = data[i];
                        var cy = data[i + 1];
                        var rx = data[i + 2];
                        var ry = data[i + 3];
                        min[0] = mathMin(min[0], min[0], cx - rx);
                        min[1] = mathMin(min[1], min[1], cy - ry);
                        max[0] = mathMax(max[0], max[0], cx + rx);
                        max[1] = mathMax(max[1], max[1], cy + ry);
                        i += 8;
                        break;
                }
                for (var j = 0; j < nPoint; j++) {
                    min[0] = mathMin(min[0], min[0], data[i]);
                    max[0] = mathMax(max[0], max[0], data[i++]);
                    min[1] = mathMin(min[1], min[1], data[i]);
                    max[1] = mathMax(max[1], max[1], data[i++]);
                }
            }

            return {
                x: min[0],
                y: min[1],
                width: max[0] - min[0],
                height: max[1] - min[1]
            };
        },

        /**
         * Rebuild path from current data
         * Rebuild path will not consider javascript implemented line dash.
         * @param {CanvasRenderingContext} ctx
         */
        rebuildPath: function (ctx) {
            var d = this.data;
            for (var i = 0; i < this._len;) {
                var cmd = d[i++];
                switch (cmd) {
                    case CMD.M:
                        ctx.moveTo(d[i++], d[i++]);
                        break;
                    case CMD.L:
                        ctx.lineTo(d[i++], d[i++]);
                        break;
                    case CMD.C:
                        ctx.bezierCurveTo(
                            d[i++], d[i++], d[i++], d[i++], d[i++], d[i++]
                        );
                        break;
                    case CMD.Q:
                        ctx.bezierCurveTo(d[i++], d[i++], d[i++], d[i++]);
                        break;
                    case CMD.A:
                        var cx = d[i++];
                        var cy = d[i++];
                        var rx = d[i++];
                        var ry = d[i++];
                        var theta = d[i++];
                        var dTheta = d[i++];
                        var psi = d[i++];
                        var fs = d[i++];
                        var r = (rx > ry) ? rx : ry;
                        var scaleX = (rx > ry) ? 1 : rx / ry;
                        var scaleY = (rx > ry) ? ry / rx : 1;
                        var isEllipse = Math.abs(rx - ry) < 1e-3;
                        if (isEllipse) {
                            ctx.translate(cx, cy);
                            ctx.rotate(psi);
                            ctx.scale(scaleX, scaleY);
                            ctx.arc(0, 0, r, theta, theta + dTheta, 1 - fs);
                            ctx.scale(1 / scaleX, 1 / scaleY);
                            ctx.rotate(-psi);
                            ctx.translate(-cx, -cy);
                        }
                        else {
                            ctx.arc(cx, cy, r, theta, theta + dTheta, 1 - fs);
                        }
                        break;
                    case CMD.Z:
                        ctx.closePath();
                }
            }
        }
    };

    PathProxy.CMD = CMD;

    return PathProxy;
});<|endoftext|>


<commit_before>/*globals define*/
/*
 * Copyright (C) 2013 Vanderbilt University, All rights reserved.
 *
 * @author brollb / https://github/brollb
 */

define(['js/DragDrop/DragSource',
        'js/DragDrop/DragHelper',
        'util/assert',
        './SnapEditorWidget.Constants'], function (dragSource,
                                                   dragHelper,
                                                   assert,
                                                   SnapEditorWidgetConstants) {

    "use strict";

    var SnapEditorWidgetDraggable,
        DRAG_HELPER_CLASS = 'diagram-designer-drag-outline',
        DRAG_HELPER_EL_BASE = $('
', {'class': DRAG_HELPER_CLASS}),
        DRAG_HELPER_ICON_MOVE = $(''),
        DRAG_HELPER_ICON_COPY = $(''),
        DRAG_HELPER_BUFFER = 0;

    SnapEditorWidgetDraggable = function () {
    };

    SnapEditorWidgetDraggable.prototype._makeDraggable = function (item) {
        var self = this;

        dragSource.makeDraggable(item.$el, {
            'helper': function (event, dragInfo) {
                //Set the cursorAt value
                $(this).draggable("option", "cursorAt", self.getCursorLocation(event, item.id));
                return self._dragHelper(item, event, dragInfo);
            },
            'drag': function(event, ui){
            },
            'dragItems': function (el) {
                return self.getDragItems(self.selectionManager.getSelectedElements());
            },
            'dragEffects': function (el, event) {
                return self.getDragEffects(self.selectionManager.getSelectedElements(), event);
            },
            'dragParams': function (el, event) {
                return self.getDragParams(self.selectionManager.getSelectedElements(), event);
            },
            'start': function (event, ui) {
                //Set the drop focus
                self.dropFocus = SnapEditorWidgetConstants.BACKGROUND;

                var ret = false;
                //enable drag mode only in
                //- DESIGN MODE
                //- if the mousedown is not on a connection drawing start point
                if (self.mode === self.OPERATING_MODES.DESIGN) {
                    //we need to check if the target element is SVGElement or not
                    //because jQuery does not work well on SVGElements
                    if (event.originalEvent.target instanceof SVGElement) {
                        var classDef = event.originalEvent.target.getAttribute("class");
                        if (classDef) {
                            ret = classDef.split(' ').indexOf(SnapEditorWidgetConstants.CONNECTOR_CLASS) === -1;
                        } else {
                            ret = true;
                        }
                    } else {
                        ret = !$(event.originalEvent.target).hasClass(SnapEditorWidgetConstants.CONNECTOR_CLASS);
                    }
                }
                return ret;
            }
        });
    };

    SnapEditorWidgetDraggable.prototype._destroyDraggable = function (item) {
        dragSource.destroyDraggable(item.$el);
    };

    /* OVERWRITE DragSource.prototype.dragHelper */
    SnapEditorWidgetDraggable.prototype._dragHelper = function (item, event, dragInfo) {
        var firstItem = null,
            items = {},
            i,
            dragElement = $('
', {'id': item.id });

        if(!item.items){
            firstItem = item.id;
            items[item.id] = { item: item, z: 100000 };

        }else{//set of items are selected
            assert(false, "Can't select multiple items to drag");
            i = item.items.length;
            while(i--){
                items[item.items[i].getId()] = { item: item.items[i], z: 100000 };
            }
        }

        //Add all the dependent items
        var keys = Object.keys(items),
            deps,
            dependent,
            dragItem;

        while(keys.length){
            dragItem = items[keys.pop()];
            deps = dragItem.item.getDependents();

            while(deps.length){
                dependent = deps.pop();
                if(dependent && items[dependent.id] === undefined){
                    items[dependent.id] = { item: dependent, z: dragItem.z + 1 };
                    keys.push(dependent.id);
                }
            }
        }

        //Create a element containing all these
        var itemId,
            itemElement,
            shiftX = item.positionX - DRAG_HELPER_BUFFER,
            shiftY = item.positionY - DRAG_HELPER_BUFFER,
            box,
            maxX = 0,
            maxY = 0;

        //Fix cursor alignment
        //shiftX = event.pageX - item.$el.parent().offset().left;
        //shiftY = event.pageY - item.$el.parent().offset().top;

        keys = Object.keys(items);
        while(keys.length){
            itemId = keys.pop();

            //set maxX, maxY
            box = this.items[itemId].getBoundingBox();
            maxX = Math.max(maxX, box.x2);
            maxY = Math.max(maxY, box.y2);

            itemElement = items[itemId].item.$el.clone();
            itemElement.css({"position": "absolute",
                             "z-index": items[itemId].z,
                             //Shift the element by shiftX, shiftY
                             "left": items[itemId].item.positionX - shiftX + "px",
                             "top": items[itemId].item.positionY - shiftY + "px"});

            dragElement.append(itemElement);
        }

        //Set height, width of the helper
        maxX += DRAG_HELPER_BUFFER - shiftX;
        maxY += DRAG_HELPER_BUFFER - shiftY;

        dragElement.width(maxX);
        dragElement.height(maxY);

        //DEBUGGING
        dragElement.css("background-color", "grey");

        return dragElement;
    };

    SnapEditorWidgetDraggable.prototype.getCursorLocation = function (event, itemId) {
        //Get the correct cursor location
        var location = {},
            item = this.items[itemId],
            mouseX,
            mouseY;

        mouseX = event.pageX - item.$el.parent().offset().left;
        mouseY = event.pageY - item.$el.parent().offset().top;

        location.left = mouseX - item.positionX + DRAG_HELPER_BUFFER;
        location.top = mouseY - item.positionY + DRAG_HELPER_BUFFER;

        return location;
    };

    SnapEditorWidgetDraggable.prototype.getDragItems = function (selectedElements) {
        this.logger.warning("SnapEditorWidgetDraggable.getDragItems is not overridden in the controller!!! selectedElements: " + selectedElements);
        return [];
    };

    SnapEditorWidgetDraggable.prototype.getDragEffects = function (selectedElements, event) {
        var ctrlKey = event.ctrlKey || event.metaKey,
            effects = [dragSource.DRAG_EFFECTS.DRAG_MOVE];

        //by default the drag is a MOVE

        //CTRL key --> copy
        if (ctrlKey) {
            effects = [dragSource.DRAG_EFFECTS.DRAG_COPY];
        }

        return effects;
    };

    SnapEditorWidgetDraggable.prototype.getDragParams = function (selectedElements, event) {
        var params = { 'positions': {}},
            i = selectedElements.length,
            itemID,
            selectionBBox = this.selectionManager._getSelectionBoundingBox(),
            mousePos = this.getAdjustedMousePos(event);

        while (i--) {
            itemID = selectedElements[i];
            if (this.itemIds.indexOf(itemID) !== -1) {
                params.positions[itemID] = {'x': this.items[itemID].positionX - mousePos.mX,
                                     'y': this.items[itemID].positionY - mousePos.mY};
            }
        }

        return params;
    };

    SnapEditorWidgetDraggable.prototype.DRAG_EFFECTS = dragSource.DRAG_EFFECTS;

    return SnapEditorWidgetDraggable;
});
<commit_msg>Removed debug highlighting and increased dragged item buffer<commit_after>/*globals define*/
/*
 * Copyright (C) 2013 Vanderbilt University, All rights reserved.
 *
 * @author brollb / https://github/brollb
 */

define(['js/DragDrop/DragSource',
        'js/DragDrop/DragHelper',
        'util/assert',
        './SnapEditorWidget.Constants'], function (dragSource,
                                                   dragHelper,
                                                   assert,
                                                   SnapEditorWidgetConstants) {

    "use strict";

    var SnapEditorWidgetDraggable,
        DRAG_HELPER_CLASS = 'diagram-designer-drag-outline',
        DRAG_HELPER_EL_BASE = $('
', {'class': DRAG_HELPER_CLASS}),
        DRAG_HELPER_ICON_MOVE = $(''),
        DRAG_HELPER_ICON_COPY = $(''),
        DRAG_HELPER_BUFFER = 15;

    SnapEditorWidgetDraggable = function () {
    };

    SnapEditorWidgetDraggable.prototype._makeDraggable = function (item) {
        var self = this;

        dragSource.makeDraggable(item.$el, {
            'helper': function (event, dragInfo) {
                //Set the cursorAt value
                $(this).draggable("option", "cursorAt", self.getCursorLocation(event, item.id));
                return self._dragHelper(item, event, dragInfo);
            },
            'drag': function(event, ui){
            },
            'dragItems': function (el) {
                return self.getDragItems(self.selectionManager.getSelectedElements());
            },
            'dragEffects': function (el, event) {
                return self.getDragEffects(self.selectionManager.getSelectedElements(), event);
            },
            'dragParams': function (el, event) {
                return self.getDragParams(self.selectionManager.getSelectedElements(), event);
            },
            'start': function (event, ui) {
                //Set the drop focus
                self.dropFocus = SnapEditorWidgetConstants.BACKGROUND;

                var ret = false;
                //enable drag mode only in
                //- DESIGN MODE
                //- if the mousedown is not on a connection drawing start point
                if (self.mode === self.OPERATING_MODES.DESIGN) {
                    //we need to check if the target element is SVGElement or not
                    //because jQuery does not work well on SVGElements
                    if (event.originalEvent.target instanceof SVGElement) {
                        var classDef = event.originalEvent.target.getAttribute("class");
                        if (classDef) {
                            ret = classDef.split(' ').indexOf(SnapEditorWidgetConstants.CONNECTOR_CLASS) === -1;
                        } else {
                            ret = true;
                        }
                    } else {
                        ret = !$(event.originalEvent.target).hasClass(SnapEditorWidgetConstants.CONNECTOR_CLASS);
                    }
                }
                return ret;
            }
        });
    };

    SnapEditorWidgetDraggable.prototype._destroyDraggable = function (item) {
        dragSource.destroyDraggable(item.$el);
    };

    /* OVERWRITE DragSource.prototype.dragHelper */
    SnapEditorWidgetDraggable.prototype._dragHelper = function (item, event, dragInfo) {
        var firstItem = null,
            items = {},
            i,
            dragElement = $('
', {'id': item.id });

        if(!item.items){
            firstItem = item.id;
            items[item.id] = { item: item, z: 100000 };

        }else{//set of items are selected
            assert(false, "Can't select multiple items to drag");
            i = item.items.length;
            while(i--){
                items[item.items[i].getId()] = { item: item.items[i], z: 100000 };
            }
        }

        //Add all the dependent items
        var keys = Object.keys(items),
            deps,
            dependent,
            dragItem;

        while(keys.length){
            dragItem = items[keys.pop()];
            deps = dragItem.item.getDependents();

            while(deps.length){
                dependent = deps.pop();
                if(dependent && items[dependent.id] === undefined){
                    items[dependent.id] = { item: dependent, z: dragItem.z + 1 };
                    keys.push(dependent.id);
                }
            }
        }

        //Create a element containing all these
        var itemId,
            itemElement,
            shiftX = item.positionX - DRAG_HELPER_BUFFER,
            shiftY = item.positionY - DRAG_HELPER_BUFFER,
            box,
            maxX = 0,
            maxY = 0;

        //Fix cursor alignment
        //shiftX = event.pageX - item.$el.parent().offset().left;
        //shiftY = event.pageY - item.$el.parent().offset().top;

        keys = Object.keys(items);
        while(keys.length){
            itemId = keys.pop();

            //set maxX, maxY
            box = this.items[itemId].getBoundingBox();
            maxX = Math.max(maxX, box.x2);
            maxY = Math.max(maxY, box.y2);

            itemElement = items[itemId].item.$el.clone();
            itemElement.css({"position": "absolute",
                             "z-index": items[itemId].z,
                             //Shift the element by shiftX, shiftY
                             "left": items[itemId].item.positionX - shiftX + "px",
                             "top": items[itemId].item.positionY - shiftY + "px"});

            dragElement.append(itemElement);
        }

        //Set height, width of the helper
        maxX += DRAG_HELPER_BUFFER - shiftX;
        maxY += DRAG_HELPER_BUFFER - shiftY;

        dragElement.width(maxX);
        dragElement.height(maxY);

        //DEBUGGING
        //dragElement.css("background-color", "grey");

        return dragElement;
    };

    SnapEditorWidgetDraggable.prototype.getCursorLocation = function (event, itemId) {
        //Get the correct cursor location
        var location = {},
            item = this.items[itemId],
            mouseX,
            mouseY;

        mouseX = event.pageX - item.$el.parent().offset().left;
        mouseY = event.pageY - item.$el.parent().offset().top;

        location.left = mouseX - item.positionX + DRAG_HELPER_BUFFER;
        location.top = mouseY - item.positionY + DRAG_HELPER_BUFFER;

        return location;
    };

    SnapEditorWidgetDraggable.prototype.getDragItems = function (selectedElements) {
        this.logger.warning("SnapEditorWidgetDraggable.getDragItems is not overridden in the controller!!! selectedElements: " + selectedElements);
        return [];
    };

    SnapEditorWidgetDraggable.prototype.getDragEffects = function (selectedElements, event) {
        var ctrlKey = event.ctrlKey || event.metaKey,
            effects = [dragSource.DRAG_EFFECTS.DRAG_MOVE];

        //by default the drag is a MOVE

        //CTRL key --> copy
        if (ctrlKey) {
            effects = [dragSource.DRAG_EFFECTS.DRAG_COPY];
        }

        return effects;
    };

    SnapEditorWidgetDraggable.prototype.getDragParams = function (selectedElements, event) {
        var params = { 'positions': {}},
            i = selectedElements.length,
            itemID,
            selectionBBox = this.selectionManager._getSelectionBoundingBox(),
            mousePos = this.getAdjustedMousePos(event);

        while (i--) {
            itemID = selectedElements[i];
            if (this.itemIds.indexOf(itemID) !== -1) {
                params.positions[itemID] = {'x': this.items[itemID].positionX - mousePos.mX,
                                     'y': this.items[itemID].positionY - mousePos.mY};
            }
        }

        return params;
    };

    SnapEditorWidgetDraggable.prototype.DRAG_EFFECTS = dragSource.DRAG_EFFECTS;

    return SnapEditorWidgetDraggable;
});
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { connect } from 'react-redux'

class CreatePollPage extends Component {
  constructor(props) {
    super(props)

    this.state = {
      title: '',
      entries: [],
    }
  }

  addEntry(name) {
    if (this.state.entries.indexOf(name) === -1) {
      this.state.entries.push(name)
    }
  }

  render() {
    return (
      <form>
        Name:
        <input id="GET-name" type="text" />
      </form>
    )
  }
}

// CreatePollPage.propTypes = {}
// function mapStateToProps(state, props) {
//   get the user here
// }

// export default connect()(CreatePollPage)
export default CreatePollPage
<commit_msg>working on the PollCreatingPage<commit_after>import React, { Component } from 'react'
import { connect } from 'react-redux'

import BarChart from '../../components/BarChart/BarChart'

class CreatePollPage extends Component {
  constructor(props) {
    super(props)

    this.state = {
      entryInput: '',
      refresh: false,
      poll: {
        title: '',
        author: '',
        entries: [],
        cuid: '0',
        dateCreated: Date.now()
      }
    }
  }

  onEntryInputChange(action) {
    this.setState({ entryInput: action.target.value })
  }

  onEntryInputKeyDown(action) {
    if (action.which === 13) {
      this.addEntry(this.state.entryInput)
    }
  }

  addEntryButtonClicked() {
    this.addEntry(this.state.entryInput)
  }

  addEntry(title) {
    if (this.findEntry(title) === -1 && title.length > 0) {
      this.state.poll.entries.push(this.createEntry(title))
      this.setState({ refresh: true })
      setTimeout(() => this.setState({ refresh: false }), 10)
    }
    this.setState({ entryInput: '' })
  }

  findEntry(title) {
    const entries = this.state.poll.entries
    for (let i = 0; i < entries.length; i++) {
      if (entries[i].title === title) {
        return i
      }
    }
    return -1
  }

  createEntry(title) {
    return {
      title,
      votes: [123123, 123123]
    }
  }

  render() {
    return (

        {!this.state.refresh ? <BarChart pollData={this.state.poll} /> : null}
        <form onSubmit={action => action.preventDefault()}>
          Entry Name
          <input
            id="add-entry"
            type="text"
            onKeyDown={this.onEntryInputKeyDown.bind(this)}
            onChange={this.onEntryInputChange.bind(this)}
            value={this.state.entryInput}
          />
        <button onClick={this.addEntryButtonClicked.bind(this)}>Add Entry</button>
        </form>

    )
  }
}

// CreatePollPage.propTypes = {}
// function mapStateToProps(state, props) {
//   get the user here
// }

// export default connect()(CreatePollPage)
export default CreatePollPage
<|endoftext|>


<commit_before>import PropTypes from 'prop-types'
import React, { Component } from 'react'
import autobind from 'autobind-decorator'
import {Checkbox} from 'react-bootstrap'
import API from 'api'
import _isEqualWith from 'lodash/isEqualWith'
import utils from 'utils'

import Autocomplete from 'components/Autocomplete'

import {Organization} from 'models'

export default class OrganizationFilter extends Component {
	static propTypes = {
		//An Autocomplete filter allows users to search the ANET database
		// for existing records and use that records ID as the search term.
		// the filterKey property tells this filter what property to set on the
		// search query. (ie authorId, organizationId, etc)
		queryKey: PropTypes.string.isRequired,
		queryIncludeChildOrgsKey: PropTypes.string.isRequired,

		//Passed by the SearchFilter row
		value: PropTypes.any,
		onChange: PropTypes.func,

		//Passed by the SearchFilterDisplay row
		asFormField: PropTypes.bool,

		//All other properties are passed directly to the Autocomplete.

	}

	static defaultProps = {
		asFormField: true
	}

	constructor(props) {
		super(props)

		const value = props.value || {}
		this.state = {
			value: value,
			includeChildOrgs: value.includeChildOrgs || false,
			queryParams: props.queryParams || {},
		}
	}

	componentDidMount() {
		this.updateFilter()
	}

	componentDidUpdate(prevProps, prevState) {
		if (!_isEqualWith(prevProps.value, this.props.value, utils.treatFunctionsAsEqual)) {
			this.setState({
				value: this.props.value,
				includeChildOrgs: this.props.value.includeChildOrgs,
			}, this.updateFilter)
		}
	}

	render() {
		let autocompleteProps = Object.without(this.props, 'value', 'queryKey', 'queryIncludeChildOrgsKey', 'queryParams', 'asFormField')

		return (
			!this.props.asFormField ?
				<React.Fragment>{this.props.value.shortName}</React.Fragment>
			:

					<Autocomplete
						objectType={Organization}
						valueKey="shortName"
						url="/api/organizations/search"
						placeholder="Filter by organization..."
						queryParams={this.state.queryParams}
						{...autocompleteProps}
						onChange={this.onAutocomplete}
						value={this.state.value}
					/>

					<Checkbox inline checked={this.state.includeChildOrgs} onChange={this.changeIncludeChildren}>
						Include sub-organizations
					</Checkbox>

		)
	}

	@autobind
	changeIncludeChildren(event) {
		this.setState({includeChildOrgs: event.target.checked}, this.updateFilter)
	}

	@autobind
	onAutocomplete(event) {
		this.setState({value: event}, this.updateFilter)
	}

	@autobind
	toQuery() {
		return {
			[this.props.queryKey]: this.state.value.id,
			[this.props.queryIncludeChildOrgsKey]: this.state.includeChildOrgs,
		}
	}

	@autobind
	updateFilter() {
		if (this.props.asFormField) {
			let {value} = this.state
			if (typeof value === 'object') {
				value.includeChildOrgs = this.state.includeChildOrgs
				value.toQuery = this.toQuery
			}
			this.props.onChange(value)
		}
	}

	@autobind
	deserialize(query, key) {
		if (query[this.props.queryKey]) {
			let getInstanceName = Organization.getInstanceName
			let graphQlQuery = getInstanceName +
				'(id:' + query[this.props.queryKey] + ') { id, shortName }'
			return API.query(graphQlQuery).then(data => {
				if (data[getInstanceName]) {
					const toQueryValue = {[this.props.queryKey]: query[this.props.queryKey]}
					if (query[this.props.queryIncludeChildOrgsKey]) {
						data[getInstanceName].includeChildOrgs = query[this.props.queryIncludeChildOrgsKey]
						toQueryValue[this.props.queryIncludeChildOrgsKey] = query[this.props.queryIncludeChildOrgsKey]
					}
					return {
						key: key,
						value: {
							...data[getInstanceName],
							toQuery: () => toQueryValue
						},
					}
				}
				else {
					return null
				}
			})
		}
		return null
	}

}
<commit_msg>NCI-Agency/anet#559: When sub-organizations are included, show this in the message<commit_after>import PropTypes from 'prop-types'
import React, { Component } from 'react'
import autobind from 'autobind-decorator'
import {Checkbox} from 'react-bootstrap'
import API from 'api'
import _isEqualWith from 'lodash/isEqualWith'
import utils from 'utils'

import Autocomplete from 'components/Autocomplete'

import {Organization} from 'models'

export default class OrganizationFilter extends Component {
	static propTypes = {
		//An Autocomplete filter allows users to search the ANET database
		// for existing records and use that records ID as the search term.
		// the filterKey property tells this filter what property to set on the
		// search query. (ie authorId, organizationId, etc)
		queryKey: PropTypes.string.isRequired,
		queryIncludeChildOrgsKey: PropTypes.string.isRequired,

		//Passed by the SearchFilter row
		value: PropTypes.any,
		onChange: PropTypes.func,

		//Passed by the SearchFilterDisplay row
		asFormField: PropTypes.bool,

		//All other properties are passed directly to the Autocomplete.

	}

	static defaultProps = {
		asFormField: true
	}

	constructor(props) {
		super(props)

		const value = props.value || {}
		this.state = {
			value: value,
			includeChildOrgs: value.includeChildOrgs || false,
			queryParams: props.queryParams || {},
		}
	}

	componentDidMount() {
		this.updateFilter()
	}

	componentDidUpdate(prevProps, prevState) {
		if (!_isEqualWith(prevProps.value, this.props.value, utils.treatFunctionsAsEqual)) {
			this.setState({
				value: this.props.value,
				includeChildOrgs: this.props.value.includeChildOrgs || false,
			}, this.updateFilter)
		}
	}

	render() {
		let autocompleteProps = Object.without(this.props, 'value', 'queryKey', 'queryIncludeChildOrgsKey', 'queryParams', 'asFormField')
		let msg = this.props.value.shortName
		if (msg && this.state.includeChildOrgs) {
			msg += ", including sub-organizations"
		}

		return (
			!this.props.asFormField ?
				<React.Fragment>{msg}</React.Fragment>
			:

					<Autocomplete
						objectType={Organization}
						valueKey="shortName"
						url="/api/organizations/search"
						placeholder="Filter by organization..."
						queryParams={this.state.queryParams}
						{...autocompleteProps}
						onChange={this.onAutocomplete}
						value={this.state.value}
					/>

					<Checkbox inline checked={this.state.includeChildOrgs} onChange={this.changeIncludeChildren}>
						Include sub-organizations
					</Checkbox>

		)
	}

	@autobind
	changeIncludeChildren(event) {
		this.setState({includeChildOrgs: event.target.checked}, this.updateFilter)
	}

	@autobind
	onAutocomplete(event) {
		this.setState({value: event}, this.updateFilter)
	}

	@autobind
	toQuery() {
		return {
			[this.props.queryKey]: this.state.value.id,
			[this.props.queryIncludeChildOrgsKey]: this.state.includeChildOrgs,
		}
	}

	@autobind
	updateFilter() {
		if (this.props.asFormField) {
			let {value} = this.state
			if (typeof value === 'object') {
				value.includeChildOrgs = this.state.includeChildOrgs
				value.toQuery = this.toQuery
			}
			this.props.onChange(value)
		}
	}

	@autobind
	deserialize(query, key) {
		if (query[this.props.queryKey]) {
			let getInstanceName = Organization.getInstanceName
			let graphQlQuery = getInstanceName +
				'(id:' + query[this.props.queryKey] + ') { id, shortName }'
			return API.query(graphQlQuery).then(data => {
				if (data[getInstanceName]) {
					const toQueryValue = {[this.props.queryKey]: query[this.props.queryKey]}
					if (query[this.props.queryIncludeChildOrgsKey]) {
						data[getInstanceName].includeChildOrgs = query[this.props.queryIncludeChildOrgsKey]
						toQueryValue[this.props.queryIncludeChildOrgsKey] = query[this.props.queryIncludeChildOrgsKey]
					}
					return {
						key: key,
						value: {
							...data[getInstanceName],
							toQuery: () => toQueryValue
						},
					}
				}
				else {
					return null
				}
			})
		}
		return null
	}

}
<|endoftext|>


<commit_before>/**
 * @name pc
 * @namespace PlayCanvas Engine
 * @description Root namespace for the PlayCanvas Engine
 * @preserve PlayCanvas Engine v__CURRENT_SDK_VERSION__ revision __REVISION__
 * http://playcanvas.com
 * Copyright 2011-2014 PlayCanvas Ltd. All rights reserved.
 * Do not distribute.
 * Contains: https://github.com/tildeio/rsvp.js - see page for license information
 */
var pc = {
        /**
        * @name pc.config
        * @description Configuration data made available to the application from the server
        * @param bootstrap
        * @param frame Options set from the containing frame
        * @param frame.url The URL of the containing frame
        * @param api_url
        * @param corazon
        * @param username
        * @param repository
        * @param script_prefix
        */
        config: {},

        common: {},
        /**
         * Storage for the applications using the PlayCanvas Engine
         */
        apps: {},
        /**
         * Storage for exported entity data
         */
        data: {},

        /**
         * @private
         * @function
         * @name pc.unpack()
         * @description Copy a set of common PlayCanvas functions/classes/namespaces into the global namespace
         */
        unpack: function () {
            console.warn("pc.unpack has been deprecated and will be removed shortly. Please update your code.");
        },

        /**
         * Convert an array-like object into a normal array.
         * For example, this is useful for converting the arguments object into an array.
         * @param {Object} arr The array to convert
         * @return {Array} An array
         * @function
         * @name pc.makeArray
         */
        makeArray: function (arr) {
            var i,
            ret = [],
            length = arr.length;

            for(i = 0; i < length; ++i) {
                ret.push(arr[i]);
            }

            return ret;
        },

        /**
         * Extended typeof() function, returns the type of the object.
         * @param {Object} obj The object to get the type of
         * @return {String} The type string: "null", "undefined", "number", "string", "boolean", "array", "object", "function", "date", "regexp" or "float32array"
         * @function
         * @name pc.type
         */
        type: function (obj) {
            if (obj === null) {
                return "null";
            }

            var type = typeof(obj);

            if (type == "undefined" || type == "number" || type == "string" || type == "boolean") {
                return type;
            }

            return _typeLookup[Object.prototype.toString.call(obj)];
        },

        /**
         * Merge the contents of two objects into a single object
         *

         * var A = {a: function() {console.log(this.a}};
         * var B = {b: function() {console.log(this.b}};
         *
         * pc.extend(A,B);
         * A.a();
         * // logs "a"
         * A.b();
         * // logs "b"
         *

         * @param {Object} target The target object of the merge
         * @param {Object} ex The object that is merged with target
         * @return {Object} The target object
         * @function
         * @name pc.extend
         */
        extend: function(target, ex) {
            var prop,
            copy;

            for(prop in ex) {
                copy = ex[prop];
                if(pc.type(copy) == "object") {
                    target[prop] = pc.extend({}, copy);
                } else if(pc.type(copy) == "array") {
                    target[prop] = pc.extend([], copy);
                } else {
                    target[prop] = copy;
                }
            }

            return target;
        },

        /**
         * Return true if the Object is not undefined
         * @param {Object} o The Object to test
         * @function
         * @name pc.isDefined
         */
        isDefined: function(o) {
            var a;
            return (o !== a);
        }
    };

    /**
     * @private
     * @name pc._typeLookup
     * @function
     * @description Create look up table for types
     */
    var _typeLookup = function () {
        var result = {},
        index,
        names = ["Array", "Object", "Function", "Date", "RegExp", "Float32Array"];

        for(index = 0; index < names.length; ++index) {
            result["[object " + names[index] + "]"] = names[index].toLowerCase();
        }

        return result;
    } ();

if (exports !== undefined) {
    exports.pc = pc;
}
<commit_msg>Fix global var undefined check.<commit_after>/**
 * @name pc
 * @namespace PlayCanvas Engine
 * @description Root namespace for the PlayCanvas Engine
 * @preserve PlayCanvas Engine v__CURRENT_SDK_VERSION__ revision __REVISION__
 * http://playcanvas.com
 * Copyright 2011-2014 PlayCanvas Ltd. All rights reserved.
 * Do not distribute.
 * Contains: https://github.com/tildeio/rsvp.js - see page for license information
 */
var pc = {
        /**
        * @name pc.config
        * @description Configuration data made available to the application from the server
        * @param bootstrap
        * @param frame Options set from the containing frame
        * @param frame.url The URL of the containing frame
        * @param api_url
        * @param corazon
        * @param username
        * @param repository
        * @param script_prefix
        */
        config: {},

        common: {},
        /**
         * Storage for the applications using the PlayCanvas Engine
         */
        apps: {},
        /**
         * Storage for exported entity data
         */
        data: {},

        /**
         * @private
         * @function
         * @name pc.unpack()
         * @description Copy a set of common PlayCanvas functions/classes/namespaces into the global namespace
         */
        unpack: function () {
            console.warn("pc.unpack has been deprecated and will be removed shortly. Please update your code.");
        },

        /**
         * Convert an array-like object into a normal array.
         * For example, this is useful for converting the arguments object into an array.
         * @param {Object} arr The array to convert
         * @return {Array} An array
         * @function
         * @name pc.makeArray
         */
        makeArray: function (arr) {
            var i,
            ret = [],
            length = arr.length;

            for(i = 0; i < length; ++i) {
                ret.push(arr[i]);
            }

            return ret;
        },

        /**
         * Extended typeof() function, returns the type of the object.
         * @param {Object} obj The object to get the type of
         * @return {String} The type string: "null", "undefined", "number", "string", "boolean", "array", "object", "function", "date", "regexp" or "float32array"
         * @function
         * @name pc.type
         */
        type: function (obj) {
            if (obj === null) {
                return "null";
            }

            var type = typeof(obj);

            if (type == "undefined" || type == "number" || type == "string" || type == "boolean") {
                return type;
            }

            return _typeLookup[Object.prototype.toString.call(obj)];
        },

        /**
         * Merge the contents of two objects into a single object
         *

         * var A = {a: function() {console.log(this.a}};
         * var B = {b: function() {console.log(this.b}};
         *
         * pc.extend(A,B);
         * A.a();
         * // logs "a"
         * A.b();
         * // logs "b"
         *

         * @param {Object} target The target object of the merge
         * @param {Object} ex The object that is merged with target
         * @return {Object} The target object
         * @function
         * @name pc.extend
         */
        extend: function(target, ex) {
            var prop,
            copy;

            for(prop in ex) {
                copy = ex[prop];
                if(pc.type(copy) == "object") {
                    target[prop] = pc.extend({}, copy);
                } else if(pc.type(copy) == "array") {
                    target[prop] = pc.extend([], copy);
                } else {
                    target[prop] = copy;
                }
            }

            return target;
        },

        /**
         * Return true if the Object is not undefined
         * @param {Object} o The Object to test
         * @function
         * @name pc.isDefined
         */
        isDefined: function(o) {
            var a;
            return (o !== a);
        }
    };

    /**
     * @private
     * @name pc._typeLookup
     * @function
     * @description Create look up table for types
     */
    var _typeLookup = function () {
        var result = {},
        index,
        names = ["Array", "Object", "Function", "Date", "RegExp", "Float32Array"];

        for(index = 0; index < names.length; ++index) {
            result["[object " + names[index] + "]"] = names[index].toLowerCase();
        }

        return result;
    } ();

if (typeof (exports) !== 'undefined') {
    exports.pc = pc;
}
<|endoftext|>


<commit_before>import runtime from './runtime.js'

// Promise API polyfill for IE11
import 'bluebird/js/browser/bluebird.js'

// fetch API polyfill for old browsers
import 'whatwg-fetch'

if (!console.time || !console.timeEnd) {
  var timers = {}
  console.time = function(key) {
    timers[key] = new Date().getTime()
  }
  console.timeEnd = function(id) {
    if (!timers[key]) return
    console.log(key + ': ' + (new Date().getTime() - timers[key]) + 'ms')
    delete timers[key]
  }
}

// from https://raw.githubusercontent.com/mrdoob/three.js/dev/src/polyfills.js

if (Number.EPSILON === undefined) {
  Number.EPSILON = Math.pow(2, -52);
}

if (Number.isInteger === undefined) {
  // Missing in IE
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
  Number.isInteger = function (value) {
    return typeof value === 'number' && isFinite(value) && Math.floor(value) === value
  }
}

if (Math.sign === undefined) {
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
  Math.sign = function (x) {
    return ( x < 0 ) ? -1 : ( x > 0 ) ? 1 : +x
  }
}

if (Function.prototype.name === undefined) {
  // Missing in IE
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
  Object.defineProperty(Function.prototype, 'name', {
    get: function () {
      return this.toString().match(/^\s*function\s*([^\(\s]*)/)[1]
    }
  })
}

if (Object.assign === undefined) {
  // Missing in IE
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
  (function () {
    Object.assign = function (target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert undefined or null to object')
      }
      var output = Object(target)
      for (var index = 1; index < arguments.length; index++) {
        var source = arguments[index]
        if (source !== undefined && source !== null) {
          for (var nextKey in source) {
            if (Object.prototype.hasOwnProperty.call(source, nextKey)) {
              output[nextKey] = source[nextKey]
            }
          }
        }
      }
      return output
    }
  })()
}

// performance.now()
if (runtime.isBrowser) {

  // browser polyfill
  // inspired by:
  // https://gist.github.com/paulirish/5438650
  // note: if we need performance.mark and other methods we might want to replace this with:
  // https://www.npmjs.com/package/performance-polyfill
  if (!window.performance) {
    window.performance = {}
  }
  if (!window.performance.now){
    var navigationStart = performance.timing ? performance.timing.navigationStart : null
    var nowOffset = navigationStart || Date.now()
    window.performance.now = function now(){
      return Date.now() - nowOffset
    }
  }

} else {

  // node: use module
  global.performance = {
    now: require('performance-now')
  }

}<commit_msg>fixes typo<commit_after>import runtime from './runtime.js'

// Promise API polyfill for IE11
import 'bluebird/js/browser/bluebird.js'

// fetch API polyfill for old browsers
import 'whatwg-fetch'

if (!console.time || !console.timeEnd) {
  var timers = {}
  console.time = function(key) {
    timers[key] = new Date().getTime()
  }
  console.timeEnd = function(key) {
    if (!timers[key]) return
    console.log(key + ': ' + (new Date().getTime() - timers[key]) + 'ms')
    delete timers[key]
  }
}

// from https://raw.githubusercontent.com/mrdoob/three.js/dev/src/polyfills.js

if (Number.EPSILON === undefined) {
  Number.EPSILON = Math.pow(2, -52);
}

if (Number.isInteger === undefined) {
  // Missing in IE
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
  Number.isInteger = function (value) {
    return typeof value === 'number' && isFinite(value) && Math.floor(value) === value
  }
}

if (Math.sign === undefined) {
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
  Math.sign = function (x) {
    return ( x < 0 ) ? -1 : ( x > 0 ) ? 1 : +x
  }
}

if (Function.prototype.name === undefined) {
  // Missing in IE
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
  Object.defineProperty(Function.prototype, 'name', {
    get: function () {
      return this.toString().match(/^\s*function\s*([^\(\s]*)/)[1]
    }
  })
}

if (Object.assign === undefined) {
  // Missing in IE
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
  (function () {
    Object.assign = function (target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert undefined or null to object')
      }
      var output = Object(target)
      for (var index = 1; index < arguments.length; index++) {
        var source = arguments[index]
        if (source !== undefined && source !== null) {
          for (var nextKey in source) {
            if (Object.prototype.hasOwnProperty.call(source, nextKey)) {
              output[nextKey] = source[nextKey]
            }
          }
        }
      }
      return output
    }
  })()
}

// performance.now()
if (runtime.isBrowser) {

  // browser polyfill
  // inspired by:
  // https://gist.github.com/paulirish/5438650
  // note: if we need performance.mark and other methods we might want to replace this with:
  // https://www.npmjs.com/package/performance-polyfill
  if (!window.performance) {
    window.performance = {}
  }
  if (!window.performance.now){
    var navigationStart = performance.timing ? performance.timing.navigationStart : null
    var nowOffset = navigationStart || Date.now()
    window.performance.now = function now(){
      return Date.now() - nowOffset
    }
  }

} else {

  // node: use module
  global.performance = {
    now: require('performance-now')
  }

}<|endoftext|>


<commit_before>import React from 'react';

// Get all possible permutations of all power sets
//
// Super simple, non-algorithmic solution since the
// number of class names will not be greater than 3
function powerSetPermutations(arr) {
  if (arr.length === 0 || arr.length === 1) return arr;
  if (arr.length === 2) {
    // prettier-ignore
    return [
      arr[0],
      arr[1],
      `${arr[0]}.${arr[1]}`,
      `${arr[1]}.${arr[0]}`
    ];
  }
  if (arr.length >= 3) {
    // Currently does not support more than 3 extra
    // class names (after `.token` has been removed)
    return [
      arr[0],
      arr[1],
      arr[2],
      `${arr[0]}.${arr[1]}`,
      `${arr[0]}.${arr[2]}`,
      `${arr[1]}.${arr[0]}`,
      `${arr[1]}.${arr[2]}`,
      `${arr[2]}.${arr[0]}`,
      `${arr[2]}.${arr[1]}`,
      `${arr[0]}.${arr[1]}.${arr[2]}`,
      `${arr[0]}.${arr[2]}.${arr[1]}`,
      `${arr[1]}.${arr[0]}.${arr[2]}`,
      `${arr[1]}.${arr[2]}.${arr[0]}`,
      `${arr[2]}.${arr[0]}.${arr[1]}`,
      `${arr[2]}.${arr[1]}.${arr[0]}`
    ];
  }
}

const classNameCombinations = {};
function getClassNameCombinations(classNames) {
  if (classNames.length === 0 || classNames.length === 1) return classNames;
  const key = classNames.join('.');
  if (!classNameCombinations[key]) {
    classNameCombinations[key] = powerSetPermutations(classNames);
  }
  return classNameCombinations[key];
}

export function createStyleObject(classNames, elementStyle = {}, stylesheet) {
  const nonTokenClassNames = classNames.filter(
    className => className !== 'token'
  );
  const classNamesCombinations = getClassNameCombinations(nonTokenClassNames);
  return classNamesCombinations.reduce((styleObject, className) => {
    return { ...styleObject, ...stylesheet[className] };
  }, elementStyle);
}

export function createClassNameString(classNames) {
  return classNames.join(' ');
}

export function createChildren(stylesheet, useInlineStyles) {
  let childrenCount = 0;
  return children => {
    childrenCount += 1;
    return children.map((child, i) =>
      createElement({
        node: child,
        stylesheet,
        useInlineStyles,
        key: `code-segment-${childrenCount}-${i}`
      })
    );
  };
}

export default function createElement({
  node,
  stylesheet,
  style = {},
  useInlineStyles,
  key
}) {
  const { properties, type, tagName: TagName, value } = node;
  if (type === 'text') {
    return value;
  } else if (TagName) {
    const childrenCreator = createChildren(stylesheet, useInlineStyles);

    let props;

    if (!useInlineStyles) {
      props = {
        ...properties,
        className: createClassNameString(properties.className)
      };
    } else {
      const allStylesheetSelectors = Object.keys(stylesheet).reduce(
        (classes, selector) => {
          selector.split('.').forEach(className => {
            if (!classes.includes(className)) classes.push(className);
          });
          return classes;
        },
        []
      );

      // For compatibility with older versions of react-syntax-highlighter
      const startingClassName =
        properties.className && properties.className.includes('token')
          ? ['token']
          : [];

      const className =
        properties.className &&
        startingClassName.concat(
          properties.className.filter(
            className => !allStylesheetSelectors.includes(className)
          )
        );

      props = {
        ...properties,
        className: createClassNameString(className) || undefined,
        style: createStyleObject(
          properties.className,
          Object.assign({}, properties.style, style),
          stylesheet
        )
      };
    }

    const children = childrenCreator(node.children);
    return (
      <TagName key={key} {...props}>
        {children}
      </TagName>
    );
  }
}
<commit_msg>Add fourth level of power set permutations<commit_after>import React from 'react';

// Get all possible permutations of all power sets
//
// Super simple, non-algorithmic solution since the
// number of class names will not be greater than 4
function powerSetPermutations(arr) {
  const arrLength = arr.length;
  if (arrLength === 0 || arrLength === 1) return arr;
  if (arrLength === 2) {
    // prettier-ignore
    return [
      arr[0],
      arr[1],
      `${arr[0]}.${arr[1]}`,
      `${arr[1]}.${arr[0]}`
    ];
  }
  if (arrLength === 3) {
    return [
      arr[0],
      arr[1],
      arr[2],
      `${arr[0]}.${arr[1]}`,
      `${arr[0]}.${arr[2]}`,
      `${arr[1]}.${arr[0]}`,
      `${arr[1]}.${arr[2]}`,
      `${arr[2]}.${arr[0]}`,
      `${arr[2]}.${arr[1]}`,
      `${arr[0]}.${arr[1]}.${arr[2]}`,
      `${arr[0]}.${arr[2]}.${arr[1]}`,
      `${arr[1]}.${arr[0]}.${arr[2]}`,
      `${arr[1]}.${arr[2]}.${arr[0]}`,
      `${arr[2]}.${arr[0]}.${arr[1]}`,
      `${arr[2]}.${arr[1]}.${arr[0]}`
    ];
  }
  if (arrLength >= 4) {
    // Currently does not support more than 4 extra
    // class names (after `.token` has been removed)
    return [
      arr[0],
      arr[1],
      arr[2],
      arr[3],
      `${arr[0]}.${arr[1]}`,
      `${arr[0]}.${arr[2]}`,
      `${arr[0]}.${arr[3]}`,
      `${arr[1]}.${arr[0]}`,
      `${arr[1]}.${arr[2]}`,
      `${arr[1]}.${arr[3]}`,
      `${arr[2]}.${arr[0]}`,
      `${arr[2]}.${arr[1]}`,
      `${arr[2]}.${arr[3]}`,
      `${arr[3]}.${arr[0]}`,
      `${arr[3]}.${arr[1]}`,
      `${arr[3]}.${arr[2]}`,
      `${arr[0]}.${arr[1]}.${arr[2]}`,
      `${arr[0]}.${arr[1]}.${arr[3]}`,
      `${arr[0]}.${arr[2]}.${arr[1]}`,
      `${arr[0]}.${arr[2]}.${arr[3]}`,
      `${arr[0]}.${arr[3]}.${arr[1]}`,
      `${arr[0]}.${arr[3]}.${arr[2]}`,
      `${arr[1]}.${arr[0]}.${arr[2]}`,
      `${arr[1]}.${arr[0]}.${arr[3]}`,
      `${arr[1]}.${arr[2]}.${arr[0]}`,
      `${arr[1]}.${arr[2]}.${arr[3]}`,
      `${arr[1]}.${arr[3]}.${arr[0]}`,
      `${arr[1]}.${arr[3]}.${arr[2]}`,
      `${arr[2]}.${arr[0]}.${arr[1]}`,
      `${arr[2]}.${arr[0]}.${arr[3]}`,
      `${arr[2]}.${arr[1]}.${arr[0]}`,
      `${arr[2]}.${arr[1]}.${arr[3]}`,
      `${arr[2]}.${arr[3]}.${arr[0]}`,
      `${arr[2]}.${arr[3]}.${arr[1]}`,
      `${arr[3]}.${arr[0]}.${arr[1]}`,
      `${arr[3]}.${arr[0]}.${arr[2]}`,
      `${arr[3]}.${arr[1]}.${arr[0]}`,
      `${arr[3]}.${arr[1]}.${arr[2]}`,
      `${arr[3]}.${arr[2]}.${arr[0]}`,
      `${arr[3]}.${arr[2]}.${arr[1]}`,
      `${arr[0]}.${arr[1]}.${arr[2]}.${arr[3]}`,
      `${arr[0]}.${arr[1]}.${arr[3]}.${arr[2]}`,
      `${arr[0]}.${arr[2]}.${arr[1]}.${arr[3]}`,
      `${arr[0]}.${arr[2]}.${arr[3]}.${arr[1]}`,
      `${arr[0]}.${arr[3]}.${arr[1]}.${arr[2]}`,
      `${arr[0]}.${arr[3]}.${arr[2]}.${arr[1]}`,
      `${arr[1]}.${arr[0]}.${arr[2]}.${arr[3]}`,
      `${arr[1]}.${arr[0]}.${arr[3]}.${arr[2]}`,
      `${arr[1]}.${arr[2]}.${arr[0]}.${arr[3]}`,
      `${arr[1]}.${arr[2]}.${arr[3]}.${arr[0]}`,
      `${arr[1]}.${arr[3]}.${arr[0]}.${arr[2]}`,
      `${arr[1]}.${arr[3]}.${arr[2]}.${arr[0]}`,
      `${arr[2]}.${arr[0]}.${arr[1]}.${arr[3]}`,
      `${arr[2]}.${arr[0]}.${arr[3]}.${arr[1]}`,
      `${arr[2]}.${arr[1]}.${arr[0]}.${arr[3]}`,
      `${arr[2]}.${arr[1]}.${arr[3]}.${arr[0]}`,
      `${arr[2]}.${arr[3]}.${arr[0]}.${arr[1]}`,
      `${arr[2]}.${arr[3]}.${arr[1]}.${arr[0]}`,
      `${arr[3]}.${arr[0]}.${arr[1]}.${arr[2]}`,
      `${arr[3]}.${arr[0]}.${arr[2]}.${arr[1]}`,
      `${arr[3]}.${arr[1]}.${arr[0]}.${arr[2]}`,
      `${arr[3]}.${arr[1]}.${arr[2]}.${arr[0]}`,
      `${arr[3]}.${arr[2]}.${arr[0]}.${arr[1]}`,
      `${arr[3]}.${arr[2]}.${arr[1]}.${arr[0]}`
    ];
  }
}

const classNameCombinations = {};
function getClassNameCombinations(classNames) {
  if (classNames.length === 0 || classNames.length === 1) return classNames;
  const key = classNames.join('.');
  if (!classNameCombinations[key]) {
    classNameCombinations[key] = powerSetPermutations(classNames);
  }
  return classNameCombinations[key];
}

export function createStyleObject(classNames, elementStyle = {}, stylesheet) {
  const nonTokenClassNames = classNames.filter(
    className => className !== 'token'
  );
  const classNamesCombinations = getClassNameCombinations(nonTokenClassNames);
  return classNamesCombinations.reduce((styleObject, className) => {
    return { ...styleObject, ...stylesheet[className] };
  }, elementStyle);
}

export function createClassNameString(classNames) {
  return classNames.join(' ');
}

export function createChildren(stylesheet, useInlineStyles) {
  let childrenCount = 0;
  return children => {
    childrenCount += 1;
    return children.map((child, i) =>
      createElement({
        node: child,
        stylesheet,
        useInlineStyles,
        key: `code-segment-${childrenCount}-${i}`
      })
    );
  };
}

export default function createElement({
  node,
  stylesheet,
  style = {},
  useInlineStyles,
  key
}) {
  const { properties, type, tagName: TagName, value } = node;
  if (type === 'text') {
    return value;
  } else if (TagName) {
    const childrenCreator = createChildren(stylesheet, useInlineStyles);

    let props;

    if (!useInlineStyles) {
      props = {
        ...properties,
        className: createClassNameString(properties.className)
      };
    } else {
      const allStylesheetSelectors = Object.keys(stylesheet).reduce(
        (classes, selector) => {
          selector.split('.').forEach(className => {
            if (!classes.includes(className)) classes.push(className);
          });
          return classes;
        },
        []
      );

      // For compatibility with older versions of react-syntax-highlighter
      const startingClassName =
        properties.className && properties.className.includes('token')
          ? ['token']
          : [];

      const className =
        properties.className &&
        startingClassName.concat(
          properties.className.filter(
            className => !allStylesheetSelectors.includes(className)
          )
        );

      props = {
        ...properties,
        className: createClassNameString(className) || undefined,
        style: createStyleObject(
          properties.className,
          Object.assign({}, properties.style, style),
          stylesheet
        )
      };
    }

    const children = childrenCreator(node.children);
    return (
      <TagName key={key} {...props}>
        {children}
      </TagName>
    );
  }
}
<|endoftext|>


<commit_before>import _ from 'lodash';
import * as errors from './errors';
import Debug from 'debug';
import DEFAULTS from './defaults';
import IN_BROWSER from './constants';
import onExit from './onExit';
import request from './request';
import STATUS from './status';
import WebSocket from 'ws';

const START_SUFFIX = '#s';
const CANCEL_SUFFIX = '#c'; // START_SUFFIX.length === CANCEL_SUFFIX.length

let debug = Debug('craft-ai:client');

export default function createInstance(cfg) {
  cfg = _.defaults(cfg, DEFAULTS);
  if (!_.has(cfg, 'owner') || !_.isString(cfg.owner)) {
    return Promise.reject(new errors.CraftAiBadRequestError('Bad Request, unable to create an instance with no or invalid project owner provided.'));
  }
  if (!_.has(cfg, 'name') || !_.isString(cfg.name)) {
    return Promise.reject(new errors.CraftAiBadRequestError('Bad Request, unable to create an instance with no or invalid project name provided.'));
  }
  if (!_.has(cfg, 'version') || !_.isString(cfg.version)) {
    return Promise.reject(new errors.CraftAiBadRequestError('Bad Request, unable to create an instance with no or invalid project version provided.'));
  }

  const appId = cfg.appId;
  const appSecret = cfg.appSecret;
  const wsUrl = cfg.wsApiUrl + '/' + cfg.owner + '/' + cfg.name + '/' + cfg.version;

  let instanceId;
  let status = STATUS.starting;

  let actions = {};

  let ws;

  let initWs = () => {
    ws = new WebSocket(wsUrl + '/' + instanceId + '/websockets');
    ws.onmessage = function(evt) {
      if (evt.data != 'ping') {
        const data = JSON.parse(evt.data);
        const actionName = data.call.substring(0, data.call.length - START_SUFFIX.length);
        if (_.endsWith(data.call, CANCEL_SUFFIX)) {
          actions[actionName].cancel(
            data.requestId,
            data.agentId,
            () => request({
              method: 'POST',
              path: '/' + instanceId + '/actions/' + data.requestId + '/cancelation'
            }, cfg)
          );
        }
        else if (_.endsWith(data.call, START_SUFFIX)) {
          actions[actionName].start(
            data.requestId,
            data.agentId,
            data.input,
            (output) => request({
              method: 'POST',
              path: '/' + instanceId + '/actions/' + data.requestId + '/success',
              body: output
            }, cfg),
            (output) => request({
              method: 'POST',
              path: '/' + instanceId + '/actions/' + data.requestId + '/failure',
              body: output
            }, cfg)
          );
        }
      }
      ws.send('Done');
    };
    ws.onopen = function() {
      ws.send('socket open');
    };
    ws.onclose = function() {
      status = STATUS.destroyed; // Should cleanly call destroy instead
    };
    ws.onerror = function() {
      status = STATUS.destroyed; // Should cleanly call destroy instead
    };
  };

  // Function that'll be called when the instance is destroyed.
  let cleanupDestroyOnExit = () => undefined;

  return request({
    method: 'PUT'
  }, cfg)
  .then(json => {

    status = STATUS.running;
    instanceId = json.instance.instance_id;

    debug(`Instance '${instanceId}' created from ${cfg.owner}/${cfg.name}/${cfg.version}`);

    let instance = {
      id: instanceId,
      cfg: cfg,
      getStatus: function() {
        return status;
      },
      getGoogleAuthUri: function(successUri, failureUri) {
        return cfg.hubApiUrl + '/auth/google?x-craft-ai-app-id=' +
          appId + '&x-craft-ai-app-secret=' + appSecret + '&success_uri=' +
          successUri + '&failure_uri=' + failureUri + '?failure=true';
      },
      destroy: function() {
        status = STATUS.stopping;
        return request({
          method: 'DELETE',
          path: '/'+ instanceId
        }, cfg)
        .then(() => {
          debug(`Instance '${instanceId}' destroyed`);
          cleanupDestroyOnExit();
          status = STATUS.destroyed;
        })
        .catch(err => {
          status = STATUS.destroyed;
          return Promise.reject(err);
        });
      },
      registerAction: function(name, start, cancel = () => undefined) {
        if (_.isUndefined(ws)) {
          initWs();
        }
        return request({
          method: 'PUT',
          path: '/' + instanceId + '/actions',
          body: {
            name: name,
            start: name + START_SUFFIX,
            cancel: name + CANCEL_SUFFIX
          }
        }, cfg)
        .then(() => {
          actions[name] = {
            start: start,
            cancel: cancel
          };
        });
      },
      createAgent: function(behavior, knowledge = {}) {
        if (_.isUndefined(behavior)) {
          return Promise.reject(new errors.CraftAiBadRequestError('Bad Request, unable to create an agent with no behavior provided.'));
        }

        return request({
          method: 'PUT',
          path: '/'+instanceId+'/agents',
          body: {
            behavior: behavior,
            knowledge: knowledge
          }
        }, cfg)
        .then((json) => {
          debug(`Agent #${json.agent.id} created using behavior ${behavior}`);
          return json.agent;
        });
      },
      getAgentKnowledge: function(agentId) {
        if (_.isUndefined(agentId)) {
          return Promise.reject(new errors.CraftAiBadRequestError('Bad Request, unable to retrieve agent knowledge with no agentId provided.'));
        }

        return request({
          method: 'GET',
          path: '/'+instanceId+'/agents/'+agentId+'/knowledge'
        }, cfg)
        .then(json => json.knowledge);
      },
      updateAgentKnowledge: function(agentId, knowledge={}, method='set') {
        if (_.isUndefined(agentId)) {
          return Promise.reject(new errors.CraftAiBadRequestError('Bad Request, unable to update agent knowledge with no agentId provided.'));
        }

        return request({
          method: 'POST',
          path: '/' + instanceId + '/agents/' + agentId + '/knowledge?method=' + method,
          body: knowledge
        }, cfg);
      },
      getInstanceKnowledge: function() {
        return request({
          method: 'GET',
          path: '/' + instanceId + '/instanceKnowledge'
        }, cfg)
        .then(json => json.knowledge);
      },
      updateInstanceKnowledge: function(knowledge={}, method='set') {
        return request({
          method: 'POST',
          path: '/' + instanceId + '/instanceKnowledge?method=' + method,
          body: knowledge
        }, cfg)
        .then((json)=>{
          return json;
        });
      },
      update: function(delay = undefined) {
        let singleUpdate = () => {
          return request({
            method: 'POST',
            path: '/' + instanceId + '/update',
            body: {
              ts: new Date().getTime()
            }
          }, cfg);
        };

        if (status !== STATUS.running) {
          return Promise.reject(new errors.CraftAiError('Can\'t update the instance, it is not running.'));
        }
        else if (_.isUndefined(delay)) {
          return singleUpdate();
        }
        else {
          return singleUpdate()
            .then(() => new Promise(resolve => setTimeout(resolve, delay)))
            .then(() => this.update(delay));
        }
      }
    };

    if (cfg.destroyOnExit) {
      cleanupDestroyOnExit = onExit(() => {
        if (IN_BROWSER) {
          // Using directly a XMLHttpRequest to make a synchronous call.
          let oReq = new XMLHttpRequest();
          oReq.open('DELETE', cfg.httpApiUrl + '/' + cfg.owner + '/' + cfg.name + '/' + cfg.version +  '/' + instance.id, false);
          oReq.setRequestHeader('content-type', 'application/json; charset=utf-8');
          oReq.setRequestHeader('accept', '');
          oReq.setRequestHeader('X-Craft-Ai-App-Id', appId);
          oReq.setRequestHeader('X-Craft-Ai-App-Secret', appSecret);
          instance.status = STATUS.destroyed;
          oReq.send();
          debug(`Instance '${instanceId}' destroyed`);
        }
        else {
          instance.destroy();
        }
      });
    }

    return instance;
  });
}
<commit_msg>supporting initialization of instance knowledge at creation<commit_after>import _ from 'lodash';
import * as errors from './errors';
import Debug from 'debug';
import DEFAULTS from './defaults';
import IN_BROWSER from './constants';
import onExit from './onExit';
import request from './request';
import STATUS from './status';
import WebSocket from 'ws';

const START_SUFFIX = '#s';
const CANCEL_SUFFIX = '#c'; // START_SUFFIX.length === CANCEL_SUFFIX.length

let debug = Debug('craft-ai:client');

export default function createInstance(cfg, knowledge) {
  cfg = _.defaults(cfg, DEFAULTS);
  if (!_.has(cfg, 'owner') || !_.isString(cfg.owner)) {
    return Promise.reject(new errors.CraftAiBadRequestError('Bad Request, unable to create an instance with no or invalid project owner provided.'));
  }
  if (!_.has(cfg, 'name') || !_.isString(cfg.name)) {
    return Promise.reject(new errors.CraftAiBadRequestError('Bad Request, unable to create an instance with no or invalid project name provided.'));
  }
  if (!_.has(cfg, 'version') || !_.isString(cfg.version)) {
    return Promise.reject(new errors.CraftAiBadRequestError('Bad Request, unable to create an instance with no or invalid project version provided.'));
  }

  const appId = cfg.appId;
  const appSecret = cfg.appSecret;
  const wsUrl = cfg.wsApiUrl + '/' + cfg.owner + '/' + cfg.name + '/' + cfg.version;

  let instanceId;
  let status = STATUS.starting;

  let actions = {};

  let ws;

  let initWs = () => {
    ws = new WebSocket(wsUrl + '/' + instanceId + '/websockets');
    ws.onmessage = function(evt) {
      if (evt.data != 'ping') {
        const data = JSON.parse(evt.data);
        const actionName = data.call.substring(0, data.call.length - START_SUFFIX.length);
        if (_.endsWith(data.call, CANCEL_SUFFIX)) {
          actions[actionName].cancel(
            data.requestId,
            data.agentId,
            () => request({
              method: 'POST',
              path: '/' + instanceId + '/actions/' + data.requestId + '/cancelation'
            }, cfg)
          );
        }
        else if (_.endsWith(data.call, START_SUFFIX)) {
          actions[actionName].start(
            data.requestId,
            data.agentId,
            data.input,
            (output) => request({
              method: 'POST',
              path: '/' + instanceId + '/actions/' + data.requestId + '/success',
              body: output
            }, cfg),
            (output) => request({
              method: 'POST',
              path: '/' + instanceId + '/actions/' + data.requestId + '/failure',
              body: output
            }, cfg)
          );
        }
      }
      ws.send('Done');
    };
    ws.onopen = function() {
      ws.send('socket open');
    };
    ws.onclose = function() {
      status = STATUS.destroyed; // Should cleanly call destroy instead
    };
    ws.onerror = function() {
      status = STATUS.destroyed; // Should cleanly call destroy instead
    };
  };

  // Function that'll be called when the instance is destroyed.
  let cleanupDestroyOnExit = () => undefined;

  return request({
    method: 'PUT',
    body: {
      knowledge: knowledge
    }
  }, cfg)
  .then(json => {

    status = STATUS.running;
    instanceId = json.instance.instance_id;

    debug(`Instance '${instanceId}' created from ${cfg.owner}/${cfg.name}/${cfg.version}`);

    let instance = {
      id: instanceId,
      cfg: cfg,
      getStatus: function() {
        return status;
      },
      getGoogleAuthUri: function(successUri, failureUri) {
        return cfg.hubApiUrl + '/auth/google?x-craft-ai-app-id=' +
          appId + '&x-craft-ai-app-secret=' + appSecret + '&success_uri=' +
          successUri + '&failure_uri=' + failureUri + '?failure=true';
      },
      destroy: function() {
        status = STATUS.stopping;
        return request({
          method: 'DELETE',
          path: '/'+ instanceId
        }, cfg)
        .then(() => {
          debug(`Instance '${instanceId}' destroyed`);
          cleanupDestroyOnExit();
          status = STATUS.destroyed;
        })
        .catch(err => {
          status = STATUS.destroyed;
          return Promise.reject(err);
        });
      },
      registerAction: function(name, start, cancel = () => undefined) {
        if (_.isUndefined(ws)) {
          initWs();
        }
        return request({
          method: 'PUT',
          path: '/' + instanceId + '/actions',
          body: {
            name: name,
            start: name + START_SUFFIX,
            cancel: name + CANCEL_SUFFIX
          }
        }, cfg)
        .then(() => {
          actions[name] = {
            start: start,
            cancel: cancel
          };
        });
      },
      createAgent: function(behavior, knowledge = {}) {
        if (_.isUndefined(behavior)) {
          return Promise.reject(new errors.CraftAiBadRequestError('Bad Request, unable to create an agent with no behavior provided.'));
        }

        return request({
          method: 'PUT',
          path: '/'+instanceId+'/agents',
          body: {
            behavior: behavior,
            knowledge: knowledge
          }
        }, cfg)
        .then((json) => {
          debug(`Agent #${json.agent.id} created using behavior ${behavior}`);
          return json.agent;
        });
      },
      getAgentKnowledge: function(agentId) {
        if (_.isUndefined(agentId)) {
          return Promise.reject(new errors.CraftAiBadRequestError('Bad Request, unable to retrieve agent knowledge with no agentId provided.'));
        }

        return request({
          method: 'GET',
          path: '/'+instanceId+'/agents/'+agentId+'/knowledge'
        }, cfg)
        .then(json => json.knowledge);
      },
      updateAgentKnowledge: function(agentId, knowledge={}, method='set') {
        if (_.isUndefined(agentId)) {
          return Promise.reject(new errors.CraftAiBadRequestError('Bad Request, unable to update agent knowledge with no agentId provided.'));
        }

        return request({
          method: 'POST',
          path: '/' + instanceId + '/agents/' + agentId + '/knowledge?method=' + method,
          body: knowledge
        }, cfg);
      },
      getInstanceKnowledge: function() {
        return request({
          method: 'GET',
          path: '/' + instanceId + '/instanceKnowledge'
        }, cfg)
        .then(json => json.knowledge);
      },
      updateInstanceKnowledge: function(knowledge={}, method='set') {
        return request({
          method: 'POST',
          path: '/' + instanceId + '/instanceKnowledge?method=' + method,
          body: knowledge
        }, cfg)
        .then((json)=>{
          return json;
        });
      },
      update: function(delay = undefined) {
        let singleUpdate = () => {
          return request({
            method: 'POST',
            path: '/' + instanceId + '/update',
            body: {
              ts: new Date().getTime()
            }
          }, cfg);
        };

        if (status !== STATUS.running) {
          return Promise.reject(new errors.CraftAiError('Can\'t update the instance, it is not running.'));
        }
        else if (_.isUndefined(delay)) {
          return singleUpdate();
        }
        else {
          return singleUpdate()
            .then(() => new Promise(resolve => setTimeout(resolve, delay)))
            .then(() => this.update(delay));
        }
      }
    };

    if (cfg.destroyOnExit) {
      cleanupDestroyOnExit = onExit(() => {
        if (IN_BROWSER) {
          // Using directly a XMLHttpRequest to make a synchronous call.
          let oReq = new XMLHttpRequest();
          oReq.open('DELETE', cfg.httpApiUrl + '/' + cfg.owner + '/' + cfg.name + '/' + cfg.version +  '/' + instance.id, false);
          oReq.setRequestHeader('content-type', 'application/json; charset=utf-8');
          oReq.setRequestHeader('accept', '');
          oReq.setRequestHeader('X-Craft-Ai-App-Id', appId);
          oReq.setRequestHeader('X-Craft-Ai-App-Secret', appSecret);
          instance.status = STATUS.destroyed;
          oReq.send();
          debug(`Instance '${instanceId}' destroyed`);
        }
        else {
          instance.destroy();
        }
      });
    }

    return instance;
  });
}
<|endoftext|>