<commit_before>"use strict";

require('js-ext/lib/object.js');
require('polyfill');

/**
 *
 *
 *
 * Copyright (c) 2014 ITSA - https://github.com/itsa
 * New BSD License - http://choosealicense.com/licenses/bsd-3-clause/
 *
 * @module focusmanager
 * @class FocusManager
 * @since 0.0.1
*/

var NAME = '[focusmanager]: ',
    async = require('utils').async,
    createHashMap = require('js-ext/extra/hashmap.js').createMap,
    DEFAULT_SELECTOR = 'input, button, select, textarea, .focusable',
    // SPECIAL_KEYS needs to be a native Object --> we need .some()
    SPECIAL_KEYS = {
        shift: 'shiftKey',
        ctrl: 'ctrlKey',
        cmd: 'metaKey',
        alt: 'altKey'
    },
    DEFAULT_KEYUP = 'shift+9',
    DEFAULT_KEYDOWN = '9',
    FM_SELECTION = 'fm-selection',
    FM_SELECTION_START = FM_SELECTION+'start',
    FM_SELECTION_END = FM_SELECTION+'end',
    FOCUSSED = 'focussed';

module.exports = function (window) {

    var DOCUMENT = window.document,
        nodePlugin, FocusManager, Event, nextFocusNode, searchFocusNode, markAsFocussed, getFocusManagerSelector, setupEvents;

    window._ITSAmodules || Object.protectedProp(window, '_ITSAmodules', createHashMap());

    require('window.ext')(window);
/*jshint boss:true */
    if (FocusManager=window._ITSAmodules.FocusManager) {
/*jshint boss:false */
        return FocusManager; // FocusManager was already created
    }

    nodePlugin = require('vdom')(window).Plugins.nodePlugin;
    Event = require('event-dom')(window);

    getFocusManagerSelector = function(focusContainerNode) {
        var selector = focusContainerNode.getAttr('fm-manage');
        (selector.toLowerCase()==='true') && (selector=DEFAULT_SELECTOR);
        return selector;
    };

    nextFocusNode = function(e, keyCode, actionkey, focusContainerNode, sourceNode, selector, downwards) {
        console.log(NAME+'nextFocusNode');
        var keys, lastIndex, i, specialKeysMatch, specialKey, len, enterPressedOnInput, primaryButtons,
            inputType, foundNode, formNode, primaryonenter, noloop;
        keys = actionkey.split('+');
        len = keys.length;
        lastIndex = len - 1;

        if ((keyCode===13) && (sourceNode.getTagName()==='INPUT')) {
            inputType = sourceNode.getAttr('type').toLowerCase();
            enterPressedOnInput = (inputType==='text') || (inputType==='password');
        }

        if (enterPressedOnInput) {
            // check if we need to press the primary button - if available
/*jshint boss:true */
            if ((primaryonenter=sourceNode.getAttr('fm-primaryonenter')) && (primaryonenter.toLowerCase()==='true')) {
/*jshint boss:false */
                primaryButtons = focusContainerNode.getAll('button.pure-button-primary');
                primaryButtons.some(function(buttonNode) {
                    buttonNode.matches(selector) && (foundNode=buttonNode);
                    return foundNode;
                });
                if (foundNode) {
                    async(function() {
                        Event.emit(foundNode, 'UI:click');
                        // _buttonPressed make event-dom to simulate a pressed button for 200ms
                        Event.emit(foundNode, 'UI:tap', {_buttonPressed: true});
                        // if the button is of type `submit`, then try to submit the form
                        formNode = foundNode.inside('form');
                        formNode && formNode.submit();
                    });
                    return foundNode;
                }
            }
        }
        // double == --> keyCode is number, keys is a string
        if (enterPressedOnInput || (keyCode==keys[lastIndex])) {
            // posible keyup --> check if special characters match:
            specialKeysMatch = true;
            SPECIAL_KEYS.some(function(value) {
                specialKeysMatch = !e[value];
                return !specialKeysMatch;
            });
            for (i=lastIndex-1; (i>=0) && !specialKeysMatch; i--) {
                specialKey = keys[i].toLowerCase();
                specialKeysMatch = e[SPECIAL_KEYS[specialKey]];
            }
        }
        if (specialKeysMatch) {
            noloop = focusContainerNode.getAttr('fm-noloop');
            noloop = noloop && (noloop.toLowerCase()==='true');
            if (downwards) {
                return sourceNode.next(selector) || (noloop ? sourceNode.last(selector) : sourceNode.first(selector));
            }
            else {
                return sourceNode.previous(selector) || (noloop ? sourceNode.first(selector) : sourceNode.last(selector));
            }
        }
        return false;
    };

    markAsFocussed = function(focusContainerNode, node) {
        console.log(NAME+'markAsFocussed');
        var selector = getFocusManagerSelector(focusContainerNode),
            index = focusContainerNode.getAll(selector).indexOf(node) || 0;
        // we also need to set the appropriate nodeData, so that when the itags re-render,
        // they don't reset this particular information
        focusContainerNode.getAll('[fm-lastitem]')
                          .removeAttrs(['fm-lastitem', 'tabindex'], true)
                          .removeData('fm-tabindex');

        // also store the lastitem's index --> in case the node gets removed,
        // or re-rendering itags which don't have the attribute-data.
        // otherwise, a refocus on the container will set the focus to the nearest item
        focusContainerNode.setData('fm-lastitem-bkp', index);
        node.setData('fm-tabindex', true);

        node.setAttrs([
            {name: 'tabindex', value: '0'},
            {name: 'fm-lastitem', value: true}
        ]);
    };

    searchFocusNode = function(initialNode) {
        console.log(NAME+'searchFocusNode');
        var focusContainerNode = initialNode.hasAttr('fm-manage') ? initialNode : initialNode.inside('[fm-manage]'),
            focusNode, alwaysDefault, fmAlwaysDefault, selector, allFocusableNodes, index;

        if (focusContainerNode) {
            if (initialNode.matches(getFocusManagerSelector(focusContainerNode))) {
                markAsFocussed(focusContainerNode, initialNode);
                focusNode = initialNode;
            }
            else {
                // find the right node that should get focus
/*jshint boss:true */
                alwaysDefault = ((fmAlwaysDefault=focusContainerNode.getAttr('fm-alwaysdefault')) && (fmAlwaysDefault.toLowerCase()==='true'));
/*jshint boss:false */
                alwaysDefault && (focusNode=focusContainerNode.getElement('[fm-defaultitem="true"]'));
                if (!focusNode) {
                    // search for last item
                    focusNode = focusContainerNode.getElement('[fm-lastitem="true"]');
                    if (!focusNode) {
                        // set `selector` right now: we might use it later on even when index is undefined
                        selector = getFocusManagerSelector(focusContainerNode);
                        // look at the lastitemindex of the focuscontainer
                        index = focusContainerNode.getData('fm-lastitem-bkp');
                        if (index!==undefined) {
                            allFocusableNodes = focusContainerNode.getAll(selector);
                            focusNode = allFocusableNodes[index];
                        }
                    }
                }
                // still not found and alwaysDefault was falsy: try the defualt node:
                !focusNode && !alwaysDefault && (focusNode=focusContainerNode.getElement('[fm-defaultitem="true"]'));
                // still not found: try the first focussable node (which we might find inside `allFocusableNodes`:
                !focusNode && (focusNode = allFocusableNodes ? allFocusableNodes[0] : focusContainerNode.getElement(selector));
                if (focusNode) {
                    markAsFocussed(focusContainerNode, focusNode);
                }
                else {
                    focusNode = initialNode;
                }
            }
        }
        else {
            focusNode = initialNode;
        }
        return focusNode;
    };

    setupEvents = function() {

        Event.before('keydown', function(e) {
            console.log(NAME+'before keydown-event');
            var focusContainerNode,
                sourceNode = e.target,
                node = sourceNode.getParent(),
                selector, keyCode, actionkey, focusNode;

            focusContainerNode = sourceNode.inside('[fm-manage]');
            if (focusContainerNode) {
                // key was pressed inside a focusmanagable container
                selector = getFocusManagerSelector(focusContainerNode);
                keyCode = e.keyCode;

                // first check for keydown:
                actionkey = node.getAttr('fm-keydown') || DEFAULT_KEYDOWN;
                focusNode = nextFocusNode(e, keyCode, actionkey, focusContainerNode, sourceNode, selector, true);
                if (!focusNode) {
                    // check for keyup:
                    actionkey = node.getAttr('fm-keyup') || DEFAULT_KEYUP;
                    focusNode = nextFocusNode(e, keyCode, actionkey, focusContainerNode, sourceNode, selector);
                }
                if (focusNode) {
                    e.preventDefaultContinue();
                    // prevent default action --> we just want to re-focus, but we DO want afterlisteners
                    // to be handled in the after-listener: someone else might want to halt the keydown event.
                    sourceNode.matches(selector) && (e._focusNode=focusNode);
                }
            }
        });

        Event.after('keydown', function(e) {
            console.log(NAME+'after keydown-event');
            var focusNode = e._focusNode;
            focusNode && focusNode.focus && focusNode.focus();
        });

        Event.after('blur', function(e) {
            console.log(NAME+'after blur-event');
            var node = e.target,
                body = DOCUMENT.body;
            if (node && node.removeAttr) {
                do {
                    // we also need to set the appropriate nodeData, so that when the itags re-render,
                    // they don't reset this particular information
                    node.removeData(FOCUSSED);
                    node.removeClass(FOCUSSED, null, null, true);
                    node = (node===body) ? null : node.getParent();
                } while (node);
            }
        });

        Event.after('focus', function(e) {
            console.log(NAME+'after focus-event');
            var node = e.target,
                body = DOCUMENT.body;
            if (node && node.setClass) {
                do {
                    // we also need to set the appropriate nodeData, so that when the itags re-render,
                    // they don't reset this particular information
                    node.setData(FOCUSSED, true);
                    node.setClass(FOCUSSED, null, null, true);
                    node = (node===body) ? null : node.getParent();
                } while (node);
            }
        });

        // focus-fix for keeping focus when a mouse gets down for a longer time
        Event.after(['mousedown', 'press'], function(e) {
            console.log(NAME+'after focus-event');
            var node = e.target;
            node.hasFocus() || node.focus();
        }, 'button');

        Event.after('tap', function(e) {
            console.log(NAME+'after tap-event');
            var focusNode = e.target,
                focusContainerNode;

            if (focusNode && focusNode.inside) {
                focusContainerNode = focusNode.hasAttr('fm-manage') ? focusNode : focusNode.inside('[fm-manage]');
            }
            if (focusContainerNode) {
                if ((focusNode===focusContainerNode) || !focusNode.matches(getFocusManagerSelector(focusContainerNode))) {
                    focusNode = searchFocusNode(focusNode);
                }
                if (focusNode.hasFocus()) {
                    markAsFocussed(focusContainerNode, focusNode);
                }
                else {
                    focusNode.focus();
                }
            }
        });

        Event.after(['keypress', 'mouseup', 'panup', 'mousedown', 'pandown'], function(e) {
            console.log(NAME+'after '+e.type+'-event');
            var focusContainerNode,
                sourceNode = e.target,
                selector;

            focusContainerNode = sourceNode.inside('[fm-manage]');
            if (focusContainerNode) {
                // key was pressed inside a focusmanagable container
                selector = getFocusManagerSelector(focusContainerNode);
                if (sourceNode.matches(selector)) {
                    sourceNode.setAttr(FM_SELECTION_START, sourceNode.selectionStart || '0')
                              .setAttr(FM_SELECTION_END, sourceNode.selectionEnd || '0');
                }
            }
        }, 'input[type="text"], textarea');

        Event.after('focus', function(e) {
            console.log(NAME+'after focus-event');
            var focusContainerNode,
                sourceNode = e.target,
                selector, selectionStart, selectionEnd;

            focusContainerNode = sourceNode.inside('[fm-manage]');
            if (focusContainerNode) {
                // key was pressed inside a focusmanagable container
                selector = getFocusManagerSelector(focusContainerNode);
                if (sourceNode.matches(selector)) {
                    // cautious: fm-selectionstart can be 0 --> which would lead into a falsy value
                    selectionStart = sourceNode.getAttr(FM_SELECTION_START);
                    (selectionStart===undefined) && (selectionStart=sourceNode.getValue().length);
                    selectionEnd = Math.max(sourceNode.getAttr(FM_SELECTION_END) || selectionStart, selectionStart);
                    sourceNode.selectionEnd = selectionEnd;
                    sourceNode.selectionStart = selectionStart;
                    markAsFocussed(focusContainerNode, sourceNode);
                }
            }
        }, 'input[type="text"], textarea');

    };

    setupEvents();

    window._ITSAmodules.FocusManager = FocusManager = nodePlugin.definePlugin('fm', {manage: 'true'});

    /**
     * In case of a manual focus (node.focus()) the node will fire an `manualfocus`-event
     * which can be prevented.
     * @event manualfocus
    */
    Event.defineEvent('UI:manualfocus')
         .defaultFn(function(e) {
             var leftScroll = window.getScrollLeft(),
                 topScroll = window.getScrollTop();
             e.target._focus();
             window.scrollTo(leftScroll, topScroll);
         });

    (function(HTMLElementPrototype) {

        HTMLElementPrototype._focus = HTMLElementPrototype.focus;
        HTMLElementPrototype.focus = function() {
            console.log(NAME+'focus');
            searchFocusNode(this).emit('manualfocus');
        };

    }(window.HTMLElement.prototype));

    return FocusManager;
};<commit_msg>bugfix dependency<commit_after>"use strict";

require('js-ext/lib/object.js');
require('polyfill');

/**
 *
 *
 *
 * Copyright (c) 2014 ITSA - https://github.com/itsa
 * New BSD License - http://choosealicense.com/licenses/bsd-3-clause/
 *
 * @module focusmanager
 * @class FocusManager
 * @since 0.0.1
*/

var NAME = '[focusmanager]: ',
    async = require('utils').async,
    createHashMap = require('js-ext/extra/hashmap.js').createMap,
    DEFAULT_SELECTOR = 'input, button, select, textarea, .focusable',
    // SPECIAL_KEYS needs to be a native Object --> we need .some()
    SPECIAL_KEYS = {
        shift: 'shiftKey',
        ctrl: 'ctrlKey',
        cmd: 'metaKey',
        alt: 'altKey'
    },
    DEFAULT_KEYUP = 'shift+9',
    DEFAULT_KEYDOWN = '9',
    FM_SELECTION = 'fm-selection',
    FM_SELECTION_START = FM_SELECTION+'start',
    FM_SELECTION_END = FM_SELECTION+'end',
    FOCUSSED = 'focussed';

module.exports = function (window) {

    var DOCUMENT = window.document,
        nodePlugin, FocusManager, Event, nextFocusNode, searchFocusNode, markAsFocussed, getFocusManagerSelector, setupEvents;

    window._ITSAmodules || Object.protectedProp(window, '_ITSAmodules', createHashMap());

    require('window-ext')(window);
/*jshint boss:true */
    if (FocusManager=window._ITSAmodules.FocusManager) {
/*jshint boss:false */
        return FocusManager; // FocusManager was already created
    }

    nodePlugin = require('vdom')(window).Plugins.nodePlugin;
    Event = require('event-dom')(window);

    getFocusManagerSelector = function(focusContainerNode) {
        var selector = focusContainerNode.getAttr('fm-manage');
        (selector.toLowerCase()==='true') && (selector=DEFAULT_SELECTOR);
        return selector;
    };

    nextFocusNode = function(e, keyCode, actionkey, focusContainerNode, sourceNode, selector, downwards) {
        console.log(NAME+'nextFocusNode');
        var keys, lastIndex, i, specialKeysMatch, specialKey, len, enterPressedOnInput, primaryButtons,
            inputType, foundNode, formNode, primaryonenter, noloop;
        keys = actionkey.split('+');
        len = keys.length;
        lastIndex = len - 1;

        if ((keyCode===13) && (sourceNode.getTagName()==='INPUT')) {
            inputType = sourceNode.getAttr('type').toLowerCase();
            enterPressedOnInput = (inputType==='text') || (inputType==='password');
        }

        if (enterPressedOnInput) {
            // check if we need to press the primary button - if available
/*jshint boss:true */
            if ((primaryonenter=sourceNode.getAttr('fm-primaryonenter')) && (primaryonenter.toLowerCase()==='true')) {
/*jshint boss:false */
                primaryButtons = focusContainerNode.getAll('button.pure-button-primary');
                primaryButtons.some(function(buttonNode) {
                    buttonNode.matches(selector) && (foundNode=buttonNode);
                    return foundNode;
                });
                if (foundNode) {
                    async(function() {
                        Event.emit(foundNode, 'UI:click');
                        // _buttonPressed make event-dom to simulate a pressed button for 200ms
                        Event.emit(foundNode, 'UI:tap', {_buttonPressed: true});
                        // if the button is of type `submit`, then try to submit the form
                        formNode = foundNode.inside('form');
                        formNode && formNode.submit();
                    });
                    return foundNode;
                }
            }
        }
        // double == --> keyCode is number, keys is a string
        if (enterPressedOnInput || (keyCode==keys[lastIndex])) {
            // posible keyup --> check if special characters match:
            specialKeysMatch = true;
            SPECIAL_KEYS.some(function(value) {
                specialKeysMatch = !e[value];
                return !specialKeysMatch;
            });
            for (i=lastIndex-1; (i>=0) && !specialKeysMatch; i--) {
                specialKey = keys[i].toLowerCase();
                specialKeysMatch = e[SPECIAL_KEYS[specialKey]];
            }
        }
        if (specialKeysMatch) {
            noloop = focusContainerNode.getAttr('fm-noloop');
            noloop = noloop && (noloop.toLowerCase()==='true');
            if (downwards) {
                return sourceNode.next(selector) || (noloop ? sourceNode.last(selector) : sourceNode.first(selector));
            }
            else {
                return sourceNode.previous(selector) || (noloop ? sourceNode.first(selector) : sourceNode.last(selector));
            }
        }
        return false;
    };

    markAsFocussed = function(focusContainerNode, node) {
        console.log(NAME+'markAsFocussed');
        var selector = getFocusManagerSelector(focusContainerNode),
            index = focusContainerNode.getAll(selector).indexOf(node) || 0;
        // we also need to set the appropriate nodeData, so that when the itags re-render,
        // they don't reset this particular information
        focusContainerNode.getAll('[fm-lastitem]')
                          .removeAttrs(['fm-lastitem', 'tabindex'], true)
                          .removeData('fm-tabindex');

        // also store the lastitem's index --> in case the node gets removed,
        // or re-rendering itags which don't have the attribute-data.
        // otherwise, a refocus on the container will set the focus to the nearest item
        focusContainerNode.setData('fm-lastitem-bkp', index);
        node.setData('fm-tabindex', true);

        node.setAttrs([
            {name: 'tabindex', value: '0'},
            {name: 'fm-lastitem', value: true}
        ]);
    };

    searchFocusNode = function(initialNode) {
        console.log(NAME+'searchFocusNode');
        var focusContainerNode = initialNode.hasAttr('fm-manage') ? initialNode : initialNode.inside('[fm-manage]'),
            focusNode, alwaysDefault, fmAlwaysDefault, selector, allFocusableNodes, index;

        if (focusContainerNode) {
            if (initialNode.matches(getFocusManagerSelector(focusContainerNode))) {
                markAsFocussed(focusContainerNode, initialNode);
                focusNode = initialNode;
            }
            else {
                // find the right node that should get focus
/*jshint boss:true */
                alwaysDefault = ((fmAlwaysDefault=focusContainerNode.getAttr('fm-alwaysdefault')) && (fmAlwaysDefault.toLowerCase()==='true'));
/*jshint boss:false */
                alwaysDefault && (focusNode=focusContainerNode.getElement('[fm-defaultitem="true"]'));
                if (!focusNode) {
                    // search for last item
                    focusNode = focusContainerNode.getElement('[fm-lastitem="true"]');
                    if (!focusNode) {
                        // set `selector` right now: we might use it later on even when index is undefined
                        selector = getFocusManagerSelector(focusContainerNode);
                        // look at the lastitemindex of the focuscontainer
                        index = focusContainerNode.getData('fm-lastitem-bkp');
                        if (index!==undefined) {
                            allFocusableNodes = focusContainerNode.getAll(selector);
                            focusNode = allFocusableNodes[index];
                        }
                    }
                }
                // still not found and alwaysDefault was falsy: try the defualt node:
                !focusNode && !alwaysDefault && (focusNode=focusContainerNode.getElement('[fm-defaultitem="true"]'));
                // still not found: try the first focussable node (which we might find inside `allFocusableNodes`:
                !focusNode && (focusNode = allFocusableNodes ? allFocusableNodes[0] : focusContainerNode.getElement(selector));
                if (focusNode) {
                    markAsFocussed(focusContainerNode, focusNode);
                }
                else {
                    focusNode = initialNode;
                }
            }
        }
        else {
            focusNode = initialNode;
        }
        return focusNode;
    };

    setupEvents = function() {

        Event.before('keydown', function(e) {
            console.log(NAME+'before keydown-event');
            var focusContainerNode,
                sourceNode = e.target,
                node = sourceNode.getParent(),
                selector, keyCode, actionkey, focusNode;

            focusContainerNode = sourceNode.inside('[fm-manage]');
            if (focusContainerNode) {
                // key was pressed inside a focusmanagable container
                selector = getFocusManagerSelector(focusContainerNode);
                keyCode = e.keyCode;

                // first check for keydown:
                actionkey = node.getAttr('fm-keydown') || DEFAULT_KEYDOWN;
                focusNode = nextFocusNode(e, keyCode, actionkey, focusContainerNode, sourceNode, selector, true);
                if (!focusNode) {
                    // check for keyup:
                    actionkey = node.getAttr('fm-keyup') || DEFAULT_KEYUP;
                    focusNode = nextFocusNode(e, keyCode, actionkey, focusContainerNode, sourceNode, selector);
                }
                if (focusNode) {
                    e.preventDefaultContinue();
                    // prevent default action --> we just want to re-focus, but we DO want afterlisteners
                    // to be handled in the after-listener: someone else might want to halt the keydown event.
                    sourceNode.matches(selector) && (e._focusNode=focusNode);
                }
            }
        });

        Event.after('keydown', function(e) {
            console.log(NAME+'after keydown-event');
            var focusNode = e._focusNode;
            focusNode && focusNode.focus && focusNode.focus();
        });

        Event.after('blur', function(e) {
            console.log(NAME+'after blur-event');
            var node = e.target,
                body = DOCUMENT.body;
            if (node && node.removeAttr) {
                do {
                    // we also need to set the appropriate nodeData, so that when the itags re-render,
                    // they don't reset this particular information
                    node.removeData(FOCUSSED);
                    node.removeClass(FOCUSSED, null, null, true);
                    node = (node===body) ? null : node.getParent();
                } while (node);
            }
        });

        Event.after('focus', function(e) {
            console.log(NAME+'after focus-event');
            var node = e.target,
                body = DOCUMENT.body;
            if (node && node.setClass) {
                do {
                    // we also need to set the appropriate nodeData, so that when the itags re-render,
                    // they don't reset this particular information
                    node.setData(FOCUSSED, true);
                    node.setClass(FOCUSSED, null, null, true);
                    node = (node===body) ? null : node.getParent();
                } while (node);
            }
        });

        // focus-fix for keeping focus when a mouse gets down for a longer time
        Event.after(['mousedown', 'press'], function(e) {
            console.log(NAME+'after focus-event');
            var node = e.target;
            node.hasFocus() || node.focus();
        }, 'button');

        Event.after('tap', function(e) {
            console.log(NAME+'after tap-event');
            var focusNode = e.target,
                focusContainerNode;

            if (focusNode && focusNode.inside) {
                focusContainerNode = focusNode.hasAttr('fm-manage') ? focusNode : focusNode.inside('[fm-manage]');
            }
            if (focusContainerNode) {
                if ((focusNode===focusContainerNode) || !focusNode.matches(getFocusManagerSelector(focusContainerNode))) {
                    focusNode = searchFocusNode(focusNode);
                }
                if (focusNode.hasFocus()) {
                    markAsFocussed(focusContainerNode, focusNode);
                }
                else {
                    focusNode.focus();
                }
            }
        });

        Event.after(['keypress', 'mouseup', 'panup', 'mousedown', 'pandown'], function(e) {
            console.log(NAME+'after '+e.type+'-event');
            var focusContainerNode,
                sourceNode = e.target,
                selector;

            focusContainerNode = sourceNode.inside('[fm-manage]');
            if (focusContainerNode) {
                // key was pressed inside a focusmanagable container
                selector = getFocusManagerSelector(focusContainerNode);
                if (sourceNode.matches(selector)) {
                    sourceNode.setAttr(FM_SELECTION_START, sourceNode.selectionStart || '0')
                              .setAttr(FM_SELECTION_END, sourceNode.selectionEnd || '0');
                }
            }
        }, 'input[type="text"], textarea');

        Event.after('focus', function(e) {
            console.log(NAME+'after focus-event');
            var focusContainerNode,
                sourceNode = e.target,
                selector, selectionStart, selectionEnd;

            focusContainerNode = sourceNode.inside('[fm-manage]');
            if (focusContainerNode) {
                // key was pressed inside a focusmanagable container
                selector = getFocusManagerSelector(focusContainerNode);
                if (sourceNode.matches(selector)) {
                    // cautious: fm-selectionstart can be 0 --> which would lead into a falsy value
                    selectionStart = sourceNode.getAttr(FM_SELECTION_START);
                    (selectionStart===undefined) && (selectionStart=sourceNode.getValue().length);
                    selectionEnd = Math.max(sourceNode.getAttr(FM_SELECTION_END) || selectionStart, selectionStart);
                    sourceNode.selectionEnd = selectionEnd;
                    sourceNode.selectionStart = selectionStart;
                    markAsFocussed(focusContainerNode, sourceNode);
                }
            }
        }, 'input[type="text"], textarea');

    };

    setupEvents();

    window._ITSAmodules.FocusManager = FocusManager = nodePlugin.definePlugin('fm', {manage: 'true'});

    /**
     * In case of a manual focus (node.focus()) the node will fire an `manualfocus`-event
     * which can be prevented.
     * @event manualfocus
    */
    Event.defineEvent('UI:manualfocus')
         .defaultFn(function(e) {
             var node = e.target,
                 leftScroll = window.getScrollLeft(),
                 topScroll = window.getScrollTop();
             node._focus();
             // reset winscroll:
             window.scrollTo(leftScroll, topScroll);
             // make sure the node is inside the viewport:
             // node.forceIntoView();
         });

    (function(HTMLElementPrototype) {

        HTMLElementPrototype._focus = HTMLElementPrototype.focus;
        HTMLElementPrototype.focus = function() {
            console.log(NAME+'focus');
            searchFocusNode(this).emit('manualfocus');
        };

    }(window.HTMLElement.prototype));

    return FocusManager;
};<|endoftext|>


<commit_before>// @flow
import * as React from 'react'
import {canPipetteUseLabware} from '@opentrons/shared-data'
import type {StepFieldName} from '../../form-types'

/*******************
** Error Messages **
********************/
export type FormErrorKey =
  | 'INCOMPATIBLE_ASPIRATE_LABWARE'
  | 'INCOMPATIBLE_DISPENSE_LABWARE'
  | 'INCOMPATIBLE_LABWARE'
  | 'WELL_RATIO_TRANSFER'
  | 'WELL_RATIO_CONSOLIDATE'
  | 'WELL_RATIO_DISTRIBUTE'
  | 'PAUSE_TYPE_REQUIRED'
  | 'TIME_PARAM_REQUIRED'

export type FormError = {
  title: string,
  body?: React.Node,
  dependentFields: Array<StepFieldName>,
}

const FORM_ERRORS: {[FormErrorKey]: FormError} = {
  INCOMPATIBLE_ASPIRATE_LABWARE: {
    title: 'Selected aspirate labware may be incompatible with selected pipette',
    dependentFields: ['aspirate_labware', 'pipette'],
  },
  INCOMPATIBLE_DISPENSE_LABWARE: {
    title: 'Selected dispense labware may be incompatible with selected pipette',
    dependentFields: ['dispense_labware', 'pipette'],
  },
  INCOMPATIBLE_LABWARE: {
    title: 'Selected labware may be incompatible with selected pipette',
    dependentFields: ['labware', 'pipette'],
  },
  PAUSE_TYPE_REQUIRED: {
    title: 'Must either pause for amount of time, or until told to resume',
    dependentFields: ['pauseForAmountOfTime'],
  },
  TIME_PARAM_REQUIRED: {
    title: 'Must include hours, minutes, or seconds',
    dependentFields: ['pauseForAmountOfTime'],
  },
  WELL_RATIO_TRANSFER: {
    title: 'In transfer actions the number of source and destination wells must match',
    body: 'You may want to use a Distribute or Consolidate instead of Transfer',
    dependentFields: ['aspirate_wells', 'dispense_wells'],
  },
  WELL_RATIO_CONSOLIDATE: {
    title: 'In consolidate actions there must be multiple source wells and one destination well',
    dependentFields: ['aspirate_wells', 'dispense_wells'],
  },
  WELL_RATIO_DISTRIBUTE: {
    title: 'In distribute actions there must be one source well and multiple destination wells',
    dependentFields: ['aspirate_wells', 'dispense_wells'],
  },
}
export type FormErrorChecker = (mixed) => ?FormError

// TODO: test these
/*******************
** Error Checkers **
********************/

// TODO: real HydratedFormData type
type HydratedFormData = any

export const incompatibleLabware = (fields: HydratedFormData): ?FormError => {
  const {labware, pipette} = fields
  if (!labware || !pipette) return null
  return (!canPipetteUseLabware(pipette.name, labware.type)) ? FORM_ERRORS.INCOMPATIBLE_LABWARE : null
}

export const incompatibleDispenseLabware = (fields: HydratedFormData): ?FormError => {
  const {dispense_labware, pipette} = fields
  if (!dispense_labware || !pipette) return null
  return (!canPipetteUseLabware(pipette.name, dispense_labware.type)) ? FORM_ERRORS.INCOMPATIBLE_DISPENSE_LABWARE : null
}

export const incompatibleAspirateLabware = (fields: HydratedFormData): ?FormError => {
  const {aspirate_labware, pipette} = fields
  if (!aspirate_labware || !pipette) return null
  return (!canPipetteUseLabware(pipette.name, aspirate_labware.type)) ? FORM_ERRORS.INCOMPATIBLE_ASPIRATE_LABWARE : null
}

export const pauseForTimeOrUntilTold = (fields: HydratedFormData): ?FormError => {
  const {pauseForAmountOfTime, pauseHour, pauseMinute, pauseSecond} = fields
  if (pauseForAmountOfTime === 'true') {
    // user selected pause for amount of time
    const hours = parseFloat(pauseHour) || 0
    const minutes = parseFloat(pauseMinute) || 0
    const seconds = parseFloat(pauseSecond) || 0
    const totalSeconds = hours * 3600 + minutes * 60 + seconds
    return totalSeconds <= 0 ? FORM_ERRORS.TIME_PARAM_REQUIRED : null
  } else if (pauseForAmountOfTime === 'false') {
    // user selected pause until resume
    return null
  } else {
    // user selected neither pause until resume nor pause for amount of time
    return FORM_ERRORS.PAUSE_TYPE_REQUIRED
  }
}

export const wellRatioTransfer = (fields: HydratedFormData): ?FormError => {
  const {aspirate_wells, dispense_wells} = fields
  if (!aspirate_wells || !dispense_wells) return null
  return aspirate_wells.length !== dispense_wells.length ? FORM_ERRORS.WELL_RATIO_TRANSFER : null
}

export const wellRatioDistribute = (fields: HydratedFormData): ?FormError => {
  const {aspirate_wells, dispense_wells} = fields
  if (!aspirate_wells || !dispense_wells) return null
  return aspirate_wells.length !== 1 || dispense_wells.length <= 1 ? FORM_ERRORS.WELL_RATIO_DISTRIBUTE : null
}

export const wellRatioConsolidate = (fields: HydratedFormData): ?FormError => {
  const {aspirate_wells, dispense_wells} = fields
  if (!aspirate_wells || !dispense_wells) return null
  return aspirate_wells.length <= 1 || dispense_wells.length !== 1 ? FORM_ERRORS.WELL_RATIO_CONSOLIDATE : null
}

/*******************
**     Helpers    **
********************/

export const composeErrors = (...errorCheckers: Array<FormErrorChecker>) => (value: mixed): Array<FormError> => (
  errorCheckers.reduce((acc, errorChecker) => {
    const possibleError = errorChecker(value)
    return possibleError ? [...acc, possibleError] : acc
  }, [])
)
<commit_msg>feat(protocol-designer): change pipette<>labware incompatible copy (#2989)<commit_after>// @flow
import * as React from 'react'
import {canPipetteUseLabware} from '@opentrons/shared-data'
import type {StepFieldName} from '../../form-types'

/*******************
** Error Messages **
********************/
export type FormErrorKey =
  | 'INCOMPATIBLE_ASPIRATE_LABWARE'
  | 'INCOMPATIBLE_DISPENSE_LABWARE'
  | 'INCOMPATIBLE_LABWARE'
  | 'WELL_RATIO_TRANSFER'
  | 'WELL_RATIO_CONSOLIDATE'
  | 'WELL_RATIO_DISTRIBUTE'
  | 'PAUSE_TYPE_REQUIRED'
  | 'TIME_PARAM_REQUIRED'

export type FormError = {
  title: string,
  body?: React.Node,
  dependentFields: Array<StepFieldName>,
}

const FORM_ERRORS: {[FormErrorKey]: FormError} = {
  INCOMPATIBLE_ASPIRATE_LABWARE: {
    title: 'Selected aspirate labware is incompatible with selected pipette',
    dependentFields: ['aspirate_labware', 'pipette'],
  },
  INCOMPATIBLE_DISPENSE_LABWARE: {
    title: 'Selected dispense labware is incompatible with selected pipette',
    dependentFields: ['dispense_labware', 'pipette'],
  },
  INCOMPATIBLE_LABWARE: {
    title: 'Selected labware is incompatible with selected pipette',
    dependentFields: ['labware', 'pipette'],
  },
  PAUSE_TYPE_REQUIRED: {
    title: 'Must either pause for amount of time, or until told to resume',
    dependentFields: ['pauseForAmountOfTime'],
  },
  TIME_PARAM_REQUIRED: {
    title: 'Must include hours, minutes, or seconds',
    dependentFields: ['pauseForAmountOfTime'],
  },
  WELL_RATIO_TRANSFER: {
    title: 'In transfer actions the number of source and destination wells must match',
    body: 'You may want to use a Distribute or Consolidate instead of Transfer',
    dependentFields: ['aspirate_wells', 'dispense_wells'],
  },
  WELL_RATIO_CONSOLIDATE: {
    title: 'In consolidate actions there must be multiple source wells and one destination well',
    dependentFields: ['aspirate_wells', 'dispense_wells'],
  },
  WELL_RATIO_DISTRIBUTE: {
    title: 'In distribute actions there must be one source well and multiple destination wells',
    dependentFields: ['aspirate_wells', 'dispense_wells'],
  },
}
export type FormErrorChecker = (mixed) => ?FormError

// TODO: test these
/*******************
** Error Checkers **
********************/

// TODO: real HydratedFormData type
type HydratedFormData = any

export const incompatibleLabware = (fields: HydratedFormData): ?FormError => {
  const {labware, pipette} = fields
  if (!labware || !pipette) return null
  return (!canPipetteUseLabware(pipette.name, labware.type)) ? FORM_ERRORS.INCOMPATIBLE_LABWARE : null
}

export const incompatibleDispenseLabware = (fields: HydratedFormData): ?FormError => {
  const {dispense_labware, pipette} = fields
  if (!dispense_labware || !pipette) return null
  return (!canPipetteUseLabware(pipette.name, dispense_labware.type)) ? FORM_ERRORS.INCOMPATIBLE_DISPENSE_LABWARE : null
}

export const incompatibleAspirateLabware = (fields: HydratedFormData): ?FormError => {
  const {aspirate_labware, pipette} = fields
  if (!aspirate_labware || !pipette) return null
  return (!canPipetteUseLabware(pipette.name, aspirate_labware.type)) ? FORM_ERRORS.INCOMPATIBLE_ASPIRATE_LABWARE : null
}

export const pauseForTimeOrUntilTold = (fields: HydratedFormData): ?FormError => {
  const {pauseForAmountOfTime, pauseHour, pauseMinute, pauseSecond} = fields
  if (pauseForAmountOfTime === 'true') {
    // user selected pause for amount of time
    const hours = parseFloat(pauseHour) || 0
    const minutes = parseFloat(pauseMinute) || 0
    const seconds = parseFloat(pauseSecond) || 0
    const totalSeconds = hours * 3600 + minutes * 60 + seconds
    return totalSeconds <= 0 ? FORM_ERRORS.TIME_PARAM_REQUIRED : null
  } else if (pauseForAmountOfTime === 'false') {
    // user selected pause until resume
    return null
  } else {
    // user selected neither pause until resume nor pause for amount of time
    return FORM_ERRORS.PAUSE_TYPE_REQUIRED
  }
}

export const wellRatioTransfer = (fields: HydratedFormData): ?FormError => {
  const {aspirate_wells, dispense_wells} = fields
  if (!aspirate_wells || !dispense_wells) return null
  return aspirate_wells.length !== dispense_wells.length ? FORM_ERRORS.WELL_RATIO_TRANSFER : null
}

export const wellRatioDistribute = (fields: HydratedFormData): ?FormError => {
  const {aspirate_wells, dispense_wells} = fields
  if (!aspirate_wells || !dispense_wells) return null
  return aspirate_wells.length !== 1 || dispense_wells.length <= 1 ? FORM_ERRORS.WELL_RATIO_DISTRIBUTE : null
}

export const wellRatioConsolidate = (fields: HydratedFormData): ?FormError => {
  const {aspirate_wells, dispense_wells} = fields
  if (!aspirate_wells || !dispense_wells) return null
  return aspirate_wells.length <= 1 || dispense_wells.length !== 1 ? FORM_ERRORS.WELL_RATIO_CONSOLIDATE : null
}

/*******************
**     Helpers    **
********************/

export const composeErrors = (...errorCheckers: Array<FormErrorChecker>) => (value: mixed): Array<FormError> => (
  errorCheckers.reduce((acc, errorChecker) => {
    const possibleError = errorChecker(value)
    return possibleError ? [...acc, possibleError] : acc
  }, [])
)
<|endoftext|>


<commit_before>/*!
 * Damoo - HTML5 Danmaku Engine v2.1.9
 * https://github.com/jamesliu96/Damoo
 *
 * Copyright (c) 2015-2016 James Liu
 * Released under the MIT license
 */

var Damoo = function({container, fontSize, fontFamily}) {
	fontFamily = fontFamily || 'Arial';
	this.canvas = new Canvas(container, fontSize, fontFamily);
	this.thread = new Thread(() => Math.floor(container.offsetHeight/fontSize-2));
};

var _preload = function(d, f) {
	var cvs = document.createElement('canvas');
	var ctx = cvs.getContext('2d');
	ctx.font = f;
	cvs.width = ctx.measureText(d.text).width;
	cvs.height = f.size * 1.5;
	ctx.font = f;
	ctx.textAlign = "start";
	ctx.textBaseline = "top";
	let shadow = d.shadow || {color: '#000'};
	if (shadow) {
		ctx.shadowOffsetX = 1;
		ctx.shadowOffsetY = 1;
		ctx.shadowColor = shadow.color;
	}
	ctx.fillStyle = "#fff";
	ctx.fillStyle = d.color;
	ctx.fillText(d.text, 0, 0);
	return cvs;
};

var _RAF = function(cb) { return setTimeout(cb, 1000/10) };
var _CAF = function(id) { clearTimeout(id); };

Damoo.prototype.curtime = function() {
	if (this._curtimeBase) {
		return this._curtimeBase+(Date.now()-this._curtimeStart)/1e3;
	}
	return Date.now()/1e3;
}

Damoo.prototype.emit = function(d) {
	if ("string" === typeof d) {
		d = { text: d };
	}
	var cvs = _preload(d, this.canvas.font);
	var defaultTime = 10;

	var fixed;
	var index;
	if (d.pos == 'top') {
		fixed = true;
		index = this.thread.allocFixedIndex(1);
	} else if (d.pos == 'bottom') {
		fixed = true;
		index = this.thread.allocFixedIndex(-1);
	} else {
		index = this.thread.allocIndex();
	}
	console.log('damoo:', d.pos, index, d.text);

	this.thread.push({
		canvas: cvs,
		fixed, index,
		pos: d.pos,
		displaytime: d.time || 10,
		timestart: this.curtime(),
		y: this.canvas.font.size*index,
	});
	return this;
};

Damoo.prototype.render = function() {
	var time = this.curtime();

	this.canvas.clear();
	this.thread.forEach(d => {
		var elapsed = time-d.timestart;
		if (elapsed > d.displaytime) {
			this.thread.remove(d);
			return;
		}
		var x;
		if (d.fixed) {
			x = (this.canvas.width-d.canvas.width)/2;
		} else {
			var w = this.canvas.width+d.canvas.width;
			x = this.canvas.width-w*(elapsed/d.displaytime);
		}
		this.canvas.context.drawImage(d.canvas, x, d.y);
	});
	this._afid = _RAF(() => this.render());
}

Damoo.prototype.clear = function() {
	this.thread.empty();
};

Damoo.prototype.updateState = function() {
	if (this.playing && this.visible) {
		if (this._afid == null) {
			this.render();
		}
	} else {
		if (this._afid) {
			_CAF(this._afid);
			this._afid = null;
		}
	}
}

Damoo.prototype.synctime = function(time) {
	this._curtimeBase = time;
	this._curtimeStart = Date.now();
}

Damoo.prototype.suspend = function() {
	if (this.playing) {
		this.playing = false;
		this.updateState();
	}
};

Damoo.prototype.resume = function() {
	if (!this.playing) {
		this.playing = true;
		this.updateState();
	}
};

Damoo.prototype.show = function() {
	if (!this.visible) {
		this.visible = true;
		this.canvas.container.appendChild(this.canvas.layer);
		this.updateState();
	}
};

Damoo.prototype.hide = function() {
	if (this.visible) {
		this.visible = false;
		this.canvas.container.removeChild(this.canvas.layer);
		this.updateState();
	}
};

var Canvas = function(container, fontSize, fontFamily) {
	this.container = container;
	this.font = new Font(fontSize, fontFamily);
	this.layer = document.createElement('canvas');
	this.layer.style.position = 'absolute';
	this.layer.style.left = 0;
	this.layer.style.top = 0;
	this.context = this.layer.getContext('2d');
	let resize = () => {
		this.width = container.offsetWidth;
		this.height = container.offsetHeight;
		this.layer.width = this.width;
		this.layer.height = this.height;
	}
	window.addEventListener('resize', resize);
	resize();
};

Canvas.prototype.clear = function() {
	this.context.clearRect(0, 0, this.width, this.height);
};

var Font = function(s, f) {
	this.size = s;
	this.family = f || "sans-serif";
};

Font.prototype.toString = function() {
	return this.size + "px " + this.family;
};

var Thread = function(rows) {
	this.rows = rows;
	this.empty();
};

Thread.prototype.allocFixedIndex = function(inc) {
	var n = this.rows();
	if (inc > 0) {
		if (this.fixedTop > n) {
			this.fixedTop = 0;
		}
		return this.fixedTop++;
	} else {
		if (this.fixedBottom > n || this.fixedBottom < 0) {
			this.fixedBottom = n;
		}
		return this.fixedBottom--;
	}
};

Thread.prototype.allocIndex = function() {
	if (this.index >= this.rows()) {
		this.index = 0;
	}
	return this.index++;
};

Thread.prototype.push = function(d) {
	this.pool.add(d);
};

Thread.prototype.forEach = function(fn) {
	this.pool.forEach(fn);
};

Thread.prototype.remove = function(d) {
	if (d.pos == 'top') {
		if (d.index < this.fixedTop) {
			this.fixedTop = d.index;
		}
	} else if (d.pos == 'bottom') {
		if (d.index > this.fixedBottom) {
			this.fixedBottom = d.index;
		}
	} else {
		if (d.index < this.index) {
			this.index = d.index;
		}
	}
	this.pool.delete(d);
};

Thread.prototype.empty = function() {
	this.index = 0;
	this.fixedTop = 0;
	this.fixedBottom = this.rows();
	this.pool = new Set();
};

module.exports = Damoo;

<commit_msg>调整弹幕时间<commit_after>/*!
 * Damoo - HTML5 Danmaku Engine v2.1.9
 * https://github.com/jamesliu96/Damoo
 *
 * Copyright (c) 2015-2016 James Liu
 * Released under the MIT license
 */

var Damoo = function({container, fontSize, fontFamily}) {
	fontFamily = fontFamily || 'Arial';
	this.canvas = new Canvas(container, fontSize, fontFamily);
	this.thread = new Thread(() => Math.floor(container.offsetHeight/fontSize-3));
};

var _preload = function(d, f) {
	var cvs = document.createElement('canvas');
	var ctx = cvs.getContext('2d');
	ctx.font = f;
	cvs.width = ctx.measureText(d.text).width;
	cvs.height = f.size * 1.5;
	ctx.font = f;
	ctx.textAlign = "start";
	ctx.textBaseline = "top";
	let shadow = d.shadow || {color: '#000'};
	if (shadow) {
		ctx.shadowOffsetX = 1;
		ctx.shadowOffsetY = 1;
		ctx.shadowColor = shadow.color;
	}
	ctx.fillStyle = "#fff";
	ctx.fillStyle = d.color;
	ctx.fillText(d.text, 0, 0);
	return cvs;
};

var _RAF = function(cb) { return setTimeout(cb, 1000/10) };
var _CAF = function(id) { clearTimeout(id); };

Damoo.prototype.curtime = function() {
	if (this._curtimeBase) {
		return this._curtimeBase+(Date.now()-this._curtimeStart)/1e3;
	}
	return Date.now()/1e3;
}

Damoo.prototype.emit = function(d) {
	if ("string" === typeof d) {
		d = { text: d };
	}
	var cvs = _preload(d, this.canvas.font);

	var fixed;
	var index;
	if (d.pos == 'top') {
		fixed = true;
		index = this.thread.allocFixedIndex(1);
	} else if (d.pos == 'bottom') {
		fixed = true;
		index = this.thread.allocFixedIndex(-1);
	} else {
		index = this.thread.allocIndex();
	}

	this.thread.push({
		canvas: cvs,
		fixed, index,
		pos: d.pos,
		displaytime: d.time || (fixed ? 5 : 10),
		timestart: this.curtime(),
		y: this.canvas.font.size*index,
	});
	return this;
};

Damoo.prototype.render = function() {
	var time = this.curtime();

	this.canvas.clear();
	this.thread.forEach(d => {
		var elapsed = time-d.timestart;
		if (elapsed > d.displaytime) {
			this.thread.remove(d);
			return;
		}
		var x;
		if (d.fixed) {
			x = (this.canvas.width-d.canvas.width)/2;
		} else {
			var w = this.canvas.width+d.canvas.width;
			x = this.canvas.width-w*(elapsed/d.displaytime);
		}
		this.canvas.context.drawImage(d.canvas, x, d.y);
	});
	this._afid = _RAF(() => this.render());
}

Damoo.prototype.clear = function() {
	this.thread.empty();
};

Damoo.prototype.updateState = function() {
	if (this.playing && this.visible) {
		if (this._afid == null) {
			this.render();
		}
	} else {
		if (this._afid) {
			_CAF(this._afid);
			this._afid = null;
		}
	}
}

Damoo.prototype.synctime = function(time) {
	this._curtimeBase = time;
	this._curtimeStart = Date.now();
}

Damoo.prototype.suspend = function() {
	if (this.playing) {
		this.playing = false;
		this.updateState();
	}
};

Damoo.prototype.resume = function() {
	if (!this.playing) {
		this.playing = true;
		this.updateState();
	}
};

Damoo.prototype.show = function() {
	if (!this.visible) {
		this.visible = true;
		this.canvas.container.appendChild(this.canvas.layer);
		this.updateState();
	}
};

Damoo.prototype.hide = function() {
	if (this.visible) {
		this.visible = false;
		this.canvas.container.removeChild(this.canvas.layer);
		this.updateState();
	}
};

var Canvas = function(container, fontSize, fontFamily) {
	this.container = container;
	this.font = new Font(fontSize, fontFamily);
	this.layer = document.createElement('canvas');
	this.layer.style.position = 'absolute';
	this.layer.style.left = 0;
	this.layer.style.top = 0;
	this.context = this.layer.getContext('2d');
	let resize = () => {
		this.width = container.offsetWidth;
		this.height = container.offsetHeight;
		this.layer.width = this.width;
		this.layer.height = this.height;
	}
	window.addEventListener('resize', resize);
	resize();
};

Canvas.prototype.clear = function() {
	this.context.clearRect(0, 0, this.width, this.height);
};

var Font = function(s, f) {
	this.size = s;
	this.family = f || "sans-serif";
};

Font.prototype.toString = function() {
	return this.size + "px " + this.family;
};

var Thread = function(rows) {
	this.rows = rows;
	this.empty();
};

Thread.prototype.allocFixedIndex = function(inc) {
	var n = this.rows();
	if (inc > 0) {
		if (this.fixedTop > n) {
			this.fixedTop = 0;
		}
		return this.fixedTop++;
	} else {
		if (this.fixedBottom > n || this.fixedBottom < 0) {
			this.fixedBottom = n;
		}
		return this.fixedBottom--;
	}
};

Thread.prototype.allocIndex = function() {
	if (this.index >= this.rows()) {
		this.index = 0;
	}
	return this.index++;
};

Thread.prototype.push = function(d) {
	this.pool.add(d);
};

Thread.prototype.forEach = function(fn) {
	this.pool.forEach(fn);
};

Thread.prototype.remove = function(d) {
	if (d.pos == 'top') {
		if (d.index < this.fixedTop) {
			this.fixedTop = d.index;
		}
	} else if (d.pos == 'bottom') {
		if (d.index > this.fixedBottom) {
			this.fixedBottom = d.index;
		}
	} else {
		if (d.index < this.index) {
			this.index = d.index;
		}
	}
	this.pool.delete(d);
};

Thread.prototype.empty = function() {
	this.index = 0;
	this.fixedTop = 0;
	this.fixedBottom = this.rows();
	this.pool = new Set();
};

module.exports = Damoo;

<|endoftext|>


<commit_before>module.exports = {
	printWidth: 120,
	tabWidth: 4,
	useTabs: true,
	endOfLine: 'auto',
	semi: true,
	singleQuote: true,
	trailingComma: 'es5',
	bracketSpacing: true,
	jsxBracketSameLine: false,
	arrowParens: 'always',
	overrides: [
		{
			files: ['*.json', '.*.json'],
			options: {
				parser: 'json',
			},
		},
		{
			files: ['*.(js|jsx)', '.*.(js|jsx)'],
			options: {
				parser: 'babylon',
			},
		},
		{
			files: ['*.(ts|tsx)', '.*.(ts|tsx)'],
			options: {
				parser: 'typescript',
			},
		},
		{
			// use 2 spaces and 80 with because stories also used in documentation
			files: ['*.stories.ts', '*.stories.tsx'],
			options: {
				useTabs: false,
				tabWidth: 2,
				printWidth: 60,
			},
		},
		{
			files: ['*.gql', '.*.graphql'],
			options: {
				parser: 'graphql',
			},
		},
		{
			files: ['*.md'],
			options: {
				useTabs: false,
				tabWidth: 2,
				printWidth: 60,
				parser: 'markdown',
			},
		},
		{
			files: ['*.mdx'],
			options: {
				useTabs: false,
				tabWidth: 2,
				printWidth: 60,
				parser: 'mdx',
			},
		},
		{
			files: ['*.html'],
			options: {
				parser: 'html',
			},
		},
		{
			files: ['*.yml', '*.yaml'],
			options: {
				useTabs: false,
				tabWidth: 2,
				parser: 'yaml',
			},
		},
	],
};
<commit_msg>fix(prettier): unify files selectors<commit_after>module.exports = {
	printWidth: 120,
	tabWidth: 4,
	useTabs: true,
	endOfLine: 'auto',
	semi: true,
	singleQuote: true,
	trailingComma: 'es5',
	bracketSpacing: true,
	jsxBracketSameLine: false,
	arrowParens: 'always',
	overrides: [
		{
			files: '*.json',
			options: {
				parser: 'json',
			},
		},
		{
			files: '*.(js|jsx)',
			options: {
				parser: 'babylon',
			},
		},
		{
			files: '*.(ts|tsx)',
			options: {
				parser: 'typescript',
			},
		},
		{
			// use 2 spaces and 80 with because stories also used in documentation
			files: '*.stories.(ts|tsx)',
			options: {
				useTabs: false,
				tabWidth: 2,
				printWidth: 60,
			},
		},
		{
			files: '*.(gql|graphql)',
			options: {
				parser: 'graphql',
			},
		},
		{
			files: '*.md',
			options: {
				useTabs: false,
				tabWidth: 2,
				printWidth: 60,
				parser: 'markdown',
			},
		},
		{
			files: '*.mdx',
			options: {
				useTabs: false,
				tabWidth: 2,
				printWidth: 60,
				parser: 'mdx',
			},
		},
		{
			files: '*.html',
			options: {
				parser: 'html',
			},
		},
		{
			files: '*.(yml|yaml)',
			options: {
				useTabs: false,
				tabWidth: 2,
				parser: 'yaml',
			},
		},
	],
};
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 Scott Bishop
 * BluJagu, LLC - www.blujagu.com
 * MIT License (MIT) - This header must remain intact.
 **/
define(['../square', './aggregates', './Select', './tableObjects'], function (square, aggregates, Select, tableObjects) {
    'use strict';

    var Table = tableObjects.Table,
        Column = tableObjects.Column,
        _memory = {},
        getColumnNames = function getColumnNames (/*columns*/) {
            var columnNames = Array.from(arguments);

            if (columnNames.length === 1 && columnNames[0].indexOf(',') !== -1) {
                columnNames = columnNames[0].split(',').map(function (el) {
                    return el.trim();
                });
            }

            return columnNames;
        };

    _memory.__proto__ = {
        'create': function create (dbName) {
            //this[dbName] = eventHub.connect(new DB(dbName));
            this[dbName] = new DB(dbName);

            return this[dbName];
        },
        'drop': function drop (dbName) {
            if (this[dbName]) {
                this[dbName] = null;
                delete this[dbName];

                return true;
            }

            return false;
        },
        'get': function get (dbName) {
            return this[dbName];
        },
        'show': function show () {
            var prop, arr = [];

            for (prop in this) {
                if (this.hasOwnProperty(prop)) {
                    arr.push(prop);
                }
            }

            return arr;
        }
    };

    var DB = function DB (dbName) {
        this._event = dbName;
    };

    DB.prototype = {
        'constructor': DB,
        '_event': '',
        '_tableCount': 0,
        'count': function count () {
            return this._tableCount;
        },
        'COUNT': function COUNT () {
            return this._tableCount;
        },
        'select': function select (/*selects*/) {
            var selects = getColumnNames.apply({}, arguments);

            return new Select(this, selects);
        },
        'SELECT': function SELECT (/*selects*/) {
            return this.select.apply(this, arguments);
        },
        'createTable': function createTable (tableName) {
            /**
             * createTable adds a new Table Object <tableName> to the DB Object
             * @param {String} tableName Name to assign to the new table
             * @returns {Function} Returns a curried function waiting for the columns argument
             */
            var db = this,
                table = new Table(db, tableName);

            db[tableName] = table;
            ++db._tableCount;

            return function (/*columns*/) {
                var columns = getColumnNames.apply({}, arguments);

                if (columns.length) {
                    db.alterTable(tableName).add.apply({}, arguments);
                }

                return table;
            };
        },
        'CREATE_TABLE': function CREATE_TABLE (tableName) {
            return this.createTable.call(this, tableName);
        },
        'alterTable': function alterTable (tableName) {
            var table = this[tableName];

            return {
                'add': function add (/*columns*/) {
                    var cols = getColumnNames.apply({}, arguments),
                        col, i = 0, len = cols.length,
                        indices = table.indices(),
                        holes = table.holes(),
                        j = 0, jLen = indices.length,
                        newColumn;

                    for (i; i < len; ++i) {
                        col = cols[i];
                        newColumn = table[col] = new Column(table, col);
                        for (j = 0; j < jLen; ++j) {
                            newColumn[indices[j]] = undefined;
                        }
                        jLen = holes.length;
                        for (j = 0; j < jLen; ++j) {
                            newColumn[holes[j]] = null;
                        }
                    }

                    return table;
                },
                'ADD': function VALUES (/*columns*/) {
                    return this.add.apply(this, arguments);
                },
                'drop': function drop (/*columns*/) {
                    var cols = getColumnNames.apply({}, arguments),
                        col, i = 0, len;

                    if (cols.length === 0 || cols[0] === '*') {
                        cols = table.columns();
                    }

                    for (len = cols.length; i < len; ++i) {
                        col = cols[i];
                        table[col] = null;
                        delete table[col];
                    }

                    return table;
                },
                'DROP': function VALUES (/*columns*/) {
                    return this.drop.apply(this, arguments);
                },
                'modify': function modify () {
                    // only needed if I support data types on columns
                }
            }
        },
        'ALTER_TABLE': function ALTER_TABLE (tableName) {
            return this.alterTable.call(this, tableName);
        },
        'insertInto': function insertInto (tableName) {
            var table = this[tableName];

            return function (/*columns*/) {
                var columns = getColumnNames.apply({}, arguments);

                return {
                    'values': function values (/*insertValues*/) {
                        var values = Array.from(arguments),
                            targetIndex = -1,
                            prop;

                        for (prop in table) {
                            if (table.hasOwnProperty(prop)) {
                                targetIndex = columns.indexOf(prop);
                                if (targetIndex > -1) {
                                    table[prop].push(values.splice(targetIndex, 1)[0]);
                                    columns.splice(targetIndex, 1);
                                } else {
                                    table[prop].push(undefined);
                                }
                            }
                        }

                        return this;
                    },
                    'VALUES': function VALUES (/*insertValues*/) {
                        return this.values.apply(this, arguments);
                    }
                };
            };
        },
        'INSERT_INTO': function INSERT_INTO (tableName) {
            return this.insertInto.call(this, tableName);
        },
        'insertJSON': function insertJSON (insertObjects /*Array*/) {

        }

    };

    return {
        'createDB': _memory.create,
        'CREATE_DATABASE': _memory.create,
        'dropDB': _memory.drop,
        'DROP_DATABASE': _memory.drop,
        'use': _memory.get,
        'USE': _memory.get,
        'show': _memory.show,
        'SHOW_DATABASES': _memory.show
    };

});<commit_msg>major api refactor<commit_after>/**
 * Copyright (c) 2015 Scott Bishop
 * BluJagu, LLC - www.blujagu.com
 * MIT License (MIT) - This header must remain intact.
 **/
define(['../square', './comparator', './Select', './tableObjects'], function (square, comparator, Select, tableObjects) {
    'use strict';

    var Table = tableObjects.Table,
        Column = tableObjects.Column,
        _memory = {},
        getColumnNames = function (/*columns*/) {
            var columnNames = Array.from(arguments);

            if (columnNames.length === 1 && columnNames[0].indexOf(',') !== -1) {
                columnNames = columnNames[0].split(',').map(function (el) {
                    return el.trim();
                });
            }

            return columnNames;
        },
        Where = function (table, column, operator, control) {
            this.validIndices = comparator(table[column], operator, control);
            this.AND = this.and = function (column, operator, control) {
                var newIndices = comparator(table[column], operator, control);

                this.validIndices = this.validIndices.filter(function (v) {
                    return newIndices.indexOf(v) !== -1;
                });

                return this;
            };
            this.OR = this.or = function (column, operator, control) {
                var cache = [];

                this.validIndices = this.validIndices.concat(comparator(table[column], operator, control));

                this.validIndices = this.validIndices.filter(function (v) {
                    if (cache.indexOf(v) === -1) {
                        cache.push(v);
                        return true;
                    }
                });

                return this;
            };
        };

    _memory.__proto__ = {
        'create': function (dbName) {
            //this[dbName] = eventHub.connect(new DB(dbName));
            this[dbName] = new DB(dbName);

            return this[dbName];
        },
        'drop': function (dbName) {
            if (this[dbName]) {
                this[dbName] = null;
                delete this[dbName];

                return true;
            }

            return false;
        },
        'get': function (dbName) {
            return this[dbName];
        },
        'show': function () {
            var prop, arr = [];

            for (prop in this) {
                if (this.hasOwnProperty(prop)) {
                    arr.push(prop);
                }
            }

            return arr;
        }
    };

    var DB = function DB (dbName) {
        this._event = dbName;
    };

    DB.prototype = {
        'constructor': DB,
        '_event': '',
        '_tableCount': 0,
        'count': function () {
            return this._tableCount;
        },
        'COUNT': function () {
            return this._tableCount;
        },
        'select': function (/*selects*/) {
            var selects = getColumnNames.apply({}, arguments);

            return new Select(this, selects);
        },
        'SELECT': function (/*selects*/) {
            return this.select.apply(this, arguments);
        },
        'createTable': function (tableName) {
            /**
             * createTable adds a new Table Object <tableName> to the DB Object
             * @param {String} tableName Name to assign to the new table
             * @returns {Function} Returns a curried function waiting for the columns argument
             */
            var db = this,
                table = new Table(db, tableName);

            db[tableName] = table;
            ++db._tableCount;

            return function (/*columns*/) {
                var columns = getColumnNames.apply({}, arguments);

                if (columns.length) {
                    db.alterTable(tableName).add.apply({}, arguments);
                }

                return table;
            };
        },
        'CREATE_TABLE': function (tableName) {
            return this.createTable.call(this, tableName);
        },
        'alterTable': function (tableName) {
            var table = this[tableName];

            return {
                'add': function (/*columns*/) {
                    var cols = getColumnNames.apply({}, arguments),
                        col, i = 0, len = cols.length,
                        indices = table.indices(),
                        holes = table.holes(),
                        j = 0, jLen = indices.length,
                        newColumn;

                    for (i; i < len; ++i) {
                        col = cols[i];
                        newColumn = table[col] = new Column(table, col);
                        for (j = 0; j < jLen; ++j) {
                            newColumn[indices[j]] = undefined;
                        }
                        jLen = holes.length;
                        for (j = 0; j < jLen; ++j) {
                            newColumn[holes[j]] = null;
                        }
                    }

                    return table;
                },
                'ADD': function (/*columns*/) {
                    return this.add.apply(this, arguments);
                },
                'drop': function (/*columns*/) {
                    var cols = getColumnNames.apply({}, arguments),
                        col, i = 0, len;

                    if (cols.length === 0 || cols[0] === '*') {
                        cols = table.columns();
                    }

                    for (len = cols.length; i < len; ++i) {
                        col = cols[i];
                        table[col] = null;
                        delete table[col];
                    }

                    return table;
                },
                'DROP': function (/*columns*/) {
                    return this.drop.apply(this, arguments);
                },
                'modify': function () {
                    // only needed if I support data types on columns
                }
            }
        },
        'ALTER_TABLE': function (tableName) {
            return this.alterTable.call(this, tableName);
        },
        'insertInto': function (tableName) {
            var table = this[tableName];

            return function (/*columns*/) {
                var columns = getColumnNames.apply({}, arguments),
                    values = function values (/*insertValues*/) {
                        var vals = Array.from(arguments),
                            columnName, prop,
                            i = 0, len = columns.length;

                        for (i; i < len; ++i) {
                            columnName = columns[i];
                            table[columnName].push(vals[i]);
                        }

                        for (prop in table) {
                            if (table.hasOwnProperty(prop)) {
                                if (columns.indexOf(prop) === -1) {
                                    table[prop].push(undefined);
                                }
                            }
                        }

                        return values;
                    };

                return {
                    'values': values,
                    'VALUES': values
                };
            };
        },
        'INSERT_INTO': function (tableName) {
            return this.insertInto.call(this, tableName);
        },
        'insertJSON': function (insertObjects /*Array*/) {
            // todo: add this
        },
        'INSERT_JSON': function (insertObjects /*Array*/) {
            // todo: add this
        },
        'update': function (tableName) {
            var table = this[tableName],
                updateMap = {},
                set = function (column, value) {
                    updateMap[column] = value;

                    return set;
                };

            set.WHERE = set.where = function (column, operator, control) {
                var w = new Where(table, column, operator, control);

                w.GO = w.go = function () {
                    var i = 0, len = this.validIndices.length, ndx, prop;

                    for (i; i < len; ++i) {
                        ndx = this.validIndices[i];
                        for (prop in table) {
                            if (table.hasOwnProperty(prop) && updateMap[prop]) {
                                table[prop][ndx] = updateMap[prop];
                            }
                        }
                    }

                    return true;
                };

                return w;
            };

            return {
                'set': set,
                'SET': set
            }
        },
        'UPDATE': function (tableName) {
            return this.update.call(this, tableName);
        },
        'delete': function (/*columnNames*/) {
            var columns = getColumnNames.apply({}, arguments),
                db = this,
                table,
                from = function (tableName) {
                    table = db[tableName];
                    if (columns.length === 0 || columns[0] === '*') {
                        columns = table.columns();
                    }

                    return {
                        'where': where,
                        'WHERE': where,
                        'go': go,
                        'GO': go
                    }
                },
                go = function () {
                    var matches = this.validIndices,
                        i = 0, len, ndx, j, colLen = columns.length, column;

                    if (matches === undefined) {
                        matches = table.indices();
                        // table.indices gives all possible matches
                    }

                    for (i, len = matches.length; i < len; ++i) {
                        ndx = matches[i];
                        for (j = 0; j < colLen; ++j) {
                            column = table[columns[j]];
                            column[ndx] = null;
                        }
                    }

                    return true;
                },
                where = function (column, operator, control) {
                    var w = new Where(table, column, operator, control);

                    w.GO = w.go = go.bind(w);

                    return w;
                };

            return {
                'from': from,
                'FROM': from
            };
        },
        'DELETE': function (/*columnNames*/) {
            return this.delete.apply(this, arguments);
        }
    };

    return {
        'createDB': _memory.create,
        'CREATE_DATABASE': _memory.create,
        'dropDB': _memory.drop,
        'DROP_DATABASE': _memory.drop,
        'use': _memory.get,
        'USE': _memory.get,
        'show': _memory.show,
        'SHOW_DATABASES': _memory.show
    };

});<|endoftext|>


<commit_before>

function parseNamedElements(root, parent, child_tags) {

  walk(root, function(dom) {
    if (dom.nodeType == 1) {

      // custom child tag
      var child = getTag(dom)

      if (child && !dom.getAttribute('each')) {
        var tag = new Tag(child, { root: dom, parent: parent })
        parent.tags[dom.getAttribute('name') || child.name] = tag
        child_tags.push(tag)
      }

      each(dom.attributes, function(attr) {
        if (/^(name|id)$/.test(attr.name)) parent[attr.value] = dom
      })
    }

  })

}

function parseExpressions(root, tag, expressions) {

  function addExpr(dom, val, extra) {
    if (val.indexOf(brackets(0)) >= 0) {
      var expr = { dom: dom, expr: val }
      expressions.push(extend(expr, extra))
    }
  }

  walk(root, function(dom) {
    var type = dom.nodeType

    // text node
    if (type == 3 && dom.parentNode.tagName != 'STYLE') addExpr(dom, dom.nodeValue)
    if (type != 1) return

    /* element */

    // loop
    var attr = dom.getAttribute('each')
    if (attr) { _each(dom, tag, attr); return false }

    // attribute expressions
    each(dom.attributes, function(attr) {
      var name = attr.name,
          bool = name.split('__')[1]

      addExpr(dom, attr.value, { attr: bool || name, bool: bool })
      if (bool) { remAttr(dom, name); return false }

    })

    // skip custom tags
    if (getTag(dom)) return false

  })

}
<commit_msg>coloses #475<commit_after>

function parseNamedElements(root, parent, child_tags) {

  walk(root, function(dom) {
    if (dom.nodeType == 1) {

      // custom child tag
      var child = getTag(dom)

      if (child && !dom.getAttribute('each')) {
        var tag = new Tag(child, { root: dom, parent: parent })
        parent.tags[dom.getAttribute('name') || child.name] = tag
        // empty the child node once we got its template
        // to avoid that its children get compiled multiple times
        dom.innerHTML = ''
        child_tags.push(tag)
      }

      each(dom.attributes, function(attr) {
        if (/^(name|id)$/.test(attr.name)) parent[attr.value] = dom
      })
    }

  })

}

function parseExpressions(root, tag, expressions) {

  function addExpr(dom, val, extra) {
    if (val.indexOf(brackets(0)) >= 0) {
      var expr = { dom: dom, expr: val }
      expressions.push(extend(expr, extra))
    }
  }

  walk(root, function(dom) {
    var type = dom.nodeType

    // text node
    if (type == 3 && dom.parentNode.tagName != 'STYLE') addExpr(dom, dom.nodeValue)
    if (type != 1) return

    /* element */

    // loop
    var attr = dom.getAttribute('each')
    if (attr) { _each(dom, tag, attr); return false }

    // attribute expressions
    each(dom.attributes, function(attr) {
      var name = attr.name,
          bool = name.split('__')[1]

      addExpr(dom, attr.value, { attr: bool || name, bool: bool })
      if (bool) { remAttr(dom, name); return false }

    })

    // skip custom tags
    if (getTag(dom)) return false

  })

}
<|endoftext|>


<commit_before>'use strict'

var ipRegex = require('ip-regex')
var defaultsDeep = require('lodash.defaultsdeep')
var defaults = require('../defaults')
var throttleModel = require('../models/throttle')

/**
 * Create and register throttler middleware
 *
 * @access public
 * @param {object} config
 * @param {function} limited will be called upon limit reached
 */
module.exports = function createThrottler (config, limited) {
  // createThrottler()
  if (!config) {
    config = {}
  }

  // createThrottler(fn)
  if (typeof config === 'function') {
    limited = config
    config = null
  }

  // createThrottler(config, false)
  if (typeof limited !== 'function') {
    limited = null
  }
  defaultsDeep(config, defaults)

  var Throttle = throttleModel(config)
  return throttleMiddleware

  function errHandler (res, next, error) {
    // DO WE WANT TO BREAK THE APP AND CAUSE A ISSUE OR DO WE WANT TO SILENTLY INTO THE NIGHT AND JUST LOG OUR ERRORS
    if (error) {
      res.statusCode = 500
      next(error)
      return true
    }
  }

  function respondWithThrottle (request, response, next, throttle) {
    var timeUntilReset = (defaults.rateLimit.ttl * 1000) - (new Date().getTime() - throttle.createdAt.getTime())
    var remaining = Math.max(0, (defaults.rateLimit.max - throttle.hits))

    response.set({
      'X-Rate-Limit-Limit': defaults.rateLimit.max,
      'X-Rate-Limit-Remaining': remaining,
      'X-Rate-Limit-Reset': timeUntilReset
    })

    if (throttle.hits < defaults.rateLimit.max) {
      return next()
    }

    response.statusCode = defaults.response.code
    if (limited) {
      return limited(request, response, throttle.hits, timeUntilReset)
    }

    return response.send(defaults.response.message)
  }
  /**
   * Check for request limit on the requesting IP
   *
   * @access public
   * @param {object} request Express-style request
   * @param {object} response Express-style response
   * @param {function} next Express-style next callback
   */

  function throttleMiddleware (request, response, next) {
    var ip = request.headers['x-forwarded-for'] ||
      request.connection.remoteAddress ||
      request.socket.remoteAddress ||
      request.connection.socket.remoteAddress || ''

    ip = ip.split(',')[0]
    if (!ipRegex().test(ip) || ip.substr(0, 7) === '::ffff:' || ip === '::1') {
      ip = '127.0.0.1'
    } else {
      ip = ip.match(ipRegex())[0]
    }

    // WE NEED TO ADD A MONGOOSE DB CONNECTION CHECK - IT FROZE TESTING AND DID THROW ANY ERRORS IT JUST WAITED
    Throttle
      .findOneAndUpdate({ip: ip}, { $inc: { hits: 1 } }, { upsert: false })
      .exec(function (error, throttle) {
        if (errHandler(response, next, error)) { return }
        if (!throttle) {
          throttle = new Throttle({
            createdAt: new Date(),
            ip: ip
          })
          throttle.save(function (error, throttle) {
            // THERE'S NO ERROR, BUT THROTTLE WAS NOT SAVE
            if (!throttle && !error) {
              error = new Error('Error checking rate limit.')
            }

            if (errHandler(response, next, error)) { return }

            respondWithThrottle(request, response, next, throttle)
          })
        } else {
          respondWithThrottle(request, response, next, throttle)
        }
      })
  }
}
<commit_msg>Check for MongoDB connection before throttling<commit_after>'use strict'

var ipRegex = require('ip-regex')
var mongoose = require('mongoose')
var defaultsDeep = require('lodash.defaultsdeep')
var pkg = require('../package')
var defaults = require('../defaults')
var throttleModel = require('../models/throttle')

/**
 * Create and register throttler middleware
 *
 * @access public
 * @param {object} config
 * @param {function} limited will be called upon limit reached
 */
module.exports = function createThrottler (config, limited) {
  // createThrottler()
  if (!config) {
    config = {}
  }

  // createThrottler(fn)
  if (typeof config === 'function') {
    limited = config
    config = null
  }

  // createThrottler(config, false)
  if (typeof limited !== 'function') {
    limited = null
  }
  defaultsDeep(config, defaults)

  var Throttle = throttleModel(config)
  return throttleMiddleware

  function errHandler (res, next, error) {
    // DO WE WANT TO BREAK THE APP AND CAUSE A ISSUE OR DO WE WANT TO SILENTLY INTO THE NIGHT AND JUST LOG OUR ERRORS
    if (error) {
      res.statusCode = 500
      next(error)
      return true
    }
  }

  function respondWithThrottle (request, response, next, throttle) {
    var timeUntilReset = (defaults.rateLimit.ttl * 1000) - (new Date().getTime() - throttle.createdAt.getTime())
    var remaining = Math.max(0, (defaults.rateLimit.max - throttle.hits))

    response.set({
      'X-Rate-Limit-Limit': defaults.rateLimit.max,
      'X-Rate-Limit-Remaining': remaining,
      'X-Rate-Limit-Reset': timeUntilReset
    })

    if (throttle.hits < defaults.rateLimit.max) {
      return next()
    }

    response.statusCode = defaults.response.code
    if (limited) {
      return limited(request, response, throttle.hits, timeUntilReset)
    }

    return response.send(defaults.response.message)
  }
  /**
   * Check for request limit on the requesting IP
   *
   * @access public
   * @param {object} request Express-style request
   * @param {object} response Express-style response
   * @param {function} next Express-style next callback
   */

  function throttleMiddleware (request, response, next) {
    var ip = request.headers['x-forwarded-for'] ||
      request.connection.remoteAddress ||
      request.socket.remoteAddress ||
      request.connection.socket.remoteAddress || ''

    ip = ip.split(',')[0]
    if (!ipRegex().test(ip) || ip.substr(0, 7) === '::ffff:' || ip === '::1') {
      ip = '127.0.0.1'
    } else {
      ip = ip.match(ipRegex())[0]
    }

    if (!mongoose.connection.readyState) {
      console.warn('MongoDB connection not set. Skipping ' + pkg.name)
      return next()
    }
    Throttle
      .findOneAndUpdate({ip: ip}, { $inc: { hits: 1 } }, { upsert: false })
      .exec(function (error, throttle) {
        if (errHandler(response, next, error)) { return }
        if (!throttle) {
          throttle = new Throttle({
            createdAt: new Date(),
            ip: ip
          })
          throttle.save(function (error, throttle) {
            // THERE'S NO ERROR, BUT THROTTLE WAS NOT SAVE
            if (!throttle && !error) {
              error = new Error('Error checking rate limit.')
            }

            if (errHandler(response, next, error)) { return }

            respondWithThrottle(request, response, next, throttle)
          })
        } else {
          respondWithThrottle(request, response, next, throttle)
        }
      })
  }
}
<|endoftext|>


<commit_before>var
  where = 'client' // Adds files only to the client
;

Package.describe({
  name    : 'semantic:ui-css',
  summary : 'Semantic UI - CSS Release of Semantic UI',
  version : '{version}',
  git     : 'git://github.com/Semantic-Org/Semantic-UI-CSS.git',
});

Package.onUse(function(api) {

  api.versionsFrom('1.0');

  api.addFiles([
    'semantic.css',
    'semantic.js'
  ], 'client');

});
<commit_msg>Update css package for meteor #1607<commit_after>var
  where = 'client' // Adds files only to the client
;

Package.describe({
  name    : 'semantic:ui-css',
  summary : 'Semantic UI - CSS Release of Semantic UI',
  version : '{version}',
  git     : 'git://github.com/Semantic-Org/Semantic-UI-CSS.git',
});

Package.onUse(function(api) {

  api.versionsFrom('1.0');

  api.addFiles([
    // icons
    'themes/default/assets/fonts/icons.eot',
    'themes/default/assets/fonts/icons.otf',
    'themes/default/assets/fonts/icons.svg',
    'themes/default/assets/fonts/icons.ttf',
    'themes/default/assets/fonts/icons.woff',
    'themes/default/assets/fonts/icons.woff2',
    'themes/default/assets/fonts/icons.woff2',

    // flags
    'themes/default/assets/images/flags.png',

    // release
    'semantic.css',
    'semantic.js'
  ], 'client');

});
<|endoftext|>