<commit_before>define([
    './../core',
    '../etc/debounce'
], function (franky) {

    franky.amd.define(
        'statlog',
        function () {
            var root = null,
                clckDemonHost = 'http://clck.yandex.ru/counter',
                clckDemonPath = '/dtype=%s/session_id=%s/events=%s/*',
                params = {
                    type: 'show',
                    root: 'testRoot',
                    statDataAttr: 'statlog',
                    dataNoRedirKey: 'statlog-noredir',
                    doc: null,
                    sendAtWill: true,
                    dataReadyKey: 'statlog-ready',
                    clickEvent: 'mousedown',
                    skipVisibleCheck: false,
                    statEnabled: false,
                    clickCounter: function (path, element) {
                        element = element || null;
                        window.cp(getRoot() + '.' + path, element);
                    }
                },
                getRoot = function () {
                    return typeof Lego !== 'undefined' && Lego.params && Lego.params.statRoot ? Lego.params.statRoot : params.root;
                },
                dumpDATA = function (params) {
                    var res = [];
                    if (root) {
                        res = JSON.stringify([{
                            event: params.type,
                            "parent-path": getRoot(),
                            blocks: root.children
                        }]);
                    }
                    return res;
                },
                isEnabled = function () {
                    return typeof Lego !== 'undefined' && Lego.params ? Lego.params.statEnabled  : params.statEnabled;
                },
                handleClicks = function () {
                    // используем делегирование для обработки клика
                    $(params.doc || document).on(params.clickEvent, "*[data-" + params.statDataAttr + "]", function (e) {
                        // считаем клики только когда пользователь попадает в выборку
                        if (isEnabled()) {
                            var clickPath = $(this).data(params.statDataAttr),
                                notRedirect = $(this).data(params.dataNoRedirKey);

                            if (clickPath) {
                                params.clickCounter(clickPath, notRedirect ? null : this);

                                if (notRedirect) {
                                    e.preventDefault();
                                    e.stopPropagation();
                                }
                            }
                        }

                    });
                };

            handleClicks();

            return {
                // Для того, чтобы сторонние компоненты могли смотреть на настройки - рассказываем о них в инстансе
                params: params,

                getSingleRequest : function (data) {

                    return franky.stringf(
                        clckDemonHost + clckDemonPath,
                        data.project,
                        data.showId,
                        JSON.stringify([{
                            "event": data.event,
                            "parent-path": data.path.substr(0, data.path.lastIndexOf('.')),
                            "blocks": [{
                                ctag: data.path.substr(data.path.lastIndexOf('.') + 1)
                            }]
                        }])
                    );
                },
                singleLog: function (statPath) {
                    var url = this.getSingleRequest({
                        project: 'clck',
                        showId: this.getShowID(),
                        event: 'show',
                        path: getRoot() + '.' + statPath
                    });
                    var img = new Image();
                    img.src = url;
                },
                // Балковое логирование с использованием CORS
                bulkLog: function (/**String*/statPath) /**Object*/ {
                    var current = root ? root : root = {},
                        self = this;

                    franky.forEach(statPath.split('.'), function (key) {
                        var existFunction = function (child) {
                            return child.ctag === key;
                        };
                        if (!current.children) {
                            current.children = [];
                        }

                        var tryToGet = franky.filter(current.children, existFunction);
                        if (!tryToGet.length) {
                            current.children.push({
                                ctag: key
                            });
                        }
                        current = franky.filter(current.children, existFunction)[0];
                    });

                    if (params.sendAtWill) {
                        self.send();
                    }
                    return this;
                },
                // Логирование счетчика с заданным путем в виде аргумента
                // e.g. statlog.add('v12.head.login').
                log: function (statPath) {
                    // Для браузеров не поддерживающих балковое логирование в виде CORS запроса используем одиночные запросы
                    var logFunc = $.support.cors ? this.bulkLog : this.singleLog;

                    // проверяем наличие пути к статистике и флаг логирования
                    if (typeof statPath !== 'undefined' && isEnabled()) {
                        return logFunc.call(this, statPath);
                    }
                },
                // добавление счетчиков по результат парсинга куска DOM
                logByDocument: function (/**Object*/p) {

                    var _params = franky.beget(params, p),
                        self = this,
                        attrName = 'data-' + _params.statDataAttr,
                        dataKey = attrName.substr(5),
                        dataNoRedirKey = dataKey + '-noredir',
                        exp =  "*["+attrName+"]",
                        l = _params.doc ? $(_params.doc).find(exp) : $(exp);

                    // обходим все элементы с data-statlog - считаем их 'элементами' для обсчета статистикой
                    $(l).each(function () {
                        // проверяем состояние видимости элемента
                        if ($(this).is(':visible') || _params.skipVisibleCheck) {
                            if (!attrName.match(/^data-/)) {
                                throw new Error("data attribute expected as statAttr");
                            }

                            // забираем путь к счетчику, считая что это дата-атрибут
                            var dataPath = $(this).data(dataKey);

                            // Чтобы не считать элемент несколько раз - используем специальный флаг
                            if (!$(this).data(_params.dataReadyKey)) {

                                // складываем в хранилище логера

                                self.log(dataPath);
                                $(this).data(_params.dataReadyKey, dataPath);
                            }

                        }
                    });
                },

                // дамп залогированных счетчиков
                dumpDATA: dumpDATA,

                // Returns showID as string
                getShowID: function () /**String*/ {
                    var res = "";
                    if (typeof Lego !== 'undefined' && Lego.params && Lego.params.msid) {
                        res = Lego.params.msid;
                    }
                    return res;
                },

                // Отправка запроса в статистику
                send: franky.debounce(function () {
                    if (root) {
                        $.ajax({
                            type: "POST",
                            url: clckDemonHost,
                            data: franky.stringf(
                                clckDemonPath,
                                'clck',
                                this.getShowID(),
                                dumpDATA(params)
                            ),
                            success: function () {
                                root = null;
                            }
                        });
                    }
                }, 1000)
            };
        }
    );
});<commit_msg>move slash to host<commit_after>define([
    './../core',
    '../etc/debounce'
], function (franky) {

    franky.amd.define(
        'statlog',
        function () {
            var root = null,
                clckDemonHost = 'http://clck.yandex.ru/counter/',
                clckDemonPath = 'dtype=%s/session_id=%s/events=%s/*',
                params = {
                    type: 'show',
                    root: 'testRoot',
                    statDataAttr: 'statlog',
                    dataNoRedirKey: 'statlog-noredir',
                    doc: null,
                    sendAtWill: true,
                    dataReadyKey: 'statlog-ready',
                    clickEvent: 'mousedown',
                    skipVisibleCheck: false,
                    statEnabled: false,
                    clickCounter: function (path, element) {
                        element = element || null;
                        window.cp(getRoot() + '.' + path, element);
                    }
                },
                getRoot = function () {
                    return typeof Lego !== 'undefined' && Lego.params && Lego.params.statRoot ? Lego.params.statRoot : params.root;
                },
                dumpDATA = function (params) {
                    var res = [];
                    if (root) {
                        res = JSON.stringify([{
                            event: params.type,
                            "parent-path": getRoot(),
                            blocks: root.children
                        }]);
                    }
                    return res;
                },
                isEnabled = function () {
                    return typeof Lego !== 'undefined' && Lego.params ? Lego.params.statEnabled  : params.statEnabled;
                },
                handleClicks = function () {
                    // используем делегирование для обработки клика
                    $(params.doc || document).on(params.clickEvent, "*[data-" + params.statDataAttr + "]", function (e) {
                        // считаем клики только когда пользователь попадает в выборку
                        if (isEnabled()) {
                            var clickPath = $(this).data(params.statDataAttr),
                                notRedirect = $(this).data(params.dataNoRedirKey);

                            if (clickPath) {
                                params.clickCounter(clickPath, notRedirect ? null : this);

                                if (notRedirect) {
                                    e.preventDefault();
                                    e.stopPropagation();
                                }
                            }
                        }

                    });
                };

            handleClicks();

            return {
                // Для того, чтобы сторонние компоненты могли смотреть на настройки - рассказываем о них в инстансе
                params: params,

                getSingleRequest : function (data) {

                    return franky.stringf(
                        clckDemonHost + clckDemonPath,
                        data.project,
                        data.showId,
                        JSON.stringify([{
                            "event": data.event,
                            "parent-path": data.path.substr(0, data.path.lastIndexOf('.')),
                            "blocks": [{
                                ctag: data.path.substr(data.path.lastIndexOf('.') + 1)
                            }]
                        }])
                    );
                },
                singleLog: function (statPath) {
                    var url = this.getSingleRequest({
                        project: 'clck',
                        showId: this.getShowID(),
                        event: 'show',
                        path: getRoot() + '.' + statPath
                    });
                    var img = new Image();
                    img.src = url;
                },
                // Балковое логирование с использованием CORS
                bulkLog: function (/**String*/statPath) /**Object*/ {
                    var current = root ? root : root = {},
                        self = this;

                    franky.forEach(statPath.split('.'), function (key) {
                        var existFunction = function (child) {
                            return child.ctag === key;
                        };
                        if (!current.children) {
                            current.children = [];
                        }

                        var tryToGet = franky.filter(current.children, existFunction);
                        if (!tryToGet.length) {
                            current.children.push({
                                ctag: key
                            });
                        }
                        current = franky.filter(current.children, existFunction)[0];
                    });

                    if (params.sendAtWill) {
                        self.send();
                    }
                    return this;
                },
                // Логирование счетчика с заданным путем в виде аргумента
                // e.g. statlog.add('v12.head.login').
                log: function (statPath) {
                    // Для браузеров не поддерживающих балковое логирование в виде CORS запроса используем одиночные запросы
                    var logFunc = $.support.cors ? this.bulkLog : this.singleLog;

                    // проверяем наличие пути к статистике и флаг логирования
                    if (typeof statPath !== 'undefined' && isEnabled()) {
                        return logFunc.call(this, statPath);
                    }
                },
                // добавление счетчиков по результат парсинга куска DOM
                logByDocument: function (/**Object*/p) {

                    var _params = franky.beget(params, p),
                        self = this,
                        attrName = 'data-' + _params.statDataAttr,
                        dataKey = attrName.substr(5),
                        dataNoRedirKey = dataKey + '-noredir',
                        exp =  "*["+attrName+"]",
                        l = _params.doc ? $(_params.doc).find(exp) : $(exp);

                    // обходим все элементы с data-statlog - считаем их 'элементами' для обсчета статистикой
                    $(l).each(function () {
                        // проверяем состояние видимости элемента
                        if ($(this).is(':visible') || _params.skipVisibleCheck) {
                            if (!attrName.match(/^data-/)) {
                                throw new Error("data attribute expected as statAttr");
                            }

                            // забираем путь к счетчику, считая что это дата-атрибут
                            var dataPath = $(this).data(dataKey);

                            // Чтобы не считать элемент несколько раз - используем специальный флаг
                            if (!$(this).data(_params.dataReadyKey)) {

                                // складываем в хранилище логера

                                self.log(dataPath);
                                $(this).data(_params.dataReadyKey, dataPath);
                            }

                        }
                    });
                },

                // дамп залогированных счетчиков
                dumpDATA: dumpDATA,

                // Returns showID as string
                getShowID: function () /**String*/ {
                    var res = "";
                    if (typeof Lego !== 'undefined' && Lego.params && Lego.params.msid) {
                        res = Lego.params.msid;
                    }
                    return res;
                },

                // Отправка запроса в статистику
                send: franky.debounce(function () {
                    if (root) {
                        $.ajax({
                            type: "POST",
                            url: clckDemonHost,
                            data: franky.stringf(
                                clckDemonPath,
                                'clck',
                                this.getShowID(),
                                dumpDATA(params)
                            ),
                            success: function () {
                                root = null;
                            }
                        });
                    }
                }, 1000)
            };
        }
    );
});
<|endoftext|>


<commit_before>import 'document-register-element'

import Node from '../motor/Node'

import jss from '../jss'

const nodeList = []
let stylesheet = null

const style = {
    motorNodeElement: {
        display:         'block',
        position:        'absolute',
        top:             '0',
        left:            '0',

        // TODO: set via JavaScript. Defaults to [0.5,0.5,0.5] (the Z axis
        // doesn't apply for DOM elements, but will for 3D objects in WebGL.)
        transformOrigin: '50% 50% 0', // default

        transformStyle:  'preserve-3d',
    },
}

// Very very stupid hack needed for Safari. See
// https://github.com/google/traceur-compiler/issues/1709
if (typeof window.HTMLElement != 'function') {
    const _HTMLElement = function HTMLElement(){}
    _HTMLElement.prototype = window.HTMLElement.prototype
    window.HTMLElement = _HTMLElement
}

class MotorHTMLNode extends window.HTMLElement {
    createdCallback() {
        //console.log('<motor-node> createdCallback() with ID', this.id)
        this._attached = false
        this._cleanedUp = true
        this.node = null // to hold the imperative API Node instance.

        // XXX: "this.mountPromise" vs "this.ready":
        // "ready" seems to be more intuitive on the HTML side because
        // if the user has a reference to a motor-node or a motor-scene
        // and it exists in DOM, then it is already "mounted" from the
        // HTML API perspective. Maybe we can use "mountPromise" for
        // the imperative API, and "ready" for the HTML API. For example:
        //
        // await $('motor-scene')[0].ready // When using the HTML API
        // await node.mountPromise // When using the imperative API
        //
        // Or, maybe we can just use ".ready" in both APIs?...
        this._resolveReadyPromise = null
        this.ready = new Promise(r => this._resolveReadyPromise = r)

        nodeList.push(this)
        if (!stylesheet) {
            //console.log('Creating Node style.', this.id)
            // XXX create stylesheet inside animation frame?
            stylesheet = jss.createStyleSheet(style).attach()
        }
        this.classList.add(stylesheet.classes.motorNodeElement)
    }

    makeImperativeNode() {
        return new Node({}, this)
    }

    /**
     * Either this gets called by the imperative API when the imperative API
     * makes one of these elements, or it gets called when this element gets
     * appended to another motor-node.
     * @private
     */
    _init(imperativeMotorNode) {
        if (imperativeMotorNode && imperativeMotorNode instanceof Node)
            this.node = imperativeMotorNode
        else
            this.node = this.makeImperativeNode()

        this.signalWhenReady()
    }

    async signalWhenReady() {
        await this.node.mountPromise
        this._resolveReadyPromise()
    }

    attachedCallback() {
        //console.log('<motor-node> attachedCallback()', this.id)

        // Check that motor-nodes are mounted to motor-scenes or motor-nodes.
        // Scene can be mounted to any element. In the future we could inspect
        // the scene mount point, and advise about posisble styling issues
        // (f.e. making the scene container have a height).
        // TODO: different check needed when using is="" attributes.
        if (this.nodeName == 'MOTOR-NODE')
            if (! (this.parentNode.nodeName == 'MOTOR-NODE' || this.parentNode.nodeName == 'MOTOR-SCENE') )
                throw new Error('A <motor-node> element must be appended only to <motor-scene> or other <motor-node> elements.')

        if (!this.node)
            this._init()

        this._attached = true

        if (this._cleanedUp) {
            this._cleanedUp = false

            // make stuff here if needed.
        }

        // Attach this motor-node's Node to the parent motor-node's
        // Node (doesn't apply to motor-scene, which doesn't have a
        // parent to attach to).
        // TODO: prevent this call if attachedCallback happened to to call to
        // addChild on the imperative side.
        if (this.nodeName != 'MOTOR-SCENE')
            this.parentNode.node.addChild(this.node, true)
    }

    // TODO XXX: remove corresponding imperative Node from it's parent.
    async detachedCallback() {
        //console.log('<motor-node> detachedCallback()', this.id)
        this._attached = false

        // XXX Deferr to the next tick before cleaning up in case the element
        // is actually being re-attached somewhere else within this same tick
        // (detaching and attaching is synchronous, so by deferring to the next
        // tick we'll be able to know if the element was re-attached or not in
        // order to clean up or not). If the element gets re-attached before
        // the next tick, then we want to preserve the style sheet, preserve
        // the animation frame, and keep the scene in the sceneList by not
        // running the following this.cleanUp() call. {{
        await Promise.resolve() // deferr to the next tick.

        // If the scene wasn't re-attached in the last tick, clean up.
        // TODO (performance): Should we coordinate this.cleanUp() with
        // animation loop to prevent jank? MotorHTMLScene.cleanUp may remove a
        // JSS stylesheet. Is that something we want to do in a frame?
        if (!this._attached && !this._cleanedUp) {
            this.cleanUp()
        }

        // }}
    }

    cleanUp() {
        nodeList.pop(this)
        if (nodeList.length == 0) {
            stylesheet.detach()
            stylesheet = null
        }

        this._cleanedUp = true
    }

    attributeChangedCallback(attribute, oldValue, newValue) {

        if (!this.blah) this.blah = 0
        if (this.blah < 10) {
            this.blah += 1
            //console.log('<motor-node> attributeChangedCallback', this.id, attribute, newValue)
        }
        this.updateNodeProperty(attribute, oldValue, newValue)
    }

    updateNodeProperty(attribute, oldValue, newValue) {
        // TODO: Handle actual values (not just string property values as
        // follows) for performance; especially when DOMMatrix is supported
        // by browsers.

        // if not initialized yet, wait.
        if (!this.node) await this.ready

        // attributes on our HTML elements are the same name as those on
        // the Node class (the setters).
        if (newValue !== oldValue) {
            if (attribute.match(/opacity/i))
                this.node[attribute] = parseFloat(newValue)
            else if (attribute.match(/sizemode/i))
                this.node[attribute] = parseStringArray(newValue)
            else if (
                attribute.match(/rotation/i)
                || attribute.match(/scale/i)
                || attribute.match(/position/i)
                || attribute.match(/absoluteSize/i)
                || attribute.match(/proportionalSize/i)
                || attribute.match(/align/i)
                || attribute.match(/mountPoint/i)
                || attribute.match(/origin/i) // origin is TODO on imperative side.
            ) {
                this.node[attribute] = parseNumberArray(newValue)
            }
            else {
                /* nothing, ignore other attributes */
            }
        }
    }
}
MotorHTMLNode = document.registerElement('motor-node', MotorHTMLNode)

export default MotorHTMLNode

function parseNumberArray(str) {
    checkIsNumberArrayString(str)

    let numbers = str.split(',')

    numbers = numbers.map(num => window.parseFloat(num))
    return numbers
}

function parseStringArray(str) {
    let strings = str.split(',')
    strings = strings.map(str => str.trim())
    return strings
}

function checkIsNumberArrayString(str) {
    if (!str.match(/^\s*(-?((\d+\.\d+)|(\d+))(\s*,\s*)?){3}\s*$/g))
        throw new Error(`Invalid array. Must be an array of numbers of length 3, for example "1, 2.5,3" without brackets. Yours was ${str}.`)
}
<commit_msg>I forgot I was `npm linked` so the changes I made locally were working. Okay, this works now!<commit_after>import 'document-register-element'

import Node from '../motor/Node'

import jss from '../jss'

const nodeList = []
let stylesheet = null

const style = {
    motorNodeElement: {
        display:         'block',
        position:        'absolute',
        top:             '0',
        left:            '0',

        // TODO: set via JavaScript. Defaults to [0.5,0.5,0.5] (the Z axis
        // doesn't apply for DOM elements, but will for 3D objects in WebGL.)
        transformOrigin: '50% 50% 0', // default

        transformStyle:  'preserve-3d',
    },
}

// Very very stupid hack needed for Safari. See
// https://github.com/google/traceur-compiler/issues/1709
if (typeof window.HTMLElement != 'function') {
    const _HTMLElement = function HTMLElement(){}
    _HTMLElement.prototype = window.HTMLElement.prototype
    window.HTMLElement = _HTMLElement
}

class MotorHTMLNode extends window.HTMLElement {
    createdCallback() {
        //console.log('<motor-node> createdCallback() with ID', this.id)
        this._attached = false
        this._cleanedUp = true
        this.node = null // to hold the imperative API Node instance.

        // XXX: "this.mountPromise" vs "this.ready":
        // "ready" seems to be more intuitive on the HTML side because
        // if the user has a reference to a motor-node or a motor-scene
        // and it exists in DOM, then it is already "mounted" from the
        // HTML API perspective. Maybe we can use "mountPromise" for
        // the imperative API, and "ready" for the HTML API. For example:
        //
        // await $('motor-scene')[0].ready // When using the HTML API
        // await node.mountPromise // When using the imperative API
        //
        // Or, maybe we can just use ".ready" in both APIs?...
        this._resolveReadyPromise = null
        this.ready = new Promise(r => this._resolveReadyPromise = r)

        nodeList.push(this)
        if (!stylesheet) {
            //console.log('Creating Node style.', this.id)
            // XXX create stylesheet inside animation frame?
            stylesheet = jss.createStyleSheet(style).attach()
        }
        this.classList.add(stylesheet.classes.motorNodeElement)
    }

    makeImperativeNode() {
        return new Node({}, this)
    }

    /**
     * Either this gets called by the imperative API when the imperative API
     * makes one of these elements, or it gets called when this element gets
     * appended to another motor-node.
     * @private
     */
    _init(imperativeMotorNode) {
        if (imperativeMotorNode && imperativeMotorNode instanceof Node)
            this.node = imperativeMotorNode
        else
            this.node = this.makeImperativeNode()

        this.signalWhenReady()
    }

    async signalWhenReady() {
        await this.node.mountPromise
        this._resolveReadyPromise()
    }

    attachedCallback() {
        //console.log('<motor-node> attachedCallback()', this.id)

        // Check that motor-nodes are mounted to motor-scenes or motor-nodes.
        // Scene can be mounted to any element. In the future we could inspect
        // the scene mount point, and advise about posisble styling issues
        // (f.e. making the scene container have a height).
        // TODO: different check needed when using is="" attributes.
        if (this.nodeName == 'MOTOR-NODE')
            if (! (this.parentNode.nodeName == 'MOTOR-NODE' || this.parentNode.nodeName == 'MOTOR-SCENE') )
                throw new Error('A <motor-node> element must be appended only to <motor-scene> or other <motor-node> elements.')

        if (!this.node)
            this._init()

        this._attached = true

        if (this._cleanedUp) {
            this._cleanedUp = false

            // make stuff here if needed.
        }

        // Attach this motor-node's Node to the parent motor-node's
        // Node (doesn't apply to motor-scene, which doesn't have a
        // parent to attach to).
        // TODO: prevent this call if attachedCallback happened to to call to
        // addChild on the imperative side.
        if (this.nodeName != 'MOTOR-SCENE')
            this.parentNode.node.addChild(this.node, true)
    }

    // TODO XXX: remove corresponding imperative Node from it's parent.
    async detachedCallback() {
        //console.log('<motor-node> detachedCallback()', this.id)
        this._attached = false

        // XXX Deferr to the next tick before cleaning up in case the element
        // is actually being re-attached somewhere else within this same tick
        // (detaching and attaching is synchronous, so by deferring to the next
        // tick we'll be able to know if the element was re-attached or not in
        // order to clean up or not). If the element gets re-attached before
        // the next tick, then we want to preserve the style sheet, preserve
        // the animation frame, and keep the scene in the sceneList by not
        // running the following this.cleanUp() call. {{
        await Promise.resolve() // deferr to the next tick.

        // If the scene wasn't re-attached in the last tick, clean up.
        // TODO (performance): Should we coordinate this.cleanUp() with
        // animation loop to prevent jank? MotorHTMLScene.cleanUp may remove a
        // JSS stylesheet. Is that something we want to do in a frame?
        if (!this._attached && !this._cleanedUp) {
            this.cleanUp()
        }

        // }}
    }

    cleanUp() {
        nodeList.pop(this)
        if (nodeList.length == 0) {
            stylesheet.detach()
            stylesheet = null
        }

        this._cleanedUp = true
    }

    attributeChangedCallback(attribute, oldValue, newValue) {

        if (!this.blah) this.blah = 0
        if (this.blah < 10) {
            this.blah += 1
            //console.log('<motor-node> attributeChangedCallback', this.id, attribute, newValue)
        }
        this.updateNodeProperty(attribute, oldValue, newValue)
    }

    async updateNodeProperty(attribute, oldValue, newValue) {
        // TODO: Handle actual values (not just string property values as
        // follows) for performance; especially when DOMMatrix is supported
        // by browsers.

        // if not initialized yet, wait.
        if (!this.node) await this.ready

        // attributes on our HTML elements are the same name as those on
        // the Node class (the setters).
        if (newValue !== oldValue) {
            if (attribute.match(/opacity/i))
                this.node[attribute] = parseFloat(newValue)
            else if (attribute.match(/sizemode/i))
                this.node[attribute] = parseStringArray(newValue)
            else if (
                attribute.match(/rotation/i)
                || attribute.match(/scale/i)
                || attribute.match(/position/i)
                || attribute.match(/absoluteSize/i)
                || attribute.match(/proportionalSize/i)
                || attribute.match(/align/i)
                || attribute.match(/mountPoint/i)
                || attribute.match(/origin/i) // origin is TODO on imperative side.
            ) {
                this.node[attribute] = parseNumberArray(newValue)
            }
            else {
                /* nothing, ignore other attributes */
            }
        }
    }
}
MotorHTMLNode = document.registerElement('motor-node', MotorHTMLNode)

export default MotorHTMLNode

function parseNumberArray(str) {
    checkIsNumberArrayString(str)

    let numbers = str.split(',')

    numbers = numbers.map(num => window.parseFloat(num))
    return numbers
}

function parseStringArray(str) {
    let strings = str.split(',')
    strings = strings.map(str => str.trim())
    return strings
}

function checkIsNumberArrayString(str) {
    if (!str.match(/^\s*(-?((\d+\.\d+)|(\d+))(\s*,\s*)?){3}\s*$/g))
        throw new Error(`Invalid array. Must be an array of numbers of length 3, for example "1, 2.5,3" without brackets. Yours was ${str}.`)
}
<|endoftext|>


<commit_before>var module_accordion = 'accordion';

//required for the targeting funcitions
module = module_accordion;

moduleTargets[module] = {

	//JS hooks
	item : module+'__item',
	trigger_manual : module+'__trigger--manual',
	trigger_auto: module+'__trigger--auto',
	reference : module+'__reference',
	content : module+'__content',
	outClickSensor : module+'__outClickSensor',

	//css classes
	item_isOpen : module+'__item--isOpen-JS',
};

if ($(Hook('content')).length) {

	$(Hook('item')+'.active-trail').modAddClass('item_isOpen').children(Hook('content')).show();

	$(Hook('trigger_manual')).on('click',function(e){
		module = module_accordion;

		preventDefault(e);//ie safe prevent default

		var target = $(this).attr('href');
		var this_item = $(target).closest(Hook('item'));

		$(target).slideToggle();
		this_item.modToggleClass('item_isOpen');
	});

	$(Hook('trigger_auto')).click(function(e){
		module = module_accordion;

		preventDefault(e);//ie safe prevent default

		var target = $(this).attr('href');
		var targetContent = $(target);
		var this_item = $($(this).attr('href')).closest(Hook('item'));

		var reference = $(this).closest(Hook('reference'));

		if (targetContent.is(':visible')){
			targetContent.slideUp();
			this_item.modRemoveClass('item_isOpen');

		} else {
			reference
				.find(Hook('item'))
					.not(this_item)
					.modRemoveClass('item_isOpen')
				.children(Hook('content'))
					.filter(':visible')
					.not(target)
					.slideUp();

			this_item.modAddClass('item_isOpen');

			targetContent.slideDown();
		}

		//this_item.modToggleClass('item_isOpen');
	});

	$(Hook('outClickSensor')).outsideClick(function(){
		module = module_accordion;
		if ($(this).find(Hook('content')).eq(0).is(':visible')){
			$(this).find(Hook(['trigger_auto', 'trigger_manual'])).eq(0).click();
		}
	})
}

<commit_msg>accordion auto-trigger bug fixes<commit_after>var module_accordion = 'accordion';

//required for the targeting funcitions
module = module_accordion;

moduleTargets[module] = {

	//JS hooks
	item : module+'__item',
	trigger_manual : module+'__trigger--manual',
	trigger_auto: module+'__trigger--auto',
	reference : module+'__reference',
	content : module+'__content',
	outClickSensor : module+'__outClickSensor',

	//css classes
	item_isOpen : module+'__item--isOpen-JS',
};

if ($(Hook('content')).length) {

	$(Hook('item')+'.active-trail').modAddClass('item_isOpen').children(Hook('content')).show();

	$(Hook('trigger_manual')).on('click',function(e){
		module = module_accordion;

		preventDefault(e);//ie safe prevent default

		var target = $(this).attr('href');
		var this_item = $(target).closest(Hook('item'));

		$(target).slideToggle();
		this_item.modToggleClass('item_isOpen');
	});

	$(Hook('trigger_auto')).click(function(e){
		module = module_accordion;

		preventDefault(e);//ie safe prevent default

		var target = $(this).attr('href');
		var targetContent = $(target);
		var this_item = $($(this).attr('href')).closest(Hook('item'));

		var reference = $(this).closest(Hook('reference'));

		if (targetContent.is(':visible')){
			//hide this item
			targetContent.slideUp();
			this_item
				.modRemoveClass('item_isOpen')

				//hide it's children
				.find(Hook('item'))
					.filter(Class('item_isOpen'))
					.modRemoveClass('item_isOpen')
					.find(Hook('content'))
						.filter(':visible')
						.slideUp();

		} else {
			//hide other items
			reference
				.find(Hook('item'))
					.not(this_item)
					.not(this_item.parentsUntil(reference))
					.modRemoveClass('item_isOpen')
				.children(Hook('content'))
					.filter(':visible')
					.not(target)
					.slideUp();

			//show this item
			this_item.modAddClass('item_isOpen');
			targetContent.slideDown();
		}
	});

	$(Hook('outClickSensor')).outsideClick(function(){
		module = module_accordion;
		if ($(this).find(Hook('content')).eq(0).is(':visible')){
			$(this).find(Hook(['trigger_auto', 'trigger_manual'])).eq(0).click();
		}
	})
}

<|endoftext|>


<commit_before>'use strict';

import DateFilter from './date_filter.react';
import Icon from './icon.react';
import SelectionModule from './selection_module.react';

export default React.createClass({
    displayName: 'FilterWidget',
    propTypes: {
        filter: React.PropTypes.array.isRequired,
        filterFieldList: React.PropTypes.array.isRequired,
        index: React.PropTypes.number.isRequired,
        updateFilter: React.PropTypes.func.isRequired,
        removeFilter: React.PropTypes.func.isRequired
    },

    getDefaultProps: function() {
        return {
            sectionClassName: 'Filter-section'
        };
    },

    componentWillMount: function() {
        this.componentWillReceiveProps(this.props);
    },

    componentWillReceiveProps: function(newProps) {
        var operator = newProps.filter[0],      // name of the operator
            field = newProps.filter[1],         // id of the field
            values = null;                       // filtering value

        if (newProps.filter.length > 2) {
            values = [];

            for (var i=2; i < newProps.filter.length; i++) {
                var valuesIdx = i - 2;

                values[valuesIdx] = null;
                if (newProps.filter[i] !== null) {
                    // always cast the underlying value to a string, otherwise we get strange behavior on dealing with input
                    values[valuesIdx] = newProps.filter[i].toString();
                }
            }
        }

        // if we know what field we are filtering by we can extract the fieldDef to help us with filtering choices
        var fieldDef;
        for(var j in newProps.filterFieldList) {
            if(newProps.filterFieldList[j].id === field) {
                fieldDef = newProps.filterFieldList[j];
            }
        }

        // once we know our field we can pull out the list of possible operators to filter on
        // also, if we know the operator then we can pull out the possible values for the field (if available)
        // TODO: why is fieldValues a function of the operator?
        var operatorList = [],
            fieldValues;
        if (fieldDef) {
            for(var idx in fieldDef.operators_lookup) {
                var operatorDef = fieldDef.operators_lookup[idx];
                operatorList.push(operatorDef);

                if(operatorDef.name === operator) {
                    // this is structured strangely
                    fieldValues = operatorDef.fields[0];
                }
            }
        }

        // this converts our fieldValues into things that are safe for us to work with through HTML
        // it also filters out values like NULL which we don't want in our value options
        if (fieldValues && fieldValues.values) {
            var safeValues = [];
            for (var idx2 in fieldValues.values) {
                var fieldValue = fieldValues.values[idx2];

                var safeValue = {};
                for(var key in fieldValue) {
                    // NOTE: we specifically prevent any keys which are NULL values because those should be expressed using IS_NULL or NOT_NULL operators
                    if (fieldValue[key] !== undefined && fieldValue[key] !== null) {
                        safeValue[key] = fieldValue[key].toString();
                    }
                }

                if (Object.getOwnPropertyNames(safeValue).length > 0) {
                    safeValues.push(safeValue);
                }
            }

            fieldValues.values = safeValues;
        }

        this.setState({
            field: field,
            operator: operator,
            operatorList: operatorList,
            values: values,
            fieldValues: fieldValues,
            fieldDef: fieldDef
        });
    },

    setField: function(value, index, filterListIndex) {
        // whenever the field is set we completely clear the filter and reset it, this is because some operators and values don't
        // make sense once you've changed the field, so starting fresh is the most sensible thing to do
        if (this.state.field !== value) {
            var filter = [null, value, null];
            this.props.updateFilter(this.props.index, filter);
        }
    },

    setOperator: function(value, index, filterListIndex) {
        // different operators will lead to different filter scenarios, so handle that here
        var operatorInfo = this.state.fieldDef.operators_lookup[value];
        var filter = this.props.filter;

        if (operatorInfo.validArgumentsFilters.length !== this.props.filter.length) {
            // looks like our new filter operator expects a different length filter from our current
            filter = [];
            for(var i=0; i < operatorInfo.validArgumentsFilters.length + 2; i++) {
                filter[i] = null;
            }

            // anything after 2 positions is going to be variable
            for (var j=0; j < filter.length; j++) {
                if (this.props.filter.length >= j+1) {
                    filter[j] = this.props.filter[j];
                }
            }

            // make sure we set the updated operator
            filter[0] = value;

        } else {
            filter[0] = value;
        }

        this.props.updateFilter(this.props.index, filter);
    },

    setValue: function(value, index, filterListIndex) {
        var filter = this.props.filter;

        if (value && value.length > 0) {
            // value casting.  we need the value in the filter to be of the proper type
            if (this.state.fieldDef.base_type === "IntegerField" ||
                    this.state.fieldDef.base_type === "SmallIntegerField" ||
                    this.state.fieldDef.base_type === "BigIntegerField") {
                value = parseInt(value);
            } else if (this.state.fieldDef.base_type === "BooleanField") {
                value = (value.toLowerCase() === "true") ? true : false;
            } else if (this.state.fieldDef.base_type === "FloatField" ||
                        this.state.fieldDef.base_type === "DecimalField") {
                value = parseFloat(value);
            }

            // TODO: we may need to do some date formatting work on DateTimeField and DateField
        } else {
            value = null;
        }

        if (value !== undefined) {
            filter[index] = value;
            this.props.updateFilter(this.props.index, filter);
        }
    },

    setDateValue: function (index, date) {
        this.setValue(date.format('YYYY-MM-DD'), index, this.props.index);
    },

    setTextValue: function(index) {
        var value = this.refs.textFilterValue.getDOMNode().value;
        // we always know the index will be 2 for the value of a filter
        this.setValue(value, index, this.props.index);
    },

    removeFilterFn: function() {
        this.props.removeFilter(this.props.index);
    },

    renderFieldList: function() {
        return (

                <SelectionModule
                    action={this.setField}
                    display='name'
                    index={1}
                    items={this.props.filterFieldList}
                    placeholder="Filter by..."
                    selectedValue={this.state.field}
                    selectedKey='id'
                    isInitiallyOpen={this.state.field === null}
                    parentIndex={this.props.index}
                />

        );
    },

    renderOperatorList: function() {
        // if we don't know our field yet then don't render anything
        if (this.state.field === null) {
            return false;
        }

        return (

                <SelectionModule
                    placeholder="..."
                    items={this.state.operatorList}
                    display='verbose_name'
                    selectedValue={this.state.operator}
                    selectedKey='name'
                    index={0}
                    isInitiallyOpen={this.state.operator === null}
                    parentIndex={this.props.index}
                    action={this.setOperator}
                />

        );
    },

    renderFilterValue: function() {
        // if we don't know our field AND operator yet then don't render anything
        if (this.state.field === null || this.state.operator === null) {
            return false;
        }

        // the first 2 positions of the filter are always for fieldId + fieldOperator
        var numValues = this.props.filter.length - 2;

        var filterValueInputs = [];
        for (var i=0; i < numValues; i++) {
            var filterIndex = i + 2;
            var filterValue = this.state.values[i];

            var valueHtml;
            if(this.state.fieldValues) {
                if(this.state.fieldValues.values) {
                    valueHtml = (
                        <SelectionModule
                            action={this.setValue}
                            display='name'
                            index={filterIndex}
                            items={this.state.fieldValues.values}
                            isInitiallyOpen={filterValue === null && i === 0}
                            placeholder="..."
                            selectedValue={filterValue}
                            selectedKey='key'
                            parentIndex={filterValue}
                        />
                    );
                } else {
                    switch(this.state.fieldValues.type) {
                        case 'date':
                            valueHtml = (
                                <DateFilter
                                    date={filterValue}
                                    index={filterIndex}
                                    onChange={this.setDateValue}
                                />
                            );
                            break;
                        default:
                            valueHtml = (
                                <input
                                    className="input p1 lg-p2"
                                    type="text"
                                    value={filterValue}
                                    onChange={this.setTextValue.bind(null, filterIndex)}
                                    ref="textFilterValue"
                                    placeholder="What value?"
                                />
                            );
                    }
                }
            }

            filterValueInputs[i] = (

                    {valueHtml}

            );
        }

        return filterValueInputs;
    },

    render: function() {
        return (

                {this.renderFieldList()}
                {this.renderOperatorList()}
                {this.renderFilterValue()}

                    <Icon name='close' width="12px" height="12px" />

        );
    }
});
<commit_msg>Don't parse timestamp values into an int even if the base_type is an int<commit_after>'use strict';

import DateFilter from './date_filter.react';
import Icon from './icon.react';
import SelectionModule from './selection_module.react';

export default React.createClass({
    displayName: 'FilterWidget',
    propTypes: {
        filter: React.PropTypes.array.isRequired,
        filterFieldList: React.PropTypes.array.isRequired,
        index: React.PropTypes.number.isRequired,
        updateFilter: React.PropTypes.func.isRequired,
        removeFilter: React.PropTypes.func.isRequired
    },

    getDefaultProps: function() {
        return {
            sectionClassName: 'Filter-section'
        };
    },

    componentWillMount: function() {
        this.componentWillReceiveProps(this.props);
    },

    componentWillReceiveProps: function(newProps) {
        var operator = newProps.filter[0],      // name of the operator
            field = newProps.filter[1],         // id of the field
            values = null;                       // filtering value

        if (newProps.filter.length > 2) {
            values = [];

            for (var i=2; i < newProps.filter.length; i++) {
                var valuesIdx = i - 2;

                values[valuesIdx] = null;
                if (newProps.filter[i] !== null) {
                    // always cast the underlying value to a string, otherwise we get strange behavior on dealing with input
                    values[valuesIdx] = newProps.filter[i].toString();
                }
            }
        }

        // if we know what field we are filtering by we can extract the fieldDef to help us with filtering choices
        var fieldDef;
        for(var j in newProps.filterFieldList) {
            if(newProps.filterFieldList[j].id === field) {
                fieldDef = newProps.filterFieldList[j];
            }
        }

        // once we know our field we can pull out the list of possible operators to filter on
        // also, if we know the operator then we can pull out the possible values for the field (if available)
        // TODO: why is fieldValues a function of the operator?
        var operatorList = [],
            fieldValues;
        if (fieldDef) {
            for(var idx in fieldDef.operators_lookup) {
                var operatorDef = fieldDef.operators_lookup[idx];
                operatorList.push(operatorDef);

                if(operatorDef.name === operator) {
                    // this is structured strangely
                    fieldValues = operatorDef.fields[0];
                }
            }
        }

        // this converts our fieldValues into things that are safe for us to work with through HTML
        // it also filters out values like NULL which we don't want in our value options
        if (fieldValues && fieldValues.values) {
            var safeValues = [];
            for (var idx2 in fieldValues.values) {
                var fieldValue = fieldValues.values[idx2];

                var safeValue = {};
                for(var key in fieldValue) {
                    // NOTE: we specifically prevent any keys which are NULL values because those should be expressed using IS_NULL or NOT_NULL operators
                    if (fieldValue[key] !== undefined && fieldValue[key] !== null) {
                        safeValue[key] = fieldValue[key].toString();
                    }
                }

                if (Object.getOwnPropertyNames(safeValue).length > 0) {
                    safeValues.push(safeValue);
                }
            }

            fieldValues.values = safeValues;
        }

        this.setState({
            field: field,
            operator: operator,
            operatorList: operatorList,
            values: values,
            fieldValues: fieldValues,
            fieldDef: fieldDef
        });
    },

    setField: function(value, index, filterListIndex) {
        // whenever the field is set we completely clear the filter and reset it, this is because some operators and values don't
        // make sense once you've changed the field, so starting fresh is the most sensible thing to do
        if (this.state.field !== value) {
            var filter = [null, value, null];
            this.props.updateFilter(this.props.index, filter);
        }
    },

    setOperator: function(value, index, filterListIndex) {
        // different operators will lead to different filter scenarios, so handle that here
        var operatorInfo = this.state.fieldDef.operators_lookup[value];
        var filter = this.props.filter;

        if (operatorInfo.validArgumentsFilters.length !== this.props.filter.length) {
            // looks like our new filter operator expects a different length filter from our current
            filter = [];
            for(var i=0; i < operatorInfo.validArgumentsFilters.length + 2; i++) {
                filter[i] = null;
            }

            // anything after 2 positions is going to be variable
            for (var j=0; j < filter.length; j++) {
                if (this.props.filter.length >= j+1) {
                    filter[j] = this.props.filter[j];
                }
            }

            // make sure we set the updated operator
            filter[0] = value;

        } else {
            filter[0] = value;
        }

        this.props.updateFilter(this.props.index, filter);
    },

    setValue: function(value, index, filterListIndex) {
        var filter = this.props.filter;

        if (value && value.length > 0) {
            // value casting.  we need the value in the filter to be of the proper type
            if (this.state.fieldDef.special_type === "timestamp_milliseconds" ||
                this.state.fieldDef.special_type === "timestamp_seconds") {
            } else if (this.state.fieldDef.base_type === "IntegerField" ||
                    this.state.fieldDef.base_type === "SmallIntegerField" ||
                    this.state.fieldDef.base_type === "BigIntegerField") {
                value = parseInt(value);
            } else if (this.state.fieldDef.base_type === "BooleanField") {
                value = (value.toLowerCase() === "true") ? true : false;
            } else if (this.state.fieldDef.base_type === "FloatField" ||
                        this.state.fieldDef.base_type === "DecimalField") {
                value = parseFloat(value);
            }

            // TODO: we may need to do some date formatting work on DateTimeField and DateField
        } else {
            value = null;
        }

        if (value !== undefined) {
            filter[index] = value;
            this.props.updateFilter(this.props.index, filter);
        }
    },

    setDateValue: function (index, date) {
        this.setValue(date.format('YYYY-MM-DD'), index, this.props.index);
    },

    setTextValue: function(index) {
        var value = this.refs.textFilterValue.getDOMNode().value;
        // we always know the index will be 2 for the value of a filter
        this.setValue(value, index, this.props.index);
    },

    removeFilterFn: function() {
        this.props.removeFilter(this.props.index);
    },

    renderFieldList: function() {
        return (

                <SelectionModule
                    action={this.setField}
                    display='name'
                    index={1}
                    items={this.props.filterFieldList}
                    placeholder="Filter by..."
                    selectedValue={this.state.field}
                    selectedKey='id'
                    isInitiallyOpen={this.state.field === null}
                    parentIndex={this.props.index}
                />

        );
    },

    renderOperatorList: function() {
        // if we don't know our field yet then don't render anything
        if (this.state.field === null) {
            return false;
        }

        return (

                <SelectionModule
                    placeholder="..."
                    items={this.state.operatorList}
                    display='verbose_name'
                    selectedValue={this.state.operator}
                    selectedKey='name'
                    index={0}
                    isInitiallyOpen={this.state.operator === null}
                    parentIndex={this.props.index}
                    action={this.setOperator}
                />

        );
    },

    renderFilterValue: function() {
        // if we don't know our field AND operator yet then don't render anything
        if (this.state.field === null || this.state.operator === null) {
            return false;
        }

        // the first 2 positions of the filter are always for fieldId + fieldOperator
        var numValues = this.props.filter.length - 2;

        var filterValueInputs = [];
        for (var i=0; i < numValues; i++) {
            var filterIndex = i + 2;
            var filterValue = this.state.values[i];

            var valueHtml;
            if(this.state.fieldValues) {
                if(this.state.fieldValues.values) {
                    valueHtml = (
                        <SelectionModule
                            action={this.setValue}
                            display='name'
                            index={filterIndex}
                            items={this.state.fieldValues.values}
                            isInitiallyOpen={filterValue === null && i === 0}
                            placeholder="..."
                            selectedValue={filterValue}
                            selectedKey='key'
                            parentIndex={filterValue}
                        />
                    );
                } else {
                    switch(this.state.fieldValues.type) {
                        case 'date':
                            valueHtml = (
                                <DateFilter
                                    date={filterValue}
                                    index={filterIndex}
                                    onChange={this.setDateValue}
                                />
                            );
                            break;
                        default:
                            valueHtml = (
                                <input
                                    className="input p1 lg-p2"
                                    type="text"
                                    value={filterValue}
                                    onChange={this.setTextValue.bind(null, filterIndex)}
                                    ref="textFilterValue"
                                    placeholder="What value?"
                                />
                            );
                    }
                }
            }

            filterValueInputs[i] = (

                    {valueHtml}

            );
        }

        return filterValueInputs;
    },

    render: function() {
        return (

                {this.renderFieldList()}
                {this.renderOperatorList()}
                {this.renderFilterValue()}

                    <Icon name='close' width="12px" height="12px" />

        );
    }
});
<|endoftext|>


<commit_before>var vector = require('./vector');
var distributions = require('./distributions');

Nonparametric = function() {};

/*
 * Two-sample Kolmogorov-Smirnov test
 */

Nonparametric.kolmogorovSmirnov = function(x, y) {
	var all = new vector.Vector(x.elements.concat(y.elements)).sort();
	var ecdfx = x.ecdf(all);
	var ecdfy = y.ecdf(all);
	var d = ecdfy.subtract(ecdfx).abs().max();

	var t = d / Math.sqrt((x.length() + y.length()) / (x.length() * y.length()));
	console.log("p", new distributions.Kolmogorov().distr(t));
	console.log("d", d);

}

module.exports.Nonparametric = Nonparametric;
<commit_msg>working on Kolmogorov<commit_after>var vector = require('./vector');
var distributions = require('./distributions');

Nonparametric = function() {};

/*
 * Two-sample Kolmogorov-Smirnov test
 */

Nonparametric.kolmogorovSmirnov = function(x, y) {
	var all = new vector.Vector(x.elements.concat(y.elements)).sort();
	var ecdfx = x.ecdf(all);
	var ecdfy = y.ecdf(all);
	var d = ecdfy.subtract(ecdfx).abs().max();

	var k = sup * Math.sqrt((x.length() + y.length()) / (x.length() * y.length()));

	console.log("d", d);
	console.log("k", k);

}

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


<commit_before>var basic = require('./basic');
var prime = exports;

/**
 * Determine if number is prime.  This is far from high performance.
 *
 * @param {Number} number to evaluate
 * @return {Boolean} return true if value is prime. false otherwise.
 */
prime.simple = function (val) {
  if (val === 1) return false;
  else if (val === 2) return true;
  else if (val !== undefined) {
    var start = 1;
    var valSqrt = Math.ceil(Math.sqrt(val));
    while (++start <= valSqrt) {
      if (val % start === 0) {
        return false;
      }
    }
    return true;
  }
};

// TODO: The maximum call stack size exceeds on this call. Either resolve this
// or abolish the call.
/**
 * Using trial method, evaluate the prime factorization of a value.
 *
 * @param {Number} number to evaluate
 * @return {Array} array of prime factors for value
 */
// prime.factorization = function (num) {
//   if (num === 1) return [1];
//   var primes = [],
//       result = [];
//   loadPrimes(num, function(p) {
//     trial(num);
//   });

//   function loadPrimes (n, callback) {
//     for (var i = 0 ; i < n ; i++) {
//       if (prime.simple(i)) primes.push(i);
//     }

//     callback(primes);
//   }

//   function trial (n) {
//     var quant = Math.floor(Math.random() * primes.length),
//         temp = basic.random(primes, quant);
//     if (basic.product(temp) === num) {
//       return temp;
//     } else {
//       trial(n);
//     }
//   }
// };
<commit_msg>Working prime.factorization<commit_after>var basic = require('./basic');
var prime = exports;

/**
 * Determine if number is prime.  This is far from high performance.
 *
 * @param {Number} number to evaluate
 * @return {Boolean} return true if value is prime. false otherwise.
 */
prime.simple = function (val) {
  if (val === 1) return false;
  else if (val === 2) return true;
  else if (val !== undefined) {
    var start = 1;
    var valSqrt = Math.ceil(Math.sqrt(val));
    while (++start <= valSqrt) {
      if (val % start === 0) {
        return false;
      }
    }
    return true;
  }
};

/**
 * Using trial method, evaluate the prime factorization of a value.
 *
 * Note: incredibly slow.
 *
 * @param {Number} number to evaluate
 * @param {Number} Max number of attempts
 * @return {Array|Boolean} array of prime factors for value; false if no set was found.
 */
prime.factorization = function (num, max) {
  if (num === 1) return [1];
  if (prime.simple(num)) return [num];

  var primes = [],
      result = [],
      temp   = [1],
      quant;

  for (var i = 0 ; i < num; i++) {
    if (prime.simple(i)) primes.push(i);
  }

  while(basic.product(temp) !== num && max > 0) {
    max--;
    quant = Math.ceil(Math.random() * (primes.length-1));
    temp = basic.random(primes, quant, true);
  }

  return (max > 0 || basic.product(temp) === num) ? temp : false;
};
<|endoftext|>


<commit_before>module.exports = {
    config: require("./config")
  , loadPlugins: false
  , corePlugins: [
        "_plugin-manager",
        "_bloggify-router"
    ]
  , server: {
        errorPages: false
    }
};
<commit_msg>Added the theme and adapter configs<commit_after>module.exports = {
    config: require("./config")
  , loadPlugins: false
  , corePlugins: [
        "_plugin-manager",
        "_bloggify-router"
    ]
  , server: {
        errorPages: false
      , public: "public"
    }
  , theme: {
        ext: "ejs"
      , path: "theme"
    }
  , adapter: {
        paths: {
            articles: "content/articles"
          , pages: "content/articles"
        }
      , parse: {}
    }
};
<|endoftext|>


<commit_before>const initialState = {
  activeModal: null,
  tool: null,
  homeLocation: null,
  progress: [],
  location: null,
  expertMode: false,
  embeddedMode: false,
  locate: false,
};

export default function main(state = initialState, action) {
  switch (action.type) {
    case 'MAIN_LOAD_STATE': {
      const s = { ...state };
      const { homeLocation, expertMode } = action.payload;
      if (homeLocation && typeof homeLocation.lat === 'number' && homeLocation.lon === 'number') {
        s.homeLocation = { lat: homeLocation.lat, lon: homeLocation.lon };
      }
      s.expertMode = !!expertMode;
      return s;
    }
    case 'TRACK_VIEWER_DOWNLOAD_TRACK':
      return { ...state, tool: 'track-viewer' };
    case 'CHANGESETS_SET_DAYS':
      return { ...state, tool: 'changesets' };
    case 'SET_ACTIVE_MODAL':
      return { ...state, activeModal: action.payload };
    case 'MAP_RESET':
      return { ...state, tool: null };
    case 'SET_TOOL':
      return { ...state, tool: action.payload };
    case 'SET_HOME_LOCATION':
      return { ...state, homeLocation: { ...action.payload } };
    case 'START_PROGRESS':
      return { ...state, progress: [...state.progress, action.payload] };
    case 'STOP_PROGRESS':
      return { ...state, progress: state.progress.filter(pid => pid !== action.payload) };
    case 'SET_LOCATION':
      return { ...state, location: { lat: action.payload.lat, lon: action.payload.lon, accuracy: action.payload.accuracy } };
    case 'SET_EXPERT_MODE':
      return { ...state, expertMode: action.payload };
    case 'SET_EMBEDDED_MODE':
      return { ...state, embeddedMode: true };
    case 'LOCATE':
      return { ...state, locate: !state.locate };
    default:
      return state;
  }
}
<commit_msg>prevented setting track viewer tool from URL<commit_after>const initialState = {
  activeModal: null,
  tool: null,
  homeLocation: null,
  progress: [],
  location: null,
  expertMode: false,
  embeddedMode: false,
  locate: false,
};

export default function main(state = initialState, action) {
  switch (action.type) {
    case 'MAIN_LOAD_STATE': {
      const s = { ...state };
      const { homeLocation, expertMode } = action.payload;
      if (homeLocation && typeof homeLocation.lat === 'number' && homeLocation.lon === 'number') {
        s.homeLocation = { lat: homeLocation.lat, lon: homeLocation.lon };
      }
      s.expertMode = !!expertMode;
      return s;
    }
    case 'SET_ACTIVE_MODAL':
      return { ...state, activeModal: action.payload };
    case 'MAP_RESET':
      return { ...state, tool: null };
    case 'SET_TOOL':
      return { ...state, tool: action.payload };
    case 'SET_HOME_LOCATION':
      return { ...state, homeLocation: { ...action.payload } };
    case 'START_PROGRESS':
      return { ...state, progress: [...state.progress, action.payload] };
    case 'STOP_PROGRESS':
      return { ...state, progress: state.progress.filter(pid => pid !== action.payload) };
    case 'SET_LOCATION':
      return { ...state, location: { lat: action.payload.lat, lon: action.payload.lon, accuracy: action.payload.accuracy } };
    case 'SET_EXPERT_MODE':
      return { ...state, expertMode: action.payload };
    case 'SET_EMBEDDED_MODE':
      return { ...state, embeddedMode: true };
    case 'LOCATE':
      return { ...state, locate: !state.locate };
    default:
      return state;
  }
}
<|endoftext|>


<commit_before>
var url = require('url')

exports.request = function (req, options) {
  updateURL(options)
}

exports.response = function (req, res, options) {
  updateURL(options)
}

function updateURL (options) {
  if (typeof options.proxy === 'string') {
    options.proxy = url.parse(options.proxy)
  }

  var absolute =
    options.proxy.protocol + '//' + options.url.host + options.url.path

  options.url.path = absolute

  options.headers.set('Host', options.url.hostname)

  options.url.hostname = options.proxy.hostname
  options.url.port = options.proxy.port
}
<commit_msg>Add support for proxy authorization<commit_after>
var url = require('url')
var querystring = require('querystring')

exports.request = function (req, options) {
  updateURL(options)
}

exports.response = function (req, res, options) {
  updateURL(options)
}

function updateURL (options) {
  if (typeof options.proxy === 'string') {
    options.proxy = url.parse(options.proxy)
  }

  var absolute =
    options.proxy.protocol + '//' + options.url.host + options.url.path

  options.url.path = absolute

  options.headers.set('Host', options.url.hostname)

  options.url.hostname = options.proxy.hostname
  options.url.port = options.proxy.port

  if (options.proxy.auth && !options.headers.get('proxy-authorization')) {
    setAuthorization(options)
  }
}

function setAuthorization (options) {
  var proxyAuthPieces = options.proxy.auth.split(':').map(function (item) {
    return querystring.unescape(item)
  })
  var authHeader = 'Basic ' + toBase64(proxyAuthPieces.join(':'))
  options.headers.set('proxy-authorization', authHeader)
}

function toBase64 (str) {
  return (new Buffer(str || '', 'utf8')).toString('base64')
}
<|endoftext|>


<commit_before>import {Map} from 'immutable';
import {createReducer} from 'redux-immutablejs';

const LIST_FOLDERS = 'garchen-panel/folder/LIST_FOLDERS';
const LIST_FOLDERS_SUCCESS = 'garchen-panel/folder/LIST_FOLDERS_SUCCESS';
const LIST_FOLDERS_FAIL = 'garchen-panel/folder/LIST_FOLDERS_FAIL';

const LIST_DELETED_FOLDERS = 'garchen-panel/folder/LIST_DELETED_FOLDERS';
const LIST_DELETED_FOLDERS_SUCCESS = 'garchen-panel/folder/LIST_DELETED_FOLDERS_SUCCESS';
const LIST_DELETED_FOLDERS_FAIL = 'garchen-panel/folder/LIST_DELETED_FOLDERS_FAIL';

const ADD_FOLDER = 'garchen-panel/folder/ADD_FOLDER';
const ADD_FOLDER_SUCCESS = 'garchen-panel/folder/ADD_FOLDER_SUCCESS';
const ADD_FOLDER_FAIL = 'garchen-panel/folder/ADD_FOLDER_FAIL';

const GET_FOLDER = 'garchen-panel/folder/GET_FOLDER';
const GET_FOLDER_SUCCESS = 'garchen-panel/folder/GET_FOLDER_SUCCESS';
const GET_FOLDER_FAIL = 'garchen-panel/folder/GET_FOLDER_FAIL';

const UPDATE_FOLDER = 'garchen-panel/folder/UPDATE_FOLDER';
const UPDATE_FOLDER_SUCCESS = 'garchen-panel/folder/UPDATE_FOLDER_SUCCESS';
const UPDATE_FOLDER_FAIL = 'garchen-panel/folder/UPDATE_FOLDER_FAIL';

const CHECK_FOLDER_EXISTS = 'garchen-panel/folder/CHECK_FOLDER_EXISTS';
const CHECK_FOLDER_EXISTS_SUCCESS = 'garchen-panel/folder/CHECK_FOLDER_EXISTS_SUCCESS';
const CHECK_FOLDER_EXISTS_FAIL = 'garchen-panel/folder/CHECK_FOLDER_EXISTS_FAIL';

const DELETE_FOLDERS = 'garchen-panel/folder/DELETE_FOLDERS';
const DELETE_FOLDERS_SUCCESS = 'garchen-panel/folder/DELETE_FOLDERS_SUCCESS';
const DELETE_FOLDERS_FAIL = 'garchen-panel/folder/DELETE_FOLDERS_FAIL';

const ADD_FOLDER_BY_CSV = 'garchen-panel/folder/ADD_FOLDER_BY_CSV';
const ADD_FOLDER_BY_CSV_SUCCESS = 'garchen-panel/folder/ADD_FOLDER_BY_CSV_SUCCESS';
const ADD_FOLDER_BY_CSV_FAIL = 'garchen-panel/folder/ADD_FOLDER_BY_CSV_FAIL';

const CANCEL_IMPORTING_CSV = 'garchen-panel/folder/CANCEL_IMPORTING_CSV';
const CANCEL_IMPORTING_CSV_SUCCESS = 'garchen-panel/folder/CANCEL_IMPORTING_CSV_SUCCESS';
const CANCEL_IMPORTING_CSV_FAIL = 'garchen-panel/folder/CANCEL_IMPORTING_CSV_FAIL';

const SET_IMPORTING_FOLDER_ID = 'garchen-panel/folder/SET_IMPORTING_FOLDER_ID';

const SET_DISPLAY_FOLDER_PERPAGE = 'garchen-panel/folder/SET_DISPLAY_FOLDER_PERPAGE';

const EXPORT_FOLDER_TO_CSV = 'garchen-panel/folder/EXPORT_FOLDER_TO_CSV';
const EXPORT_FOLDER_TO_CSV_SUCCESS = 'garchen-panel/folder/EXPORT_FOLDER_TO_CSV_SUCCESS';
const EXPORT_FOLDER_TO_CSV_FAIL = 'garchen-panel/folder/EXPORT_FOLDER_TO_CSV_FAIL';

const SET_IS_PROCESSING_CSV = 'garchen-panel/folder/SET_IS_PROCESSING_CSV';
const SET_IS_OPENING_DIALOG = 'garchen-panel/folder/SET_IS_OPENING_DIALOG';

const MARK_DELETED_AT_TO_FOLDERS = 'garchen-panel/folder/MARK_DELETED_AT_TO_FOLDERS';
const MARK_DELETED_AT_TO_FOLDERS_SUCCESS = 'garchen-panel/folder/MARK_DELETED_AT_TO_FOLDERS_SUCCESS';
const MARK_DELETED_AT_TO_FOLDERS_FAIL = 'garchen-panel/folder/MARK_DELETED_AT_TO_FOLDERS_FAIL';

const CLEAR_RECYCLE_BIN = 'garchen-panel/folder/CLEAR_RECYCLE_BIN';
const CLEAR_RECYCLE_BIN_SUCCESS = 'garchen-panel/folder/CLEAR_RECYCLE_BIN_SUCCESS';
const CLEAR_RECYCLE_BIN_FAIL = 'garchen-panel/folder/CLEAR_RECYCLE_BIN_FAIL';

const RESTORE_FOLDERS = 'garchen-panel/folder/RESTORE_FOLDERS';
const RESTORE_FOLDERS_SUCCESS = 'garchen-panel/folder/RESTORE_FOLDERS_SUCCESS';
const RESTORE_FOLDERS_FAIL = 'garchen-panel/folder/RESTORE_FOLDERS_FAIL';

const FOLDER_PERPAGE = 20;

const DELETED_FOLDER_PERPAGE = 20;

const initialState = Map({
  perpage: FOLDER_PERPAGE,
  folder: null,
  folders: [],
  folderCount: 0,
  isProcessingCsv: false,
  isOpeningDialog: false,
  errorCsvMessage: null,
  errorCsvMessageId: null,
  errorCsvFilename: null,
  importingFolderId: null,

  deletedFolders: [],
  deletedFolderCount: 0,
  deletedFoldersPerPage: DELETED_FOLDER_PERPAGE
});

export default createReducer(initialState, {

  [GET_FOLDER_SUCCESS]: (state, action) => {
    return state.set('folder', action.result);
  },

  [LIST_FOLDERS_SUCCESS]: (state, action) => {
    return state.set('folders', action.result.data)
      .set('folderCount', action.result.total);
  },

  [LIST_DELETED_FOLDERS_SUCCESS]: (state, action) => {
    return state.set('deletedFolders', action.result.data)
      .set('deletedFolderCount', action.result.total);
  },

  [ADD_FOLDER_BY_CSV]: (state) => {
    return state.set('errorCsvMessage', null)
      .set('isOpeningDialog', true)
      .set('errorCsvMessageId', null)
      .set('errorCsvFilename', null);
  },

  [ADD_FOLDER_BY_CSV_SUCCESS]: (state) => {
    return state.set('isProcessingCsv', false)
      .set('isOpeningDialog', false)
      .set('importingFolderId', null);
  },

  [ADD_FOLDER_BY_CSV_FAIL]: (state, action) => {
    const {messageId, filename, message} = action.error;
    return state.set('isProcessingCsv', false)
      .set('isOpeningDialog', false)
      .set('importingFolderId', null)
      .set('errorCsvMessage', message)
      .set('errorCsvMessageId', messageId)
      .set('errorCsvFilename', filename);
  },

  [CANCEL_IMPORTING_CSV_SUCCESS]: (state) => {
    return state.set('isProcessingCsv', false)
      .set('importingFolderId', null)
      .set('errorCsvMessage', null)
      .set('errorCsvMessageId', null)
      .set('errorCsvFilename', null);
  },

  [SET_IMPORTING_FOLDER_ID]: (state, action) => {
    return state.set('importingFolderId', action.folderId);
  },

  [SET_DISPLAY_FOLDER_PERPAGE]: (state, action) => {
    return state.set('perpage', action.perpage);
  },

  [SET_IS_PROCESSING_CSV]: (state, action) => {
    return state.set('isProcessingCsv', action.isProcessingCsv);
  },

  [SET_IS_OPENING_DIALOG]: (state, action) => {
    return state.set('isOpeningDialog', action.isOpeningDialog);
  }
});

export function setIsOpeningDialog(isOpeningDialog) {
  return {
    type: SET_IS_OPENING_DIALOG,
    isOpeningDialog
  };
}

export function setIsProcessingCsv(isProcessingCsv) {
  return {
    type: SET_IS_PROCESSING_CSV,
    isProcessingCsv
  };
}

export function setImportingFolderId(folderId) {
  return {
    type: SET_IMPORTING_FOLDER_ID,
    folderId
  };
}

export function getFolder(data) {
  return {
    types: [GET_FOLDER, GET_FOLDER_SUCCESS, GET_FOLDER_FAIL],
    promise: (client) => client.send('get-folder', data)
  };
}

export function listFolders(data) {
  return {
    types: [LIST_FOLDERS, LIST_FOLDERS_SUCCESS, LIST_FOLDERS_FAIL],
    promise: (client) => client.send('list-folders', data)
  };
}

export function listDeletedFolders(data) {
  data.isDeleted = true;
  return {
    types: [LIST_DELETED_FOLDERS, LIST_DELETED_FOLDERS_SUCCESS, LIST_DELETED_FOLDERS_FAIL],
    promise: (client) => client.send('list-folders', data)
  };
}

export function addFolder(data) {
  return {
    types: [ADD_FOLDER, ADD_FOLDER_SUCCESS, ADD_FOLDER_FAIL],
    promise: (client) => {
      return client.send('add-folder', data);
    }
  };
}

export function updateFolder(data) {
  return {
    types: [UPDATE_FOLDER, UPDATE_FOLDER_SUCCESS, UPDATE_FOLDER_FAIL],
    promise: (client) => {
      return client.send('update-folder', data);
    }
  };
}

export function markDeletedAtToFolders(folderIds) {
  return {
    types: [MARK_DELETED_AT_TO_FOLDERS, MARK_DELETED_AT_TO_FOLDERS_SUCCESS, MARK_DELETED_AT_TO_FOLDERS_FAIL],
    promise: (client) => {
      return client.send('mark-deleted-at-to-folders', {folderIds});
    }
  };
}

export function deleteFolders(folderIds) {
  return {
    types: [DELETE_FOLDERS, DELETE_FOLDERS_SUCCESS, DELETE_FOLDERS_FAIL],
    promise: (client) => {
      return client.send('delete-folders', {folderIds});
    }
  };
}

export function restoreFolders(folderIds) {
  return {
    types: [RESTORE_FOLDERS, RESTORE_FOLDERS_SUCCESS, RESTORE_FOLDERS_FAIL],
    promise: (client) => {
      return client.send('restore-folders', {folderIds});
    }
  };
}

export function checkFolderExists(data) {
  return {
    types: [CHECK_FOLDER_EXISTS, CHECK_FOLDER_EXISTS_SUCCESS, CHECK_FOLDER_EXISTS_FAIL],
    promise: (client) => {
      return client.send('check-folder-exists', data);
    }
  };
}

export function cancelImportingCsv() {
  return {
    types: [CANCEL_IMPORTING_CSV, CANCEL_IMPORTING_CSV_SUCCESS, CANCEL_IMPORTING_CSV_FAIL],
    promise: (client) => {
      return client.send('cancel-importing-csv');
    }
  };
}

export function addFolderByCsv(writeDelay) {
  return {
    types: [ADD_FOLDER_BY_CSV, ADD_FOLDER_BY_CSV_SUCCESS, ADD_FOLDER_BY_CSV_FAIL],
    promise: (client) => {
      return client.send('add-folder-by-csv', {writeDelay});
    }
  };
}

export function setDisplayFolderPerPage(perpage) {
  return {
    type: SET_DISPLAY_FOLDER_PERPAGE,
    perpage
  };
}

export function exportFolderToCsv(folderId) {
  return {
    types: [EXPORT_FOLDER_TO_CSV, EXPORT_FOLDER_TO_CSV_SUCCESS, EXPORT_FOLDER_TO_CSV_FAIL],
    promise: (client) => {
      return client.send('export-folder-to-csv', {folderId});
    }
  };
}

export function clearRecycleBin() {
  return {
    types: [CLEAR_RECYCLE_BIN, CLEAR_RECYCLE_BIN_SUCCESS, CLEAR_RECYCLE_BIN_FAIL],
    promise: (client) => {
      return client.send('clear-recycle-bin');
    }
  };
}
<commit_msg>set default DELETED_FOLDER_PERPAGE to 10<commit_after>import {Map} from 'immutable';
import {createReducer} from 'redux-immutablejs';

const LIST_FOLDERS = 'garchen-panel/folder/LIST_FOLDERS';
const LIST_FOLDERS_SUCCESS = 'garchen-panel/folder/LIST_FOLDERS_SUCCESS';
const LIST_FOLDERS_FAIL = 'garchen-panel/folder/LIST_FOLDERS_FAIL';

const LIST_DELETED_FOLDERS = 'garchen-panel/folder/LIST_DELETED_FOLDERS';
const LIST_DELETED_FOLDERS_SUCCESS = 'garchen-panel/folder/LIST_DELETED_FOLDERS_SUCCESS';
const LIST_DELETED_FOLDERS_FAIL = 'garchen-panel/folder/LIST_DELETED_FOLDERS_FAIL';

const ADD_FOLDER = 'garchen-panel/folder/ADD_FOLDER';
const ADD_FOLDER_SUCCESS = 'garchen-panel/folder/ADD_FOLDER_SUCCESS';
const ADD_FOLDER_FAIL = 'garchen-panel/folder/ADD_FOLDER_FAIL';

const GET_FOLDER = 'garchen-panel/folder/GET_FOLDER';
const GET_FOLDER_SUCCESS = 'garchen-panel/folder/GET_FOLDER_SUCCESS';
const GET_FOLDER_FAIL = 'garchen-panel/folder/GET_FOLDER_FAIL';

const UPDATE_FOLDER = 'garchen-panel/folder/UPDATE_FOLDER';
const UPDATE_FOLDER_SUCCESS = 'garchen-panel/folder/UPDATE_FOLDER_SUCCESS';
const UPDATE_FOLDER_FAIL = 'garchen-panel/folder/UPDATE_FOLDER_FAIL';

const CHECK_FOLDER_EXISTS = 'garchen-panel/folder/CHECK_FOLDER_EXISTS';
const CHECK_FOLDER_EXISTS_SUCCESS = 'garchen-panel/folder/CHECK_FOLDER_EXISTS_SUCCESS';
const CHECK_FOLDER_EXISTS_FAIL = 'garchen-panel/folder/CHECK_FOLDER_EXISTS_FAIL';

const DELETE_FOLDERS = 'garchen-panel/folder/DELETE_FOLDERS';
const DELETE_FOLDERS_SUCCESS = 'garchen-panel/folder/DELETE_FOLDERS_SUCCESS';
const DELETE_FOLDERS_FAIL = 'garchen-panel/folder/DELETE_FOLDERS_FAIL';

const ADD_FOLDER_BY_CSV = 'garchen-panel/folder/ADD_FOLDER_BY_CSV';
const ADD_FOLDER_BY_CSV_SUCCESS = 'garchen-panel/folder/ADD_FOLDER_BY_CSV_SUCCESS';
const ADD_FOLDER_BY_CSV_FAIL = 'garchen-panel/folder/ADD_FOLDER_BY_CSV_FAIL';

const CANCEL_IMPORTING_CSV = 'garchen-panel/folder/CANCEL_IMPORTING_CSV';
const CANCEL_IMPORTING_CSV_SUCCESS = 'garchen-panel/folder/CANCEL_IMPORTING_CSV_SUCCESS';
const CANCEL_IMPORTING_CSV_FAIL = 'garchen-panel/folder/CANCEL_IMPORTING_CSV_FAIL';

const SET_IMPORTING_FOLDER_ID = 'garchen-panel/folder/SET_IMPORTING_FOLDER_ID';

const SET_DISPLAY_FOLDER_PERPAGE = 'garchen-panel/folder/SET_DISPLAY_FOLDER_PERPAGE';

const EXPORT_FOLDER_TO_CSV = 'garchen-panel/folder/EXPORT_FOLDER_TO_CSV';
const EXPORT_FOLDER_TO_CSV_SUCCESS = 'garchen-panel/folder/EXPORT_FOLDER_TO_CSV_SUCCESS';
const EXPORT_FOLDER_TO_CSV_FAIL = 'garchen-panel/folder/EXPORT_FOLDER_TO_CSV_FAIL';

const SET_IS_PROCESSING_CSV = 'garchen-panel/folder/SET_IS_PROCESSING_CSV';
const SET_IS_OPENING_DIALOG = 'garchen-panel/folder/SET_IS_OPENING_DIALOG';

const MARK_DELETED_AT_TO_FOLDERS = 'garchen-panel/folder/MARK_DELETED_AT_TO_FOLDERS';
const MARK_DELETED_AT_TO_FOLDERS_SUCCESS = 'garchen-panel/folder/MARK_DELETED_AT_TO_FOLDERS_SUCCESS';
const MARK_DELETED_AT_TO_FOLDERS_FAIL = 'garchen-panel/folder/MARK_DELETED_AT_TO_FOLDERS_FAIL';

const CLEAR_RECYCLE_BIN = 'garchen-panel/folder/CLEAR_RECYCLE_BIN';
const CLEAR_RECYCLE_BIN_SUCCESS = 'garchen-panel/folder/CLEAR_RECYCLE_BIN_SUCCESS';
const CLEAR_RECYCLE_BIN_FAIL = 'garchen-panel/folder/CLEAR_RECYCLE_BIN_FAIL';

const RESTORE_FOLDERS = 'garchen-panel/folder/RESTORE_FOLDERS';
const RESTORE_FOLDERS_SUCCESS = 'garchen-panel/folder/RESTORE_FOLDERS_SUCCESS';
const RESTORE_FOLDERS_FAIL = 'garchen-panel/folder/RESTORE_FOLDERS_FAIL';

const FOLDER_PERPAGE = 20;

const DELETED_FOLDER_PERPAGE = 10;

const initialState = Map({
  perpage: FOLDER_PERPAGE,
  folder: null,
  folders: [],
  folderCount: 0,
  isProcessingCsv: false,
  isOpeningDialog: false,
  errorCsvMessage: null,
  errorCsvMessageId: null,
  errorCsvFilename: null,
  importingFolderId: null,

  deletedFolders: [],
  deletedFolderCount: 0,
  deletedFoldersPerPage: DELETED_FOLDER_PERPAGE
});

export default createReducer(initialState, {

  [GET_FOLDER_SUCCESS]: (state, action) => {
    return state.set('folder', action.result);
  },

  [LIST_FOLDERS_SUCCESS]: (state, action) => {
    return state.set('folders', action.result.data)
      .set('folderCount', action.result.total);
  },

  [LIST_DELETED_FOLDERS_SUCCESS]: (state, action) => {
    return state.set('deletedFolders', action.result.data)
      .set('deletedFolderCount', action.result.total);
  },

  [ADD_FOLDER_BY_CSV]: (state) => {
    return state.set('errorCsvMessage', null)
      .set('isOpeningDialog', true)
      .set('errorCsvMessageId', null)
      .set('errorCsvFilename', null);
  },

  [ADD_FOLDER_BY_CSV_SUCCESS]: (state) => {
    return state.set('isProcessingCsv', false)
      .set('isOpeningDialog', false)
      .set('importingFolderId', null);
  },

  [ADD_FOLDER_BY_CSV_FAIL]: (state, action) => {
    const {messageId, filename, message} = action.error;
    return state.set('isProcessingCsv', false)
      .set('isOpeningDialog', false)
      .set('importingFolderId', null)
      .set('errorCsvMessage', message)
      .set('errorCsvMessageId', messageId)
      .set('errorCsvFilename', filename);
  },

  [CANCEL_IMPORTING_CSV_SUCCESS]: (state) => {
    return state.set('isProcessingCsv', false)
      .set('importingFolderId', null)
      .set('errorCsvMessage', null)
      .set('errorCsvMessageId', null)
      .set('errorCsvFilename', null);
  },

  [SET_IMPORTING_FOLDER_ID]: (state, action) => {
    return state.set('importingFolderId', action.folderId);
  },

  [SET_DISPLAY_FOLDER_PERPAGE]: (state, action) => {
    return state.set('perpage', action.perpage);
  },

  [SET_IS_PROCESSING_CSV]: (state, action) => {
    return state.set('isProcessingCsv', action.isProcessingCsv);
  },

  [SET_IS_OPENING_DIALOG]: (state, action) => {
    return state.set('isOpeningDialog', action.isOpeningDialog);
  }
});

export function setIsOpeningDialog(isOpeningDialog) {
  return {
    type: SET_IS_OPENING_DIALOG,
    isOpeningDialog
  };
}

export function setIsProcessingCsv(isProcessingCsv) {
  return {
    type: SET_IS_PROCESSING_CSV,
    isProcessingCsv
  };
}

export function setImportingFolderId(folderId) {
  return {
    type: SET_IMPORTING_FOLDER_ID,
    folderId
  };
}

export function getFolder(data) {
  return {
    types: [GET_FOLDER, GET_FOLDER_SUCCESS, GET_FOLDER_FAIL],
    promise: (client) => client.send('get-folder', data)
  };
}

export function listFolders(data) {
  return {
    types: [LIST_FOLDERS, LIST_FOLDERS_SUCCESS, LIST_FOLDERS_FAIL],
    promise: (client) => client.send('list-folders', data)
  };
}

export function listDeletedFolders(data) {
  data.isDeleted = true;
  return {
    types: [LIST_DELETED_FOLDERS, LIST_DELETED_FOLDERS_SUCCESS, LIST_DELETED_FOLDERS_FAIL],
    promise: (client) => client.send('list-folders', data)
  };
}

export function addFolder(data) {
  return {
    types: [ADD_FOLDER, ADD_FOLDER_SUCCESS, ADD_FOLDER_FAIL],
    promise: (client) => {
      return client.send('add-folder', data);
    }
  };
}

export function updateFolder(data) {
  return {
    types: [UPDATE_FOLDER, UPDATE_FOLDER_SUCCESS, UPDATE_FOLDER_FAIL],
    promise: (client) => {
      return client.send('update-folder', data);
    }
  };
}

export function markDeletedAtToFolders(folderIds) {
  return {
    types: [MARK_DELETED_AT_TO_FOLDERS, MARK_DELETED_AT_TO_FOLDERS_SUCCESS, MARK_DELETED_AT_TO_FOLDERS_FAIL],
    promise: (client) => {
      return client.send('mark-deleted-at-to-folders', {folderIds});
    }
  };
}

export function deleteFolders(folderIds) {
  return {
    types: [DELETE_FOLDERS, DELETE_FOLDERS_SUCCESS, DELETE_FOLDERS_FAIL],
    promise: (client) => {
      return client.send('delete-folders', {folderIds});
    }
  };
}

export function restoreFolders(folderIds) {
  return {
    types: [RESTORE_FOLDERS, RESTORE_FOLDERS_SUCCESS, RESTORE_FOLDERS_FAIL],
    promise: (client) => {
      return client.send('restore-folders', {folderIds});
    }
  };
}

export function checkFolderExists(data) {
  return {
    types: [CHECK_FOLDER_EXISTS, CHECK_FOLDER_EXISTS_SUCCESS, CHECK_FOLDER_EXISTS_FAIL],
    promise: (client) => {
      return client.send('check-folder-exists', data);
    }
  };
}

export function cancelImportingCsv() {
  return {
    types: [CANCEL_IMPORTING_CSV, CANCEL_IMPORTING_CSV_SUCCESS, CANCEL_IMPORTING_CSV_FAIL],
    promise: (client) => {
      return client.send('cancel-importing-csv');
    }
  };
}

export function addFolderByCsv(writeDelay) {
  return {
    types: [ADD_FOLDER_BY_CSV, ADD_FOLDER_BY_CSV_SUCCESS, ADD_FOLDER_BY_CSV_FAIL],
    promise: (client) => {
      return client.send('add-folder-by-csv', {writeDelay});
    }
  };
}

export function setDisplayFolderPerPage(perpage) {
  return {
    type: SET_DISPLAY_FOLDER_PERPAGE,
    perpage
  };
}

export function exportFolderToCsv(folderId) {
  return {
    types: [EXPORT_FOLDER_TO_CSV, EXPORT_FOLDER_TO_CSV_SUCCESS, EXPORT_FOLDER_TO_CSV_FAIL],
    promise: (client) => {
      return client.send('export-folder-to-csv', {folderId});
    }
  };
}

export function clearRecycleBin() {
  return {
    types: [CLEAR_RECYCLE_BIN, CLEAR_RECYCLE_BIN_SUCCESS, CLEAR_RECYCLE_BIN_FAIL],
    promise: (client) => {
      return client.send('clear-recycle-bin');
    }
  };
}
<|endoftext|>


<commit_before>var elf       = require ( "../runtime/runtime" )
  , ParserDSL = require ( "./dsl"              )
  , ParserAPI = require ( "./api"              )
  , AST       = require ( "./ast"              )
  ;

var Parser = elf.Object.clone(function () {
  this.extend(ParserAPI);
  this.extend(ParserDSL)

  this.keywords.push("symbol_table")
  this.symbol_table = require("./symbol_table.js");

  this.init = function () {
    this.symbol_table = this.symbol_table.clone();
    this.prefix( "(literal)", function (token) { return token; } );
    this.prefix( "(name)"   , function (token) { return token; } );
    this.prefix ("(", function (node) {
      var expr = this.expression();
      this.advance(")");
      return expr;
    });
    this.symbol( "(error)" );
  }

  this.parse = function (source, lexer) {
    this.tokens = arguments.length === 1 ? source : lexer.lex(source);
    this.advance();

    var stmts = this.statements();
    if (this.token.type === "(eof)") this.advance("(eof)");

    return AST.create(stmts);
  };

  this.borrow = function (obj) {
    var symbols = Array.prototype.slice.call(arguments, 1);

    symbols.forEach(function (symbol_name) {
      this.symbol_table.symbols[symbol_name] = obj.symbol_table.symbols[symbol_name]
    }.bind(this));
  };

  this.extended = function (extendee) {
    this.symbol_table.symbols.slots().forEach(function (symbol_name) {
      extendee.symbol_table.symbols[symbol_name] = this.symbol_table.symbols[symbol_name]
    }.bind(this));
  };

  this._type = "Parser";
});

module.exports = Parser;<commit_msg>simplified the parsers extended hook<commit_after>var elf       = require ( "../runtime/runtime" )
  , ParserDSL = require ( "./dsl"              )
  , ParserAPI = require ( "./api"              )
  , AST       = require ( "./ast"              )
  ;

var Parser = elf.Object.clone(function () {
  this.extend(ParserAPI);
  this.extend(ParserDSL)

  this.keywords.push("symbol_table")
  this.symbol_table = require("./symbol_table.js");

  this.init = function () {
    this.symbol_table = this.symbol_table.clone();
    this.prefix( "(literal)", function (token) { return token; } );
    this.prefix( "(name)"   , function (token) { return token; } );
    this.prefix ("(", function (node) {
      var expr = this.expression();
      this.advance(")");
      return expr;
    });
    this.symbol( "(error)" );
  }

  this.parse = function (source, lexer) {
    this.tokens = arguments.length === 1 ? source : lexer.lex(source);
    this.advance();

    var stmts = this.statements();
    if (this.token.type === "(eof)") this.advance("(eof)");

    return AST.create(stmts);
  };

  this.borrow = function (obj) {
    var symbols = Array.prototype.slice.call(arguments, 1);

    symbols.forEach(function (symbol_name) {
      this.symbol_table.symbols[symbol_name] = obj.symbol_table.symbols[symbol_name]
    }.bind(this));
  };

  this.extended = function (extendee) {
    extendee.symbol_table = this.symbol_table.clone();
  };

  this._type = "Parser";
});

module.exports = Parser;<|endoftext|>


<commit_before>/*
 * grunticon
 * https://github.com/filamentgroup/grunticon
 *
 * Copyright (c) 2012 Scott Jehl, Filament Group, Inc
 * Licensed under the MIT license.
 */

/*global phantom:true*/
/*global require:true*/

/*
phantom args sent from grunticon.js:
	[0] - input directory path
	[1] - output directory path
	[2] - png folder name
	[3] - default width
	[4] - default height
*/

(function(){
	"use strict";

	var system = require("system");
	var fs = require( "fs" );

	phantom.onError = function(msg, trace) {
		var msgStack = ['PHANTOM ERROR: ' + msg];
		if (trace && trace.length) {
			msgStack.push('TRACE:');
			trace.forEach(function(t) {
				msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line + (t.function ? ' (in function ' + t.function +')' : ''));
			});
		}
		system.stderr.write( msgStack.join('\n') );
		phantom.exit(1);
	};

	var RSVP = require('./rsvp');
	var processor = require('./processor');

	var options = {
		inputdir: phantom.args[0],
		dest: phantom.args[1],
		pngout:  phantom.args[2],
		defaultWidth: phantom.args[3],
		defaultHeight: phantom.args[4]
	};

	if( fs.isDirectory( options.inputdir ) && !options.inputdir.match( fs.separator + '$' ) ){
		options.inputdir += fs.separator;
	}
	if( !options.dest.match( fs.separator + '$' ) ){
		options.dest += fs.separator;
	}
	if( options.pngout !== undefined && options.pngout !== "" && !options.pngout.match( fs.separator + '$' ) ){
		options.pngout += fs.separator;
	}

	var files;

	if( fs.isDirectory( options.inputdir ) ){
		files = fs.list( options.inputdir );
	} else {
		var filenameArr = options.inputdir.split( fs.separator );
		var filename = filenameArr[ filenameArr.length - 1 ];
		filenameArr.pop();
		if( !fs.exists( options.inputdir ) ){
			throw new Error( "File doesn't exist: " + filename );
		}
		options.inputdir = filenameArr.join( fs.separator ) + fs.separator;
		files = [ filename ];
	}

	files = files.filter( function( file ){
		var svgRegex = /\.svg$/i,
			pngRegex = /\.png$/i,
			isSvg = file.match( svgRegex ),
			isPng = file.match( pngRegex );

		return isSvg || isPng;
	});

	var promises = files.map( function( file ){
		return processor.processFile( options.inputdir + file, options );
	});

	RSVP.all( promises )
	.then( function(){
		phantom.exit();
	})
	.catch(function(err){
		throw new Error( err );
	});
})();
<commit_msg>Error catching via RSVP<commit_after>/*
 * grunticon
 * https://github.com/filamentgroup/grunticon
 *
 * Copyright (c) 2012 Scott Jehl, Filament Group, Inc
 * Licensed under the MIT license.
 */

/*global phantom:true*/
/*global require:true*/

/*
phantom args sent from grunticon.js:
	[0] - input directory path
	[1] - output directory path
	[2] - png folder name
	[3] - default width
	[4] - default height
*/

(function(){
	"use strict";

	var system = require("system");
	var fs = require( "fs" );

	phantom.onError = function(msg, trace) {
		var msgStack = ['PHANTOM ERROR: ' + msg];
		if (trace && trace.length) {
			msgStack.push('TRACE:');
			trace.forEach(function(t) {
				msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line + (t.function ? ' (in function ' + t.function +')' : ''));
			});
		}
		system.stderr.write( msgStack.join('\n') );
		phantom.exit(1);
	};

	var RSVP = require('./rsvp');
	var processor = require('./processor');

	RSVP.on('error', function(reason) {
		throw new Error( reason );
	});

	var options = {
		inputdir: phantom.args[0],
		dest: phantom.args[1],
		pngout:  phantom.args[2],
		defaultWidth: phantom.args[3],
		defaultHeight: phantom.args[4]
	};

	if( fs.isDirectory( options.inputdir ) && !options.inputdir.match( fs.separator + '$' ) ){
		options.inputdir += fs.separator;
	}
	if( !options.dest.match( fs.separator + '$' ) ){
		options.dest += fs.separator;
	}
	if( options.pngout !== undefined && options.pngout !== "" && !options.pngout.match( fs.separator + '$' ) ){
		options.pngout += fs.separator;
	}

	var files;

	if( fs.isDirectory( options.inputdir ) ){
		files = fs.list( options.inputdir );
	} else {
		var filenameArr = options.inputdir.split( fs.separator );
		var filename = filenameArr[ filenameArr.length - 1 ];
		filenameArr.pop();
		if( !fs.exists( options.inputdir ) ){
			throw new Error( "File doesn't exist: " + filename );
		}
		options.inputdir = filenameArr.join( fs.separator ) + fs.separator;
		files = [ filename ];
	}

	files = files.filter( function( file ){
		var svgRegex = /\.svg$/i,
			pngRegex = /\.png$/i,
			isSvg = file.match( svgRegex ),
			isPng = file.match( pngRegex );

		return isSvg || isPng;
	});

	var promises = files.map( function( file ){
		return processor.processFile( options.inputdir + file, options );
	});

	RSVP.all( promises )
	.then( function(){
		phantom.exit();
	})
	.catch(function(err){
		throw new Error( err );
	});
})();
<|endoftext|>