<commit_before>(function() {

    /**
     * @fileOverview Надстройки nb над jQueryUI
     */

    $.nb = {};

    $.widget('nb.baseDialog', $.ui.dialog, {
        options: {
            height: 'auto',
            minHeight: 'auto',
            width: 'auto'
        },
        open: function() {
            this._super();
            var that = this;

            if (!this.options.modal) {
                this._onmousedown = function(e) {
                    if (e.which !== 1) {
                        return;
                    }

                    if ($.contains(that.uiDialog[0], e.target)) {
                        return;
                    }

                    that.close();
                };

                this.document.on('mousedown', this._onmousedown);
            }

            this._onpopupclose = nb.on('popup-close', function() {
                that.close();
            });
        },
        close: function() {
            this._super();
            this.document.off('mousedown', this._onmousedown);
            nb.off('popup-close', this._onpopupclose);
        },
        _create: function() {
            this.options.dialogClass += _getUIDialogExtraClass.call(this);
            this.options.dialogClass += (this.options.position.fixed) ? ' ui-dialog-fixed' : '';
            this._super();
            this.element[0].widget = this;
        },
        _destroy: function() {
            this._super();
            delete this.element[0].widget;
        },
        _createTitlebar: function() {
            this.uiDialogTitlebarClose = $();
        }
    });

    // диалог с хвостиком
    jQuery.widget('nb.contextDialog', $.nb.baseDialog, {

        tailOffset: 13,

        options: {
            tail: 'center',
            height: 'auto',
            minHeight: 'auto',
            width: 'auto',
            show: {
                effect: 'nb',
                duration: 150
            },
            hide: {
                effect: 'nb',
                duration: 150
            },
            draggable: false,
            resizable: false,
            dialogClass: 'nb-popup-outer ui-dialog-no-close',
            position: {
                my: 'center top',
                at: 'center bottom',
                // horizontal: fit, пытаемся уместить в window
                // vertical: flip - выбирает наилучший вариант - вверх или вних
                collision: "fit flip"
            }
        },

        _create: function() {
            this._super();
            var $tail = $('

');

            if (this.options.tail != 'center') {
                $tail.addClass('nb-popup__tail_to_' + this.options.tail);
            }

            //TODO: проверить, что вызывается один раз
            $tail.prependTo(this.uiDialog);
        },

        _position: function() {
            var position = this.options.position;
            this._super();

            var $handler = position.of;
            var handlerOffset = $handler.offset();

            //TODO: вот этого this.uiDialog.css('top', '+=13px'); можно не делать, если сразу в position писать {at: 'center top+13'}
            // положение надо вычислять все руками, потому что jquery-ui никак не сообщает о том, была ли коллизия

            // позиционирования слева или справа
            if (position.at && /^\s*(left|right)/.test(position.at)) {
                var popupLeft = parseInt(this.uiDialog.css('left'), 10);
                if (popupLeft > handlerOffset.left) {
                    // попап находится справа
                    nb.node.setMod(this.uiDialog[0], 'nb-popup_to', 'right');
                    this.uiDialog.data('nb-tail-dir', 'right');
                    this.uiDialog.css('left', '+=' + this.tailOffset * 2);

                } else {
                    nb.node.setMod(this.uiDialog[0], 'nb-popup_to', 'left');
                    this.uiDialog.data('nb-tail-dir', 'left');
                    this.uiDialog.css('left', '-=' + this.tailOffset * 2);
                }

            } else {
                var popupTop = parseInt(this.uiDialog.css('top'), 10);
                if (popupTop > handlerOffset.top) {
                    nb.node.setMod(this.uiDialog[0], 'nb-popup_to', 'bottom');
                    this.uiDialog.data('nb-tail-dir', 'bottom');
                    this.uiDialog.css('top', '+=' + this.tailOffset * 2);

                } else {
                    nb.node.setMod(this.uiDialog[0], 'nb-popup_to', 'top');
                    this.uiDialog.data('nb-tail-dir', 'top');
                    this.uiDialog.css('top', '-=' + this.tailOffset * 2);
                }
            }
        }
    });

    jQuery.effects.effect.nb = function(o, done) {
        var $this = $(this);
        var mode = $.effects.setMode($this, o.mode || "hide");
        var tailDir = $this.data('nb-tail-dir');

        var res = {
            show: {
                'bottom': {
                    opacity: 1,
                    top: '-=' + $.nb.contextDialog.prototype.tailOffset
                },
                'top': {
                    opacity: 1,
                    top: '+=' + $.nb.contextDialog.prototype.tailOffset
                },
                'left': {
                    opacity: 1,
                    left: '+=' + $.nb.contextDialog.prototype.tailOffset
                },
                'right': {
                    opacity: 1,
                    left: '-=' + $.nb.contextDialog.prototype.tailOffset
                }

            },
            hide: {
                'bottom': {
                    opacity: 0,
                    top: '+=' + $.nb.contextDialog.prototype.tailOffset
                },
                'top': {
                    opacity: 0,
                    top: '-=' + $.nb.contextDialog.prototype.tailOffset
                },
                'left': {
                    opacity: 0,
                    left: '-=' + $.nb.contextDialog.prototype.tailOffset
                },
                'right': {
                    opacity: 0,
                    left: '+=' + $.nb.contextDialog.prototype.tailOffset
                }
            }
        };

        if (mode == 'show') {
            $this.show();
        }

        $this.animate(res[mode][tailDir], {
            queue: false,
            duration: o.duration,
            easing: o.easing,
            complete: function() {
                if (mode == 'hide') {
                    $this.hide();
                }
                done();
            }
        });
    };

    //TODO: не понимаю зачем this.moved и this._home

    var popup = {};

    // ----------------------------------------------------------------------------------------------------------------- //

    popup.events = {
        'init': 'oninit',
        'open': 'onopen',
        'click .nb-popup__close': 'onclose',
        'close': 'onclose',
        'destroy': 'ondestroy',
        'position': 'onposition'
    };

    // ----------------------------------------------------------------------------------------------------------------- //

    popup.onposition = function(e, params) {
        var where = params.where;
        var how = params.how;
        this._move(where, how, params);
    };

    popup.ondestroy = function() {
        if (this.node && this.node.widget) {
            this.node.widget.destroy();
        }
    };

    popup.oninit = function() {
        var data = this.data();

        if ('modal' in data) {
            this.modal = true;
        }

        // Храним исходное положение попапа, чтобы возвращать его на место
        var previous = this.node.previousSibling;
        this._home = previous ? { previous: previous } : { parent: this.node.parentNode };
    };

    // ----------------------------------------------------------------------------------------------------------------- //

    /**
     *
     * @param {String} evtName название события
     * @param {Object} params
     * @param {Boolean} [params.closeOpened=true] закрыть ранее открытые окна
     */
    popup.onopen = function(evtName, params) {
        var where = params.where;
        var how = params.how;

        if (typeof params.closeOpened === 'undefined') {
            params.closeOpened = true;
        }

        //  Специальный флаг-костыль.
        //  Если он true, то это значит, что мы только что передвинули открытый попап в другое место
        //  и его не нужно закрывать на клик.
        this.moved = false;

        if (this.where) {
            //  Попап уже открыт
            //  FIXME: Буэээ. Уродливое условие для варианта, когда заданы координаты вместо ноды.
            if (where === this.where || ( (where instanceof Array) && where[0] === this.where[0] && where[1] === this.where[1] )) {
                //  На той же ноде. Значит закрываем его.
                this.trigger('close');
            } else {
                this.moved = true;
                //  На другой ноде. Передвигаем его в нужное место.
                this._move(where, how, params);
            }
        } else {
            //  Попап закрыт. Будем открывать.

            // закрыть все открытые попапы
            if (params.closeOpened) {
                nb.trigger('popup-close');
            }

            $(this.node).removeClass('_hidden');
            //  Передвигаем попап.
            this._move(where, how, params);
            this.trigger('show');

            // Сообщаем в космос, что открылся попап
            nb.trigger('popup-opened', this);
        }
    };

    popup.onclose = function() {

         //  Снимаем флаг о том, что попап открыт.
        this.where = null;

        if (this.node && this.node.widget && this.node.widget.isOpen()) {
            this.node.widget.close();
        }
    };

    // ----------------------------------------------------------------------------------------------------------------- //

    popup._move = function(where, how, params) {
        //  Запоминаем, на какой ноде мы открываем попап.
        this.where = where;
        var that = this;
        var using;

        var data = this.data();
        var isFixed = !!((how && how.fixed) ? how.fixed : data.how);

        if (params.animate) {
            using =  function(props) {
                // без stop событие complete срабатывает дважды
                $(this).stop().animate({
                    left : props.left,
                    top : props.top
                }, {
                    duration: 'fast',
                    queue: false,
                    complete: function() {
                        that.trigger('position.complete');
                    }
                });
            };
        }

        //  Модальный попап двигать не нужно.
        if (this.modal) {
            $(this.node).baseDialog({
                height: data.height,
                minHeight: data.minheight,
                width: data.width,
                show: 'fade',
                hide: 'fade',
                modal: true,
                resizable: false,
                draggable: false,
                dialogClass: 'nb-popup-outer ui-dialog-fixed',
                close: function() {
                    that.trigger('close');
                },
                appendTo: params.appendTo,
                position: {
                    using: using
                }
            });

            return;
        }

        how = how || {};

        $(this.node).contextDialog({
            tail: data.tail,
            position: {
                // где попап
                at: (how.at ? how.at : 'center bottom'),// + ' center',
                // где ссылка, которая открыла попап
                my: (how.my ? how.my : 'center top'),// + ' center',
                fixed: isFixed,
                of: $(this.where),
                // horizontal: fit, пытаемся уместить в window
                // vertical: flip - выбирает наилучший вариант - вверх или вних
                collision: (how.collision ? how.collision : 'fit flip'),
                using: using
            },
            close: function() {
                that.trigger('close');
            }
        });
    };

    nb.define('popup', popup);

    /**
     *  Функция возвращает строку с модификаторами
     *  для обертки попапа, которую добавляет jquery ui,
     *  в соответсвии с модификаторами самого попапа
     *
     *  Например, для попапа заданы классы-модификаторы nb-popup_mod и nb-popup_another-mod,
     *  функция вернет строку 'nb-popup-outer_mod nb-popup-outer_another-mod'
     *
     */
    function _getUIDialogExtraClass() {
        var popupClasses = this.element.attr('class').split(' ') || [];
        // не матчимся на _ в начале слова
        // иначе это глобальный класс
        var modRe = /\w+\_/;

        return $.map(popupClasses, function(item) {
            var bemParts = item.split(modRe);
            var l = bemParts.length;

            return (l > 1) ? 'nb-popup-outer_' + bemParts[l-1] : '';

        }).join(' ');
    }

})();

// ----------------------------------------------------------------------------------------------------------------- //

nb.define('popup-toggler', {

    events: {
        'click': 'onclick'
    },

    'onclick': function() {
        if (this.getMod('_disabled')) {
            return;
        }

        var data = this.data()['popup-toggler'];

        //  Находим соответствующий попап.
        //  Соответствие задается атрибутом `id`.
        var popup = nb.find(data['id']);

        if (popup) {
            popup.trigger('open', {
                //  Относительно чего позиционировать попап.
                //  Если заданы точные координаты в `data.where`, то по ним.
                //  Иначе относительно ноды этого блока.
                where: data.where || this.node,

                //  Как позиционировать попап.
                how: data.how
            });

            return false;
        }
    }

});
<commit_msg>refactors<commit_after>(function() {

    /**
     * @fileOverview Надстройки nb над jQueryUI
     */

    $.nb = {};

    $.widget('nb.baseDialog', $.ui.dialog, {
        options: {
            height: 'auto',
            minHeight: 'auto',
            width: 'auto'
        },
        open: function() {
            this._super();
            var that = this;

            if (!this.options.modal) {
                this._onmousedown = function(e) {
                    if (e.which !== 1) {
                        return;
                    }

                    if ($.contains(that.uiDialog[0], e.target)) {
                        return;
                    }

                    that.close();
                };

                this.document.on('mousedown', this._onmousedown);
            }

            this._onpopupclose = nb.on('popup-close', function() {
                that.close();
            });
        },
        close: function() {
            this._super();
            this.document.off('mousedown', this._onmousedown);
            nb.off('popup-close', this._onpopupclose);
        },
        _create: function() {
            this.options.dialogClass += _getUIDialogExtraClass.call(this);
            this.options.dialogClass += (this.options.position.fixed) ? ' ui-dialog-fixed' : '';
            this._super();
            this.element[0].widget = this;
        },
        _destroy: function() {
            this._super();
            delete this.element[0].widget;
        },
        _createTitlebar: function() {
            this.uiDialogTitlebarClose = $();
        }
    });

    // диалог с хвостиком
    jQuery.widget('nb.contextDialog', $.nb.baseDialog, {

        tailOffset: 13,

        options: {
            tail: 'center',
            height: 'auto',
            minHeight: 'auto',
            width: 'auto',
            show: {
                effect: 'nb',
                duration: 150
            },
            hide: {
                effect: 'nb',
                duration: 150
            },
            draggable: false,
            resizable: false,
            dialogClass: 'nb-popup-outer ui-dialog-no-close',
            position: {
                my: 'center top',
                at: 'center bottom',
                // horizontal: fit, пытаемся уместить в window
                // vertical: flip - выбирает наилучший вариант - вверх или вних
                collision: "fit flip"
            }
        },

        _create: function() {
            this._super();
            var $tail = $('

');

            if (this.options.tail != 'center') {
                $tail.addClass('nb-popup__tail_to_' + this.options.tail);
            }

            //TODO: проверить, что вызывается один раз
            $tail.prependTo(this.uiDialog);
        },

        _position: function() {
            var position = this.options.position;
            this._super();

            var $handler = position.of;
            var handlerOffset = $handler.offset();

            //TODO: вот этого this.uiDialog.css('top', '+=13px'); можно не делать, если сразу в position писать {at: 'center top+13'}
            // положение надо вычислять все руками, потому что jquery-ui никак не сообщает о том, была ли коллизия

            // позиционирования слева или справа
            if (position.at && /^\s*(left|right)/.test(position.at)) {
                var popupLeft = parseInt(this.uiDialog.css('left'), 10);
                if (popupLeft > handlerOffset.left) {
                    // попап находится справа
                    nb.node.setMod(this.uiDialog[0], 'nb-popup_to', 'right');
                    this.uiDialog.data('nb-tail-dir', 'right');
                    this.uiDialog.css('left', '+=' + this.tailOffset * 2);

                } else {
                    nb.node.setMod(this.uiDialog[0], 'nb-popup_to', 'left');
                    this.uiDialog.data('nb-tail-dir', 'left');
                    this.uiDialog.css('left', '-=' + this.tailOffset * 2);
                }

            } else {
                var popupTop = parseInt(this.uiDialog.css('top'), 10);
                if (popupTop > handlerOffset.top) {
                    nb.node.setMod(this.uiDialog[0], 'nb-popup_to', 'bottom');
                    this.uiDialog.data('nb-tail-dir', 'bottom');
                    this.uiDialog.css('top', '+=' + this.tailOffset * 2);

                } else {
                    nb.node.setMod(this.uiDialog[0], 'nb-popup_to', 'top');
                    this.uiDialog.data('nb-tail-dir', 'top');
                    this.uiDialog.css('top', '-=' + this.tailOffset * 2);
                }
            }
        }
    });

    jQuery.effects.effect.nb = function(o, done) {
        var $this = $(this);
        var mode = $.effects.setMode($this, o.mode || "hide");
        var tailDir = $this.data('nb-tail-dir');

        var res = {
            show: {
                'bottom': {
                    opacity: 1,
                    top: '-=' + $.nb.contextDialog.prototype.tailOffset
                },
                'top': {
                    opacity: 1,
                    top: '+=' + $.nb.contextDialog.prototype.tailOffset
                },
                'left': {
                    opacity: 1,
                    left: '+=' + $.nb.contextDialog.prototype.tailOffset
                },
                'right': {
                    opacity: 1,
                    left: '-=' + $.nb.contextDialog.prototype.tailOffset
                }

            },
            hide: {
                'bottom': {
                    opacity: 0,
                    top: '+=' + $.nb.contextDialog.prototype.tailOffset
                },
                'top': {
                    opacity: 0,
                    top: '-=' + $.nb.contextDialog.prototype.tailOffset
                },
                'left': {
                    opacity: 0,
                    left: '-=' + $.nb.contextDialog.prototype.tailOffset
                },
                'right': {
                    opacity: 0,
                    left: '+=' + $.nb.contextDialog.prototype.tailOffset
                }
            }
        };

        if (mode == 'show') {
            $this.show();
        }

        $this.animate(res[mode][tailDir], {
            queue: false,
            duration: o.duration,
            easing: o.easing,
            complete: function() {
                if (mode == 'hide') {
                    $this.hide();
                }
                done();
            }
        });
    };

    //TODO: не понимаю зачем this.moved и this._home

    var popup = {};

    // ----------------------------------------------------------------------------------------------------------------- //

    popup.events = {
        'init': 'oninit',
        'open': 'onopen',
        'click .nb-popup__close': 'onclose',
        'close': 'onclose',
        'destroy': 'ondestroy',
        'position': 'onposition'
    };

    // ----------------------------------------------------------------------------------------------------------------- //

    popup.onposition = function(e, params) {
        var where = params.where;
        var how = params.how;
        this._move(where, how, params);
    };

    popup.ondestroy = function() {
        if (this.node && this.node.widget) {
            this.node.widget.destroy();
        }
    };

    popup.oninit = function() {
        var data = this.data();

        if ('modal' in data) {
            this.modal = true;
        }

        // Храним исходное положение попапа, чтобы возвращать его на место
        var previous = this.node.previousSibling;
        this._home = previous ? { previous: previous } : { parent: this.node.parentNode };
    };

    // ----------------------------------------------------------------------------------------------------------------- //

    /**
     *
     * @param {String} evtName название события
     * @param {Object} params
     * @param {Boolean} [params.closeOpened=true] закрыть ранее открытые окна
     */
    popup.onopen = function(evtName, params) {
        var where = params.where;
        var how = params.how;

        if (typeof params.closeOpened === 'undefined') {
            params.closeOpened = true;
        }

        //  Специальный флаг-костыль.
        //  Если он true, то это значит, что мы только что передвинули открытый попап в другое место
        //  и его не нужно закрывать на клик.
        this.moved = false;

        if (this.where) {
            //  Попап уже открыт
            //  FIXME: Буэээ. Уродливое условие для варианта, когда заданы координаты вместо ноды.
            if (where === this.where || ( (where instanceof Array) && where[0] === this.where[0] && where[1] === this.where[1] )) {
                //  На той же ноде. Значит закрываем его.
                this.trigger('close');
            } else {
                this.moved = true;
                //  На другой ноде. Передвигаем его в нужное место.
                this._move(where, how, params);
            }
        } else {
            //  Попап закрыт. Будем открывать.

            // закрыть все открытые попапы
            if (params.closeOpened) {
                nb.trigger('popup-close');
            }

            $(this.node).removeClass('_hidden');
            //  Передвигаем попап.
            this._move(where, how, params);
            this.trigger('show');

            // Сообщаем в космос, что открылся попап
            nb.trigger('popup-opened', this);
        }
    };

    popup.onclose = function() {

         //  Снимаем флаг о том, что попап открыт.
        this.where = null;

        if (this.node && this.node.widget && this.node.widget.isOpen()) {
            this.node.widget.close();
        }
    };

    // ----------------------------------------------------------------------------------------------------------------- //

    popup._move = function(where, how, params) {
        //  Запоминаем, на какой ноде мы открываем попап.
        this.where = where;
        var that = this;
        var using;

        var data = this.data();
        var isFixed = !!(how && how.fixed || data.how);

        if (params.animate) {
            using =  function(props) {
                // без stop событие complete срабатывает дважды
                $(this).stop().animate({
                    left : props.left,
                    top : props.top
                }, {
                    duration: 'fast',
                    queue: false,
                    complete: function() {
                        that.trigger('position.complete');
                    }
                });
            };
        }

        //  Модальный попап двигать не нужно.
        if (this.modal) {
            $(this.node).baseDialog({
                height: data.height,
                minHeight: data.minheight,
                width: data.width,
                show: 'fade',
                hide: 'fade',
                modal: true,
                resizable: false,
                draggable: false,
                dialogClass: 'nb-popup-outer ui-dialog-fixed',
                close: function() {
                    that.trigger('close');
                },
                appendTo: params.appendTo,
                position: {
                    using: using
                }
            });

            return;
        }

        how = how || {};

        $(this.node).contextDialog({
            tail: data.tail,
            position: {
                // где попап
                at: (how.at ? how.at : 'center bottom'),// + ' center',
                // где ссылка, которая открыла попап
                my: (how.my ? how.my : 'center top'),// + ' center',
                fixed: isFixed,
                of: $(this.where),
                // horizontal: fit, пытаемся уместить в window
                // vertical: flip - выбирает наилучший вариант - вверх или вних
                collision: (how.collision ? how.collision : 'fit flip'),
                using: using
            },
            close: function() {
                that.trigger('close');
            }
        });
    };

    nb.define('popup', popup);

    /**
     *  Функция возвращает строку с модификаторами
     *  для обертки попапа, которую добавляет jquery ui,
     *  в соответсвии с модификаторами самого попапа
     *
     *  Например, для попапа заданы классы-модификаторы nb-popup_mod и nb-popup_another-mod,
     *  функция вернет строку 'nb-popup-outer_mod nb-popup-outer_another-mod'
     *
     */
    function _getUIDialogExtraClass() {
        var popupClasses = this.element.attr('class').split(' ') || [];
        // не матчимся на _ в начале слова
        // иначе это глобальный класс,
        // не мачимся на __, чтобы ислючить элемент
        var modRe = /\w+\_(?!_)/;
        var uiDialogClasses;

        uiDialogClasses = $.map(popupClasses, function(item) {
            var parts = item.split(modRe);
            var l = parts.length;
            var modifier = parts.pop();
            var newClass = '';

            // в массиве должно быть больше 1 элемента
            // иначе модификатора не было
            if (l > 1) {
                newClass = 'nb-popup-outer_' + modifier;
            }

            return newClass;
        });

        return uiDialogClasses.join(' ');
    }

})();

// ----------------------------------------------------------------------------------------------------------------- //

nb.define('popup-toggler', {

    events: {
        'click': 'onclick'
    },

    'onclick': function() {
        if (this.getMod('_disabled')) {
            return;
        }

        var data = this.data()['popup-toggler'];

        //  Находим соответствующий попап.
        //  Соответствие задается атрибутом `id`.
        var popup = nb.find(data['id']);

        if (popup) {
            popup.trigger('open', {
                //  Относительно чего позиционировать попап.
                //  Если заданы точные координаты в `data.where`, то по ним.
                //  Иначе относительно ноды этого блока.
                where: data.where || this.node,

                //  Как позиционировать попап.
                how: data.how
            });

            return false;
        }
    }

});
<|endoftext|>


<commit_before>(function() {

/**
 * @fileOverview Надстройки nb над jQueryUI
 */

$.nb = {};

// диалог, закрывающий по нажатию вне
jQuery.widget('nb.dialogCloseOnOuterClick', $.ui.dialog, {
    open: function() {
        var that = this;
        this._super();

        this._on(this.document, {
            mousedown: function(e) {
                if (!$.contains(this.uiDialog[0], e.target)) {
                    this.close();
                }
            }
        });

        this._onpopupclose = nb.on('popup-close', function() {
            that.close();
        });
    },
    close: function() {
        this._super();

        this._off(this.document, 'mousedown');
        nb.off('popup-close', this._onpopupclose);
    }
});

// диалог с хвостиком + dialogCloseOnOuterClick
jQuery.widget('nb.contextDialog', $.nb.dialogCloseOnOuterClick, {

    tailOffset: 13,

    options: {
        height: 'auto',
        minHeight: 'auto',
        width: 'auto',
        show: {
            effect: 'nb',
            duration: 150
        },
        hide: {
            effect: 'nb',
            duration: 150
        },
        draggable: false,
        resizable: false,
        dialogClass: 'nb-popup-outer ui-dialog-no-close',
        position: {
            my: 'center top',
            at: 'center bottom',
            // horizontal: fit, пытаемся уместить в window
            // vertical: flip - выбирает наилучший вариант - вверх или вних
            collision: "fit flip"
        }
    },

    _create: function() {
        this._super();
        //TODO: проверить, что вызывается один раз
        $('

').prependTo(this.uiDialog);
    },

    _position: function() {
        var position = this.options.position;
        this._super();

        var $handler = position.of;
        var handlerOffset = $handler.offset();

        //TODO: вот этого this.uiDialog.css('top', '+=13px'); можно не делать, если сразу в position писать {at: 'center top+13'}
        // положение надо вычислять все руками, потому что jquery-ui никак не сообщает о том, была ли коллизия

        // позиционирования слева или справа
        if (position.at && /^\s*(left|right)/.test(position.at) ) {
            var popupLeft = parseInt(this.uiDialog.css('left'), 10);
            if (popupLeft > handlerOffset.left) {
                // попап находится справа
                nb.node.setMod(this.uiDialog[0], 'nb-popup_tail_to', 'right');
                this.uiDialog.data('nb-tail-dir', 'right');
                this.uiDialog.css('left', '+=' + this.tailOffset * 2);

            } else {
                nb.node.setMod(this.uiDialog[0], 'nb-popup_tail_to', 'left');
                this.uiDialog.data('nb-tail-dir', 'left');
                this.uiDialog.css('left', '-=' + this.tailOffset * 2);
            }

        } else {
            var popupTop = parseInt(this.uiDialog.css('top'), 10);
            if (popupTop > handlerOffset.top) {
                nb.node.setMod(this.uiDialog[0], 'nb-popup_tail_to', 'bottom');
                this.uiDialog.data('nb-tail-dir', 'bottom');
                this.uiDialog.css('top', '+=' + this.tailOffset * 2);

            } else {
                nb.node.setMod(this.uiDialog[0], 'nb-popup_tail_to', 'top');
                this.uiDialog.data('nb-tail-dir', 'top');
                this.uiDialog.css('top', '-=' + this.tailOffset * 2);
            }
        }
    }
});

jQuery.effects.effect.nb = function(o, done) {
    var $this = $(this);
    var mode = $.effects.setMode( $this, o.mode || "hide" );
    var tailDir = $this.data('nb-tail-dir');

    if (tailDir)

    var res = {
        show: {
            'bottom': {
                opacity: 1,
                top: '-=' + $.nb.contextDialog.prototype.tailOffset
            },
            'top': {
                opacity: 1,
                top: '+=' + $.nb.contextDialog.prototype.tailOffset
            },
            'left': {
                opacity: 1,
                left: '+=' + $.nb.contextDialog.prototype.tailOffset
            },
            'right': {
                opacity: 1,
                left: '-=' + $.nb.contextDialog.prototype.tailOffset
            }

        },
        hide: {
            'bottom': {
                opacity: 0,
                    top: '+=' + $.nb.contextDialog.prototype.tailOffset
            },
            'top': {
                opacity: 0,
                    top: '-=' + $.nb.contextDialog.prototype.tailOffset
            },
            'left': {
                opacity: 0,
                    left: '-=' + $.nb.contextDialog.prototype.tailOffset
            },
            'right': {
                opacity: 0,
                    left: '+=' + $.nb.contextDialog.prototype.tailOffset
            }
        }
    };

    if (mode == 'show') {
        $this.show();
    }

    $this.animate(res[mode][tailDir], {
        queue: false,
        duration: o.duration,
        easing: o.easing,
        complete: function() {
            if (mode == 'hide') {
                $this.hide();
            }
            done();
        }
    });
};

//TODO: не понимаю зачем this.moved и this._home

var popup = {};

// ----------------------------------------------------------------------------------------------------------------- //

popup.events = {
    'init': 'oninit',
    'open': 'onopen',
    'close': 'onclose'
};

// ----------------------------------------------------------------------------------------------------------------- //

popup.oninit = function() {
    var data = this.data();

    if ('modal' in data) {
        this.modal = true;
    }

    // Храним исходное положение попапа, чтобы возвращать его на место
    var previous = this.node.previousSibling;
    this._home = previous ? { previous: previous } : { parent: this.node.parentNode };
};

// ----------------------------------------------------------------------------------------------------------------- //

popup.onopen = function(e, params) {
    var where = params.where;
    var how = params.how;

    //  Специальный флаг-костыль.
    //  Если он true, то это значит, что мы только что передвинули открытый попап в другое место
    //  и его не нужно закрывать на клик.
    this.moved = false;

    if (this.where) {
        //  Попап уже открыт
        //  FIXME: Буэээ. Уродливое условие для варианта, когда заданы координаты вместо ноды.
        if ( where === this.where || ( (where instanceof Array) && where[0] === this.where[0] && where[1] === this.where[1] ) ) {
            //  На той же ноде. Значит закрываем его.
            this.trigger('close');
        } else {
            this.moved = true;
            //  На другой ноде. Передвигаем его в нужное место.
            this._move(where, how);
        }
    } else {
        //  Попап закрыт. Будем открывать.

        //  На всякий случай даем сигнал, что нужно закрыть все открытые попапы.
        nb.trigger('popup-close');

        $(this.node).removeClass('_hidden');
        //  Передвигаем попап.
        this._move(where, how);
        this.trigger('show');

        // Сообщаем в космос, что открылся попап
        nb.trigger('popup-opened', this);
    }
};

popup.onclose = function() {
    //  Снимаем флаг о том, что попап открыт.
    this.where = null;
};

// ----------------------------------------------------------------------------------------------------------------- //

popup._move = function(where, how) {
    //  Запоминаем, на какой ноде мы открываем попап.
    this.where = where;
    var that = this;

    //  Модальный попап двигать не нужно.
    if (this.modal) {
        $(this.node).dialogCloseOnOuterClick({
            show: 'fade',
            hide: 'fade',
            modal: true,
            resizable: false,
            draggable: false,
            dialogClass: 'nb-popup-outer ui-dialog-fixed',
            close: function() {
                that.trigger('close');
            }
        });

        return;
    }

    how = how || {};

    $(this.node).contextDialog({
        position: {
            // где попап
            at: (how.where ? how.where : 'center bottom'),// + ' center',
            // где ссылка, которая открыла попап
            my: (how.what ? how.what : 'center top'),// + ' center',
            of: $(this.where),
            // horizontal: fit, пытаемся уместить в window
            // vertical: flip - выбирает наилучший вариант - вверх или вних
            collision: "fit flip"
        },
        close: function() {
            that.trigger('close');
        }
    });
};

nb.define('popup', popup);

})();

// ----------------------------------------------------------------------------------------------------------------- //

nb.define('popup-toggler', {

    events: {
        'click': 'onclick'
    },

    'onclick': function() {
        if (this.getMod('_disabled')) {
            return;
        }

        var data = this.data()['popup-toggler'];

        //  Находим соответствующий попап.
        //  Соответствие задается атрибутом `id`.
        var popup = nb.find( data['id'] );

        if (popup) {
            popup.trigger('open', {
                //  Относительно чего позиционировать попап.
                //  Если заданы точные координаты в `data.where`, то по ним.
                //  Иначе относительно ноды этого блока.
                where: data.where || this.node,

                //  Как позиционировать попап.
                how: data.how
            });

            return false;
        }
    }

});
<commit_msg>modal popups<commit_after>(function() {

/**
 * @fileOverview Надстройки nb над jQueryUI
 */

$.nb = {};

// диалог, закрывающий по нажатию вне
jQuery.widget('nb.dialogCloseOnOuterClick', $.ui.dialog, {
    open: function() {
        var that = this;
        this._super();

        this._on(this.document, {
            mousedown: function(e) {
                if (!$.contains(this.uiDialog[0], e.target)) {
                    this.close();
                }
            }
        });

        this._onpopupclose = nb.on('popup-close', function() {
            that.close();
        });
    },
    close: function() {
        this._super();

        this._off(this.document, 'mousedown');
        nb.off('popup-close', this._onpopupclose);
    }
});

// диалог с хвостиком + dialogCloseOnOuterClick
jQuery.widget('nb.contextDialog', $.nb.dialogCloseOnOuterClick, {

    tailOffset: 13,

    options: {
        height: 'auto',
        minHeight: 'auto',
        width: 'auto',
        show: {
            effect: 'nb',
            duration: 150
        },
        hide: {
            effect: 'nb',
            duration: 150
        },
        draggable: false,
        resizable: false,
        dialogClass: 'nb-popup-outer ui-dialog-no-close',
        position: {
            my: 'center top',
            at: 'center bottom',
            // horizontal: fit, пытаемся уместить в window
            // vertical: flip - выбирает наилучший вариант - вверх или вних
            collision: "fit flip"
        }
    },

    _create: function() {
        this._super();
        //TODO: проверить, что вызывается один раз
        $('

').prependTo(this.uiDialog);
    },

    _createTitlebar: function(){},
    _title: function(){},
    _createButtonPane: function(){},
    _createButtons: function(){},

    _position: function() {
        var position = this.options.position;
        this._super();

        var $handler = position.of;
        var handlerOffset = $handler.offset();

        //TODO: вот этого this.uiDialog.css('top', '+=13px'); можно не делать, если сразу в position писать {at: 'center top+13'}
        // положение надо вычислять все руками, потому что jquery-ui никак не сообщает о том, была ли коллизия

        // позиционирования слева или справа
        if (position.at && /^\s*(left|right)/.test(position.at) ) {
            var popupLeft = parseInt(this.uiDialog.css('left'), 10);
            if (popupLeft > handlerOffset.left) {
                // попап находится справа
                nb.node.setMod(this.uiDialog[0], 'nb-popup_tail_to', 'right');
                this.uiDialog.data('nb-tail-dir', 'right');
                this.uiDialog.css('left', '+=' + this.tailOffset * 2);

            } else {
                nb.node.setMod(this.uiDialog[0], 'nb-popup_tail_to', 'left');
                this.uiDialog.data('nb-tail-dir', 'left');
                this.uiDialog.css('left', '-=' + this.tailOffset * 2);
            }

        } else {
            var popupTop = parseInt(this.uiDialog.css('top'), 10);
            if (popupTop > handlerOffset.top) {
                nb.node.setMod(this.uiDialog[0], 'nb-popup_tail_to', 'bottom');
                this.uiDialog.data('nb-tail-dir', 'bottom');
                this.uiDialog.css('top', '+=' + this.tailOffset * 2);

            } else {
                nb.node.setMod(this.uiDialog[0], 'nb-popup_tail_to', 'top');
                this.uiDialog.data('nb-tail-dir', 'top');
                this.uiDialog.css('top', '-=' + this.tailOffset * 2);
            }
        }
    }
});

jQuery.effects.effect.nb = function(o, done) {
    var $this = $(this);
    var mode = $.effects.setMode( $this, o.mode || "hide" );
    var tailDir = $this.data('nb-tail-dir');

    if (tailDir)

    var res = {
        show: {
            'bottom': {
                opacity: 1,
                top: '-=' + $.nb.contextDialog.prototype.tailOffset
            },
            'top': {
                opacity: 1,
                top: '+=' + $.nb.contextDialog.prototype.tailOffset
            },
            'left': {
                opacity: 1,
                left: '+=' + $.nb.contextDialog.prototype.tailOffset
            },
            'right': {
                opacity: 1,
                left: '-=' + $.nb.contextDialog.prototype.tailOffset
            }

        },
        hide: {
            'bottom': {
                opacity: 0,
                    top: '+=' + $.nb.contextDialog.prototype.tailOffset
            },
            'top': {
                opacity: 0,
                    top: '-=' + $.nb.contextDialog.prototype.tailOffset
            },
            'left': {
                opacity: 0,
                    left: '-=' + $.nb.contextDialog.prototype.tailOffset
            },
            'right': {
                opacity: 0,
                    left: '+=' + $.nb.contextDialog.prototype.tailOffset
            }
        }
    };

    if (mode == 'show') {
        $this.show();
    }

    $this.animate(res[mode][tailDir], {
        queue: false,
        duration: o.duration,
        easing: o.easing,
        complete: function() {
            if (mode == 'hide') {
                $this.hide();
            }
            done();
        }
    });
};

//TODO: не понимаю зачем this.moved и this._home

var popup = {};

// ----------------------------------------------------------------------------------------------------------------- //

popup.events = {
    'init': 'oninit',
    'open': 'onopen',
    'close': 'onclose'
};

// ----------------------------------------------------------------------------------------------------------------- //

popup.oninit = function() {
    var data = this.data();

    if ('modal' in data) {
        this.modal = true;
    }

    // Храним исходное положение попапа, чтобы возвращать его на место
    var previous = this.node.previousSibling;
    this._home = previous ? { previous: previous } : { parent: this.node.parentNode };
};

// ----------------------------------------------------------------------------------------------------------------- //

popup.onopen = function(e, params) {
    var where = params.where;
    var how = params.how;

    //  Специальный флаг-костыль.
    //  Если он true, то это значит, что мы только что передвинули открытый попап в другое место
    //  и его не нужно закрывать на клик.
    this.moved = false;

    if (this.where) {
        //  Попап уже открыт
        //  FIXME: Буэээ. Уродливое условие для варианта, когда заданы координаты вместо ноды.
        if ( where === this.where || ( (where instanceof Array) && where[0] === this.where[0] && where[1] === this.where[1] ) ) {
            //  На той же ноде. Значит закрываем его.
            this.trigger('close');
        } else {
            this.moved = true;
            //  На другой ноде. Передвигаем его в нужное место.
            this._move(where, how);
        }
    } else {
        //  Попап закрыт. Будем открывать.

        //  На всякий случай даем сигнал, что нужно закрыть все открытые попапы.
        nb.trigger('popup-close');

        $(this.node).removeClass('_hidden');
        //  Передвигаем попап.
        this._move(where, how);
        this.trigger('show');

        // Сообщаем в космос, что открылся попап
        nb.trigger('popup-opened', this);
    }
};

popup.onclose = function() {
    //  Снимаем флаг о том, что попап открыт.
    this.where = null;
};

// ----------------------------------------------------------------------------------------------------------------- //

popup._move = function(where, how) {
    //  Запоминаем, на какой ноде мы открываем попап.
    this.where = where;
    var that = this;

    //  Модальный попап двигать не нужно.
    if (this.modal) {
        $(this.node).dialogCloseOnOuterClick({
            show: 'fade',
            hide: 'fade',
            modal: true,
            resizable: false,
            draggable: false,
            dialogClass: 'nb-popup-outer ui-dialog-fixed',
            close: function() {
                that.trigger('close');
            }
        });

        return;
    }

    how = how || {};

    $(this.node).contextDialog({
        position: {
            // где попап
            at: (how.where ? how.where : 'center bottom'),// + ' center',
            // где ссылка, которая открыла попап
            my: (how.what ? how.what : 'center top'),// + ' center',
            of: $(this.where),
            // horizontal: fit, пытаемся уместить в window
            // vertical: flip - выбирает наилучший вариант - вверх или вних
            collision: "fit flip"
        },
        close: function() {
            that.trigger('close');
        }
    });
};

nb.define('popup', popup);

})();

// ----------------------------------------------------------------------------------------------------------------- //

nb.define('popup-toggler', {

    events: {
        'click': 'onclick'
    },

    'onclick': function() {
        if (this.getMod('_disabled')) {
            return;
        }

        var data = this.data()['popup-toggler'];

        //  Находим соответствующий попап.
        //  Соответствие задается атрибутом `id`.
        var popup = nb.find( data['id'] );

        if (popup) {
            popup.trigger('open', {
                //  Относительно чего позиционировать попап.
                //  Если заданы точные координаты в `data.where`, то по ним.
                //  Иначе относительно ноды этого блока.
                where: data.where || this.node,

                //  Как позиционировать попап.
                how: data.how
            });

            return false;
        }
    }

});
<|endoftext|>


<commit_before>$(document).ready(function() {
    //setup socket.io-client
    var socket = new io.connect();

    //setup handler for receiving the strict with all the expansion pins from the server
    socket.on('getEeproms', function (data) {
        eeproms = data;
        var boneversion = eeproms['/sys/bus/i2c/drivers/at24/1-0050/eeprom'].version.substr(2);
        var boneserial = eeproms['/sys/bus/i2c/drivers/at24/1-0050/eeprom'].serialNumber;

        var bonestring = "BeagleBone " + boneversion + "
";
        bonestring += "Serial number: " + boneserial + "
";

        printPin(eeproms, '/sys/bus/i2c/drivers/at24/3-0054/eeprom');
        printPin(eeproms, '/sys/bus/i2c/drivers/at24/3-0055/eeprom');
        printPin(eeproms, '/sys/bus/i2c/drivers/at24/3-0056/eeprom');
        printPin(eeproms, '/sys/bus/i2c/drivers/at24/3-0057/eeprom');

        $("#eeprom").html(bonestring);
    });
    socket.emit('getEeproms','');
});

function printPin(eeproms, eeprom) {
    var pinString = "";
    address = eeprom.split("/")[6].substr(4);
	if(eeproms[eeprom]) {
        capename = eeproms[eeprom].boardName;
        capebuilder = eeproms[eeprom].manufacturer;
        $('#cape' + address).svg({onLoad: drawBone});
	    $('#cape' + address).width(scale*90 + 'px');
	    $('#cape' + address).height(scale*87 + 'px');
        for(var pin in eeproms[eeprom].mux) {
            if(eeproms[eeprom].mux[pin].used == "used") {
                colourPin($('#cape' + address).svg('get'), pin, eeproms[eeprom].mux[pin].function);
            }
        }
    }
}

var scale = 5;
var radius1 = 25.4/4 * scale;
var radius2 = 25.4/2 * scale;
var bottomside = (2.15 * 25.4) * scale - 2 * radius2;
var topside = (2.15 * 25.4) * scale - 2 * radius1;
var largeside = (3.4 * 25.4) * scale - radius1 - radius2;

function drawBone(svg) {
    var beaglebonesvg = svg.group("beaglebone", {transform: 'translate(' + 15*scale +',1)'});
    var path = svg.createPath();

    svg.path(beaglebonesvg, path.move(radius1,0,false).
    line(topside, 0,true).arc(radius1, radius1, 90, false, true, radius1, radius1, true).
    line(0, largeside, true).arc(radius2, radius2, -90, false, true, -radius2, radius2,true).
    line(-bottomside, 0, true).arc(radius2, radius2, 90, false, true, -radius2, -radius2,true).
    line(0, -largeside, true).arc(radius1, radius1, 90, false, true, radius1, -radius1, true)
    .close(),
    {fill: '#fafafa', stroke: '#000000', strokeWidth: 1});
    svg.rect(beaglebonesvg, 0, 18 * scale,5 * scale, 58 * scale, {fill: '#fafafa', stroke: '#000000', strokeWidth: 1}); //P9
    svg.rect(beaglebonesvg, bottomside + 2 * radius2 - 5*scale, 18 * scale,5 * scale, 58 * scale, {fill: '#fafafa', stroke: '#000000', strokeWidth: 1}); //P8
    for (i=0;i<=22;i++) {
        //P9
        svg.rect(beaglebonesvg, scale/3, 18.5 * scale + 2.5 * i * scale, 2 * scale, 2 * scale,{fill: '#cdcdcd'});
        svg.rect(beaglebonesvg, 2.6*scale,18.5 * scale + 2.5 * i * scale, 2 * scale, 2 * scale,{fill: '#cdcdcd'});
    }
    for (i=0;i<=22;i++) {
        //P8
        svg.rect(beaglebonesvg, scale/3 + bottomside + 2 * radius2 - 5*scale, 18.4 * scale + 2.5 * i * scale, 2 * scale, 2 * scale,{fill: '#cdcdcd'});
        svg.rect(beaglebonesvg, 2.6*scale + bottomside + 2 * radius2 - 5*scale,18.4 * scale + 2.5 * i * scale, 2 * scale, 2 * scale,{fill: '#cdcdcd'});
    }
    svg.text(beaglebonesvg, 27*scale, 30, capebuilder, {'font-family':"Verdana", 'font-size':16, 'text-anchor':"middle"});
    svg.text(beaglebonesvg, 27*scale, 50, capename, {'font-family':"Verdana", 'font-size':16, 'text-anchor':"middle"});
    svg.text(beaglebonesvg, 27*scale, 70, "I²C address 0x" + address, {'font-family':"Verdana", 'font-size':16, 'text-anchor':"middle"});
}

function colourPin(svg, pin, mux) {
	var beaglebonesvg = svg.group("beaglebone", {transform: 'translate(' + 15*scale +',1)'});
	var connector = pin.substr(0,2);
	var pinnumber = pin.substr(3);

	var i = Math.ceil(pinnumber/2) - 1;
	var carry = pinnumber % 2;

	var size = 2 * scale;
	var x = 0;
	var y = 0;
	if(connector == "P8") {
		if(carry == 1){
			x = scale/3 + bottomside + 2 * radius2 - 5*scale;
			y = 18.4 * scale + 2.5 * i * scale;
		} else {
			x = 2.6*scale + bottomside + 2 * radius2 - 5*scale;
			y = 18.4 * scale + 2.5 * i * scale;
		}
	}
	if(connector == "P9") {
		if(carry == 1) {
			x = scale/3;
			y =  18.5 * scale + 2.5 * i * scale;
		} else {
			x = 2.6*scale;
			y = 18.5 * scale + 2.5 * i * scale;
		}
	};
	svg.rect(beaglebonesvg, x, y, size, size , {fill: '#000000'});
	svg.text(beaglebonesvg, x + size/1.6 - 1, y + size - 1, "" + pinnumber, {'font-family':"Verdana", 'font-size':scale*1.5, 'text-anchor':"middle", 'fill':"#bbbbbb"});
	if(carry == 1){
		svg.text(beaglebonesvg,x - scale, y + size, "" + mux, {'font-family':"Verdana", 'font-size':size, 'text-anchor':"end", 'fill':"#222222"});
	} else {
		svg.text(beaglebonesvg,x + scale*3, y + size, "" + mux, {'font-family':"Verdana", 'font-size':size, 'text-anchor':"start", 'fill':"#222222"});
	}
}

<commit_msg>bone101: Display "Black" string for boardName A335BNLT<commit_after>$(document).ready(function() {
    //setup socket.io-client
    var socket = new io.connect();

    //setup handler for receiving the strict with all the expansion pins from the server
    socket.on('getEeproms', function (data) {
        eeproms = data;
        var bonename = eeproms['/sys/bus/i2c/drivers/at24/1-0050/eeprom'].boardName;
        var boneversion = eeproms['/sys/bus/i2c/drivers/at24/1-0050/eeprom'].version.substr(2);
        var boneserial = eeproms['/sys/bus/i2c/drivers/at24/1-0050/eeprom'].serialNumber;

        var bonestring = "BeagleBone ";
        if(bonename.match("A335BNLT")) bonestring += "Black ";
        bonestring += " revision " + boneversion + "
";
        bonestring += "Serial number: " + boneserial + "
";

        printPin(eeproms, '/sys/bus/i2c/drivers/at24/3-0054/eeprom');
        printPin(eeproms, '/sys/bus/i2c/drivers/at24/3-0055/eeprom');
        printPin(eeproms, '/sys/bus/i2c/drivers/at24/3-0056/eeprom');
        printPin(eeproms, '/sys/bus/i2c/drivers/at24/3-0057/eeprom');

        $("#eeprom").html(bonestring);
    });
    socket.emit('getEeproms','');
});

function printPin(eeproms, eeprom) {
    var pinString = "";
    address = eeprom.split("/")[6].substr(4);
	if(eeproms[eeprom]) {
        capename = eeproms[eeprom].boardName;
        capebuilder = eeproms[eeprom].manufacturer;
        $('#cape' + address).svg({onLoad: drawBone});
	    $('#cape' + address).width(scale*90 + 'px');
	    $('#cape' + address).height(scale*87 + 'px');
        for(var pin in eeproms[eeprom].mux) {
            if(eeproms[eeprom].mux[pin].used == "used") {
                colourPin($('#cape' + address).svg('get'), pin, eeproms[eeprom].mux[pin].function);
            }
        }
    }
}

var scale = 5;
var radius1 = 25.4/4 * scale;
var radius2 = 25.4/2 * scale;
var bottomside = (2.15 * 25.4) * scale - 2 * radius2;
var topside = (2.15 * 25.4) * scale - 2 * radius1;
var largeside = (3.4 * 25.4) * scale - radius1 - radius2;

function drawBone(svg) {
    var beaglebonesvg = svg.group("beaglebone", {transform: 'translate(' + 15*scale +',1)'});
    var path = svg.createPath();

    svg.path(beaglebonesvg, path.move(radius1,0,false).
    line(topside, 0,true).arc(radius1, radius1, 90, false, true, radius1, radius1, true).
    line(0, largeside, true).arc(radius2, radius2, -90, false, true, -radius2, radius2,true).
    line(-bottomside, 0, true).arc(radius2, radius2, 90, false, true, -radius2, -radius2,true).
    line(0, -largeside, true).arc(radius1, radius1, 90, false, true, radius1, -radius1, true)
    .close(),
    {fill: '#fafafa', stroke: '#000000', strokeWidth: 1});
    svg.rect(beaglebonesvg, 0, 18 * scale,5 * scale, 58 * scale, {fill: '#fafafa', stroke: '#000000', strokeWidth: 1}); //P9
    svg.rect(beaglebonesvg, bottomside + 2 * radius2 - 5*scale, 18 * scale,5 * scale, 58 * scale, {fill: '#fafafa', stroke: '#000000', strokeWidth: 1}); //P8
    for (i=0;i<=22;i++) {
        //P9
        svg.rect(beaglebonesvg, scale/3, 18.5 * scale + 2.5 * i * scale, 2 * scale, 2 * scale,{fill: '#cdcdcd'});
        svg.rect(beaglebonesvg, 2.6*scale,18.5 * scale + 2.5 * i * scale, 2 * scale, 2 * scale,{fill: '#cdcdcd'});
    }
    for (i=0;i<=22;i++) {
        //P8
        svg.rect(beaglebonesvg, scale/3 + bottomside + 2 * radius2 - 5*scale, 18.4 * scale + 2.5 * i * scale, 2 * scale, 2 * scale,{fill: '#cdcdcd'});
        svg.rect(beaglebonesvg, 2.6*scale + bottomside + 2 * radius2 - 5*scale,18.4 * scale + 2.5 * i * scale, 2 * scale, 2 * scale,{fill: '#cdcdcd'});
    }
    svg.text(beaglebonesvg, 27*scale, 30, capebuilder, {'font-family':"Verdana", 'font-size':16, 'text-anchor':"middle"});
    svg.text(beaglebonesvg, 27*scale, 50, capename, {'font-family':"Verdana", 'font-size':16, 'text-anchor':"middle"});
    svg.text(beaglebonesvg, 27*scale, 70, "I²C address 0x" + address, {'font-family':"Verdana", 'font-size':16, 'text-anchor':"middle"});
}

function colourPin(svg, pin, mux) {
	var beaglebonesvg = svg.group("beaglebone", {transform: 'translate(' + 15*scale +',1)'});
	var connector = pin.substr(0,2);
	var pinnumber = pin.substr(3);

	var i = Math.ceil(pinnumber/2) - 1;
	var carry = pinnumber % 2;

	var size = 2 * scale;
	var x = 0;
	var y = 0;
	if(connector == "P8") {
		if(carry == 1){
			x = scale/3 + bottomside + 2 * radius2 - 5*scale;
			y = 18.4 * scale + 2.5 * i * scale;
		} else {
			x = 2.6*scale + bottomside + 2 * radius2 - 5*scale;
			y = 18.4 * scale + 2.5 * i * scale;
		}
	}
	if(connector == "P9") {
		if(carry == 1) {
			x = scale/3;
			y =  18.5 * scale + 2.5 * i * scale;
		} else {
			x = 2.6*scale;
			y = 18.5 * scale + 2.5 * i * scale;
		}
	};
	svg.rect(beaglebonesvg, x, y, size, size , {fill: '#000000'});
	svg.text(beaglebonesvg, x + size/1.6 - 1, y + size - 1, "" + pinnumber, {'font-family':"Verdana", 'font-size':scale*1.5, 'text-anchor':"middle", 'fill':"#bbbbbb"});
	if(carry == 1){
		svg.text(beaglebonesvg,x - scale, y + size, "" + mux, {'font-family':"Verdana", 'font-size':size, 'text-anchor':"end", 'fill':"#222222"});
	} else {
		svg.text(beaglebonesvg,x + scale*3, y + size, "" + mux, {'font-family':"Verdana", 'font-size':size, 'text-anchor':"start", 'fill':"#222222"});
	}
}

<|endoftext|>


<commit_before>$(function() {
    // When we're using HTTPS, use WSS too.
    var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
    var chatsock = new ReconnectingWebSocket(ws_scheme + '://' + window.location.host + "/chat" + window.location.pathname);

    (function my_func() {
    // your code
    var message = {
            handle: 'keepalive',
            message: 'vote',
            typo: 'keepalive'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        console.log(1)
        setTimeout( my_func, 30);
     })();

    chatsock.onmessage = function(message) {
        var data = JSON.parse(message.data);
        var chat = $("#chat")
        var ele = $('

')

        ele.append(
            $("	").text(data.timestamp)
        )
        ele.append(
            $("	").text(data.handle)
        )
        ele.append(
            $("	").text(data.message)
        )
        chat.append(ele)
    };

    $("#chatform").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: $('#message').val(),
            typo: 'Vote'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });

    $("#startGame").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: 'vote',
            typo: 'startGame'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });

    $("#identification").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: 'vote',
            typo: 'identification'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });

    $("#jugdementView").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: 'vote',
            typo: 'judgement'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });
    $("#poison").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: $('#message').val(),
            typo: 'poison'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });

    $("#save").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: $('#message').val(),
            typo: 'save'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });

    $("#bloom").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: 'vote',
            typo: 'save'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });

    $("#bloom").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: 'vote',
            typo: 'save'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });
});<commit_msg>fix sharen bug<commit_after>$(function() {
    // When we're using HTTPS, use WSS too.
    var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
    var chatsock = new ReconnectingWebSocket(ws_scheme + '://' + window.location.host + "/chat" + window.location.pathname);
    chatsock.onmessage = function(message) {
        var data = JSON.parse(message.data);
        var chat = $("#chat")
        var ele = $('

')

        ele.append(
            $("	").text(data.timestamp)
        )
        ele.append(
            $("	").text(data.handle)
        )
        ele.append(
            $("	").text(data.message)
        )
        chat.append(ele)
    };

    $("#chatform").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: $('#message').val(),
            typo: 'Vote'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });

    $("#startGame").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: 'vote',
            typo: 'startGame'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });

    $("#identification").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: 'vote',
            typo: 'identification'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });

    $("#jugdementView").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: 'vote',
            typo: 'judgement'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });
    $("#poison").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: $('#message').val(),
            typo: 'poison'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });

    $("#save").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: $('#message').val(),
            typo: 'save'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });

    $("#bloom").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: 'vote',
            typo: 'save'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });

    $("#bloom").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: 'vote',
            typo: 'save'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });
});

(function my_func() {
    // your code
    var message = {
            handle: 'keepalive',
            message: 'vote',
            typo: 'keepalive'
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        console.log(1)
        setTimeout( my_func, 30);
     })();<|endoftext|>


<commit_before>// 2014-2015 Markus Hsi-Yang Fritz

var maze = function () {
  var my = {};

  my.data = null;

  my.main = function (selector) {
    $('#footer-icon').click(function () {
      var revealing = parseInt($('footer').css('bottom')) < 0;
      $('footer').animate({
        bottom: revealing
                ? 0
                : -1 * parseInt($('footer').css('height'))
      }, 800, function () {
        if (revealing) {
          $('#footer-icon').removeClass('fa-chevron-circle-up');
          $('#footer-icon').addClass('fa-chevron-circle-down');
        } else {
          $('#footer-icon').removeClass('fa-chevron-circle-down');
          $('#footer-icon').addClass('fa-chevron-circle-up');
        }
      });
    });

    // remove focus after being clicked
    $('.button-header').focus(function () {
      this.blur();
    });

    $('#match-info').click(function () {
      $('#matches-info').toggleClass('hide');
    });

    $('#checkbox-scale').click(function () {
      if ($('#checkbox-scale').prop('checked')) {
        $('#config-dim').prop('disabled', true);
      } else {
        $('#config-dim').prop('disabled', false);
      }
    });

    $('#drop-ref').on('dragenter', dropZoneEnter);
    $('#drop-ref').on('dragleave', dropZoneExit);
    $('#drop-ref').on('dragover', dropZoneOver);
    $('#drop-ref').on('drop', function (e) {
      $(this).removeClass('dropzone-hover');
      getDroppedFasta(e, 'ref');
    });

    $('#drop-query').on('dragenter', dropZoneEnter);
    $('#drop-query').on('dragleave', dropZoneExit);
    $('#drop-query').on('dragover', dropZoneOver);
    $('#drop-query').on('drop', function (e) {
      $(this).removeClass('dropzone-hover');
      getDroppedFasta(e, 'query');
    });

    function dropZoneEnter(e) {
      e.stopPropagation();
      e.preventDefault();
      $(this).addClass('dropzone-hover');
    }

    function dropZoneExit(e) {
      e.stopPropagation();
      e.preventDefault();
      $(this).removeClass('dropzone-hover');
    }

    function dropZoneOver(e) {
      e.stopPropagation();
      e.preventDefault();
    }

    function getDroppedFasta(e, type) {
      e.stopPropagation();
      e.preventDefault();

      var dt = e.dataTransfer || (e.originalEvent && e.originalEvent.dataTransfer);
      var files = e.target.files || (dt && dt.files);
      var f = files[0];

      readFasta(f, type, /\.gz$/.test(f.name));
    }

    function readFasta(f, type, isGzip) {
      var fReader = new FileReader();
      if (isGzip) {
        fReader.readAsArrayBuffer(f);
      } else {
        fReader.readAsText(f);
      }
      fReader.onload = function (e) {
        var fContent = e.target.result;
        if (isGzip) {
          fContent = pako.ungzip(fContent, {'to': 'string'});
        }
        my[type] = parseFastaString(fContent);
        if (my.ref && my.query) {
          $('#visualize').prop('disabled', false);
        }
      }
    }

    $('#visualize').click(function () {
      $('#config-modal').modal('hide');
      $(selector).empty();
      $('#control-btn-left').addClass('hide');
      $('#control-btn-right').addClass('hide');
      $('.spinner').toggleClass('hide');

      var matches = $('#config-matches label.active').text().trim();
      var length = $('#config-length').val();

      $.post('/matches', {
          'matches': matches,
          'length': length,
          'ref': JSON.stringify(my.ref[0]),
          'query': JSON.stringify(my.query)
        }, function (res) {
          $('.spinner').toggleClass('hide');
          my.data = res;
          my.vis(selector, 0);
        }, 'json'
      );
    });
  };

  my.vis = function (selector, dataIdx) {
    $(selector).empty();

    var data = my.data[dataIdx]
    var l1 = my.ref[0].seq.length;
    var l2 = my.query[dataIdx].seq.length;

    $('#control-btn-left').removeClass('hide');
    $('#control-btn-right').removeClass('hide');

    if (dataIdx > 0) {
      $('#control-btn-left').removeClass('disabled');
      $('#control-btn-left:not(disabled)').click(function () {
        my.vis(selector, dataIdx-1);
      });
    } else {
      $('#control-btn-left').addClass('disabled');
    }

    if (dataIdx < my.data.length - 1) {
      $('#control-btn-right').removeClass('disabled');
      $('#control-btn-right:not(disabled)').click(function () {
        my.vis(selector, dataIdx+1);
      });
    } else {
      $('#control-btn-right').addClass('disabled');
    }

    if ($('#checkbox-scale').prop('checked')) {
      my.outerWidth = Math.min($(window).width(), $(window).height()) * 0.8;
    } else {
      my.outerWidth = +$('#config-dim').val();
    }
    my.outerHeight = my.outerWidth;
    my.margin = { top: 25, bottom: 15, left: 50, right: 50 };
    var innerWidth = my.outerWidth - my.margin.left - my.margin.right;
    my.innerWidth = innerWidth;
    var innerHeight = my.outerHeight - my.margin.top - my.margin.bottom;
    my.innerHeight = innerHeight;

    var x = d3.scale.linear()
      .domain([1, l1])
      .range([0, my.innerWidth]);

    var y = d3.scale.linear()
      .domain([1, l2])
      .range([0, my.innerHeight]);

    var xAxisB = d3.svg.axis()
      .scale(x)
      .orient('bottom')
      .tickSize(-my.innerHeight);

    var xAxisT = d3.svg.axis()
      .scale(x)
      .orient('top')
      .tickSize(0);

    var yAxisR = d3.svg.axis()
      .scale(y)
      .orient('right')
      .tickSize(-my.innerWidth);

    var yAxisL = d3.svg.axis()
      .scale(y)
      .orient('left')
      .tickSize(-my.innerWidth);

    var svg = d3.select(selector).append('svg')
      .attr('width', my.outerWidth)
      .attr('height', my.outerHeight);

    var g = svg.append('g')
      .attr('transform', 'translate(' + my.margin.left + ', ' + my.margin.top + ')');

    g.append('g')
      .attr('class', 'x axis b')
      .attr('transform', 'translate(0, ' + my.innerHeight + ')')
      .call(xAxisB);

    g.append('g')
      .attr('class', 'x axis t')
      .call(xAxisT);

    g.append('g')
      .attr('class', 'y axis r')
      .attr('transform', 'translate(' + my.innerWidth + ', 0)')
      .call(yAxisR);

    g.append('g')
      .attr('class', 'y axis l')
      .call(yAxisL);

    g.selectAll('line.matches')
      .data(data.fwd.concat(data.rev))
      .enter()
      .append('line')
      .attr('class', 'geom matches')
      .attr('x1', function (d) { return x(d[0]); })
      .attr('x2', function (d) { return x(d[1]); })
      .attr('y1', function (d) { return y(d[2]); })
      .attr('y2', function (d) { return y(d[3]); })
      // TODO should do this via CSS classes:
      .style('stroke', function (d) {
        return d[2] < d[3] ? 'black' : 'red'
      });
  };

  return my;
}();

$(maze.main.bind(null, '#vis'));

function LineReader(str) {
  this.str = str;
  this.i = 0;
  this.next = nextLine;
}

function nextLine() {
  l = '';
  for (; this.i < this.str.length; this.i += 1) {
    if (this.str[this.i] === '\n') {
      this.i += 1;
      break;
    }
    l += this.str[this.i];
  }
  return l;
}

function parseFastaString(s) {
  var seqs = [];
  var name = seq = null;

  var lr = new LineReader(s);
  while (l = lr.next()) {
    if (l[0] === '>') {
      if (name) {
        seqs.push({'name': name, 'seq': seq});
      }
      seq = '';
      name = />(\w+)/.exec(l)[1];
    } else {
      seq += l;
    }
  }

  if (name) {
    seqs.push({'name': name, 'seq': seq});
  }

  return seqs;
}
<commit_msg>Use toggleClass instead of add & remove<commit_after>// 2014-2015 Markus Hsi-Yang Fritz

var maze = function () {
  var my = {};

  my.data = null;

  my.main = function (selector) {
    $('#footer-icon').click(function () {
      var revealing = parseInt($('footer').css('bottom')) < 0;
      $('footer').animate({
        bottom: revealing
                ? 0
                : -1 * parseInt($('footer').css('height'))
      }, 800, function () {
        $('#footer-icon').toggleClass('fa-chevron-circle-up');
        $('#footer-icon').toggleClass('fa-chevron-circle-down');
      });
    });

    // remove focus after being clicked
    $('.button-header').focus(function () {
      this.blur();
    });

    $('#match-info').click(function () {
      $('#matches-info').toggleClass('hide');
    });

    $('#checkbox-scale').click(function () {
      if ($('#checkbox-scale').prop('checked')) {
        $('#config-dim').prop('disabled', true);
      } else {
        $('#config-dim').prop('disabled', false);
      }
    });

    $('#drop-ref').on('dragenter', dropZoneEnter);
    $('#drop-ref').on('dragleave', dropZoneExit);
    $('#drop-ref').on('dragover', dropZoneOver);
    $('#drop-ref').on('drop', function (e) {
      $(this).removeClass('dropzone-hover');
      getDroppedFasta(e, 'ref');
    });

    $('#drop-query').on('dragenter', dropZoneEnter);
    $('#drop-query').on('dragleave', dropZoneExit);
    $('#drop-query').on('dragover', dropZoneOver);
    $('#drop-query').on('drop', function (e) {
      $(this).removeClass('dropzone-hover');
      getDroppedFasta(e, 'query');
    });

    function dropZoneEnter(e) {
      e.stopPropagation();
      e.preventDefault();
      $(this).addClass('dropzone-hover');
    }

    function dropZoneExit(e) {
      e.stopPropagation();
      e.preventDefault();
      $(this).removeClass('dropzone-hover');
    }

    function dropZoneOver(e) {
      e.stopPropagation();
      e.preventDefault();
    }

    function getDroppedFasta(e, type) {
      e.stopPropagation();
      e.preventDefault();

      var dt = e.dataTransfer || (e.originalEvent && e.originalEvent.dataTransfer);
      var files = e.target.files || (dt && dt.files);
      var f = files[0];

      readFasta(f, type, /\.gz$/.test(f.name));
    }

    function readFasta(f, type, isGzip) {
      var fReader = new FileReader();
      if (isGzip) {
        fReader.readAsArrayBuffer(f);
      } else {
        fReader.readAsText(f);
      }
      fReader.onload = function (e) {
        var fContent = e.target.result;
        if (isGzip) {
          fContent = pako.ungzip(fContent, {'to': 'string'});
        }
        my[type] = parseFastaString(fContent);
        if (my.ref && my.query) {
          $('#visualize').prop('disabled', false);
        }
      }
    }

    $('#visualize').click(function () {
      $('#config-modal').modal('hide');
      $(selector).empty();
      $('#control-btn-left').addClass('hide');
      $('#control-btn-right').addClass('hide');
      $('.spinner').toggleClass('hide');

      var matches = $('#config-matches label.active').text().trim();
      var length = $('#config-length').val();

      $.post('/matches', {
          'matches': matches,
          'length': length,
          'ref': JSON.stringify(my.ref[0]),
          'query': JSON.stringify(my.query)
        }, function (res) {
          $('.spinner').toggleClass('hide');
          my.data = res;
          my.vis(selector, 0);
        }, 'json'
      );
    });
  };

  my.vis = function (selector, dataIdx) {
    $(selector).empty();

    var data = my.data[dataIdx]
    var l1 = my.ref[0].seq.length;
    var l2 = my.query[dataIdx].seq.length;

    $('#control-btn-left').removeClass('hide');
    $('#control-btn-right').removeClass('hide');

    if (dataIdx > 0) {
      $('#control-btn-left').removeClass('disabled');
      $('#control-btn-left:not(disabled)').click(function () {
        my.vis(selector, dataIdx-1);
      });
    } else {
      $('#control-btn-left').addClass('disabled');
    }

    if (dataIdx < my.data.length - 1) {
      $('#control-btn-right').removeClass('disabled');
      $('#control-btn-right:not(disabled)').click(function () {
        my.vis(selector, dataIdx+1);
      });
    } else {
      $('#control-btn-right').addClass('disabled');
    }

    if ($('#checkbox-scale').prop('checked')) {
      my.outerWidth = Math.min($(window).width(), $(window).height()) * 0.8;
    } else {
      my.outerWidth = +$('#config-dim').val();
    }
    my.outerHeight = my.outerWidth;
    my.margin = { top: 25, bottom: 15, left: 50, right: 50 };
    var innerWidth = my.outerWidth - my.margin.left - my.margin.right;
    my.innerWidth = innerWidth;
    var innerHeight = my.outerHeight - my.margin.top - my.margin.bottom;
    my.innerHeight = innerHeight;

    var x = d3.scale.linear()
      .domain([1, l1])
      .range([0, my.innerWidth]);

    var y = d3.scale.linear()
      .domain([1, l2])
      .range([0, my.innerHeight]);

    var xAxisB = d3.svg.axis()
      .scale(x)
      .orient('bottom')
      .tickSize(-my.innerHeight);

    var xAxisT = d3.svg.axis()
      .scale(x)
      .orient('top')
      .tickSize(0);

    var yAxisR = d3.svg.axis()
      .scale(y)
      .orient('right')
      .tickSize(-my.innerWidth);

    var yAxisL = d3.svg.axis()
      .scale(y)
      .orient('left')
      .tickSize(-my.innerWidth);

    var svg = d3.select(selector).append('svg')
      .attr('width', my.outerWidth)
      .attr('height', my.outerHeight);

    var g = svg.append('g')
      .attr('transform', 'translate(' + my.margin.left + ', ' + my.margin.top + ')');

    g.append('g')
      .attr('class', 'x axis b')
      .attr('transform', 'translate(0, ' + my.innerHeight + ')')
      .call(xAxisB);

    g.append('g')
      .attr('class', 'x axis t')
      .call(xAxisT);

    g.append('g')
      .attr('class', 'y axis r')
      .attr('transform', 'translate(' + my.innerWidth + ', 0)')
      .call(yAxisR);

    g.append('g')
      .attr('class', 'y axis l')
      .call(yAxisL);

    g.selectAll('line.matches')
      .data(data.fwd.concat(data.rev))
      .enter()
      .append('line')
      .attr('class', 'geom matches')
      .attr('x1', function (d) { return x(d[0]); })
      .attr('x2', function (d) { return x(d[1]); })
      .attr('y1', function (d) { return y(d[2]); })
      .attr('y2', function (d) { return y(d[3]); })
      // TODO should do this via CSS classes:
      .style('stroke', function (d) {
        return d[2] < d[3] ? 'black' : 'red'
      });
  };

  return my;
}();

$(maze.main.bind(null, '#vis'));

function LineReader(str) {
  this.str = str;
  this.i = 0;
  this.next = nextLine;
}

function nextLine() {
  l = '';
  for (; this.i < this.str.length; this.i += 1) {
    if (this.str[this.i] === '\n') {
      this.i += 1;
      break;
    }
    l += this.str[this.i];
  }
  return l;
}

function parseFastaString(s) {
  var seqs = [];
  var name = seq = null;

  var lr = new LineReader(s);
  while (l = lr.next()) {
    if (l[0] === '>') {
      if (name) {
        seqs.push({'name': name, 'seq': seq});
      }
      seq = '';
      name = />(\w+)/.exec(l)[1];
    } else {
      seq += l;
    }
  }

  if (name) {
    seqs.push({'name': name, 'seq': seq});
  }

  return seqs;
}
<|endoftext|>


<commit_before>let Simulation = require('./simulation')
let modules = require('./strategies')
let min = 14226 // 0.1 USD
let max = 142251558 // 1000 USD

let results = []
let utxos = Simulation.generateTxos(15, min, max)

// n samples
for (var j = 0; j < 100; ++j) {
  // for each strategy
  for (var name in modules) {
    let f = modules[name]
    let simulation = new Simulation(name, f, 56)
    utxos.forEach(x => simulation.addUTXO(x))

    // n transactions
    for (let i = 0; i < 50; ++i) {
      let outputs = Simulation.generateTxos(1, min, max)
      outputs.forEach(x => (x.address = 'A'))

      simulation.run(outputs)
    }

    results.push(simulation)
  }
}

function pad (i) {
  if (typeof i === 'number') i = Math.round(i * 1000) / 1000
  return ('          ' + i).slice(-10)
}

// sort by transactions ASCENDING
// then fees DESCENDING
// top 20 only
results.sort((a, b) => {
  if (a.stats.transactions !== a.stats.transactions) return a.stats.transactions - b.stats.transactions
  return b.stats.fees - a.stats.fees
}).slice(0, 20).forEach(x => {
  let { stats } = x
  let nInputs = stats.inputs / stats.transactions
  let nOutputs = stats.outputs / stats.transactions
  let failedRatio = stats.failed / (stats.failed + stats.transactions)
  let feeRateAverage = Math.floor(stats.fees / stats.bytes)
  let feeAverage = Math.floor(stats.fees / stats.transactions)

  console.log(
    pad(stats.name),
    '| fee', pad('' + feeAverage),
    '| feeRate', pad('' + feeRateAverage),
    '| nInputs', pad(nInputs),
    '| nOutputs', pad(nOutputs),
    '| DNF', Math.round(100 * failedRatio) + '%'
  )
})
<commit_msg>add result merging option<commit_after>let Simulation = require('./simulation')
let modules = require('./strategies')
let min = 14226 // 0.1 USD
let max = 142251558 // 1000 USD

let results = []
let utxos = Simulation.generateTxos(15, min, max)

// n samples
for (var j = 0; j < 1000; ++j) {
  // for each strategy
  for (var name in modules) {
    let f = modules[name]
    let simulation = new Simulation(name, f, 56)
    utxos.forEach(x => simulation.addUTXO(x))

    // n transactions
    for (let i = 0; i < 50; ++i) {
      let outputs = Simulation.generateTxos(1, min, max)
      outputs.forEach(x => (x.address = 'A'))

      simulation.run(outputs)
    }

    results.push(simulation)
  }
}

function pad (i) {
  if (typeof i === 'number') i = Math.round(i * 1000) / 1000
  return ('          ' + i).slice(-10)
}

function merge (results) {
  let resultMap = {}

  results.forEach(x => {
    let { stats } = x
    let result = resultMap[stats.name]

    if (result) {
      result.inputs += stats.inputs
      result.outputs += stats.outputs
      result.transactions += stats.transactions
      result.failed += stats.failed
      result.fees += stats.fees
      result.bytes += stats.bytes
    } else {
      resultMap[stats.name] = Object.assign({}, stats)
    }
  })

  return Object.keys(resultMap).map(k => ({ stats: resultMap[k] }))
}

// sort by transactions ASCENDING
// then fees DESCENDING
// top 20 only
merge(results).sort((a, b) => {
  let aDNF = a.stats.failed / (a.stats.failed + a.stats.transactions)
  let bDNF = b.stats.failed / (b.stats.failed + b.stats.transactions)

  return aDNF - bDNF
}).slice(0, 20).forEach(x => {
  let { stats } = x
  let nInputs = stats.inputs / stats.transactions
  let nOutputs = stats.outputs / stats.transactions
  let DNF = stats.failed / (stats.failed + stats.transactions)
  let feeRateAverage = Math.floor(stats.fees / stats.bytes)
  let feeAverage = Math.floor(stats.fees / stats.transactions)

  console.log(
    pad(stats.name),
    '| fee', pad('' + feeAverage),
    '| feeRate', pad('' + feeRateAverage),
    '| nInputs', pad(nInputs),
    '| nOutputs', pad(nOutputs),
    '| DNF', Math.round(100 * DNF) + '%'
  )
})
<|endoftext|>


<commit_before>/**
 * Worker that monitors health metrics and saves results
 **/
var config = require('../config');
var redis = require('../store/redis');
var db = require('../store/db');
var cassandra = require('../store/cassandra');
var utility = require('../util/utility');
var request = require('request');
var api_key = config.STEAM_API_KEY.split(',')[0];
var health = {
    random_player: function random_player(cb)
    {
        db.raw(`select account_id from players tablesample system(1) limit 1`).asCallback(function (err, result)
        {
            if (err)
            {
                return cb(err);
            }
            if (!result.rows[0])
            {
                return cb();
            }
            request(config.ROOT_URL + "/api/players/" + result.rows[0].account_id, function (err, resp, body)
            {
                var fail = err || resp.statusCode !== 200;
                return cb(fail,
                {
                    metric: Number(fail),
                    threshold: 1,
                });
            });
        });
    },
    steam_api: function steam_api(cb)
    {
        request("http://api.steampowered.com" + "/IDOTA2Match_570/GetMatchHistory/V001/?key=" + api_key, function (err, resp, body)
        {
            if (err || resp.statusCode !== 200)
            {
                return cb("bad http response");
            }
            try
            {
                var fail = err || resp.statusCode !== 200 || JSON.parse(body).result.status !== 1;
                return cb(fail,
                {
                    metric: Number(fail),
                    threshold: 1,
                });
            }
            catch (e)
            {
                return cb('malformed http response');
            }
        });
    },
    seq_num_delay: function seq_num_delay(cb)
    {
        utility.getData(utility.generateJob("api_history",
        {}).url, function (err, body)
        {
            if (err)
            {
                return cb("failed to get current sequence number");
            }
            //get match_seq_num, compare with real seqnum
            var curr_seq_num = body.result.matches[0].match_seq_num;
            redis.get('match_seq_num', function (err, num)
            {
                if (err)
                {
                    return cb(err);
                }
                num = Number(num);
                var metric = curr_seq_num - num;
                return cb(err,
                {
                    metric: metric,
                    threshold: 10000,
                });
            });
        });
    },
    redis_usage: function redis_usage(cb)
    {
        redis.info(function (err, info)
        {
            if (err)
            {
                return cb(err);
            }
            return cb(err,
            {
                metric: redis.server_info.used_memory,
                threshold: 13 * Math.pow(10, 9),
            });
        });
    },
    postgres_usage: function postgres_usage(cb)
    {
        db.raw(`select pg_database_size('yasp')`).asCallback(function (err, result)
        {
            if (err)
            {
                return cb(err);
            }
            return cb(err,
            {
                metric: result.rows[0].pg_database_size,
                threshold: 2 * Math.pow(10, 11),
            });
        });
    },
    cassandra_usage: function cassandra_usage(cb)
    {
        cassandra.execute(`select mean_partition_size, partitions_count from system.size_estimates where keyspace_name = 'yasp'`, function (err, result)
        {
            if (err)
            {
                return cb(err);
            }
            var size = 0;
            result.rows.forEach(function (r)
            {
                size += r.mean_partition_size * r.partitions_count * 0.6 * 4;
            });
            return cb(err,
            {
                metric: size,
                threshold: 8 * Math.pow(10, 12),
            });
        });
    },
};
for (var key in health)
{
    invokeInterval(health[key]);
}

function invokeInterval(func)
{
    //invokes the function immediately, waits for callback, waits the delay, and then calls it again
    (function invoker()
    {
        console.log("running %s", func.name);
        console.time(func.name);
        func(function (err, result)
        {
            if (err)
            {
                console.error(err);
                result = {
                    metric: 1,
                    threshold: 0,
                };
            }
            if (result)
            {
                result.timestamp = ~~(new Date() / 1000);
                redis.hset('health', func.name, JSON.stringify(result));
            }
            console.timeEnd(func.name);
            setTimeout(invoker, result && result.delay ? result.delay : 10000);
        });
    })();
}
<commit_msg>retry failed account_ids in monitor<commit_after>/**
 * Worker that monitors health metrics and saves results
 **/
var config = require('../config');
var redis = require('../store/redis');
var db = require('../store/db');
var cassandra = require('../store/cassandra');
var utility = require('../util/utility');
var request = require('request');
var api_key = config.STEAM_API_KEY.split(',')[0];
var failing_account_id;
var health = {
    random_player: function random_player(cb)
    {
        db.raw(`select account_id from players tablesample system(1) limit 1`).asCallback(function (err, result)
        {
            if (err)
            {
                return cb(err);
            }
            if (!result.rows[0])
            {
                return cb();
            }
            request(config.ROOT_URL + "/api/players/" + (failing_account_id || result.rows[0].account_id), function (err, resp, body)
            {
                var fail = err || resp.statusCode !== 200;
                if (fail)
                {
                    failing_account_id = result.rows[0].account_id;
                    console.log('[FAILING] account_id %s', failing_account_id);
                }
                return cb(fail,
                {
                    metric: Number(fail),
                    threshold: 1,
                });
            });
        });
    },
    steam_api: function steam_api(cb)
    {
        request("http://api.steampowered.com" + "/IDOTA2Match_570/GetMatchHistory/V001/?key=" + api_key, function (err, resp, body)
        {
            if (err || resp.statusCode !== 200)
            {
                return cb("bad http response");
            }
            try
            {
                var fail = err || resp.statusCode !== 200 || JSON.parse(body).result.status !== 1;
                return cb(fail,
                {
                    metric: Number(fail),
                    threshold: 1,
                });
            }
            catch (e)
            {
                return cb('malformed http response');
            }
        });
    },
    seq_num_delay: function seq_num_delay(cb)
    {
        utility.getData(utility.generateJob("api_history",
        {}).url, function (err, body)
        {
            if (err)
            {
                return cb("failed to get current sequence number");
            }
            //get match_seq_num, compare with real seqnum
            var curr_seq_num = body.result.matches[0].match_seq_num;
            redis.get('match_seq_num', function (err, num)
            {
                if (err)
                {
                    return cb(err);
                }
                num = Number(num);
                var metric = curr_seq_num - num;
                return cb(err,
                {
                    metric: metric,
                    threshold: 10000,
                });
            });
        });
    },
    redis_usage: function redis_usage(cb)
    {
        redis.info(function (err, info)
        {
            if (err)
            {
                return cb(err);
            }
            return cb(err,
            {
                metric: redis.server_info.used_memory,
                threshold: 13 * Math.pow(10, 9),
            });
        });
    },
    postgres_usage: function postgres_usage(cb)
    {
        db.raw(`select pg_database_size('yasp')`).asCallback(function (err, result)
        {
            if (err)
            {
                return cb(err);
            }
            return cb(err,
            {
                metric: result.rows[0].pg_database_size,
                threshold: 2 * Math.pow(10, 11),
            });
        });
    },
    cassandra_usage: function cassandra_usage(cb)
    {
        cassandra.execute(`select mean_partition_size, partitions_count from system.size_estimates where keyspace_name = 'yasp'`, function (err, result)
        {
            if (err)
            {
                return cb(err);
            }
            var size = 0;
            result.rows.forEach(function (r)
            {
                size += r.mean_partition_size * r.partitions_count * 0.5 * 4;
            });
            return cb(err,
            {
                metric: size,
                threshold: 8 * Math.pow(10, 12),
            });
        });
    },
};
for (var key in health)
{
    invokeInterval(health[key]);
}

function invokeInterval(func)
{
    //invokes the function immediately, waits for callback, waits the delay, and then calls it again
    (function invoker()
    {
        console.log("running %s", func.name);
        console.time(func.name);
        func(function (err, result)
        {
            if (err)
            {
                console.error(err);
                result = {
                    metric: 1,
                    threshold: 0,
                };
            }
            if (result)
            {
                result.timestamp = ~~(new Date() / 1000);
                redis.hset('health', func.name, JSON.stringify(result));
            }
            console.timeEnd(func.name);
            setTimeout(invoker, result && result.delay ? result.delay : 10000);
        });
    })();
}
<|endoftext|>