<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 * Distributed under the BSD license:
 *
 * Copyright (c) 2010, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ***** END LICENSE BLOCK ***** */

define(function(require, exports, module) {
"use strict";

// tokenizing lines longer than this makes editor very slow
var MAX_TOKEN_COUNT = 1000;
/**
 *
 *
 * This class takes a set of highlighting rules, and creates a tokenizer out of them. For more information, see [the wiki on extending highlighters](https://github.com/ajaxorg/ace/wiki/Creating-or-Extending-an-Edit-Mode#wiki-extendingTheHighlighter).
 * @class Tokenizer
 **/

/**
 * Constructs a new tokenizer based on the given rules and flags.
 * @param {Object} rules The highlighting rules
 *
 * @constructor
 **/
var Tokenizer = function(rules) {
    this.states = rules;

    this.regExps = {};
    this.matchMappings = {};
    for (var key in this.states) {
        var state = this.states[key];
        var ruleRegExps = [];
        var matchTotal = 0;
        var mapping = this.matchMappings[key] = {defaultToken: "text"};
        var flag = "g";

        var splitterRurles = [];
        for (var i = 0; i < state.length; i++) {
            var rule = state[i];
            if (rule.defaultToken)
                mapping.defaultToken = rule.defaultToken;
            if (rule.caseInsensitive)
                flag = "gi";
            if (rule.regex == null)
                continue;

            if (rule.regex instanceof RegExp)
                rule.regex = rule.regex.toString().slice(1, -1);

            // Count number of matching groups. 2 extra groups from the full match
            // And the catch-all on the end (used to force a match);
            var adjustedregex = rule.regex;
            var matchcount = new RegExp("(?:(" + adjustedregex + ")|(.))").exec("a").length - 2;
            if (Array.isArray(rule.token)) {
                if (rule.token.length == 1 || matchcount == 1) {
                    rule.token = rule.token[0];
                } else if (matchcount - 1 != rule.token.length) {
                    throw new Error("number of classes and regexp groups in '" +
                        rule.token + "'\n'" + rule.regex +  "' doesn't match\n"
                        + (matchcount - 1) + "!=" + rule.token.length);
                } else {
                    rule.tokenArray = rule.token;
                    rule.token = null;
                    rule.onMatch = this.$arrayTokens;
                }
            } else if (typeof rule.token == "function" && !rule.onMatch) {
                if (matchcount > 1)
                    rule.onMatch = this.$applyToken;
                else
                    rule.onMatch = rule.token;
            }

            if (matchcount > 1) {
                if (/\\\d/.test(rule.regex)) {
                    // Replace any backreferences and offset appropriately.
                    adjustedregex = rule.regex.replace(/\\([0-9]+)/g, function (match, digit) {
                        return "\\" + (parseInt(digit, 10) + matchTotal + 1);
                    });
                } else {
                    matchcount = 1;
                    adjustedregex = this.removeCapturingGroups(rule.regex);
                }
                if (!rule.splitRegex && typeof rule.token != "string")
                    splitterRurles.push(rule); // flag will be known only at the very end
            }

            mapping[matchTotal] = i;
            matchTotal += matchcount;

            ruleRegExps.push(adjustedregex);

            // makes property access faster
            if (!rule.onMatch)
                rule.onMatch = null;
            rule.__proto__ = null;
        }

        splitterRurles.forEach(function(rule) {
            rule.splitRegex = this.createSplitterRegexp(rule.regex, flag);
        }, this);

        this.regExps[key] = new RegExp("(" + ruleRegExps.join(")|(") + ")|($)", flag);
    }
};

(function() {
    this.$applyToken = function(str) {
        var values = this.splitRegex.exec(str).slice(1);
        var types = this.token.apply(this, values);

        // required for compatibility with old modes
        if (typeof types === "string")
            return [{type: types, value: str}];

        var tokens = [];
        for (var i = 0, l = types.length; i < l; i++) {
            if (values[i])
                tokens[tokens.length] = {
                    type: types[i],
                    value: values[i]
                };
        }
        return tokens;
    },

    this.$arrayTokens = function(str) {
        if (!str)
            return [];
        var values = this.splitRegex.exec(str);
        if (!values)
            return "text";
        var tokens = [];
        var types = this.tokenArray;
        for (var i = 0, l = types.length; i < l; i++) {
            if (values[i + 1])
                tokens[tokens.length] = {
                    type: types[i],
                    value: values[i + 1]
                };
        }
        return tokens;
    };

    this.removeCapturingGroups = function(src) {
        var r = src.replace(
            /\[(?:\\.|[^\]])*?\]|\\.|\(\?[:=!]|(\()/g,
            function(x, y) {return y ? "(?:" : x;}
        );
        return r;
    };

    this.createSplitterRegexp = function(src, flag) {
        if (src.indexOf("(?=") != -1) {
            var stack = 0;
            var inChClass = false;
            var lastCapture = {};
            src.replace(/(\\.)|(\((?:\?[=!])?)|(\))|([\[\]])/g, function(
                m, esc, parenOpen, parenClose, square, index
            ) {
                if (inChClass) {
                    inChClass = square != "]";
                } else if (square) {
                    inChClass = true;
                } else if (parenClose) {
                    if (stack == lastCapture.stack) {
                        lastCapture.end = index+1;
                        lastCapture.stack = -1;
                    }
                    stack--;
                } else if (parenOpen) {
                    stack++;
                    if (parenOpen.length != 1) {
                        lastCapture.stack = stack
                        lastCapture.start = index;
                    }
                }
                return m;
            });

            if (lastCapture.end != null && /^\)*$/.test(src.substr(lastCapture.end)))
                src = src.substring(0, lastCapture.start) + src.substr(lastCapture.end);
        }
        return new RegExp(src, (flag||"").replace("g", ""));
    };

    /**
    * Returns an object containing two properties: `tokens`, which contains all the tokens; and `state`, the current state.
    * @returns {Object}
    **/
    this.getLineTokens = function(line, startState) {
        if (startState && typeof startState != "string") {
            var stack = startState.slice(0);
            startState = stack[0];
        } else
            var stack = [];

        var currentState = startState || "start";
        var state = this.states[currentState];
        var mapping = this.matchMappings[currentState];
        var re = this.regExps[currentState];
        re.lastIndex = 0;

        var match, tokens = [];
        var lastIndex = 0;

        var token = {type: null, value: ""};

        while (match = re.exec(line)) {
            var type = mapping.defaultToken;
            var rule = null;
            var value = match[0];
            var index = re.lastIndex;

            if (index - value.length > lastIndex) {
                var skipped = line.substring(lastIndex, index - value.length);
                if (token.type == type) {
                    token.value += skipped;
                } else {
                    if (token.type)
                        tokens.push(token);
                    token = {type: type, value: skipped};
                }
            }

            for (var i = 0; i < match.length-2; i++) {
                if (match[i + 1] === undefined)
                    continue;

                rule = state[mapping[i]];

                if (rule.onMatch)
                    type = rule.onMatch(value, currentState, stack);
                else
                    type = rule.token;

                if (rule.next) {
                    if (typeof rule.next == "string")
                        currentState = rule.next;
                    else
                        currentState = rule.next(currentState, stack);

                    state = this.states[currentState];
                    if (!state) {
                        window.console && console.error && console.error(currentState, "doesn't exist");
                        currentState = "start";
                        state = this.states[currentState];
                    }
                    mapping = this.matchMappings[currentState];
                    lastIndex = index;
                    re = this.regExps[currentState];
                    re.lastIndex = index;
                }
                break;
            }

            if (value) {
                if (typeof type == "string") {
                    if ((!rule || rule.merge !== false) && token.type === type) {
                        token.value += value;
                    } else {
                        if (token.type)
                            tokens.push(token);
                        token = {type: type, value: value};
                    }
                } else if (type) {
                    if (token.type)
                        tokens.push(token);
                    token = {type: null, value: ""};
                    for (var i = 0; i < type.length; i++)
                        tokens.push(type[i]);
                }
            }

            if (lastIndex == line.length)
                break;

            lastIndex = index;

            if (tokens.length > MAX_TOKEN_COUNT) {
                // chrome doens't show contents of text nodes with very long text
                while (lastIndex < line.length) {
                    if (token.type)
                        tokens.push(token);
                    token = {
                        value: line.substring(lastIndex, lastIndex += 2000),
                        type: "overflow"
                    }
                }
                currentState = "start";
                stack = [];
                break;
            }
        }

        if (token.type)
            tokens.push(token);

        return {
            tokens : tokens,
            state : stack.length ? stack : currentState
        };
    };

}).call(Tokenizer.prototype);

exports.Tokenizer = Tokenizer;
});
<commit_msg>allow setting MaxTokenCount in tokenizer<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 * Distributed under the BSD license:
 *
 * Copyright (c) 2010, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ***** END LICENSE BLOCK ***** */

define(function(require, exports, module) {
"use strict";

// tokenizing lines longer than this makes editor very slow
var MAX_TOKEN_COUNT = 1000;
/**
 * This class takes a set of highlighting rules, and creates a tokenizer out of them. For more information, see [the wiki on extending highlighters](https://github.com/ajaxorg/ace/wiki/Creating-or-Extending-an-Edit-Mode#wiki-extendingTheHighlighter).
 * @class Tokenizer
 **/

/**
 * Constructs a new tokenizer based on the given rules and flags.
 * @param {Object} rules The highlighting rules
 *
 * @constructor
 **/
var Tokenizer = function(rules) {
    this.states = rules;

    this.regExps = {};
    this.matchMappings = {};
    for (var key in this.states) {
        var state = this.states[key];
        var ruleRegExps = [];
        var matchTotal = 0;
        var mapping = this.matchMappings[key] = {defaultToken: "text"};
        var flag = "g";

        var splitterRurles = [];
        for (var i = 0; i < state.length; i++) {
            var rule = state[i];
            if (rule.defaultToken)
                mapping.defaultToken = rule.defaultToken;
            if (rule.caseInsensitive)
                flag = "gi";
            if (rule.regex == null)
                continue;

            if (rule.regex instanceof RegExp)
                rule.regex = rule.regex.toString().slice(1, -1);

            // Count number of matching groups. 2 extra groups from the full match
            // And the catch-all on the end (used to force a match);
            var adjustedregex = rule.regex;
            var matchcount = new RegExp("(?:(" + adjustedregex + ")|(.))").exec("a").length - 2;
            if (Array.isArray(rule.token)) {
                if (rule.token.length == 1 || matchcount == 1) {
                    rule.token = rule.token[0];
                } else if (matchcount - 1 != rule.token.length) {
                    throw new Error("number of classes and regexp groups in '" +
                        rule.token + "'\n'" + rule.regex +  "' doesn't match\n"
                        + (matchcount - 1) + "!=" + rule.token.length);
                } else {
                    rule.tokenArray = rule.token;
                    rule.token = null;
                    rule.onMatch = this.$arrayTokens;
                }
            } else if (typeof rule.token == "function" && !rule.onMatch) {
                if (matchcount > 1)
                    rule.onMatch = this.$applyToken;
                else
                    rule.onMatch = rule.token;
            }

            if (matchcount > 1) {
                if (/\\\d/.test(rule.regex)) {
                    // Replace any backreferences and offset appropriately.
                    adjustedregex = rule.regex.replace(/\\([0-9]+)/g, function (match, digit) {
                        return "\\" + (parseInt(digit, 10) + matchTotal + 1);
                    });
                } else {
                    matchcount = 1;
                    adjustedregex = this.removeCapturingGroups(rule.regex);
                }
                if (!rule.splitRegex && typeof rule.token != "string")
                    splitterRurles.push(rule); // flag will be known only at the very end
            }

            mapping[matchTotal] = i;
            matchTotal += matchcount;

            ruleRegExps.push(adjustedregex);

            // makes property access faster
            if (!rule.onMatch)
                rule.onMatch = null;
            rule.__proto__ = null;
        }

        splitterRurles.forEach(function(rule) {
            rule.splitRegex = this.createSplitterRegexp(rule.regex, flag);
        }, this);

        this.regExps[key] = new RegExp("(" + ruleRegExps.join(")|(") + ")|($)", flag);
    }
};

(function() {
    this.$setMaxTokenCount = function(m) {
        MAX_TOKEN_COUNT = m | 0;
    };

    this.$applyToken = function(str) {
        var values = this.splitRegex.exec(str).slice(1);
        var types = this.token.apply(this, values);

        // required for compatibility with old modes
        if (typeof types === "string")
            return [{type: types, value: str}];

        var tokens = [];
        for (var i = 0, l = types.length; i < l; i++) {
            if (values[i])
                tokens[tokens.length] = {
                    type: types[i],
                    value: values[i]
                };
        }
        return tokens;
    },

    this.$arrayTokens = function(str) {
        if (!str)
            return [];
        var values = this.splitRegex.exec(str);
        if (!values)
            return "text";
        var tokens = [];
        var types = this.tokenArray;
        for (var i = 0, l = types.length; i < l; i++) {
            if (values[i + 1])
                tokens[tokens.length] = {
                    type: types[i],
                    value: values[i + 1]
                };
        }
        return tokens;
    };

    this.removeCapturingGroups = function(src) {
        var r = src.replace(
            /\[(?:\\.|[^\]])*?\]|\\.|\(\?[:=!]|(\()/g,
            function(x, y) {return y ? "(?:" : x;}
        );
        return r;
    };

    this.createSplitterRegexp = function(src, flag) {
        if (src.indexOf("(?=") != -1) {
            var stack = 0;
            var inChClass = false;
            var lastCapture = {};
            src.replace(/(\\.)|(\((?:\?[=!])?)|(\))|([\[\]])/g, function(
                m, esc, parenOpen, parenClose, square, index
            ) {
                if (inChClass) {
                    inChClass = square != "]";
                } else if (square) {
                    inChClass = true;
                } else if (parenClose) {
                    if (stack == lastCapture.stack) {
                        lastCapture.end = index+1;
                        lastCapture.stack = -1;
                    }
                    stack--;
                } else if (parenOpen) {
                    stack++;
                    if (parenOpen.length != 1) {
                        lastCapture.stack = stack
                        lastCapture.start = index;
                    }
                }
                return m;
            });

            if (lastCapture.end != null && /^\)*$/.test(src.substr(lastCapture.end)))
                src = src.substring(0, lastCapture.start) + src.substr(lastCapture.end);
        }
        return new RegExp(src, (flag||"").replace("g", ""));
    };

    /**
    * Returns an object containing two properties: `tokens`, which contains all the tokens; and `state`, the current state.
    * @returns {Object}
    **/
    this.getLineTokens = function(line, startState) {
        if (startState && typeof startState != "string") {
            var stack = startState.slice(0);
            startState = stack[0];
        } else
            var stack = [];

        var currentState = startState || "start";
        var state = this.states[currentState];
        var mapping = this.matchMappings[currentState];
        var re = this.regExps[currentState];
        re.lastIndex = 0;

        var match, tokens = [];
        var lastIndex = 0;

        var token = {type: null, value: ""};

        while (match = re.exec(line)) {
            var type = mapping.defaultToken;
            var rule = null;
            var value = match[0];
            var index = re.lastIndex;

            if (index - value.length > lastIndex) {
                var skipped = line.substring(lastIndex, index - value.length);
                if (token.type == type) {
                    token.value += skipped;
                } else {
                    if (token.type)
                        tokens.push(token);
                    token = {type: type, value: skipped};
                }
            }

            for (var i = 0; i < match.length-2; i++) {
                if (match[i + 1] === undefined)
                    continue;

                rule = state[mapping[i]];

                if (rule.onMatch)
                    type = rule.onMatch(value, currentState, stack);
                else
                    type = rule.token;

                if (rule.next) {
                    if (typeof rule.next == "string")
                        currentState = rule.next;
                    else
                        currentState = rule.next(currentState, stack);

                    state = this.states[currentState];
                    if (!state) {
                        window.console && console.error && console.error(currentState, "doesn't exist");
                        currentState = "start";
                        state = this.states[currentState];
                    }
                    mapping = this.matchMappings[currentState];
                    lastIndex = index;
                    re = this.regExps[currentState];
                    re.lastIndex = index;
                }
                break;
            }

            if (value) {
                if (typeof type == "string") {
                    if ((!rule || rule.merge !== false) && token.type === type) {
                        token.value += value;
                    } else {
                        if (token.type)
                            tokens.push(token);
                        token = {type: type, value: value};
                    }
                } else if (type) {
                    if (token.type)
                        tokens.push(token);
                    token = {type: null, value: ""};
                    for (var i = 0; i < type.length; i++)
                        tokens.push(type[i]);
                }
            }

            if (lastIndex == line.length)
                break;

            lastIndex = index;

            if (tokens.length > MAX_TOKEN_COUNT) {
                // chrome doens't show contents of text nodes with very long text
                while (lastIndex < line.length) {
                    if (token.type)
                        tokens.push(token);
                    token = {
                        value: line.substring(lastIndex, lastIndex += 2000),
                        type: "overflow"
                    }
                }
                currentState = "start";
                stack = [];
                break;
            }
        }

        if (token.type)
            tokens.push(token);

        return {
            tokens : tokens,
            state : stack.length ? stack : currentState
        };
    };

}).call(Tokenizer.prototype);

exports.Tokenizer = Tokenizer;
});
<|endoftext|>


<commit_before>/* jslint node: true */
/* global describe, it, expect */

'use strict';

describe('social', function() {
    afterAll(function() {
        global.base = global.classes = global.ga = global.analytics = null;
        global.navigator = global.open = global.screen = global.social = null;
    });

    beforeAll(function(done) {
        var jsdom = require('jsdom');
        jsdom.env('

',
                [__dirname + '/../../jquery-2.1.4.js'], function(err, win) {
            global.window = win;
            global.document = win.document;
            global.navigator = { userAgent: 'chrome' };
            global.chrome = { runtime: { id: 'a' } };
            global.jQuery = global.$ = require('jquery');
            require(__dirname + '/../../src/chrome/assets/js/social.js');
            global.base = $('div.base');
            global.classes = ['fa-envelope', 'fa-twitter', 'fa-facebook',
                              'fa-google-plus', 'fa-linkedin', 'fa-star', 'fa-unknown'];
            global.ga = function() {};
            global.analytics = spyOn(global, 'ga').and.callThrough();
            global.open = spyOn(window, 'open').and.callFake(function() {});
            for (var i=0, j=classes.length; i<j; i++) {
                base.append('');
            }
            global.screen = { height: 0, left: 0, top: 0, width: 0 };
            global.social = base.children('a').social();
            done();
        });
    });

    it('should prepare and open the links', function() {
        var args = {
            facebook: ['https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fchrome.google.com%2Fwebstore%2Fdetail%2Fa', 'facebook_window', 'copyhistory=no,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,height=436,width=626,left=-313,top=-218'],
            'google-plus': ['https://plus.google.com/share?url=https%3A%2F%2Fchrome.google.com%2Fwebstore%2Fdetail%2Fa', 'google-plus_window', 'copyhistory=no,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,height=600,width=600,left=-300,top=-300'],
            linkedin: ['https://www.linkedin.com/shareArticle?mini=true&summary=Selenium%20Page%20Object%20Generator%20is%20a%20nimble%20and%20flexible%20%23Selenium%20%23PageObjectModel%20%23Generator%20to%20improve%20%23Agile%20%23Testing%20process%20velocity.&title=Selenium%20Page%20Object%20Generator%20-%20to%20improve%20agile%20testing%20process%20velocity.&url=https%3A%2F%2Fchrome.google.com%2Fwebstore%2Fdetail%2Fa', 'linkedin_window', 'copyhistory=no,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,height=600,width=600,left=-300,top=-300'],
            star: ['https://chrome.google.com/webstore/detail/a/reviews', 'star_window', 'copyhistory=no,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,height=350,width=900,left=-450,top=-175'],
            twitter: ['https://twitter.com/share?text=Selenium%20Page%20Object%20Generator%20is%20a%20nimble%20and%20flexible%20%23Selenium%20%23PageObjectModel%20%23Generator%20to%20improve%20%23Agile%20%23Testing%20process%20velocity.&url=https%3A%2F%2Fchrome.google.com%2Fwebstore%2Fdetail%2Fa&via=rickypc2000', 'twitter_window', 'copyhistory=no,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,height=500,width=685,left=-342.5,top=-250'],
            unknown: ['', 'unknown_window', 'copyhistory=no,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,height=600,width=600,left=-300,top=-300']
        };

        social.each(function(index) {
            var this_ = $(this);
            expect(this_.hasClass('fa-' + this_.data('type'))).toBeTruthy();

            if (this_.data('type') === 'envelope') {
                this_.get(0).onclick = function() {};
                var envelope = spyOn(this_.get(0), 'onclick').and.callThrough();
                expect(this_.get(0).href).toEqual('mailto:?subject=Selenium%20Page%20Object%20Generator%20-%20to%20improve%20agile%20testing%20process%20velocity.&body=Selenium%20Page%20Object%20Generator%20is%20a%20nimble%20and%20flexible%20%23Selenium%20%23PageObjectModel%20%23Generator%20to%20improve%20%23Agile%20%23Testing%20process%20velocity.%20https%3A%2F%2Fchrome.google.com%2Fwebstore%2Fdetail%2Fa');
                expect(this_.get(0).target).toEqual('_blank');
                // more coverage
                this_.trigger('click');
                expect(envelope).toHaveBeenCalled();
            }
            else {
                this_.trigger('click');
                expect(analytics).toHaveBeenCalledWith('send', 'event', this_.data('type'), 'click');
                expect(open).toHaveBeenCalledWith.apply(expect(open), args[this_.data('type')]);
                // more coverage
                this_.trigger('click');
                expect(analytics).toHaveBeenCalledWith('send', 'event', this_.data('type'), 'click');
                expect(open).toHaveBeenCalledWith.apply(expect(open), args[this_.data('type')]);
            }
        });
    });
});
<commit_msg>Uses jsdom old API.<commit_after>/* jslint node: true */
/* global describe, it, expect */

'use strict';

describe('social', function() {
    afterAll(function() {
        global.base = global.classes = global.ga = global.analytics = null;
        global.navigator = global.open = global.screen = global.social = null;
    });

    beforeAll(function(done) {
        var jsdom = require('jsdom/lib/old-api.js');
        jsdom.env('

',
                [__dirname + '/../../jquery-3.3.1.js'], function(err, win) {
            global.window = win;
            global.document = win.document;
            global.navigator = { userAgent: 'chrome' };
            global.chrome = { runtime: { id: 'a' } };
            global.jQuery = global.$ = require('jquery');
            require(__dirname + '/../../src/chrome/assets/js/social.js');
            global.base = $('div.base');
            global.classes = ['fa-envelope', 'fa-twitter', 'fa-facebook',
                              'fa-google-plus', 'fa-linkedin', 'fa-star', 'fa-unknown'];
            global.ga = function() {};
            global.analytics = spyOn(global, 'ga').and.callThrough();
            global.open = spyOn(window, 'open').and.callFake(function() {});
            for (var i=0, j=classes.length; i<j; i++) {
                base.append('');
            }
            global.screen = { height: 0, left: 0, top: 0, width: 0 };
            global.social = base.children('a').social();
            done();
        });
    });

    it('should prepare and open the links', function() {
        var args = {
            facebook: ['https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fchrome.google.com%2Fwebstore%2Fdetail%2Fa', 'facebook_window', 'copyhistory=no,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,height=436,width=626,left=-313,top=-218'],
            'google-plus': ['https://plus.google.com/share?url=https%3A%2F%2Fchrome.google.com%2Fwebstore%2Fdetail%2Fa', 'google-plus_window', 'copyhistory=no,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,height=600,width=600,left=-300,top=-300'],
            linkedin: ['https://www.linkedin.com/shareArticle?mini=true&summary=Selenium%20Page%20Object%20Generator%20is%20a%20nimble%20and%20flexible%20%23Selenium%20%23PageObjectModel%20%23Generator%20to%20improve%20%23Agile%20%23Testing%20process%20velocity.&title=Selenium%20Page%20Object%20Generator%20-%20to%20improve%20agile%20testing%20process%20velocity.&url=https%3A%2F%2Fchrome.google.com%2Fwebstore%2Fdetail%2Fa', 'linkedin_window', 'copyhistory=no,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,height=600,width=600,left=-300,top=-300'],
            star: ['https://chrome.google.com/webstore/detail/a/reviews', 'star_window', 'copyhistory=no,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,height=350,width=900,left=-450,top=-175'],
            twitter: ['https://twitter.com/share?text=Selenium%20Page%20Object%20Generator%20is%20a%20nimble%20and%20flexible%20%23Selenium%20%23PageObjectModel%20%23Generator%20to%20improve%20%23Agile%20%23Testing%20process%20velocity.&url=https%3A%2F%2Fchrome.google.com%2Fwebstore%2Fdetail%2Fa&via=rickypc2000', 'twitter_window', 'copyhistory=no,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,height=500,width=685,left=-342.5,top=-250'],
            unknown: ['', 'unknown_window', 'copyhistory=no,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,height=600,width=600,left=-300,top=-300']
        };

        social.each(function(index) {
            var this_ = $(this);
            expect(this_.hasClass('fa-' + this_.data('type'))).toBeTruthy();

            if (this_.data('type') === 'envelope') {
                this_.get(0).onclick = function() {};
                var envelope = spyOn(this_.get(0), 'onclick').and.callThrough();
                expect(this_.get(0).href).toEqual('mailto:?subject=Selenium%20Page%20Object%20Generator%20-%20to%20improve%20agile%20testing%20process%20velocity.&body=Selenium%20Page%20Object%20Generator%20is%20a%20nimble%20and%20flexible%20%23Selenium%20%23PageObjectModel%20%23Generator%20to%20improve%20%23Agile%20%23Testing%20process%20velocity.%20https%3A%2F%2Fchrome.google.com%2Fwebstore%2Fdetail%2Fa');
                expect(this_.get(0).target).toEqual('_blank');
                // more coverage
                this_.trigger('click');
                expect(envelope).toHaveBeenCalled();
            }
            else {
                this_.trigger('click');
                expect(analytics).toHaveBeenCalledWith('send', 'event', this_.data('type'), 'click');
                expect(open).toHaveBeenCalledWith.apply(expect(open), args[this_.data('type')]);
                // more coverage
                this_.trigger('click');
                expect(analytics).toHaveBeenCalledWith('send', 'event', this_.data('type'), 'click');
                expect(open).toHaveBeenCalledWith.apply(expect(open), args[this_.data('type')]);
            }
        });
    });
});
<|endoftext|>


<commit_before>var http = require('https');

function ImgurClient(options) {
	'use strict';
	options = options || {};
	if (options.clientId === undefined) {
		throw new Error('clientId is required!');
	}
	var publicAPI,
		host = 'api.imgur.com',
		uploadUrl = 'https://api.imgur.com/3/upload',
		albumPath = '/3/album'
	;

	function upload() {
		console.log("uploading");
	}

	function getOptions() {
		return options;
	}

	function fetchAlbum(ambumId, callback) {
		var opts = {
				hostname: host,
				headers: {
					'Authorization': 'Client-ID ' + 'e63ca2024c581ec'
				},
				path: albumPath + '/' + ambumId,
				method: 'GET'
			},
			data;
		var req = http.request(opts, function (res) {
			res.on('data', function (chunk) {
				data += chunk;
			});
			res.on('end', function () {
				console.log(data);
				console.log("request has ended");
			});
		});
		req.on('error', function (err) {
			callback(err);
		});
		req.end();
	}

	publicAPI = {
		upload: upload,
		getOptions: getOptions,
		fetchAlbum: fetchAlbum
	};

	return publicAPI;
}

exports = module.exports = ImgurClient;
<commit_msg>adding DRYing up the requests<commit_after>var http = require('https');

function ImgurClient(options) {
	'use strict';
	options = options || {};
	if (options.clientId === undefined) {
		throw new Error('clientId is required!');
	}
	var publicAPI,
		host = 'api.imgur.com',
		imagePath = '/3/image',
		albumPath = '/3/album'
	;

	function upload() {
		console.log("uploading");
	}

	function _request(opts, callback) {
		var data = '';
		var req = http.request(opts, function (res) {
			if (res.statusCode === 200) {
				console.log(res.statusCode);
				res.on('data', function (chunk) {
					data += chunk;
				});
				res.on('end', function () {
					var json = JSON.parse(data);
					callback(null, json);
				});
			} else {
				var err = new Error("Bad statusCode: " + res.statusCode);
				callback(err);
			}
		});
		req.on('error', function (err) {
			callback(err);
		});
		req.end();
	}

	function fetchAlbum(ambumId, callback) {
		var opts = {
				hostname: host,
				headers: {
					'Authorization': 'Client-ID ' + options.clientId
				},
				path: albumPath + '/' + ambumId,
				method: 'GET'
			};
		_request(opts, callback);
	}

	function fetchImage(imageId, callback) {
		var opts = {
				hostname: host,
				headers: {
					'Authorization': 'Client-ID ' + options.clientId
				},
				path: imagePath + '/' + imageId,
				method: 'GET'
			};
		_request(opts, callback);
	}

	publicAPI = {
		upload: upload,
		fetchImage: fetchImage,
		fetchAlbum: fetchAlbum
	};

	return publicAPI;
}

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


<commit_before>define(["moment", "numeral", "tablesort", "tablesort.number", "moment.de"],
  function (moment, numeral, Tablesort) {
    function showGeoURI(d) {
      function showLatitude(d) {
        var suffix = Math.sign(d) > -1 ? "' N" : "' S";
        d = Math.abs(d);
        var a = Math.floor(d);
        var min = (d * 60) % 60;
        a = (a < 10 ? "0" : "") + a;

        return a + "° " + numeral(min).format("0.000") + suffix;
      }

      function showLongitude(d) {
        var suffix = Math.sign(d) > -1 ? "' E" : "' W";
        d = Math.abs(d);
        var a = Math.floor(d);
        var min = (d * 60) % 60;
        a = (a < 100 ? "0" + (a < 10 ? "0" : "") : "") + a;

        return a + "° " + numeral(min).format("0.000") + suffix;
      }

      if (!has_location(d)) {
        return undefined;
      }

      return function (el) {
        var latitude = d.nodeinfo.location.latitude;
        var longitude = d.nodeinfo.location.longitude;
        var a = document.createElement("a");
        a.textContent = showLatitude(latitude) + " " +
          showLongitude(longitude);

        a.href = "geo:" + latitude + "," + longitude;
        el.appendChild(a);
      };
    }

    function showStatus(d) {
      return function (el) {
        el.classList.add(d.flags.unseen ? "unseen" : (d.flags.online ? "online" : "offline"));
        if (d.flags.online) {
          el.textContent = "online, letzte Nachricht " + d.lastseen.fromNow() + " (" + d.lastseen.format("DD.MM.YYYY,  H:mm:ss") + ")";
        } else {
          el.textContent = "offline, letzte Nachricht " + d.lastseen.fromNow() + " (" + d.lastseen.format("DD.MM.YYYY,  H:mm:ss") + ")";
        }
      };
    }

    function showFirmware(d) {
      var release = dictGet(d.nodeinfo, ["software", "firmware", "release"]);
      var base = dictGet(d.nodeinfo, ["software", "firmware", "base"]);

      if (release === null || base === null) {
        return undefined;
      }

      return release + " / " + base;
    }

    function showSite(d, config) {
      var site = dictGet(d.nodeinfo, ["system", "site_code"]);
      var rt = site;
      if (config.siteNames) {
        config.siteNames.forEach(function (t) {
          if (site === t.site) {
            rt = t.name;
          }
        });
      }
      return rt;
    }

    function showUptime(d) {
      if (!("uptime" in d.statistics)) {
        return undefined;
      }

      return moment.duration(d.statistics.uptime, "seconds").humanize();
    }

    function showFirstseen(d) {
      if (!("firstseen" in d)) {
        return undefined;
      }

      return d.firstseen.fromNow(true);
    }

    function showClients(d) {
      if (!d.flags.online) {
        return undefined;
      }

      return function (el) {
        el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : "keine"));
        el.appendChild(document.createElement("br"));

        var span = document.createElement("span");
        span.classList.add("clients");
        span.textContent = " ".repeat(d.statistics.clients);
        el.appendChild(span);
      };
    }

    function showIPs(d) {
      var ips = dictGet(d.nodeinfo, ["network", "addresses"]);
      if (ips === null) {
        return undefined;
      }

      ips.sort();

      return function (el) {
        ips.forEach(function (ip, i) {
          var link = !ip.startsWith("fe80:");

          if (i > 0) {
            el.appendChild(document.createElement("br"));
          }

          if (link) {
            var a = document.createElement("a");
            a.href = "http://[" + ip + "]/";
            a.textContent = ip;
            el.appendChild(a);
          } else {
            el.appendChild(document.createTextNode(ip));
          }
        });
      };
    }

    function showBar(className, v) {
      var span = document.createElement("span");
      span.classList.add("bar");
      span.classList.add(className);

      var bar = document.createElement("span");
      bar.style.width = (v * 100) + "%";
      span.appendChild(bar);

      var label = document.createElement("label");
      label.textContent = (Math.round(v * 100)) + " %";
      span.appendChild(label);

      return span;
    }

    function showLoadBar(className, v) {
      var span = document.createElement("span");
      span.classList.add("bar");
      span.classList.add(className);

      var bar = document.createElement("span");
      if (v >= 1) {
        bar.style.width = ((v * 100) % 100) + "%";
        bar.style.background = "rgba(255, 50, 50, 0.9)";
        span.style.background = "rgba(255, 50, 50, 0.6)";
        span.appendChild(bar);
      }
      else {
        bar.style.width = (v * 100) + "%";
        span.appendChild(bar);
      }

      var label = document.createElement("label");
      label.textContent = (v);
      span.appendChild(label);

      return span;
    }

    function showLoad(d) {
      if (!("loadavg" in d.statistics)) {
        return undefined;
      }

      return function (el) {
        el.appendChild(showLoadBar("load-avg", d.statistics.loadavg));
      };
    }

    function showRAM(d) {
      if (!("memory_usage" in d.statistics)) {
        return undefined;
      }

      return function (el) {
        el.appendChild(showBar("memory-usage", d.statistics.memory_usage));
      };
    }

    function showPages(d) {
      var webpages = dictGet(d.nodeinfo, ["pages"]);
      if (webpages === null) {
        return undefined;
      }

      webpages.sort();

      return function (el) {
        webpages.forEach(function (webpage, i) {
          if (i > 0) {
            el.appendChild(document.createElement("br"));
          }

          var a = document.createElement("span");
          var link = document.createElement("a");
          link.href = webpage;
          if (webpage.search(/^https:\/\//i) !== -1) {
            var lock = document.createElement("span");
            lock.className = "ion-android-lock";
            a.appendChild(lock);
            var t1 = document.createTextNode(" ");
            a.appendChild(t1);
            link.textContent = webpage.replace(/^https:\/\//i, "");
          }
          else {
            link.textContent = webpage.replace(/^http:\/\//i, "");
          }
          a.appendChild(link);
          el.appendChild(a);
        });
      };
    }

    function showAutoupdate(d) {
      var au = dictGet(d.nodeinfo, ["software", "autoupdater"]);
      if (!au) {
        return undefined;
      }

      return au.enabled ? "aktiviert (" + au.branch + ")" : "deaktiviert";
    }

    function showStatImg(o, d) {
      var subst = {};
      subst["{NODE_ID}"] = d.nodeinfo.node_id ? d.nodeinfo.node_id : "unknown";
      subst["{NODE_NAME}"] = d.nodeinfo.hostname ? d.nodeinfo.hostname : "unknown";
      return showStat(o, subst);
    }

    return function (config, el, router, d) {
      var h2 = document.createElement("h2");
      h2.textContent = d.nodeinfo.hostname;
      el.appendChild(h2);

      var attributes = document.createElement("table");
      attributes.classList.add("attributes");

      attributeEntry(attributes, "Status", showStatus(d));
      attributeEntry(attributes, "Gateway", d.flags.gateway ? "ja" : null);
      attributeEntry(attributes, "Koordinaten", showGeoURI(d));

      if (config.showContact) {
        attributeEntry(attributes, "Kontakt", dictGet(d.nodeinfo, ["owner", "contact"]));
      }

      attributeEntry(attributes, "Hardware", dictGet(d.nodeinfo, ["hardware", "model"]));
      attributeEntry(attributes, "Primäre MAC", dictGet(d.nodeinfo, ["network", "mac"]));
      attributeEntry(attributes, "Node ID", dictGet(d.nodeinfo, ["node_id"]));
      attributeEntry(attributes, "Firmware", showFirmware(d));
      attributeEntry(attributes, "Site", showSite(d, config));
      attributeEntry(attributes, "Uptime", showUptime(d));
      attributeEntry(attributes, "Teil des Netzes", showFirstseen(d));
      attributeEntry(attributes, "Systemlast", showLoad(d));
      attributeEntry(attributes, "Arbeitsspeicher", showRAM(d));
      attributeEntry(attributes, "IP Adressen", showIPs(d));
      attributeEntry(attributes, "Webseite", showPages(d));
      attributeEntry(attributes, "Gewähltes Gateway", dictGet(d.statistics, ["gateway"]));
      attributeEntry(attributes, "Autom. Updates", showAutoupdate(d));
      attributeEntry(attributes, "Clients", showClients(d));

      el.appendChild(attributes);

      if (config.nodeInfos) {
        config.nodeInfos.forEach(function (nodeInfo) {
          var h4 = document.createElement("h4");
          h4.textContent = nodeInfo.name;
          el.appendChild(h4);
          el.appendChild(showStatImg(nodeInfo, d));
        });
      }

      if (d.neighbours.length > 0) {
        var h3 = document.createElement("h3");
        h3.textContent = "Links (" + d.neighbours.length + ")";
        el.appendChild(h3);

        var table = document.createElement("table");
        var thead = document.createElement("thead");

        var tr = document.createElement("tr");
        var th1 = document.createElement("th");
        th1.textContent = " ";
        tr.appendChild(th1);

        var th2 = document.createElement("th");
        th2.textContent = "Knoten";
        th2.classList.add("sort-default");
        tr.appendChild(th2);

        var th3 = document.createElement("th");
        th3.textContent = "TQ";
        tr.appendChild(th3);

        var th4 = document.createElement("th");
        th4.textContent = "Typ";
        tr.appendChild(th4);

        var th5 = document.createElement("th");
        th5.textContent = "Entfernung";
        tr.appendChild(th5);

        thead.appendChild(tr);
        table.appendChild(thead);

        var tbody = document.createElement("tbody");

        d.neighbours.forEach(function (d) {
          var unknown = !(d.node);
          var tr = document.createElement("tr");

          var td1 = document.createElement("td");
          td1.appendChild(document.createTextNode(d.incoming ? " ← " : " → "));
          tr.appendChild(td1);

          var td2 = document.createElement("td");
          var a1 = document.createElement("a");
          a1.classList.add("hostname");
          a1.textContent = unknown ? d.id : d.node.nodeinfo.hostname;
          if (!unknown) {
            a1.href = "#";
          }
          a1.onclick = router.node(d.node);
          td2.appendChild(a1);

          if (!unknown && has_location(d.node)) {
            var span = document.createElement("span");
            span.classList.add("icon");
            span.classList.add("ion-location");
            td2.appendChild(span);
          }

          tr.appendChild(td2);

          var td3 = document.createElement("td");
          var a2 = document.createElement("a");
          a2.href = "#";
          a2.textContent = showTq(d.link);
          a2.onclick = router.link(d.link);
          td3.appendChild(a2);
          tr.appendChild(td3);

          var td4 = document.createElement("td");
          var a3 = document.createElement("a");
          a3.href = "#";
          a3.textContent = d.link.type;
          a3.onclick = router.link(d.link);
          td4.appendChild(a3);
          tr.appendChild(td4);

          var td5 = document.createElement("td");
          var a4 = document.createElement("a");
          a4.href = "#";
          a4.textContent = showDistance(d.link);
          a4.onclick = router.link(d.link);
          td5.appendChild(a4);
          td5.setAttribute("data-sort", d.link.distance !== undefined ? -d.link.distance : 1);
          tr.appendChild(td5);

          tbody.appendChild(tr);
        });

        table.appendChild(tbody);
        table.className = "node-links";

        new Tablesort(table);

        el.appendChild(table);
      }
    };
  });
<commit_msg>[TASK] Replace all specialchars in NODE_NAME in stat urls<commit_after>define(["moment", "numeral", "tablesort", "tablesort.number", "moment.de"],
  function (moment, numeral, Tablesort) {
    function showGeoURI(d) {
      function showLatitude(d) {
        var suffix = Math.sign(d) > -1 ? "' N" : "' S";
        d = Math.abs(d);
        var a = Math.floor(d);
        var min = (d * 60) % 60;
        a = (a < 10 ? "0" : "") + a;

        return a + "° " + numeral(min).format("0.000") + suffix;
      }

      function showLongitude(d) {
        var suffix = Math.sign(d) > -1 ? "' E" : "' W";
        d = Math.abs(d);
        var a = Math.floor(d);
        var min = (d * 60) % 60;
        a = (a < 100 ? "0" + (a < 10 ? "0" : "") : "") + a;

        return a + "° " + numeral(min).format("0.000") + suffix;
      }

      if (!has_location(d)) {
        return undefined;
      }

      return function (el) {
        var latitude = d.nodeinfo.location.latitude;
        var longitude = d.nodeinfo.location.longitude;
        var a = document.createElement("a");
        a.textContent = showLatitude(latitude) + " " +
          showLongitude(longitude);

        a.href = "geo:" + latitude + "," + longitude;
        el.appendChild(a);
      };
    }

    function showStatus(d) {
      return function (el) {
        el.classList.add(d.flags.unseen ? "unseen" : (d.flags.online ? "online" : "offline"));
        if (d.flags.online) {
          el.textContent = "online, letzte Nachricht " + d.lastseen.fromNow() + " (" + d.lastseen.format("DD.MM.YYYY,  H:mm:ss") + ")";
        } else {
          el.textContent = "offline, letzte Nachricht " + d.lastseen.fromNow() + " (" + d.lastseen.format("DD.MM.YYYY,  H:mm:ss") + ")";
        }
      };
    }

    function showFirmware(d) {
      var release = dictGet(d.nodeinfo, ["software", "firmware", "release"]);
      var base = dictGet(d.nodeinfo, ["software", "firmware", "base"]);

      if (release === null || base === null) {
        return undefined;
      }

      return release + " / " + base;
    }

    function showSite(d, config) {
      var site = dictGet(d.nodeinfo, ["system", "site_code"]);
      var rt = site;
      if (config.siteNames) {
        config.siteNames.forEach(function (t) {
          if (site === t.site) {
            rt = t.name;
          }
        });
      }
      return rt;
    }

    function showUptime(d) {
      if (!("uptime" in d.statistics)) {
        return undefined;
      }

      return moment.duration(d.statistics.uptime, "seconds").humanize();
    }

    function showFirstseen(d) {
      if (!("firstseen" in d)) {
        return undefined;
      }

      return d.firstseen.fromNow(true);
    }

    function showClients(d) {
      if (!d.flags.online) {
        return undefined;
      }

      return function (el) {
        el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : "keine"));
        el.appendChild(document.createElement("br"));

        var span = document.createElement("span");
        span.classList.add("clients");
        span.textContent = " ".repeat(d.statistics.clients);
        el.appendChild(span);
      };
    }

    function showIPs(d) {
      var ips = dictGet(d.nodeinfo, ["network", "addresses"]);
      if (ips === null) {
        return undefined;
      }

      ips.sort();

      return function (el) {
        ips.forEach(function (ip, i) {
          var link = !ip.startsWith("fe80:");

          if (i > 0) {
            el.appendChild(document.createElement("br"));
          }

          if (link) {
            var a = document.createElement("a");
            a.href = "http://[" + ip + "]/";
            a.textContent = ip;
            el.appendChild(a);
          } else {
            el.appendChild(document.createTextNode(ip));
          }
        });
      };
    }

    function showBar(className, v) {
      var span = document.createElement("span");
      span.classList.add("bar");
      span.classList.add(className);

      var bar = document.createElement("span");
      bar.style.width = (v * 100) + "%";
      span.appendChild(bar);

      var label = document.createElement("label");
      label.textContent = (Math.round(v * 100)) + " %";
      span.appendChild(label);

      return span;
    }

    function showLoadBar(className, v) {
      var span = document.createElement("span");
      span.classList.add("bar");
      span.classList.add(className);

      var bar = document.createElement("span");
      if (v >= 1) {
        bar.style.width = ((v * 100) % 100) + "%";
        bar.style.background = "rgba(255, 50, 50, 0.9)";
        span.style.background = "rgba(255, 50, 50, 0.6)";
        span.appendChild(bar);
      }
      else {
        bar.style.width = (v * 100) + "%";
        span.appendChild(bar);
      }

      var label = document.createElement("label");
      label.textContent = (v);
      span.appendChild(label);

      return span;
    }

    function showLoad(d) {
      if (!("loadavg" in d.statistics)) {
        return undefined;
      }

      return function (el) {
        el.appendChild(showLoadBar("load-avg", d.statistics.loadavg));
      };
    }

    function showRAM(d) {
      if (!("memory_usage" in d.statistics)) {
        return undefined;
      }

      return function (el) {
        el.appendChild(showBar("memory-usage", d.statistics.memory_usage));
      };
    }

    function showPages(d) {
      var webpages = dictGet(d.nodeinfo, ["pages"]);
      if (webpages === null) {
        return undefined;
      }

      webpages.sort();

      return function (el) {
        webpages.forEach(function (webpage, i) {
          if (i > 0) {
            el.appendChild(document.createElement("br"));
          }

          var a = document.createElement("span");
          var link = document.createElement("a");
          link.href = webpage;
          if (webpage.search(/^https:\/\//i) !== -1) {
            var lock = document.createElement("span");
            lock.className = "ion-android-lock";
            a.appendChild(lock);
            var t1 = document.createTextNode(" ");
            a.appendChild(t1);
            link.textContent = webpage.replace(/^https:\/\//i, "");
          }
          else {
            link.textContent = webpage.replace(/^http:\/\//i, "");
          }
          a.appendChild(link);
          el.appendChild(a);
        });
      };
    }

    function showAutoupdate(d) {
      var au = dictGet(d.nodeinfo, ["software", "autoupdater"]);
      if (!au) {
        return undefined;
      }

      return au.enabled ? "aktiviert (" + au.branch + ")" : "deaktiviert";
    }

    function showStatImg(o, d) {
      var subst = {};
      subst["{NODE_ID}"] = d.nodeinfo.node_id ? d.nodeinfo.node_id : "unknown";
      subst["{NODE_NAME}"] = d.nodeinfo.hostname ? d.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_') : "unknown";
      return showStat(o, subst);
    }

    return function (config, el, router, d) {
      var h2 = document.createElement("h2");
      h2.textContent = d.nodeinfo.hostname;
      el.appendChild(h2);

      var attributes = document.createElement("table");
      attributes.classList.add("attributes");

      attributeEntry(attributes, "Status", showStatus(d));
      attributeEntry(attributes, "Gateway", d.flags.gateway ? "ja" : null);
      attributeEntry(attributes, "Koordinaten", showGeoURI(d));

      if (config.showContact) {
        attributeEntry(attributes, "Kontakt", dictGet(d.nodeinfo, ["owner", "contact"]));
      }

      attributeEntry(attributes, "Hardware", dictGet(d.nodeinfo, ["hardware", "model"]));
      attributeEntry(attributes, "Primäre MAC", dictGet(d.nodeinfo, ["network", "mac"]));
      attributeEntry(attributes, "Node ID", dictGet(d.nodeinfo, ["node_id"]));
      attributeEntry(attributes, "Firmware", showFirmware(d));
      attributeEntry(attributes, "Site", showSite(d, config));
      attributeEntry(attributes, "Uptime", showUptime(d));
      attributeEntry(attributes, "Teil des Netzes", showFirstseen(d));
      attributeEntry(attributes, "Systemlast", showLoad(d));
      attributeEntry(attributes, "Arbeitsspeicher", showRAM(d));
      attributeEntry(attributes, "IP Adressen", showIPs(d));
      attributeEntry(attributes, "Webseite", showPages(d));
      attributeEntry(attributes, "Gewähltes Gateway", dictGet(d.statistics, ["gateway"]));
      attributeEntry(attributes, "Autom. Updates", showAutoupdate(d));
      attributeEntry(attributes, "Clients", showClients(d));

      el.appendChild(attributes);

      if (config.nodeInfos) {
        config.nodeInfos.forEach(function (nodeInfo) {
          var h4 = document.createElement("h4");
          h4.textContent = nodeInfo.name;
          el.appendChild(h4);
          el.appendChild(showStatImg(nodeInfo, d));
        });
      }

      if (d.neighbours.length > 0) {
        var h3 = document.createElement("h3");
        h3.textContent = "Links (" + d.neighbours.length + ")";
        el.appendChild(h3);

        var table = document.createElement("table");
        var thead = document.createElement("thead");

        var tr = document.createElement("tr");
        var th1 = document.createElement("th");
        th1.textContent = " ";
        tr.appendChild(th1);

        var th2 = document.createElement("th");
        th2.textContent = "Knoten";
        th2.classList.add("sort-default");
        tr.appendChild(th2);

        var th3 = document.createElement("th");
        th3.textContent = "TQ";
        tr.appendChild(th3);

        var th4 = document.createElement("th");
        th4.textContent = "Typ";
        tr.appendChild(th4);

        var th5 = document.createElement("th");
        th5.textContent = "Entfernung";
        tr.appendChild(th5);

        thead.appendChild(tr);
        table.appendChild(thead);

        var tbody = document.createElement("tbody");

        d.neighbours.forEach(function (d) {
          var unknown = !(d.node);
          var tr = document.createElement("tr");

          var td1 = document.createElement("td");
          td1.appendChild(document.createTextNode(d.incoming ? " ← " : " → "));
          tr.appendChild(td1);

          var td2 = document.createElement("td");
          var a1 = document.createElement("a");
          a1.classList.add("hostname");
          a1.textContent = unknown ? d.id : d.node.nodeinfo.hostname;
          if (!unknown) {
            a1.href = "#";
          }
          a1.onclick = router.node(d.node);
          td2.appendChild(a1);

          if (!unknown && has_location(d.node)) {
            var span = document.createElement("span");
            span.classList.add("icon");
            span.classList.add("ion-location");
            td2.appendChild(span);
          }

          tr.appendChild(td2);

          var td3 = document.createElement("td");
          var a2 = document.createElement("a");
          a2.href = "#";
          a2.textContent = showTq(d.link);
          a2.onclick = router.link(d.link);
          td3.appendChild(a2);
          tr.appendChild(td3);

          var td4 = document.createElement("td");
          var a3 = document.createElement("a");
          a3.href = "#";
          a3.textContent = d.link.type;
          a3.onclick = router.link(d.link);
          td4.appendChild(a3);
          tr.appendChild(td4);

          var td5 = document.createElement("td");
          var a4 = document.createElement("a");
          a4.href = "#";
          a4.textContent = showDistance(d.link);
          a4.onclick = router.link(d.link);
          td5.appendChild(a4);
          td5.setAttribute("data-sort", d.link.distance !== undefined ? -d.link.distance : 1);
          tr.appendChild(td5);

          tbody.appendChild(tr);
        });

        table.appendChild(tbody);
        table.className = "node-links";

        new Tablesort(table);

        el.appendChild(table);
      }
    };
  });
<|endoftext|>


<commit_before>define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
  function (SortTable, V, d3Interpolate, moment, helper) {
    'use strict';
    V = V.default;

    function showGeoURI(d) {
      if (!helper.hasLocation(d)) {
        return undefined;
      }

      return function (el) {
        var a = document.createElement('a');
        a.textContent = Number(d.nodeinfo.location.latitude.toFixed(6)) + ', ' + Number(d.nodeinfo.location.longitude.toFixed(6));
        a.href = 'geo:' + d.nodeinfo.location.latitude + ',' + d.nodeinfo.location.longitude;
        el.appendChild(a);
      };
    }

    function showStatus(d) {
      return function (el) {
        el.classList.add(d.flags.unseen ? 'unseen' : (d.flags.online ? 'online' : 'offline'));
        el.textContent = _.t((d.flags.online ? 'node.lastOnline' : 'node.lastOffline'), {
          time: d.lastseen.fromNow(),
          date: d.lastseen.format('DD.MM.YYYY, H:mm:ss')
        });
      };
    }

    function showFirmware(d) {
      var release = helper.dictGet(d.nodeinfo, ['software', 'firmware', 'release']);
      var base = helper.dictGet(d.nodeinfo, ['software', 'firmware', 'base']);

      if (release === null || base === null) {
        return undefined;
      }

      return release + ' / ' + base;
    }

    function showSite(d, config) {
      var site = helper.dictGet(d.nodeinfo, ['system', 'site_code']);
      var rt = site;
      if (config.siteNames) {
        config.siteNames.forEach(function (t) {
          if (site === t.site) {
            rt = t.name;
          }
        });
      }
      return rt;
    }

    function showUptime(d) {
      if (!('uptime' in d.statistics)) {
        return undefined;
      }

      return moment.duration(d.statistics.uptime, 'seconds').humanize();
    }

    function showFirstseen(d) {
      if (!('firstseen' in d)) {
        return undefined;
      }

      return d.firstseen.fromNow(true);
    }

    function showClients(d) {
      if (!d.flags.online) {
        return undefined;
      }

      return function (el) {
        el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : _.t('none')));
        el.appendChild(document.createElement('br'));

        var span = document.createElement('span');
        span.classList.add('clients');
        span.innerHTML = ''.repeat(d.statistics.clients);
        el.appendChild(span);
      };
    }

    function showIPs(d) {
      var ips = helper.dictGet(d.nodeinfo, ['network', 'addresses']);
      if (ips === null) {
        return undefined;
      }

      ips.sort();

      return function (el) {
        ips.forEach(function (ip, i) {
          var link = !ip.startsWith('fe80:');

          if (i > 0) {
            el.appendChild(document.createElement('br'));
          }

          if (link) {
            var a = document.createElement('a');
            a.href = 'http://[' + ip + ']/';
            a.textContent = ip;
            el.appendChild(a);
          } else {
            el.appendChild(document.createTextNode(ip));
          }
        });
      };
    }

    function showBar(v, width, warning) {
      var span = document.createElement('span');
      span.classList.add('bar');

      var bar = document.createElement('span');
      bar.style.width = (width * 100) + '%';
      if (warning) {
        span.classList.add('warning');
      }
      span.appendChild(bar);

      var label = document.createElement('label');
      label.textContent = v;
      span.appendChild(label);

      return span;
    }

    function showLoad(d) {
      if (!('loadavg' in d.statistics)) {
        return undefined;
      }

      return function (el) {
        var value = d.statistics.loadavg.toFixed(2);
        var width = d.statistics.loadavg % 1;
        var warning = false;
        if (d.statistics.loadavg >= d.nodeinfo.hardware.nproc) {
          warning = true;
        }
        el.appendChild(showBar(value, width, warning));
      };
    }

    function showRAM(d) {
      if (!('memory_usage' in d.statistics)) {
        return undefined;
      }

      return function (el) {
        var value = Math.round(d.statistics.memory_usage * 100) + ' %';
        var width = d.statistics.memory_usage;
        var warning = false;
        if (d.statistics.memory_usage >= 0.8) {
          warning = true;
        }
        el.appendChild(showBar(value, width, warning));
      };
    }

    function showAutoupdate(d) {
      var au = helper.dictGet(d.nodeinfo, ['software', 'autoupdater']);
      if (!au) {
        return undefined;
      }

      return au.enabled ? _.t('node.activated', { branch: au.branch }) : _.t('node.deactivated');
    }

    function showStatImg(o, d) {
      var subst = {};
      subst['{NODE_ID}'] = d.nodeinfo.node_id;
      subst['{NODE_NAME}'] = d.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_');
      subst['{TIME}'] = d.lastseen.format('DDMMYYYYHmmss');
      subst['{LOCALE}'] = _.locale();
      return helper.showStat(o, subst);
    }

    return function (config, el, router, d, gateways) {
      var linkScale = d3Interpolate.interpolate('#F02311', '#04C714');

      function renderNeighbourRow(n) {
        var icons = [];
        icons.push(V.h('span', { props: { className: n.incoming ? 'ion-arrow-left-c' : 'ion-arrow-right-c' } }));
        if (helper.hasLocation(n.node)) {
          icons.push(V.h('span', { props: { className: 'ion-location' } }));
        }

        var name = V.h('a', {
          props: {
            className: 'online',
            href: router.generateLink({ node: n.node.nodeinfo.node_id })
          }, on: {
            click: function (e) {
              router.fullUrl({ node: n.node.nodeinfo.node_id }, e);
            }
          }
        }, n.node.nodeinfo.hostname);

        var td1 = V.h('td', icons);
        var td2 = V.h('td', name);
        var td3 = V.h('td', (n.node.statistics.clients ? n.node.statistics.clients.toString() : '0'));
        var td4 = V.h('td', { style: { color: linkScale(1 / n.link.tq) } }, helper.showTq(n.link));
        var td5 = V.h('td', helper.showDistance(n.link));

        return V.h('tr', [td1, td2, td3, td4, td5]);
      }

      var h2 = document.createElement('h2');
      h2.textContent = d.nodeinfo.hostname;
      el.appendChild(h2);

      var attributes = document.createElement('table');
      attributes.classList.add('attributes');

      helper.attributeEntry(attributes, 'node.status', showStatus(d));
      helper.attributeEntry(attributes, 'node.gateway', d.flags.gateway ? 'ja' : null);
      helper.attributeEntry(attributes, 'node.coordinates', showGeoURI(d));

      if (config.nodeInfobox && config.nodeInfobox.contact) {
        helper.attributeEntry(attributes, 'node.contact', helper.dictGet(d.nodeinfo, ['owner', 'contact']));
      }

      helper.attributeEntry(attributes, 'node.hardware', helper.dictGet(d.nodeinfo, ['hardware', 'model']));
      helper.attributeEntry(attributes, 'node.primaryMac', helper.dictGet(d.nodeinfo, ['network', 'mac']));
      helper.attributeEntry(attributes, 'node.id', helper.dictGet(d.nodeinfo, ['node_id']));
      helper.attributeEntry(attributes, 'node.firmware', showFirmware(d));
      helper.attributeEntry(attributes, 'node.site', showSite(d, config));
      helper.attributeEntry(attributes, 'node.uptime', showUptime(d));
      helper.attributeEntry(attributes, 'node.firstSeen', showFirstseen(d));
      if (config.nodeInfobox && config.nodeInfobox.hardwareUsage) {
        helper.attributeEntry(attributes, 'node.systemLoad', showLoad(d));
        helper.attributeEntry(attributes, 'node.ram', showRAM(d));
      }
      helper.attributeEntry(attributes, 'node.ipAddresses', showIPs(d));
      helper.attributeEntry(attributes, 'node.selectedGateway', gateways[helper.dictGet(d.statistics, ['gateway'])]);
      helper.attributeEntry(attributes, 'node.update', showAutoupdate(d));
      helper.attributeEntry(attributes, 'node.clients', showClients(d));

      el.appendChild(attributes);

      if (d.neighbours.length > 0) {
        var h3 = document.createElement('h3');
        h3.textContent = _.t('node.link', d.neighbours.length) + '(' + d.neighbours.length + ')';
        el.appendChild(h3);

        var headings = [{
          name: ''
        }, {
          name: 'node.nodes',
          sort: function (a, b) {
            return a.node.nodeinfo.hostname.localeCompare(b.node.nodeinfo.hostname);
          },
          reverse: false
        }, {
          name: 'node.clients',
          class: 'ion-people',
          sort: function (a, b) {
            return ('clients' in a.node.statistics ? a.node.statistics.clients : -1) -
              ('clients' in b.node.statistics ? b.node.statistics.clients : -1);
          },
          reverse: true
        }, {
          name: 'node.tq',
          class: 'ion-connection-bars',
          sort: function (a, b) {
            return a.link.tq - b.link.tq;
          },
          reverse: true
        }, {
          name: 'node.distance',
          class: 'ion-arrow-resize',
          sort: function (a, b) {
            return (a.link.distance === undefined ? -1 : a.link.distance) -
              (b.link.distance === undefined ? -1 : b.link.distance);
          },
          reverse: true
        }];

        var table = new SortTable(headings, 1, renderNeighbourRow);
        table.setData(d.neighbours);
        table.el.elm.classList.add('node-links');
        el.appendChild(table.el.elm);
      }

      if (config.nodeInfos) {
        config.nodeInfos.forEach(function (nodeInfo) {
          var h4 = document.createElement('h4');
          h4.textContent = nodeInfo.name;
          el.appendChild(h4);
          el.appendChild(showStatImg(nodeInfo, d));
        });
      }
    };
  });
<commit_msg>[TASK] Add space between label and connection count<commit_after>define(['sorttable', 'snabbdom', 'd3-interpolate', 'moment', 'helper'],
  function (SortTable, V, d3Interpolate, moment, helper) {
    'use strict';
    V = V.default;

    function showGeoURI(d) {
      if (!helper.hasLocation(d)) {
        return undefined;
      }

      return function (el) {
        var a = document.createElement('a');
        a.textContent = Number(d.nodeinfo.location.latitude.toFixed(6)) + ', ' + Number(d.nodeinfo.location.longitude.toFixed(6));
        a.href = 'geo:' + d.nodeinfo.location.latitude + ',' + d.nodeinfo.location.longitude;
        el.appendChild(a);
      };
    }

    function showStatus(d) {
      return function (el) {
        el.classList.add(d.flags.unseen ? 'unseen' : (d.flags.online ? 'online' : 'offline'));
        el.textContent = _.t((d.flags.online ? 'node.lastOnline' : 'node.lastOffline'), {
          time: d.lastseen.fromNow(),
          date: d.lastseen.format('DD.MM.YYYY, H:mm:ss')
        });
      };
    }

    function showFirmware(d) {
      var release = helper.dictGet(d.nodeinfo, ['software', 'firmware', 'release']);
      var base = helper.dictGet(d.nodeinfo, ['software', 'firmware', 'base']);

      if (release === null || base === null) {
        return undefined;
      }

      return release + ' / ' + base;
    }

    function showSite(d, config) {
      var site = helper.dictGet(d.nodeinfo, ['system', 'site_code']);
      var rt = site;
      if (config.siteNames) {
        config.siteNames.forEach(function (t) {
          if (site === t.site) {
            rt = t.name;
          }
        });
      }
      return rt;
    }

    function showUptime(d) {
      if (!('uptime' in d.statistics)) {
        return undefined;
      }

      return moment.duration(d.statistics.uptime, 'seconds').humanize();
    }

    function showFirstseen(d) {
      if (!('firstseen' in d)) {
        return undefined;
      }

      return d.firstseen.fromNow(true);
    }

    function showClients(d) {
      if (!d.flags.online) {
        return undefined;
      }

      return function (el) {
        el.appendChild(document.createTextNode(d.statistics.clients > 0 ? d.statistics.clients : _.t('none')));
        el.appendChild(document.createElement('br'));

        var span = document.createElement('span');
        span.classList.add('clients');
        span.innerHTML = ''.repeat(d.statistics.clients);
        el.appendChild(span);
      };
    }

    function showIPs(d) {
      var ips = helper.dictGet(d.nodeinfo, ['network', 'addresses']);
      if (ips === null) {
        return undefined;
      }

      ips.sort();

      return function (el) {
        ips.forEach(function (ip, i) {
          var link = !ip.startsWith('fe80:');

          if (i > 0) {
            el.appendChild(document.createElement('br'));
          }

          if (link) {
            var a = document.createElement('a');
            a.href = 'http://[' + ip + ']/';
            a.textContent = ip;
            el.appendChild(a);
          } else {
            el.appendChild(document.createTextNode(ip));
          }
        });
      };
    }

    function showBar(v, width, warning) {
      var span = document.createElement('span');
      span.classList.add('bar');

      var bar = document.createElement('span');
      bar.style.width = (width * 100) + '%';
      if (warning) {
        span.classList.add('warning');
      }
      span.appendChild(bar);

      var label = document.createElement('label');
      label.textContent = v;
      span.appendChild(label);

      return span;
    }

    function showLoad(d) {
      if (!('loadavg' in d.statistics)) {
        return undefined;
      }

      return function (el) {
        var value = d.statistics.loadavg.toFixed(2);
        var width = d.statistics.loadavg % 1;
        var warning = false;
        if (d.statistics.loadavg >= d.nodeinfo.hardware.nproc) {
          warning = true;
        }
        el.appendChild(showBar(value, width, warning));
      };
    }

    function showRAM(d) {
      if (!('memory_usage' in d.statistics)) {
        return undefined;
      }

      return function (el) {
        var value = Math.round(d.statistics.memory_usage * 100) + ' %';
        var width = d.statistics.memory_usage;
        var warning = false;
        if (d.statistics.memory_usage >= 0.8) {
          warning = true;
        }
        el.appendChild(showBar(value, width, warning));
      };
    }

    function showAutoupdate(d) {
      var au = helper.dictGet(d.nodeinfo, ['software', 'autoupdater']);
      if (!au) {
        return undefined;
      }

      return au.enabled ? _.t('node.activated', { branch: au.branch }) : _.t('node.deactivated');
    }

    function showStatImg(o, d) {
      var subst = {};
      subst['{NODE_ID}'] = d.nodeinfo.node_id;
      subst['{NODE_NAME}'] = d.nodeinfo.hostname.replace(/[^a-z0-9\-]/ig, '_');
      subst['{TIME}'] = d.lastseen.format('DDMMYYYYHmmss');
      subst['{LOCALE}'] = _.locale();
      return helper.showStat(o, subst);
    }

    return function (config, el, router, d, gateways) {
      var linkScale = d3Interpolate.interpolate('#F02311', '#04C714');

      function renderNeighbourRow(n) {
        var icons = [];
        icons.push(V.h('span', { props: { className: n.incoming ? 'ion-arrow-left-c' : 'ion-arrow-right-c' } }));
        if (helper.hasLocation(n.node)) {
          icons.push(V.h('span', { props: { className: 'ion-location' } }));
        }

        var name = V.h('a', {
          props: {
            className: 'online',
            href: router.generateLink({ node: n.node.nodeinfo.node_id })
          }, on: {
            click: function (e) {
              router.fullUrl({ node: n.node.nodeinfo.node_id }, e);
            }
          }
        }, n.node.nodeinfo.hostname);

        var td1 = V.h('td', icons);
        var td2 = V.h('td', name);
        var td3 = V.h('td', (n.node.statistics.clients ? n.node.statistics.clients.toString() : '0'));
        var td4 = V.h('td', { style: { color: linkScale(1 / n.link.tq) } }, helper.showTq(n.link));
        var td5 = V.h('td', helper.showDistance(n.link));

        return V.h('tr', [td1, td2, td3, td4, td5]);
      }

      var h2 = document.createElement('h2');
      h2.textContent = d.nodeinfo.hostname;
      el.appendChild(h2);

      var attributes = document.createElement('table');
      attributes.classList.add('attributes');

      helper.attributeEntry(attributes, 'node.status', showStatus(d));
      helper.attributeEntry(attributes, 'node.gateway', d.flags.gateway ? 'ja' : null);
      helper.attributeEntry(attributes, 'node.coordinates', showGeoURI(d));

      if (config.nodeInfobox && config.nodeInfobox.contact) {
        helper.attributeEntry(attributes, 'node.contact', helper.dictGet(d.nodeinfo, ['owner', 'contact']));
      }

      helper.attributeEntry(attributes, 'node.hardware', helper.dictGet(d.nodeinfo, ['hardware', 'model']));
      helper.attributeEntry(attributes, 'node.primaryMac', helper.dictGet(d.nodeinfo, ['network', 'mac']));
      helper.attributeEntry(attributes, 'node.id', helper.dictGet(d.nodeinfo, ['node_id']));
      helper.attributeEntry(attributes, 'node.firmware', showFirmware(d));
      helper.attributeEntry(attributes, 'node.site', showSite(d, config));
      helper.attributeEntry(attributes, 'node.uptime', showUptime(d));
      helper.attributeEntry(attributes, 'node.firstSeen', showFirstseen(d));
      if (config.nodeInfobox && config.nodeInfobox.hardwareUsage) {
        helper.attributeEntry(attributes, 'node.systemLoad', showLoad(d));
        helper.attributeEntry(attributes, 'node.ram', showRAM(d));
      }
      helper.attributeEntry(attributes, 'node.ipAddresses', showIPs(d));
      helper.attributeEntry(attributes, 'node.selectedGateway', gateways[helper.dictGet(d.statistics, ['gateway'])]);
      helper.attributeEntry(attributes, 'node.update', showAutoupdate(d));
      helper.attributeEntry(attributes, 'node.clients', showClients(d));

      el.appendChild(attributes);

      if (d.neighbours.length > 0) {
        var h3 = document.createElement('h3');
        h3.textContent = _.t('node.link', d.neighbours.length) + ' (' + d.neighbours.length + ')';
        el.appendChild(h3);

        var headings = [{
          name: ''
        }, {
          name: 'node.nodes',
          sort: function (a, b) {
            return a.node.nodeinfo.hostname.localeCompare(b.node.nodeinfo.hostname);
          },
          reverse: false
        }, {
          name: 'node.clients',
          class: 'ion-people',
          sort: function (a, b) {
            return ('clients' in a.node.statistics ? a.node.statistics.clients : -1) -
              ('clients' in b.node.statistics ? b.node.statistics.clients : -1);
          },
          reverse: true
        }, {
          name: 'node.tq',
          class: 'ion-connection-bars',
          sort: function (a, b) {
            return a.link.tq - b.link.tq;
          },
          reverse: true
        }, {
          name: 'node.distance',
          class: 'ion-arrow-resize',
          sort: function (a, b) {
            return (a.link.distance === undefined ? -1 : a.link.distance) -
              (b.link.distance === undefined ? -1 : b.link.distance);
          },
          reverse: true
        }];

        var table = new SortTable(headings, 1, renderNeighbourRow);
        table.setData(d.neighbours);
        table.el.elm.classList.add('node-links');
        el.appendChild(table.el.elm);
      }

      if (config.nodeInfos) {
        config.nodeInfos.forEach(function (nodeInfo) {
          var h4 = document.createElement('h4');
          h4.textContent = nodeInfo.name;
          el.appendChild(h4);
          el.appendChild(showStatImg(nodeInfo, d));
        });
      }
    };
  });
<|endoftext|>


<commit_before>const fs = require('fs')
const inquirer = require('inquirer')
const git = require('gift')

const { fileExist } = require('./fs.utils')
const { log } = require('./log.utils')

module.exports = exports = (configFilename) => {
  return (options) => {
    const userForceOverwrite = options.force || false
    const questions = [
      {
        name: 'overwrite_file',
        message: 'A configuration file already exist. Do you want to continue ?',
        type: 'confirm',
        when: () => fileExist(configFilename) && !userForceOverwrite
      },
      {
        name: 'repo_name',
        message: 'Repository url:',
        type: 'input',
        validate: url => URL_REGEX.test(url),
        when: data => !fileExist(configFilename) || data.overwrite_file || userForceOverwrite
      },
      {
        name: 'folder_path',
        message: 'Folder path:',
        type: 'input',
        validate: path => PATH_REGEX.test(path),
        when: data => !fileExist(configFilename) || data.overwrite_file || userForceOverwrite
      }
    ]

    inquirer.prompt(questions)
      .then(data => {
        console.log(data)
        const { repo_name = null, folder_path, overwrite_file = true } = data

        if (!overwrite_file) {
          return
        }

        if (!fileExist(folder_path)) {
          log('info', 'Folder does not exist. It will be created.', ' Info ')
          fs.mkdirSync(folder_path)
        }

        const folderStat = fs.statSync(folder_path)
        if (!folderStat.isDirectory()) {
          log('error', `${folder_path} is not a folder.`, ' Abort ')
          return
        }

        const folderIsEmpty = fs.readdirSync(folder_path).length < 1
        if (!folderIsEmpty) {
          log('error', 'Folder is not empty', ' Abort ')
          return
        }

        if (repo_name == null) {
          return
        }

        git.clone(repo_name, folder_path, (error, result) => {
          console.log(error, result)
        })

        fs.writeFileSync(configFilename, JSON.stringify({ repo_name, folder_path }, null, 4))
      })
  }
}

const URL_REGEX = /^((?:(https?):\/\/)?((?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9])\.(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9])\.)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9])\.)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9]))|(?:(?:(?:\w+\.){1,2}[\w]{2,3})))(?::(\d+))?((?:\/[\w]+)*)(?:\/|(\/[\w]+\.[\w]{3,4})|(\?(?:([\w]+=[\w]+)&)*([\w]+=[\w]+))?|\?(?:(wsdl|wadl))))$/
const PATH_REGEX = /^(?:(?:~|\.{1,2})?\/)+(?:[a-zA-Z\.\-\_]+\/?)*$/
<commit_msg>Put git clone step in this own then step<commit_after>const fs = require('fs')
const inquirer = require('inquirer')

const { fileExist } = require('./fs.utils')
const { log } = require('./log.utils')
const { gitClone } = require('./git.utils')

module.exports = exports = (configFilename) => {
  return (options) => {
    const userForceOverwrite = options.force || false
    const questions = [
      {
        name: 'overwrite_file',
        message: 'A configuration file already exist. Do you want to continue ?',
        type: 'confirm',
        when: () => fileExist(configFilename) && !userForceOverwrite
      },
      {
        name: 'repo_name',
        message: 'Repository url:',
        type: 'input',
        validate: url => URL_REGEX.test(url),
        when: data => !fileExist(configFilename) || data.overwrite_file || userForceOverwrite
      },
      {
        name: 'folder_path',
        message: 'Folder path:',
        type: 'input',
        validate: path => PATH_REGEX.test(path),
        when: data => !fileExist(configFilename) || data.overwrite_file || userForceOverwrite
      }
    ]

    inquirer.prompt(questions)
      .then(data => {
        const { repo_name = null, folder_path, overwrite_file = true } = data

        if (!overwrite_file) {
          return data
        }

        if (!fileExist(folder_path)) {
          log('info', 'Folder does not exist. It will be created.', ' Info ')
          fs.mkdirSync(folder_path)
        }

        const folderStat = fs.statSync(folder_path)
        if (!folderStat.isDirectory()) {
          throw new Error('folder_is_not_directory')
        }

        const folderIsEmpty = fs.readdirSync(folder_path).length < 1
        if (!folderIsEmpty) {
          throw new Error('folder_is_not_empty')
        }

        fs.writeFileSync(configFilename, JSON.stringify({ repo_name, folder_path }, null, 4))
        return { repo_name, folder_path }
      })
      .then(({ repo_name, folder_path }) => {
        if (repo_name == null) {
          log('warn', 'Impossible to cloned git repository. Need repository URL.', ' Warn ')
          return { repo_name, folder_path }
        }

        return gitClone(repo_name, folder_path)
          .then((repo) => {
            log('info', 'Git repository cloned successuly.', ' Info ')
            return { repo_name, folder_path }
          })
      })
      .catch((error) => {
        switch (error.message) {
          case 'folder_is_not_directory':
            log('error', `${folder_path} is not a folder.`, ' Abort ')
            break
          case 'folder_is_not_empty':
            log('error', 'Folder is not empty.', ' Abort ')
            break
          default:
            log('error', 'An error occured.', ' Fail ')
            console.log(error)
        }
      })
  }
}

const URL_REGEX = /^((?:(https?):\/\/)?((?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9])\.(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9])\.)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9])\.)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]|[0-9]))|(?:(?:(?:\w+\.){1,2}[\w]{2,3})))(?::(\d+))?((?:\/[\w]+)*)(?:\/|(\/[\w]+\.[\w]{3,4})|(\?(?:([\w]+=[\w]+)&)*([\w]+=[\w]+))?|\?(?:(wsdl|wadl))))$/
const PATH_REGEX = /^(?:(?:~|\.{1,2})?\/)+(?:[a-zA-Z\.\-\_]+\/?)*$/
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

const Gather = require('./gather');

// Request the current page by issuing a sync request to ''.
const requestPage = `
  (function() {
    var request = new XMLHttpRequest();
    request.open('GET', '', false);
    request.send(null);
    return request.status;
  })();
`;

class Offline extends Gather {

  static goOffline(driver) {
    return driver.sendCommand('Network.emulateNetworkConditions', {
      offline: true,
      // values of 0 remove any active throttling
      latency: 0,
      downloadThroughput: 0,
      uploadThroughput: 0
    });
  }

  static goOnline(driver) {
    return driver.sendCommand('Network.emulateNetworkConditions', {
      offline: false,
      latency: 0,
      downloadThroughput: 0,
      uploadThroughput: 0
    });
  }

  static getOfflinePageStatus(driver) {
    return driver.sendCommand('Runtime.evaluate', {
      expression: requestPage
    });
  }

  static gather(options) {
    const driver = options.driver;

    // TODO eventually we will want to walk all network
    // requests that the page initially made and retry them.
    return Offline.goOffline(driver).then(_ => {
      let responseCode;

      return Offline.getOfflinePageStatus(driver).then(ret => {
        responseCode = ret.result.value;
      }).then(_ => Offline.goOnline(driver)).then(_ => {
        return {responseCode};
      });
    });
  }
}

module.exports = Offline;
<commit_msg>offline: comment on 0 values. <commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

const Gather = require('./gather');

// Request the current page by issuing a sync request to ''.
const requestPage = `
  (function() {
    var request = new XMLHttpRequest();
    request.open('GET', '', false);
    request.send(null);
    return request.status;
  })();
`;

class Offline extends Gather {

  static goOffline(driver) {
    return driver.sendCommand('Network.emulateNetworkConditions', {
      offline: true,
      // values of 0 remove any active throttling. crbug.com/456324#c9
      latency: 0,
      downloadThroughput: 0,
      uploadThroughput: 0
    });
  }

  static goOnline(driver) {
    return driver.sendCommand('Network.emulateNetworkConditions', {
      offline: false,
      latency: 0,
      downloadThroughput: 0,
      uploadThroughput: 0
    });
  }

  static getOfflinePageStatus(driver) {
    return driver.sendCommand('Runtime.evaluate', {
      expression: requestPage
    });
  }

  static gather(options) {
    const driver = options.driver;

    // TODO eventually we will want to walk all network
    // requests that the page initially made and retry them.
    return Offline.goOffline(driver).then(_ => {
      let responseCode;

      return Offline.getOfflinePageStatus(driver).then(ret => {
        responseCode = ret.result.value;
      }).then(_ => Offline.goOnline(driver)).then(_ => {
        return {responseCode};
      });
    });
  }
}

module.exports = Offline;
<|endoftext|>


<commit_before>var _ = require('lodash');
var optimist = require('optimist');
var prompt = require('prompt');

var schema = {
  properties: {
    consumerKey: {
      required: true
    },
    consumerSecret: {
      required: true
    },
    friendId: {
      required: true
    }
  }
};

prompt.override = optimist.argv;
prompt.start();

prompt.get(schema, function(err, input) {
  var oauth = new OAuth.OAuth(
  'https://secure.splitwise.com/api/v3.0/get_request_token',
  'https://secure.splitwise.com/api/v3.0/get_access_token',
  result.consumerKey,
  result.consumerSecret,
  '1.0',
  null,
  'HMAC-SHA1');

  var file = require(__dirname + '\\friend.json');
  var some = _.first(file.results, 20);
  _.each(some, function(tx) {
    console.log('----------------------------------')
    console.log('Who Paid: ' + tx.sender.name);
    console.log('Who Owes: ' + tx.receiver.name);
    console.log('Amount: ' + tx.amount);
    console.log('Description: ' + tx.message);
    console.log('Date: ' + tx.happenedAt.iso.substring(0, tx.happenedAt.iso.indexOf('T')));
    console.log(tx.receiver.name + ' owes ' + tx.sender.name + ' $' + tx.amount + ' for ' + tx.message + ' on ' + tx.happenedAt.iso.substring(0, tx.happenedAt.iso.indexOf('T')));
  });
});
<commit_msg>Refactor into variable.<commit_after>var _ = require('lodash');
var optimist = require('optimist');
var prompt = require('prompt');

var schema = {
  properties: {
    consumerKey: {
      required: true
    },
    consumerSecret: {
      required: true
    },
    friendId: {
      required: true
    }
  }
};

prompt.override = optimist.argv;
prompt.start();

prompt.get(schema, function(err, input) {
  var oauth = new OAuth.OAuth(
  'https://secure.splitwise.com/api/v3.0/get_request_token',
  'https://secure.splitwise.com/api/v3.0/get_access_token',
  result.consumerKey,
  result.consumerSecret,
  '1.0',
  null,
  'HMAC-SHA1');

  var file = require(__dirname + '\\friend.json');
  var some = _.first(file.results, 20);
  _.each(some, function(tx) {
    console.log('----------------------------------')
    console.log('Who Paid: ' + tx.sender.name);
    console.log('Who Owes: ' + tx.receiver.name);
    console.log('Amount: ' + tx.amount);
    console.log('Description: ' + tx.message);
    console.log('Date: ' + tx.happenedAt.iso.substring(0, tx.happenedAt.iso.indexOf('T')));
    var natural = tx.receiver.name + ' owes ' + tx.sender.name + ' $' + tx.amount + ' for ' + tx.message + ' on ' + tx.happenedAt.iso.substring(0, tx.happenedAt.iso.indexOf('T'));
    console.log(natural);
  });
});
<|endoftext|>