<commit_before>var FontManager = (function(){

    var maxWaitingTime = 5000;
    var emptyChar = {
        w: 0,
        size:0,
        shapes:[]
    };
    var combinedCharacters = [];
    //Hindi characters
    combinedCharacters = combinedCharacters.concat([2304, 2305, 2306, 2307, 2362, 2363, 2364, 2364, 2366
    , 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379
    , 2380, 2381, 2382, 2383, 2387, 2388, 2389, 2390, 2391, 2402, 2403]);

    function setUpNode(font, family){
        var parentNode = createTag('span');
        parentNode.style.fontFamily    = family;
        var node = createTag('span');
        // Characters that vary significantly among different fonts
        node.innerHTML = 'giItT1WQy@!-/#';
        // Visible - so we can measure it - but not on the screen
        parentNode.style.position      = 'absolute';
        parentNode.style.left          = '-10000px';
        parentNode.style.top           = '-10000px';
        // Large font size makes even subtle changes obvious
        parentNode.style.fontSize      = '300px';
        // Reset any font properties
        parentNode.style.fontVariant   = 'normal';
        parentNode.style.fontStyle     = 'normal';
        parentNode.style.fontWeight    = 'normal';
        parentNode.style.letterSpacing = '0';
        parentNode.appendChild(node);
        document.body.appendChild(parentNode);

        // Remember width with no applied web font
        var width = node.offsetWidth;
        node.style.fontFamily = font + ', '+family;
        return {node:node, w:width, parent:parentNode};
    }

    function checkLoadedFonts() {
        var i, len = this.fonts.length;
        var node, w;
        var loadedCount = len;
        for(i=0;i<len; i+= 1){
            if(this.fonts[i].loaded){
                loadedCount -= 1;
                continue;
            }
            if(this.fonts[i].fOrigin === 'n' || this.fonts[i].origin === 0){
                this.fonts[i].loaded = true;
            } else{
                node = this.fonts[i].monoCase.node;
                w = this.fonts[i].monoCase.w;
                if(node.offsetWidth !== w){
                    loadedCount -= 1;
                    this.fonts[i].loaded = true;
                }else{
                    node = this.fonts[i].sansCase.node;
                    w = this.fonts[i].sansCase.w;
                    if(node.offsetWidth !== w){
                        loadedCount -= 1;
                        this.fonts[i].loaded = true;
                    }
                }
                if(this.fonts[i].loaded){
                    this.fonts[i].sansCase.parent.parentNode.removeChild(this.fonts[i].sansCase.parent);
                    this.fonts[i].monoCase.parent.parentNode.removeChild(this.fonts[i].monoCase.parent);
                }
            }
        }

        if(loadedCount !== 0 && Date.now() - this.initTime < maxWaitingTime){
            setTimeout(this.checkLoadedFonts.bind(this),20);
        }else{
            setTimeout(function(){this.isLoaded = true;}.bind(this),0);

        }
    }

    function createHelper(def, fontData){
        var tHelper = createNS('text');
        tHelper.style.fontSize = '100px';
        //tHelper.style.fontFamily = fontData.fFamily;
        tHelper.setAttribute('font-family', fontData.fFamily);
        tHelper.setAttribute('font-style', fontData.fStyle);
        tHelper.setAttribute('font-weight', fontData.fWeight);
        tHelper.textContent = '1';
        if(fontData.fClass){
            tHelper.style.fontFamily = 'inherit';
            tHelper.className = fontData.fClass;
        } else {
            tHelper.style.fontFamily = fontData.fFamily;
        }
        def.appendChild(tHelper);
        var tCanvasHelper = createTag('canvas').getContext('2d');
        tCanvasHelper.font = fontData.fWeight + ' ' + fontData.fStyle + ' 100px '+ fontData.fFamily;
        //tCanvasHelper.font = ' 100px '+ fontData.fFamily;
        return tHelper;
    }

    function addFonts(fontData, defs){
        if(!fontData){
            this.isLoaded = true;
            return;
        }
        if(this.chars){
            this.isLoaded = true;
            this.fonts = fontData.list;
            return;
        }

        var fontArr = fontData.list;
        var i, len = fontArr.length;
        var _pendingFonts = len;
        for(i=0; i<len; i+= 1){
            var shouldLoadFont = true;
            var loadedSelector;
            var j;
            fontArr[i].loaded = false;
            fontArr[i].monoCase = setUpNode(fontArr[i].fFamily,'monospace');
            fontArr[i].sansCase = setUpNode(fontArr[i].fFamily,'sans-serif');
            if(!fontArr[i].fPath) {
                fontArr[i].loaded = true;
                _pendingFonts -= 1;
            }else if(fontArr[i].fOrigin === 'p' || fontArr[i].origin === 3){
                loadedSelector = document.querySelectorAll('style[f-forigin="p"][f-family="'+ fontArr[i].fFamily +'"], style[f-origin="3"][f-family="'+ fontArr[i].fFamily +'"]');

                if (loadedSelector.length > 0) {
                    shouldLoadFont = false;
                }

                if (shouldLoadFont) {
                    var s = createTag('style');
                    s.setAttribute('f-forigin', fontArr[i].fOrigin);
                    s.setAttribute('f-origin', fontArr[i].origin);
                    s.setAttribute('f-family', fontArr[i].fFamily);
                    s.type = "text/css";
                    s.innerHTML = "@font-face {" + "font-family: "+fontArr[i].fFamily+"; font-style: normal; src: url('"+fontArr[i].fPath+"');}";
                    defs.appendChild(s);
                }
            } else if(fontArr[i].fOrigin === 'g' || fontArr[i].origin === 1){
                loadedSelector = document.querySelectorAll('link[f-forigin="g"], link[f-origin="1"]');

                for (j = 0; j < loadedSelector.length; j++) {
                    if (loadedSelector[j].href.indexOf(fontArr[i].fPath) !== -1) {
                        // Font is already loaded
                        shouldLoadFont = false;
                    }
                }

                if (shouldLoadFont) {
                    var l = createTag('link');
                    l.setAttribute('f-forigin', fontArr[i].fOrigin);
                    l.setAttribute('f-origin', fontArr[i].origin);
                    l.type = "text/css";
                    l.rel = "stylesheet";
                    l.href = fontArr[i].fPath;
                    document.body.appendChild(l);
                }
            } else if(fontArr[i].fOrigin === 't' || fontArr[i].origin === 2){
                loadedSelector = document.querySelectorAll('script[f-forigin="t"], script[f-origin="2"]');

                for (j = 0; j < loadedSelector.length; j++) {
                    if (fontArr[i].fPath === loadedSelector[j].src) {
                        // Font is already loaded
                        shouldLoadFont = false;
                    }
                }

                if (shouldLoadFont) {
                    var sc = createTag('link');
                    sc.setAttribute('f-forigin', fontArr[i].fOrigin);
                    sc.setAttribute('f-origin', fontArr[i].origin);
                    sc.setAttribute('rel','stylesheet');
                    sc.setAttribute('href',fontArr[i].fPath);
                    defs.appendChild(sc);
                }
            }
            fontArr[i].helper = createHelper(defs,fontArr[i]);
            fontArr[i].cache = {};
            this.fonts.push(fontArr[i]);
        }
        if (_pendingFonts === 0) {
            this.isLoaded = true;
        } else {
            //On some cases even if the font is loaded, it won't load correctly when measuring text on canvas.
            //Adding this timeout seems to fix it
           setTimeout(this.checkLoadedFonts.bind(this), 100);
        }
    }

    function addChars(chars){
        if(!chars){
            return;
        }
        if(!this.chars){
            this.chars = [];
        }
        var i, len = chars.length;
        var j, jLen = this.chars.length, found;
        for(i=0;i<len;i+=1){
            j = 0;
            found = false;
            while(j<jLen){
                if(this.chars[j].style === chars[i].style && this.chars[j].fFamily === chars[i].fFamily && this.chars[j].ch === chars[i].ch){
                    found = true;
                }
                j += 1;
            }
            if(!found){
                this.chars.push(chars[i]);
                jLen += 1;
            }
        }
    }

    function getCharData(char, style, font){
        var i = 0, len = this.chars.length;
        while( i < len) {
            if(this.chars[i].ch === char && this.chars[i].style === style && this.chars[i].fFamily === font){
                return this.chars[i];
            }
            i+= 1;
        }
        if(console && console.warn) {
            console.warn('Missing character from exported characters list: ', char, style, font);
        }
        return emptyChar;
    }

    function measureText(char, fontName, size) {
        var fontData = this.getFontByName(fontName);
        var index = char.charCodeAt(0);
        if(!fontData.cache[index + 1]) {
            var tHelper = fontData.helper;
            //Canvas version
            //fontData.cache[index] = tHelper.measureText(char).width / 100;
            //SVG version
            //console.log(tHelper.getBBox().width)
            if (char === ' ') {
                tHelper.textContent = '|' + char + '|';
                var doubleSize = tHelper.getComputedTextLength();
                tHelper.textContent = '||';
                var singleSize = tHelper.getComputedTextLength();
                fontData.cache[index + 1] = (doubleSize - singleSize)/100;
            } else {
                tHelper.textContent = char;
                fontData.cache[index + 1] = (tHelper.getComputedTextLength())/100;
            }
        }
        return fontData.cache[index + 1] * size;
    }

    function getFontByName(name){
        var i = 0, len = this.fonts.length;
        while(i<len){
            if(this.fonts[i].fName === name) {
                return this.fonts[i];
            }
            i += 1;
        }
        return this.fonts[0];
    }

    function getCombinedCharacterCodes() {
        return combinedCharacters;
    }

    function loaded() {
        return this.isLoaded;
    }

    var Font = function(){
        this.fonts = [];
        this.chars = null;
        this.typekitLoaded = 0;
        this.isLoaded = false;
        this.initTime = Date.now();
    };
    //TODO: for now I'm adding these methods to the Class and not the prototype. Think of a better way to implement it.
    Font.getCombinedCharacterCodes = getCombinedCharacterCodes;

    Font.prototype.addChars = addChars;
    Font.prototype.addFonts = addFonts;
    Font.prototype.getCharData = getCharData;
    Font.prototype.getFontByName = getFontByName;
    Font.prototype.measureText = measureText;
    Font.prototype.checkLoadedFonts = checkLoadedFonts;
    Font.prototype.loaded = loaded;

    return Font;

}());<commit_msg>fixes #1489 setting class attribute via setAttribute<commit_after>var FontManager = (function(){

    var maxWaitingTime = 5000;
    var emptyChar = {
        w: 0,
        size:0,
        shapes:[]
    };
    var combinedCharacters = [];
    //Hindi characters
    combinedCharacters = combinedCharacters.concat([2304, 2305, 2306, 2307, 2362, 2363, 2364, 2364, 2366
    , 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379
    , 2380, 2381, 2382, 2383, 2387, 2388, 2389, 2390, 2391, 2402, 2403]);

    function setUpNode(font, family){
        var parentNode = createTag('span');
        parentNode.style.fontFamily    = family;
        var node = createTag('span');
        // Characters that vary significantly among different fonts
        node.innerHTML = 'giItT1WQy@!-/#';
        // Visible - so we can measure it - but not on the screen
        parentNode.style.position      = 'absolute';
        parentNode.style.left          = '-10000px';
        parentNode.style.top           = '-10000px';
        // Large font size makes even subtle changes obvious
        parentNode.style.fontSize      = '300px';
        // Reset any font properties
        parentNode.style.fontVariant   = 'normal';
        parentNode.style.fontStyle     = 'normal';
        parentNode.style.fontWeight    = 'normal';
        parentNode.style.letterSpacing = '0';
        parentNode.appendChild(node);
        document.body.appendChild(parentNode);

        // Remember width with no applied web font
        var width = node.offsetWidth;
        node.style.fontFamily = font + ', '+family;
        return {node:node, w:width, parent:parentNode};
    }

    function checkLoadedFonts() {
        var i, len = this.fonts.length;
        var node, w;
        var loadedCount = len;
        for(i=0;i<len; i+= 1){
            if(this.fonts[i].loaded){
                loadedCount -= 1;
                continue;
            }
            if(this.fonts[i].fOrigin === 'n' || this.fonts[i].origin === 0){
                this.fonts[i].loaded = true;
            } else{
                node = this.fonts[i].monoCase.node;
                w = this.fonts[i].monoCase.w;
                if(node.offsetWidth !== w){
                    loadedCount -= 1;
                    this.fonts[i].loaded = true;
                }else{
                    node = this.fonts[i].sansCase.node;
                    w = this.fonts[i].sansCase.w;
                    if(node.offsetWidth !== w){
                        loadedCount -= 1;
                        this.fonts[i].loaded = true;
                    }
                }
                if(this.fonts[i].loaded){
                    this.fonts[i].sansCase.parent.parentNode.removeChild(this.fonts[i].sansCase.parent);
                    this.fonts[i].monoCase.parent.parentNode.removeChild(this.fonts[i].monoCase.parent);
                }
            }
        }

        if(loadedCount !== 0 && Date.now() - this.initTime < maxWaitingTime){
            setTimeout(this.checkLoadedFonts.bind(this),20);
        }else{
            setTimeout(function(){this.isLoaded = true;}.bind(this),0);

        }
    }

    function createHelper(def, fontData){
        var tHelper = createNS('text');
        tHelper.style.fontSize = '100px';
        //tHelper.style.fontFamily = fontData.fFamily;
        tHelper.setAttribute('font-family', fontData.fFamily);
        tHelper.setAttribute('font-style', fontData.fStyle);
        tHelper.setAttribute('font-weight', fontData.fWeight);
        tHelper.textContent = '1';
        if(fontData.fClass){
            tHelper.style.fontFamily = 'inherit';
            tHelper.setAttribute('class', fontData.fClass);
        } else {
            tHelper.style.fontFamily = fontData.fFamily;
        }
        def.appendChild(tHelper);
        var tCanvasHelper = createTag('canvas').getContext('2d');
        tCanvasHelper.font = fontData.fWeight + ' ' + fontData.fStyle + ' 100px '+ fontData.fFamily;
        //tCanvasHelper.font = ' 100px '+ fontData.fFamily;
        return tHelper;
    }

    function addFonts(fontData, defs){
        if(!fontData){
            this.isLoaded = true;
            return;
        }
        if(this.chars){
            this.isLoaded = true;
            this.fonts = fontData.list;
            return;
        }

        var fontArr = fontData.list;
        var i, len = fontArr.length;
        var _pendingFonts = len;
        for(i=0; i<len; i+= 1){
            var shouldLoadFont = true;
            var loadedSelector;
            var j;
            fontArr[i].loaded = false;
            fontArr[i].monoCase = setUpNode(fontArr[i].fFamily,'monospace');
            fontArr[i].sansCase = setUpNode(fontArr[i].fFamily,'sans-serif');
            if(!fontArr[i].fPath) {
                fontArr[i].loaded = true;
                _pendingFonts -= 1;
            }else if(fontArr[i].fOrigin === 'p' || fontArr[i].origin === 3){
                loadedSelector = document.querySelectorAll('style[f-forigin="p"][f-family="'+ fontArr[i].fFamily +'"], style[f-origin="3"][f-family="'+ fontArr[i].fFamily +'"]');

                if (loadedSelector.length > 0) {
                    shouldLoadFont = false;
                }

                if (shouldLoadFont) {
                    var s = createTag('style');
                    s.setAttribute('f-forigin', fontArr[i].fOrigin);
                    s.setAttribute('f-origin', fontArr[i].origin);
                    s.setAttribute('f-family', fontArr[i].fFamily);
                    s.type = "text/css";
                    s.innerHTML = "@font-face {" + "font-family: "+fontArr[i].fFamily+"; font-style: normal; src: url('"+fontArr[i].fPath+"');}";
                    defs.appendChild(s);
                }
            } else if(fontArr[i].fOrigin === 'g' || fontArr[i].origin === 1){
                loadedSelector = document.querySelectorAll('link[f-forigin="g"], link[f-origin="1"]');

                for (j = 0; j < loadedSelector.length; j++) {
                    if (loadedSelector[j].href.indexOf(fontArr[i].fPath) !== -1) {
                        // Font is already loaded
                        shouldLoadFont = false;
                    }
                }

                if (shouldLoadFont) {
                    var l = createTag('link');
                    l.setAttribute('f-forigin', fontArr[i].fOrigin);
                    l.setAttribute('f-origin', fontArr[i].origin);
                    l.type = "text/css";
                    l.rel = "stylesheet";
                    l.href = fontArr[i].fPath;
                    document.body.appendChild(l);
                }
            } else if(fontArr[i].fOrigin === 't' || fontArr[i].origin === 2){
                loadedSelector = document.querySelectorAll('script[f-forigin="t"], script[f-origin="2"]');

                for (j = 0; j < loadedSelector.length; j++) {
                    if (fontArr[i].fPath === loadedSelector[j].src) {
                        // Font is already loaded
                        shouldLoadFont = false;
                    }
                }

                if (shouldLoadFont) {
                    var sc = createTag('link');
                    sc.setAttribute('f-forigin', fontArr[i].fOrigin);
                    sc.setAttribute('f-origin', fontArr[i].origin);
                    sc.setAttribute('rel','stylesheet');
                    sc.setAttribute('href',fontArr[i].fPath);
                    defs.appendChild(sc);
                }
            }
            fontArr[i].helper = createHelper(defs,fontArr[i]);
            fontArr[i].cache = {};
            this.fonts.push(fontArr[i]);
        }
        if (_pendingFonts === 0) {
            this.isLoaded = true;
        } else {
            //On some cases even if the font is loaded, it won't load correctly when measuring text on canvas.
            //Adding this timeout seems to fix it
           setTimeout(this.checkLoadedFonts.bind(this), 100);
        }
    }

    function addChars(chars){
        if(!chars){
            return;
        }
        if(!this.chars){
            this.chars = [];
        }
        var i, len = chars.length;
        var j, jLen = this.chars.length, found;
        for(i=0;i<len;i+=1){
            j = 0;
            found = false;
            while(j<jLen){
                if(this.chars[j].style === chars[i].style && this.chars[j].fFamily === chars[i].fFamily && this.chars[j].ch === chars[i].ch){
                    found = true;
                }
                j += 1;
            }
            if(!found){
                this.chars.push(chars[i]);
                jLen += 1;
            }
        }
    }

    function getCharData(char, style, font){
        var i = 0, len = this.chars.length;
        while( i < len) {
            if(this.chars[i].ch === char && this.chars[i].style === style && this.chars[i].fFamily === font){
                return this.chars[i];
            }
            i+= 1;
        }
        if(console && console.warn) {
            console.warn('Missing character from exported characters list: ', char, style, font);
        }
        return emptyChar;
    }

    function measureText(char, fontName, size) {
        var fontData = this.getFontByName(fontName);
        var index = char.charCodeAt(0);
        if(!fontData.cache[index + 1]) {
            var tHelper = fontData.helper;
            //Canvas version
            //fontData.cache[index] = tHelper.measureText(char).width / 100;
            //SVG version
            //console.log(tHelper.getBBox().width)
            if (char === ' ') {
                tHelper.textContent = '|' + char + '|';
                var doubleSize = tHelper.getComputedTextLength();
                tHelper.textContent = '||';
                var singleSize = tHelper.getComputedTextLength();
                fontData.cache[index + 1] = (doubleSize - singleSize)/100;
            } else {
                tHelper.textContent = char;
                fontData.cache[index + 1] = (tHelper.getComputedTextLength())/100;
            }
        }
        return fontData.cache[index + 1] * size;
    }

    function getFontByName(name){
        var i = 0, len = this.fonts.length;
        while(i<len){
            if(this.fonts[i].fName === name) {
                return this.fonts[i];
            }
            i += 1;
        }
        return this.fonts[0];
    }

    function getCombinedCharacterCodes() {
        return combinedCharacters;
    }

    function loaded() {
        return this.isLoaded;
    }

    var Font = function(){
        this.fonts = [];
        this.chars = null;
        this.typekitLoaded = 0;
        this.isLoaded = false;
        this.initTime = Date.now();
    };
    //TODO: for now I'm adding these methods to the Class and not the prototype. Think of a better way to implement it.
    Font.getCombinedCharacterCodes = getCombinedCharacterCodes;

    Font.prototype.addChars = addChars;
    Font.prototype.addFonts = addFonts;
    Font.prototype.getCharData = getCharData;
    Font.prototype.getFontByName = getFontByName;
    Font.prototype.measureText = measureText;
    Font.prototype.checkLoadedFonts = checkLoadedFonts;
    Font.prototype.loaded = loaded;

    return Font;

}());<|endoftext|>


<commit_before>var FontManager = (function(){

    var maxWaitingTime = 5000;
    var emptyChar = {
        w: 0,
        size:0,
        shapes:[]
    };
    var combinedCharacters = [];
    //Hindi characters
    combinedCharacters = combinedCharacters.concat([2304, 2305, 2306, 2307, 2362, 2363, 2364, 2364, 2366
    , 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379
    , 2380, 2381, 2382, 2383, 2387, 2388, 2389, 2390, 2391, 2402, 2403]);

    function trimFontOptions(font) {
        var familyArray = font.split(',');
        var i, len = familyArray.length;
        var enabledFamilies = [];
        for (i = 0; i < len; i += 1) {
            if (familyArray[i] !== 'sans-serif' && familyArray[i] !== 'monospace') {
                enabledFamilies.push(familyArray[i]);
            }
        }
        return enabledFamilies.join(',');
    }

    function setUpNode(font, family){
        var parentNode = createTag('span');
        parentNode.style.fontFamily    = family;
        var node = createTag('span');
        // Characters that vary significantly among different fonts
        node.innerHTML = 'giItT1WQy@!-/#';
        // Visible - so we can measure it - but not on the screen
        parentNode.style.position      = 'absolute';
        parentNode.style.left          = '-10000px';
        parentNode.style.top           = '-10000px';
        // Large font size makes even subtle changes obvious
        parentNode.style.fontSize      = '300px';
        // Reset any font properties
        parentNode.style.fontVariant   = 'normal';
        parentNode.style.fontStyle     = 'normal';
        parentNode.style.fontWeight    = 'normal';
        parentNode.style.letterSpacing = '0';
        parentNode.appendChild(node);
        document.body.appendChild(parentNode);

        // Remember width with no applied web font
        var width = node.offsetWidth;
        node.style.fontFamily = trimFontOptions(font) + ', ' + family;
        return {node:node, w:width, parent:parentNode};
    }

    function checkLoadedFonts() {
        var i, len = this.fonts.length;
        var node, w;
        var loadedCount = len;
        for(i=0;i<len; i+= 1){
            if(this.fonts[i].loaded){
                loadedCount -= 1;
                continue;
            }
            if(this.fonts[i].fOrigin === 'n' || this.fonts[i].origin === 0){
                this.fonts[i].loaded = true;
            } else{
                node = this.fonts[i].monoCase.node;
                w = this.fonts[i].monoCase.w;
                if(node.offsetWidth !== w){
                    loadedCount -= 1;
                    this.fonts[i].loaded = true;
                }else{
                    node = this.fonts[i].sansCase.node;
                    w = this.fonts[i].sansCase.w;
                    if(node.offsetWidth !== w){
                        loadedCount -= 1;
                        this.fonts[i].loaded = true;
                    }
                }
                if(this.fonts[i].loaded){
                    this.fonts[i].sansCase.parent.parentNode.removeChild(this.fonts[i].sansCase.parent);
                    this.fonts[i].monoCase.parent.parentNode.removeChild(this.fonts[i].monoCase.parent);
                }
            }
        }

        if(loadedCount !== 0 && Date.now() - this.initTime < maxWaitingTime){
            setTimeout(this.checkLoadedFontsBinded, 20);
        }else{
            setTimeout(this.setIsLoadedBinded, 10);

        }
    }

    function createHelper(def, fontData){
        var tHelper = createNS('text');
        tHelper.style.fontSize = '100px';
        //tHelper.style.fontFamily = fontData.fFamily;
        tHelper.setAttribute('font-family', fontData.fFamily);
        tHelper.setAttribute('font-style', fontData.fStyle);
        tHelper.setAttribute('font-weight', fontData.fWeight);
        tHelper.textContent = '1';
        if(fontData.fClass){
            tHelper.style.fontFamily = 'inherit';
            tHelper.setAttribute('class', fontData.fClass);
        } else {
            tHelper.style.fontFamily = fontData.fFamily;
        }
        def.appendChild(tHelper);
        var tCanvasHelper = createTag('canvas').getContext('2d');
        tCanvasHelper.font = fontData.fWeight + ' ' + fontData.fStyle + ' 100px '+ fontData.fFamily;
        //tCanvasHelper.font = ' 100px '+ fontData.fFamily;
        return tHelper;
    }

    function addFonts(fontData, defs){
        if(!fontData){
            this.isLoaded = true;
            return;
        }
        if(this.chars){
            this.isLoaded = true;
            this.fonts = fontData.list;
            return;
        }

        var fontArr = fontData.list;
        var i, len = fontArr.length;
        var _pendingFonts = len;
        for(i=0; i<len; i+= 1){
            var shouldLoadFont = true;
            var loadedSelector;
            var j;
            fontArr[i].loaded = false;
            fontArr[i].monoCase = setUpNode(fontArr[i].fFamily,'monospace');
            fontArr[i].sansCase = setUpNode(fontArr[i].fFamily,'sans-serif');
            if(!fontArr[i].fPath) {
                fontArr[i].loaded = true;
                _pendingFonts -= 1;
            }else if(fontArr[i].fOrigin === 'p' || fontArr[i].origin === 3){
                loadedSelector = document.querySelectorAll('style[f-forigin="p"][f-family="'+ fontArr[i].fFamily +'"], style[f-origin="3"][f-family="'+ fontArr[i].fFamily +'"]');

                if (loadedSelector.length > 0) {
                    shouldLoadFont = false;
                }

                if (shouldLoadFont) {
                    var s = createTag('style');
                    s.setAttribute('f-forigin', fontArr[i].fOrigin);
                    s.setAttribute('f-origin', fontArr[i].origin);
                    s.setAttribute('f-family', fontArr[i].fFamily);
                    s.type = "text/css";
                    s.innerHTML = "@font-face {" + "font-family: "+fontArr[i].fFamily+"; font-style: normal; src: url('"+fontArr[i].fPath+"');}";
                    defs.appendChild(s);
                }
            } else if(fontArr[i].fOrigin === 'g' || fontArr[i].origin === 1){
                loadedSelector = document.querySelectorAll('link[f-forigin="g"], link[f-origin="1"]');

                for (j = 0; j < loadedSelector.length; j++) {
                    if (loadedSelector[j].href.indexOf(fontArr[i].fPath) !== -1) {
                        // Font is already loaded
                        shouldLoadFont = false;
                    }
                }

                if (shouldLoadFont) {
                    var l = createTag('link');
                    l.setAttribute('f-forigin', fontArr[i].fOrigin);
                    l.setAttribute('f-origin', fontArr[i].origin);
                    l.type = "text/css";
                    l.rel = "stylesheet";
                    l.href = fontArr[i].fPath;
                    document.body.appendChild(l);
                }
            } else if(fontArr[i].fOrigin === 't' || fontArr[i].origin === 2){
                loadedSelector = document.querySelectorAll('script[f-forigin="t"], script[f-origin="2"]');

                for (j = 0; j < loadedSelector.length; j++) {
                    if (fontArr[i].fPath === loadedSelector[j].src) {
                        // Font is already loaded
                        shouldLoadFont = false;
                    }
                }

                if (shouldLoadFont) {
                    var sc = createTag('link');
                    sc.setAttribute('f-forigin', fontArr[i].fOrigin);
                    sc.setAttribute('f-origin', fontArr[i].origin);
                    sc.setAttribute('rel','stylesheet');
                    sc.setAttribute('href',fontArr[i].fPath);
                    defs.appendChild(sc);
                }
            }
            fontArr[i].helper = createHelper(defs,fontArr[i]);
            fontArr[i].cache = {};
            this.fonts.push(fontArr[i]);
        }
        if (_pendingFonts === 0) {
            this.isLoaded = true;
        } else {
            //On some cases even if the font is loaded, it won't load correctly when measuring text on canvas.
            //Adding this timeout seems to fix it
           setTimeout(this.checkLoadedFonts.bind(this), 100);
        }
    }

    function addChars(chars){
        if(!chars){
            return;
        }
        if(!this.chars){
            this.chars = [];
        }
        var i, len = chars.length;
        var j, jLen = this.chars.length, found;
        for(i=0;i<len;i+=1){
            j = 0;
            found = false;
            while(j<jLen){
                if(this.chars[j].style === chars[i].style && this.chars[j].fFamily === chars[i].fFamily && this.chars[j].ch === chars[i].ch){
                    found = true;
                }
                j += 1;
            }
            if(!found){
                this.chars.push(chars[i]);
                jLen += 1;
            }
        }
    }

    function getCharData(char, style, font){
        var i = 0, len = this.chars.length;
        while( i < len) {
            if(this.chars[i].ch === char && this.chars[i].style === style && this.chars[i].fFamily === font){

                return this.chars[i];
            }
            i+= 1;
        }
        if((typeof char === 'string' && char.charCodeAt(0) !== 13 || !char) && console && console.warn) {
            console.warn('Missing character from exported characters list: ', char, style, font);
        }
        return emptyChar;
    }

    function measureText(char, fontName, size) {
        var fontData = this.getFontByName(fontName);
        var index = char.charCodeAt(0);
        if(!fontData.cache[index + 1]) {
            var tHelper = fontData.helper;
            //Canvas version
            //fontData.cache[index] = tHelper.measureText(char).width / 100;
            //SVG version
            //console.log(tHelper.getBBox().width)
            if (char === ' ') {
                tHelper.textContent = '|' + char + '|';
                var doubleSize = tHelper.getComputedTextLength();
                tHelper.textContent = '||';
                var singleSize = tHelper.getComputedTextLength();
                fontData.cache[index + 1] = (doubleSize - singleSize)/100;
            } else {
                tHelper.textContent = char;
                fontData.cache[index + 1] = (tHelper.getComputedTextLength())/100;
            }
        }
        return fontData.cache[index + 1] * size;
    }

    function getFontByName(name){
        var i = 0, len = this.fonts.length;
        while(i<len){
            if(this.fonts[i].fName === name) {
                return this.fonts[i];
            }
            i += 1;
        }
        return this.fonts[0];
    }

    function getCombinedCharacterCodes() {
        return combinedCharacters;
    }

    function setIsLoaded() {
        this.isLoaded = true
    }

    var Font = function(){
        this.fonts = [];
        this.chars = null;
        this.typekitLoaded = 0;
        this.isLoaded = false;
        this.initTime = Date.now();
        this.setIsLoadedBinded = this.setIsLoaded.bind(this)
        this.checkLoadedFontsBinded = this.checkLoadedFonts.bind(this)
    };
    //TODO: for now I'm adding these methods to the Class and not the prototype. Think of a better way to implement it.
    Font.getCombinedCharacterCodes = getCombinedCharacterCodes;

    var fontPrototype = {
        addChars: addChars,
        addFonts: addFonts,
        getCharData: getCharData,
        getFontByName: getFontByName,
        measureText: measureText,
        checkLoadedFonts: checkLoadedFonts,
        setIsLoaded: setIsLoaded,
    }

    Font.prototype = fontPrototype;

    return Font;

}());<commit_msg>No more .innerHTML in FontManager.js<commit_after>var FontManager = (function(){

    var maxWaitingTime = 5000;
    var emptyChar = {
        w: 0,
        size:0,
        shapes:[]
    };
    var combinedCharacters = [];
    //Hindi characters
    combinedCharacters = combinedCharacters.concat([2304, 2305, 2306, 2307, 2362, 2363, 2364, 2364, 2366
    , 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379
    , 2380, 2381, 2382, 2383, 2387, 2388, 2389, 2390, 2391, 2402, 2403]);

    function trimFontOptions(font) {
        var familyArray = font.split(',');
        var i, len = familyArray.length;
        var enabledFamilies = [];
        for (i = 0; i < len; i += 1) {
            if (familyArray[i] !== 'sans-serif' && familyArray[i] !== 'monospace') {
                enabledFamilies.push(familyArray[i]);
            }
        }
        return enabledFamilies.join(',');
    }

    function setUpNode(font, family){
        var parentNode = createTag('span');
        parentNode.style.fontFamily    = family;
        var node = createTag('span');
        // Characters that vary significantly among different fonts
        node.innerText = 'giItT1WQy@!-/#';
        // Visible - so we can measure it - but not on the screen
        parentNode.style.position      = 'absolute';
        parentNode.style.left          = '-10000px';
        parentNode.style.top           = '-10000px';
        // Large font size makes even subtle changes obvious
        parentNode.style.fontSize      = '300px';
        // Reset any font properties
        parentNode.style.fontVariant   = 'normal';
        parentNode.style.fontStyle     = 'normal';
        parentNode.style.fontWeight    = 'normal';
        parentNode.style.letterSpacing = '0';
        parentNode.appendChild(node);
        document.body.appendChild(parentNode);

        // Remember width with no applied web font
        var width = node.offsetWidth;
        node.style.fontFamily = trimFontOptions(font) + ', ' + family;
        return {node:node, w:width, parent:parentNode};
    }

    function checkLoadedFonts() {
        var i, len = this.fonts.length;
        var node, w;
        var loadedCount = len;
        for(i=0;i<len; i+= 1){
            if(this.fonts[i].loaded){
                loadedCount -= 1;
                continue;
            }
            if(this.fonts[i].fOrigin === 'n' || this.fonts[i].origin === 0){
                this.fonts[i].loaded = true;
            } else{
                node = this.fonts[i].monoCase.node;
                w = this.fonts[i].monoCase.w;
                if(node.offsetWidth !== w){
                    loadedCount -= 1;
                    this.fonts[i].loaded = true;
                }else{
                    node = this.fonts[i].sansCase.node;
                    w = this.fonts[i].sansCase.w;
                    if(node.offsetWidth !== w){
                        loadedCount -= 1;
                        this.fonts[i].loaded = true;
                    }
                }
                if(this.fonts[i].loaded){
                    this.fonts[i].sansCase.parent.parentNode.removeChild(this.fonts[i].sansCase.parent);
                    this.fonts[i].monoCase.parent.parentNode.removeChild(this.fonts[i].monoCase.parent);
                }
            }
        }

        if(loadedCount !== 0 && Date.now() - this.initTime < maxWaitingTime){
            setTimeout(this.checkLoadedFontsBinded, 20);
        }else{
            setTimeout(this.setIsLoadedBinded, 10);

        }
    }

    function createHelper(def, fontData){
        var tHelper = createNS('text');
        tHelper.style.fontSize = '100px';
        //tHelper.style.fontFamily = fontData.fFamily;
        tHelper.setAttribute('font-family', fontData.fFamily);
        tHelper.setAttribute('font-style', fontData.fStyle);
        tHelper.setAttribute('font-weight', fontData.fWeight);
        tHelper.textContent = '1';
        if(fontData.fClass){
            tHelper.style.fontFamily = 'inherit';
            tHelper.setAttribute('class', fontData.fClass);
        } else {
            tHelper.style.fontFamily = fontData.fFamily;
        }
        def.appendChild(tHelper);
        var tCanvasHelper = createTag('canvas').getContext('2d');
        tCanvasHelper.font = fontData.fWeight + ' ' + fontData.fStyle + ' 100px '+ fontData.fFamily;
        //tCanvasHelper.font = ' 100px '+ fontData.fFamily;
        return tHelper;
    }

    function addFonts(fontData, defs){
        if(!fontData){
            this.isLoaded = true;
            return;
        }
        if(this.chars){
            this.isLoaded = true;
            this.fonts = fontData.list;
            return;
        }

        var fontArr = fontData.list;
        var i, len = fontArr.length;
        var _pendingFonts = len;
        for(i=0; i<len; i+= 1){
            var shouldLoadFont = true;
            var loadedSelector;
            var j;
            fontArr[i].loaded = false;
            fontArr[i].monoCase = setUpNode(fontArr[i].fFamily,'monospace');
            fontArr[i].sansCase = setUpNode(fontArr[i].fFamily,'sans-serif');
            if(!fontArr[i].fPath) {
                fontArr[i].loaded = true;
                _pendingFonts -= 1;
            }else if(fontArr[i].fOrigin === 'p' || fontArr[i].origin === 3){
                loadedSelector = document.querySelectorAll('style[f-forigin="p"][f-family="'+ fontArr[i].fFamily +'"], style[f-origin="3"][f-family="'+ fontArr[i].fFamily +'"]');

                if (loadedSelector.length > 0) {
                    shouldLoadFont = false;
                }

                if (shouldLoadFont) {
                    var s = createTag('style');
                    s.setAttribute('f-forigin', fontArr[i].fOrigin);
                    s.setAttribute('f-origin', fontArr[i].origin);
                    s.setAttribute('f-family', fontArr[i].fFamily);
                    s.type = "text/css";
                    s.innerText = "@font-face {" + "font-family: "+fontArr[i].fFamily+"; font-style: normal; src: url('"+fontArr[i].fPath+"');}";
                    defs.appendChild(s);
                }
            } else if(fontArr[i].fOrigin === 'g' || fontArr[i].origin === 1){
                loadedSelector = document.querySelectorAll('link[f-forigin="g"], link[f-origin="1"]');

                for (j = 0; j < loadedSelector.length; j++) {
                    if (loadedSelector[j].href.indexOf(fontArr[i].fPath) !== -1) {
                        // Font is already loaded
                        shouldLoadFont = false;
                    }
                }

                if (shouldLoadFont) {
                    var l = createTag('link');
                    l.setAttribute('f-forigin', fontArr[i].fOrigin);
                    l.setAttribute('f-origin', fontArr[i].origin);
                    l.type = "text/css";
                    l.rel = "stylesheet";
                    l.href = fontArr[i].fPath;
                    document.body.appendChild(l);
                }
            } else if(fontArr[i].fOrigin === 't' || fontArr[i].origin === 2){
                loadedSelector = document.querySelectorAll('script[f-forigin="t"], script[f-origin="2"]');

                for (j = 0; j < loadedSelector.length; j++) {
                    if (fontArr[i].fPath === loadedSelector[j].src) {
                        // Font is already loaded
                        shouldLoadFont = false;
                    }
                }

                if (shouldLoadFont) {
                    var sc = createTag('link');
                    sc.setAttribute('f-forigin', fontArr[i].fOrigin);
                    sc.setAttribute('f-origin', fontArr[i].origin);
                    sc.setAttribute('rel','stylesheet');
                    sc.setAttribute('href',fontArr[i].fPath);
                    defs.appendChild(sc);
                }
            }
            fontArr[i].helper = createHelper(defs,fontArr[i]);
            fontArr[i].cache = {};
            this.fonts.push(fontArr[i]);
        }
        if (_pendingFonts === 0) {
            this.isLoaded = true;
        } else {
            //On some cases even if the font is loaded, it won't load correctly when measuring text on canvas.
            //Adding this timeout seems to fix it
           setTimeout(this.checkLoadedFonts.bind(this), 100);
        }
    }

    function addChars(chars){
        if(!chars){
            return;
        }
        if(!this.chars){
            this.chars = [];
        }
        var i, len = chars.length;
        var j, jLen = this.chars.length, found;
        for(i=0;i<len;i+=1){
            j = 0;
            found = false;
            while(j<jLen){
                if(this.chars[j].style === chars[i].style && this.chars[j].fFamily === chars[i].fFamily && this.chars[j].ch === chars[i].ch){
                    found = true;
                }
                j += 1;
            }
            if(!found){
                this.chars.push(chars[i]);
                jLen += 1;
            }
        }
    }

    function getCharData(char, style, font){
        var i = 0, len = this.chars.length;
        while( i < len) {
            if(this.chars[i].ch === char && this.chars[i].style === style && this.chars[i].fFamily === font){

                return this.chars[i];
            }
            i+= 1;
        }
        if((typeof char === 'string' && char.charCodeAt(0) !== 13 || !char) && console && console.warn) {
            console.warn('Missing character from exported characters list: ', char, style, font);
        }
        return emptyChar;
    }

    function measureText(char, fontName, size) {
        var fontData = this.getFontByName(fontName);
        var index = char.charCodeAt(0);
        if(!fontData.cache[index + 1]) {
            var tHelper = fontData.helper;
            //Canvas version
            //fontData.cache[index] = tHelper.measureText(char).width / 100;
            //SVG version
            //console.log(tHelper.getBBox().width)
            if (char === ' ') {
                tHelper.textContent = '|' + char + '|';
                var doubleSize = tHelper.getComputedTextLength();
                tHelper.textContent = '||';
                var singleSize = tHelper.getComputedTextLength();
                fontData.cache[index + 1] = (doubleSize - singleSize)/100;
            } else {
                tHelper.textContent = char;
                fontData.cache[index + 1] = (tHelper.getComputedTextLength())/100;
            }
        }
        return fontData.cache[index + 1] * size;
    }

    function getFontByName(name){
        var i = 0, len = this.fonts.length;
        while(i<len){
            if(this.fonts[i].fName === name) {
                return this.fonts[i];
            }
            i += 1;
        }
        return this.fonts[0];
    }

    function getCombinedCharacterCodes() {
        return combinedCharacters;
    }

    function setIsLoaded() {
        this.isLoaded = true
    }

    var Font = function(){
        this.fonts = [];
        this.chars = null;
        this.typekitLoaded = 0;
        this.isLoaded = false;
        this.initTime = Date.now();
        this.setIsLoadedBinded = this.setIsLoaded.bind(this)
        this.checkLoadedFontsBinded = this.checkLoadedFonts.bind(this)
    };
    //TODO: for now I'm adding these methods to the Class and not the prototype. Think of a better way to implement it.
    Font.getCombinedCharacterCodes = getCombinedCharacterCodes;

    var fontPrototype = {
        addChars: addChars,
        addFonts: addFonts,
        getCharData: getCharData,
        getFontByName: getFontByName,
        measureText: measureText,
        checkLoadedFonts: checkLoadedFonts,
        setIsLoaded: setIsLoaded,
    }

    Font.prototype = fontPrototype;

    return Font;

}());
<|endoftext|>


<commit_before>/**
 * theme.js
 * Created by anonymous on 03/01/16 2:42.
 */

(function() {
    'use strict';

    angular
        .module('app')
        .config(defaultTheme)
        .config(warn);

    defaultTheme.$inject = ['$mdThemingProvider'];
    warn.$inject     = ['$mdThemingProvider'];

    /* @ngInject */
    function defaultTheme($mdThemingProvider) {
        $mdThemingProvider.theme('default')
            .primaryPalette('grey')
            .accentPalette('pink')
            .warnPalette('red');
    }

    /* @ngInject */
    function warn($mdThemingProvider) {
        $mdThemingProvider.theme('warn');
    }

})();

<commit_msg>Modified ./resources/angular-material/config/theme.js<commit_after>/**
 * theme.js
 * Created by anonymous on 03/01/16 2:42.
 */

(function () {
    'use strict';

    angular
        .module('app')
        .config(defaultTheme)
        .config(warn);

    defaultTheme.$inject = ['$mdThemingProvider'];
    warn.$inject         = ['$mdThemingProvider'];

    /* @ngInject */
    function defaultTheme($mdThemingProvider) {
        $mdThemingProvider.theme('default')
            .primaryPalette('grey')
            .accentPalette('pink')
            .warnPalette('red');
    }

    /* @ngInject */
    function warn($mdThemingProvider) {
        $mdThemingProvider.theme('warn');
    }

})();

<|endoftext|>


<commit_before>gpf.require.define({
    releases: "../../build/releases.json"

}, function (require) {
    "use strict";

    /*global Chartist*/
    /*jshint nonew: false */
    /*eslint-disable no-new, max-nested-callbacks */

    var TWO_DIGITS_NUMBER = 10;

    function zero (value) {
        if (value < TWO_DIGITS_NUMBER) {
            return "0" + value;
        }
        return value;
    }

    function showDate (value) {
        var date = new Date(value);
        return date.getFullYear() + "-" + zero(date.getMonth() + 1);
    }

    var Func = Function;

    function buildGetter (path) {
        return new Func("release", "return release." + path);
    }

    function buildSeries (definitions) {
        return Object.keys(definitions).reduce(function (series, name) {
            var getter = buildGetter(definitions[name]);
            series.push({
                name: name,
                data: require.releases.map(function (release) {
                    return {
                        x: new Date(release.date),
                        y: getter(release)
                    };
                })
            });
            return series;
        }, []);
    }

    return {

        series: function (definitions) {
            new Chartist.Line(".charts", {
                series: buildSeries(definitions)
            }, {
                fullWidth: true,
                chartPadding: {
                    right: 40
                },
                axisX: {
                    type: Chartist.FixedScaleAxis,
                    divisor: 5,
                    labelInterpolationFnc: showDate
                },
                axisY: {
                    onlyInteger: true
                }
            });
        }

    };

});
<commit_msg>no-magic-numbers (#280)<commit_after>gpf.require.define({
    releases: "../../build/releases.json"

}, function (require) {
    "use strict";

    /*global Chartist*/
    /*jshint nonew: false */
    /*eslint-disable no-new, max-nested-callbacks */

    var TWO_DIGITS_NUMBER = 10;

    function showDate (value) {
        var date = new Date(value);
        return (/\d\d\d\d-\d\d/).exec(date.toISOString()).toString();
    }

    var Func = Function;

    function buildGetter (path) {
        return new Func("release", "return release." + path);
    }

    function buildSeries (definitions) {
        return Object.keys(definitions).reduce(function (series, name) {
            var getter = buildGetter(definitions[name]);
            series.push({
                name: name,
                data: require.releases.map(function (release) {
                    return {
                        x: new Date(release.date),
                        y: getter(release)
                    };
                })
            });
            return series;
        }, []);
    }

    return {

        series: function (definitions) {
            new Chartist.Line(".charts", {
                series: buildSeries(definitions)
            }, {
                fullWidth: true,
                chartPadding: {
                    right: 40
                },
                axisX: {
                    type: Chartist.FixedScaleAxis,
                    divisor: 5,
                    labelInterpolationFnc: showDate
                },
                axisY: {
                    onlyInteger: true
                }
            });
        }

    };

});
<|endoftext|>


<commit_before>var _ = require('lodash');
var crossfilter = require('crossfilter');
var d3 = window.d3;
var EventEmitter = require('events').EventEmitter;

var moment = require('moment-timezone');

var MS_IN_24 = 86400000;

d3.chart('Brush', {
  initialize: function() {
    var chart = this;

    this.width = this.base.attr('width');
    this.height = this.base.attr('height');

    this.base.append('g').attr('id', 'brushMainGroup');

    var xPosition = function(d) {
      return chart.xScale()(d);
    };

    this.layer('brushTicks', this.base.append('g').attr('id', 'brushTicks'), {
      dataBind: function() {
        return this.selectAll('line')
          .data(chart.ticks);
      },
      insert: function() {
        return this.append('line');
      },
      events: {
        enter: function() {
          var xScale = chart.xScale();
          var margins = chart.margins().main;
          var tickLength = chart.tickLength();
          this.attr({
            x1: xPosition,
            x2: xPosition,
            y1: margins.top,
            y2: margins.top + tickLength
          });
        }
      }
    });

    this.layer('brushAxisText', this.base.append('g').attr('id', 'brushAxisText'), {
      dataBind: function() {
        return this.selectAll('text')
          .data(chart.textTicks || chart.ticks);
      },
      insert: function() {
        return this.append('text');
      },
      events: {
        enter: function() {
          var xScale = chart.xScale(), tz = chart.timezone();
          var tickShift = chart.tickShift();
          if (chart.brushTickInterval() !== 'month') {
            tickShift.x = 0;
          }
          this.attr({
            x: function(d) {
              return xPosition(d) + tickShift.x;
            },
            y: tickShift.y
          })
          .classed('centered', chart.brushTickInterval() !== 'month')
          .text(function(d) {
            var format = chart.brushTickInterval() === 'month' ? 'MMM': 'MMM D';
            return moment.utc(d).tz(tz).format(format);
          });
        }
      }
    });
  },
  brushTickInterval: function(brushTickInterval) {
    if (!arguments.length) { return this._brushTickInterval; }
    this._brushTickInterval = brushTickInterval;
    return this;
  },
  cornerRadius: function(cornerRadius) {
    if (!arguments.length) { return this._cornerRadius; }
    this._cornerRadius = cornerRadius;
    return this;
  },
  emitter: function(emitter) {
    if (!arguments.length) { return this._emitter; }
    this._emitter = emitter;
    return this;
  },
  initialExtent: function(initialExtent) {
    if (!arguments.length) { return this._initialExtent; }
    this._initialExtent = initialExtent;
    return this;
  },
  margins: function(margins) {
    if (!arguments.length) { return this._margins; }
    this._margins = margins;
    return this;
  },
  tickLength: function(tickLength) {
    if (!arguments.length) { return this._tickLength; }
    this._tickLength = tickLength;
    return this;
  },
  tickShift: function(tickShift) {
    if (!arguments.length) { return this._tickShift; }
    this._tickShift = tickShift;
    return this;
  },
  timezone: function(timezone) {
    if (!arguments.length) { return this._timezone; }
    this._timezone = timezone;
    return this;
  },
  setExtent: function(newExtent) {
    var xScale = this.xScale(), timezone = this.timezone();
    var scaleDomain = xScale.domain();
    if (newExtent[0] < scaleDomain[0]) {
      var extentSize = (newExtent[1] - newExtent[0])/MS_IN_24;
      var s = moment.utc(scaleDomain[0]).tz(timezone).startOf('day');
      newExtent = [s, d3.time.day.utc.offset(s, extentSize)];
    }
    this.brushHandleGroup.call(this.brush.extent(newExtent));
    this.fixBrushHandlers(this.brushHandleGroup);
    return this;
  },
  xScale: function(xScale) {
    if (!arguments.length) { return this._xScale; }
    var w = this.width;
    var mainMargins = this.margins().main;
    this._xScale = xScale.range([
      mainMargins.left,
      w - mainMargins.right
    ]);
    var domain = xScale.domain();
    var domainDays = (domain[1] - domain[0])/MS_IN_24;
    var smallDaysLimit = 40, mediumDaysLimit = 90;
    this._brushTickInterval = domainDays < mediumDaysLimit ? 'week' : 'month';
    // we suggest 4 ticks, but d3 makes the final determination about how many to generate
    // and that final number could be higher or lower
    var ticks = xScale.ticks(4);
    this.ticks = ticks;
    // don't want tick labels to appear too close to edge
    // so only show if > two weeks from start of floor of end-of-domain month
    var lastTick = ticks[ticks.length - 1];
    if (this._brushTickInterval === 'month' && (domain[1] - lastTick) / MS_IN_24 < 14) {
      this.textTicks = ticks.slice();
      this.textTicks.pop();
    }
    this.makeBrush();
    return this;
  },
  makeBrush: function() {
    var chart = this, emitter = this.emitter();
    function brushed() {

      var origExtent = chart.brush.extent(), newExtent;
      var timezone = chart.timezone();
      // preserve width of handle on drag
      if (d3.event.mode === 'move') {
        var s = moment.utc(origExtent[0]).tz(timezone).startOf('day');
        var e = moment(s).add(Math.round((origExtent[1] - origExtent[0])/MS_IN_24), 'days');
        newExtent = [s, e];
      }
      // on resize, round to midnights
      else {
        newExtent = origExtent.map(d3.time.day.utc.round);

        // if empty when rounded, use floor & ceil instead
        // i.e., enforce min of 1 day
        if (newExtent[0] >= newExtent[1]) {
          newExtent[0] = moment.utc(origExtent[0]).tz(timezone).startOf('day');
          newExtent[1] = moment.utc(origExtent[1]).tz(timezone).startOf('day');
        }
      }
      emitter.emit('brushed', [newExtent[0].toISOString(), newExtent[1].toISOString()]);
      d3.select(this).call(chart.brush.extent(newExtent));
      chart.fixBrushHandlers(d3.select(this));
    }

    var xScale = this.xScale();
    var initial = chart.initialExtent();

    var extentDates = [Date.parse(initial[0]), Date.parse(initial[1])];

    this.brush = d3.svg.brush()
      .x(xScale)
      .extent(extentDates)
      .on('brush', brushed);

    this.brushHandleGroup = this.base.append('g')
      .attr('id', 'brushHandleGroup')
      .call(this.brush);

    this.fixBrushHandlers(this.brushHandleGroup);

    var mainMargins = this.margins().main;

    var cornerRadius = this.cornerRadius();

    this.brushHandleGroup.select('rect.background')
      .attr({
        height: this.height - mainMargins.top - mainMargins.bottom,
        transform: 'translate(0,' + mainMargins.top + ')',
        rx: cornerRadius,
        ry: cornerRadius
      })
      .style('visibility', 'visible');

    this.brushHandleGroup.select('rect.extent')
      .attr({
        height: this.height - mainMargins.top - mainMargins.bottom,
        transform: 'translate(0,' + mainMargins.top + ')',
        rx: cornerRadius,
        ry: cornerRadius
      });
  },
  fixBrushHandlers: function(brushNode) {
    var oldMousedown = brushNode.on('mousedown.brush');
    brushNode.on('mousedown.brush', function() {
      brushNode.on('mouseup.brush', function() {
        clearHandlers();
      });

      brushNode.on('mousemove.brush', function() {
        clearHandlers();
        oldMousedown.call(this);
      });

      function clearHandlers() {
        brushNode.on('mousemove.brush', null);
        brushNode.on('mouseup.brush', null);
      }
    });
  },
  remove: function() {
    this.base.remove();
    return this;
  }
});

var chart;

module.exports = {
  create: function(el, dateDomain, opts) {
    opts = opts || {};
    var defaults = {
      baseMargin: opts.baseMargin || 10,
      brushHeight: el.offsetHeight,
      cornerRadius: 10,
      initialExtent: [d3.time.day.utc.offset(new Date(dateDomain[1]), -14), new Date(dateDomain[1])],
      tickLength: 10,
      tickShift: {x: 5, y: 3}
    };
    defaults.margins = {
      main: {
        top: defaults.baseMargin + 11,
        right: defaults.baseMargin + 30,
        bottom: defaults.baseMargin - 5,
        left: defaults.baseMargin + 30
      }
    };
    _.defaults(opts, defaults);

    var xScale = d3.time.scale.utc()
      .domain([
        moment.utc(dateDomain[0]).tz(opts.timezone).startOf('day'),
        moment.utc(dateDomain[1]).tz(opts.timezone).startOf('day').add(1, 'days')
      ]);

    chart = d3.select(el)
      .append('svg')
      .attr({
        width: el.offsetWidth,
        height: opts.brushHeight
      })
      .chart('Brush')
      .cornerRadius(opts.cornerRadius)
      .emitter(this.emitter)
      .initialExtent(opts.initialExtent)
      .margins(opts.margins)
      .tickLength(opts.tickLength)
      .tickShift(opts.tickShift)
      .timezone(opts.timezone)
      .xScale(xScale);

    return this;
  },
  getCurrentDay: function() {
    return new Date(chart.brush.extent()[1].valueOf() - MS_IN_24/2);
  },
  emitter: new EventEmitter(),
  render: function(data, opts) {
    opts = opts || {};
    var defaults = {};
    _.defaults(opts, defaults);

    chart.draw();

    return this;
  },
  setExtent: function(newExtent) {
    chart.setExtent(newExtent);
  },
  destroy: function() {
    this.emitter.removeAllListeners();
    chart.remove();

    return this;
  }
};<commit_msg>fix stringification of trends scrollbar tick date labels<commit_after>var _ = require('lodash');
var crossfilter = require('crossfilter');
var d3 = window.d3;
var EventEmitter = require('events').EventEmitter;

var moment = require('moment-timezone');

var MS_IN_24 = 86400000;

d3.chart('Brush', {
  initialize: function() {
    var chart = this;

    this.width = this.base.attr('width');
    this.height = this.base.attr('height');

    this.base.append('g').attr('id', 'brushMainGroup');

    var xPosition = function(d) {
      var zone = moment.tz.zone(chart.timezone());
      return chart.xScale()(moment.utc(d).add('minutes', zone.parse(d.valueOf())).toDate());
    };

    this.layer('brushTicks', this.base.append('g').attr('id', 'brushTicks'), {
      dataBind: function() {
        return this.selectAll('line')
          .data(chart.ticks);
      },
      insert: function() {
        return this.append('line');
      },
      events: {
        enter: function() {
          var xScale = chart.xScale();
          var margins = chart.margins().main;
          var tickLength = chart.tickLength();
          this.attr({
            x1: xPosition,
            x2: xPosition,
            y1: margins.top,
            y2: margins.top + tickLength
          });
        }
      }
    });

    this.layer('brushAxisText', this.base.append('g').attr('id', 'brushAxisText'), {
      dataBind: function() {
        return this.selectAll('text')
          .data(chart.textTicks || chart.ticks);
      },
      insert: function() {
        return this.append('text');
      },
      events: {
        enter: function() {
          var xScale = chart.xScale(), tz = chart.timezone();
          var tickShift = chart.tickShift();
          if (chart.brushTickInterval() !== 'month') {
            tickShift.x = 0;
          }
          this.attr({
            x: function(d) {
              return xPosition(d) + tickShift.x;
            },
            y: tickShift.y
          })
          .classed('centered', chart.brushTickInterval() !== 'month')
          .text(function(d) {
            var format = chart.brushTickInterval() === 'month' ? 'MMM': 'MMM D';
            return moment.utc(d).format(format);
          });
        }
      }
    });
  },
  brushTickInterval: function(brushTickInterval) {
    if (!arguments.length) { return this._brushTickInterval; }
    this._brushTickInterval = brushTickInterval;
    return this;
  },
  cornerRadius: function(cornerRadius) {
    if (!arguments.length) { return this._cornerRadius; }
    this._cornerRadius = cornerRadius;
    return this;
  },
  emitter: function(emitter) {
    if (!arguments.length) { return this._emitter; }
    this._emitter = emitter;
    return this;
  },
  initialExtent: function(initialExtent) {
    if (!arguments.length) { return this._initialExtent; }
    this._initialExtent = initialExtent;
    return this;
  },
  margins: function(margins) {
    if (!arguments.length) { return this._margins; }
    this._margins = margins;
    return this;
  },
  tickLength: function(tickLength) {
    if (!arguments.length) { return this._tickLength; }
    this._tickLength = tickLength;
    return this;
  },
  tickShift: function(tickShift) {
    if (!arguments.length) { return this._tickShift; }
    this._tickShift = tickShift;
    return this;
  },
  timezone: function(timezone) {
    if (!arguments.length) { return this._timezone; }
    this._timezone = timezone;
    return this;
  },
  setExtent: function(newExtent) {
    var xScale = this.xScale(), timezone = this.timezone();
    var scaleDomain = xScale.domain();
    if (newExtent[0] < scaleDomain[0]) {
      var extentSize = (newExtent[1] - newExtent[0])/MS_IN_24;
      var s = moment.utc(scaleDomain[0]).tz(timezone).startOf('day');
      newExtent = [s, d3.time.day.utc.offset(s, extentSize)];
    }
    this.brushHandleGroup.call(this.brush.extent(newExtent));
    this.fixBrushHandlers(this.brushHandleGroup);
    return this;
  },
  xScale: function(xScale) {
    if (!arguments.length) { return this._xScale; }
    var w = this.width;
    var mainMargins = this.margins().main;
    this._xScale = xScale.range([
      mainMargins.left,
      w - mainMargins.right
    ]);
    var domain = xScale.domain();
    var domainDays = (domain[1] - domain[0])/MS_IN_24;
    var smallDaysLimit = 40, mediumDaysLimit = 90;
    this._brushTickInterval = domainDays < mediumDaysLimit ? 'week' : 'month';
    // we suggest 4 ticks, but d3 makes the final determination about how many to generate
    // and that final number could be higher or lower
    var ticks = xScale.ticks(4);
    this.ticks = ticks;
    // don't want tick labels to appear too close to edge
    // so only show if > two weeks from start of floor of end-of-domain month
    var lastTick = ticks[ticks.length - 1];
    if (this._brushTickInterval === 'month' && (domain[1] - lastTick) / MS_IN_24 < 14) {
      this.textTicks = ticks.slice();
      this.textTicks.pop();
    }
    this.makeBrush();
    return this;
  },
  makeBrush: function() {
    var chart = this, emitter = this.emitter();
    function brushed() {

      var origExtent = chart.brush.extent(), newExtent;
      var timezone = chart.timezone();
      // preserve width of handle on drag
      if (d3.event.mode === 'move') {
        var s = moment.utc(origExtent[0]).tz(timezone).startOf('day');
        var e = moment(s).add(Math.round((origExtent[1] - origExtent[0])/MS_IN_24), 'days');
        newExtent = [s, e];
      }
      // on resize, round to midnights
      else {
        newExtent = origExtent.map(d3.time.day.utc.round);

        // if empty when rounded, use floor & ceil instead
        // i.e., enforce min of 1 day
        if (newExtent[0] >= newExtent[1]) {
          newExtent[0] = moment.utc(origExtent[0]).tz(timezone).startOf('day');
          newExtent[1] = moment.utc(origExtent[1]).tz(timezone).startOf('day');
        }
      }
      emitter.emit('brushed', [newExtent[0].toISOString(), newExtent[1].toISOString()]);
      d3.select(this).call(chart.brush.extent(newExtent));
      chart.fixBrushHandlers(d3.select(this));
    }

    var xScale = this.xScale();
    var initial = chart.initialExtent();

    var extentDates = [Date.parse(initial[0]), Date.parse(initial[1])];

    this.brush = d3.svg.brush()
      .x(xScale)
      .extent(extentDates)
      .on('brush', brushed);

    this.brushHandleGroup = this.base.append('g')
      .attr('id', 'brushHandleGroup')
      .call(this.brush);

    this.fixBrushHandlers(this.brushHandleGroup);

    var mainMargins = this.margins().main;

    var cornerRadius = this.cornerRadius();

    this.brushHandleGroup.select('rect.background')
      .attr({
        height: this.height - mainMargins.top - mainMargins.bottom,
        transform: 'translate(0,' + mainMargins.top + ')',
        rx: cornerRadius,
        ry: cornerRadius
      })
      .style('visibility', 'visible');

    this.brushHandleGroup.select('rect.extent')
      .attr({
        height: this.height - mainMargins.top - mainMargins.bottom,
        transform: 'translate(0,' + mainMargins.top + ')',
        rx: cornerRadius,
        ry: cornerRadius
      });
  },
  fixBrushHandlers: function(brushNode) {
    var oldMousedown = brushNode.on('mousedown.brush');
    brushNode.on('mousedown.brush', function() {
      brushNode.on('mouseup.brush', function() {
        clearHandlers();
      });

      brushNode.on('mousemove.brush', function() {
        clearHandlers();
        oldMousedown.call(this);
      });

      function clearHandlers() {
        brushNode.on('mousemove.brush', null);
        brushNode.on('mouseup.brush', null);
      }
    });
  },
  remove: function() {
    this.base.remove();
    return this;
  }
});

var chart;

module.exports = {
  create: function(el, dateDomain, opts) {
    opts = opts || {};
    var defaults = {
      baseMargin: opts.baseMargin || 10,
      brushHeight: el.offsetHeight,
      cornerRadius: 10,
      initialExtent: [d3.time.day.utc.offset(new Date(dateDomain[1]), -14), new Date(dateDomain[1])],
      tickLength: 10,
      tickShift: {x: 5, y: 3}
    };
    defaults.margins = {
      main: {
        top: defaults.baseMargin + 11,
        right: defaults.baseMargin + 30,
        bottom: defaults.baseMargin - 5,
        left: defaults.baseMargin + 30
      }
    };
    _.defaults(opts, defaults);

    var xScale = d3.time.scale.utc()
      .domain([
        moment.utc(dateDomain[0]).tz(opts.timezone).startOf('day'),
        moment.utc(dateDomain[1]).tz(opts.timezone).startOf('day').add(1, 'days')
      ]);

    chart = d3.select(el)
      .append('svg')
      .attr({
        width: el.offsetWidth,
        height: opts.brushHeight
      })
      .chart('Brush')
      .cornerRadius(opts.cornerRadius)
      .emitter(this.emitter)
      .initialExtent(opts.initialExtent)
      .margins(opts.margins)
      .tickLength(opts.tickLength)
      .tickShift(opts.tickShift)
      .timezone(opts.timezone)
      .xScale(xScale);

    return this;
  },
  getCurrentDay: function() {
    return new Date(chart.brush.extent()[1].valueOf() - MS_IN_24/2);
  },
  emitter: new EventEmitter(),
  render: function(data, opts) {
    opts = opts || {};
    var defaults = {};
    _.defaults(opts, defaults);

    chart.draw();

    return this;
  },
  setExtent: function(newExtent) {
    chart.setExtent(newExtent);
  },
  destroy: function() {
    this.emitter.removeAllListeners();
    chart.remove();

    return this;
  }
};<|endoftext|>


<commit_before>'use strict';

var savedLinesReader = require('../saved-lines-reader');
var React = require('react');
var Display = require('./Display');
require('buffer');

var Track = require('../track').Track;
var OldTrack = require('../track').OldTrack;

var DEBUG = false;

var defaultLines = [
  {
    x1: 15,
    y1: 180,
    x2: 190,
    y2: 190,
    extended: 0,
    flipped: false,
    leftLine: null,
    rightLine: null,
    id: 0,
    type: 0
  }
];
var App = React.createClass({

  getInitialState() {
    return {
      tracks: [],
      track: new Track(defaultLines, {x: 0, y: 0}, DEBUG),
      selected: '',
      timer: false,
      frame: 0,
      grid: false,
      slowmo: false,
      floor: false,
      accArrow: false,
      snapDot: false,
      color: false
    };
  },

  onSelectTrack(e) {
    let trackData = this.state.tracks[e.target.value];
    let startPos = trackData.startPosition;
    let version = trackData.version;
    let VersionedTrack = Track;
    if (version === '6.1') {
      VersionedTrack = OldTrack;
    }
    let track = new VersionedTrack(trackData.lines, { x: startPos[0], y: startPos[1] }, DEBUG);
    console.log(track)
    track.label = trackData.label;
    this.setState({
      track: track,
      selected: e.target.value
    });
    this.stopPlayback();
  },

  onTogglePlayback() {
    if (!this.state.timer) {
      var step = () => {
        let timer = setTimeout(step, 1000 / this.getFPS());
        this.setState({ frame: this.state.frame + 1, timer: timer });
      };

      step();

    } else {
      this.stopPlayback();
    }
  },

  stopPlayback() {
    clearTimeout(this.state.timer);
    this.setState({ frame: 0, timer: null });
  },

  onPause() {
    clearTimeout(this.state.timer);
    this.setState({ timer: null });
  },

  onToggle(key) {
    return () => {
      let nextState = {};
      nextState[key] = !this.state[key];
      this.setState(nextState);
    };
  },

  onFileInput(e) {
    var reader = new FileReader();
    var file = e.target.files[0];
    if (!file) {
      return;
    }

    reader.onload = (upload) => {
      try {
        this.setState({
          tracks: savedLinesReader(new Buffer(new Uint8Array(upload.target.result))),
          track: null,
          selected: ''
        });
        this.stopPlayback();
      } catch (e) {
        alert(`There is something wrong with this .sol!\n${e}`);
      }
    };

    reader.readAsArrayBuffer(file);
  },

  getRider() {
    return this.state.track.getRiderAtFrame(this.state.frame);
  },

  getFPS() {
    let fps = 40;
    return this.state.slowmo ? fps / 8 : fps;
  },

  renderToggle(key) {
    if (this.state[key] === undefined) {
      throw new Error('Key does not exist in state, cannot toggle: ', key);
    }
    return (

        {key}: <input type="checkbox" checked={this.state[key]} onChange={this.onToggle(key)} />

    );
  },

  render() {
    return (

Input a .sol file to view your tracks.

<input type="file" onChange={this.onFileInput} />

          {
            this.state.tracks.length > 0 ?
              <select value={this.state.selected} onChange={this.onSelectTrack}>
                <option key="-1" value="" disabled>Select a track to render...</option>
                {
                  this.state.tracks.map((track, i) =>
                    <option key={i} value={i}>{track.label}</option>
                  )
                }
              </select>
              : null
          }

        { ['grid', 'color'].map(this.renderToggle) }
        {
          this.state.color ?
            ['floor', 'accArrow', 'snapDot'].map(this.renderToggle)
          : null
        }
        {
          this.state.track ?

              { this.renderToggle('slowmo') }
              <button onClick={() => {console.log(this.state.track.lines)}}>Print lines</button>
              <button onClick={this.onTogglePlayback}>{ this.state.timer ? 'Stop' : 'Play'}</button>
              <button onClick={this.onPause}>Pause</button>
              <button onClick={() => this.setState({ frame: this.state.frame + 1 })}>Step forward</button>
              <button onClick={() => this.setState({ frame: Math.max(0, this.state.frame - 1) })}>Step backward</button>

            : null
        }
        {
          this.state.track ?
            <Display {...this.state} rider={this.getRider()} />
            : null
        }

    );
  }

});

module.exports = App;
<commit_msg>add track name and version labels<commit_after>'use strict';

var savedLinesReader = require('../saved-lines-reader');
var React = require('react');
var Display = require('./Display');
require('buffer');

var Track = require('../track').Track;
var OldTrack = require('../track').OldTrack;

var DEBUG = false;

var defaultLines = [
  {
    x1: 15,
    y1: 180,
    x2: 190,
    y2: 190,
    extended: 0,
    flipped: false,
    leftLine: null,
    rightLine: null,
    id: 0,
    type: 0
  }
];
var App = React.createClass({

  getInitialState() {
    return {
      tracks: [],
      track: new Track(defaultLines, {x: 0, y: 0}, DEBUG),
      selected: '',
      timer: false,
      frame: 0,
      grid: false,
      slowmo: false,
      floor: false,
      accArrow: false,
      snapDot: false,
      color: false
    };
  },

  onSelectTrack(e) {
    let trackData = this.state.tracks[e.target.value];
    let startPos = trackData.startPosition;
    let version = trackData.version;
    let VersionedTrack = Track;
    if (version === '6.1') {
      VersionedTrack = OldTrack;
    }
    let track = new VersionedTrack(trackData.lines, { x: startPos[0], y: startPos[1] }, DEBUG);
    console.log(track)
    track.label = trackData.label;
    this.setState({
      track: track,
      selected: e.target.value
    });
    this.stopPlayback();
  },

  onTogglePlayback() {
    if (!this.state.timer) {
      var step = () => {
        let timer = setTimeout(step, 1000 / this.getFPS());
        this.setState({ frame: this.state.frame + 1, timer: timer });
      };

      step();

    } else {
      this.stopPlayback();
    }
  },

  stopPlayback() {
    clearTimeout(this.state.timer);
    this.setState({ frame: 0, timer: null });
  },

  onPause() {
    clearTimeout(this.state.timer);
    this.setState({ timer: null });
  },

  onToggle(key) {
    return () => {
      let nextState = {};
      nextState[key] = !this.state[key];
      this.setState(nextState);
    };
  },

  onFileInput(e) {
    var reader = new FileReader();
    var file = e.target.files[0];
    if (!file) {
      return;
    }

    reader.onload = (upload) => {
      try {
        this.setState({
          tracks: savedLinesReader(new Buffer(new Uint8Array(upload.target.result))),
          track: null,
          selected: ''
        });
        this.stopPlayback();
      } catch (e) {
        alert(`There is something wrong with this .sol!\n${e}`);
      }
    };

    reader.readAsArrayBuffer(file);
  },

  getRider() {
    return this.state.track.getRiderAtFrame(this.state.frame);
  },

  getFPS() {
    let fps = 40;
    return this.state.slowmo ? fps / 8 : fps;
  },

  renderToggle(key) {
    if (this.state[key] === undefined) {
      throw new Error('Key does not exist in state, cannot toggle: ', key);
    }
    return (

        {key}: <input type="checkbox" checked={this.state[key]} onChange={this.onToggle(key)} />

    );
  },

  render() {
    return (

Input a .sol file to view your tracks.

<input type="file" onChange={this.onFileInput} />

          {
            this.state.tracks.length > 0 ?
              <select value={this.state.selected} onChange={this.onSelectTrack}>
                <option key="-1" value="" disabled>Select a track to render...</option>
                {
                  this.state.tracks.map((track, i) =>
                    <option key={i} value={i}>{track.label}</option>
                  )
                }
              </select>
              : null
          }

        {
          this.state.track ?

            Track name: { this.state.tracks[this.state.selected].label }

            Version: { this.state.tracks[this.state.selected].version }

          : null
        }
        { ['grid', 'color'].map(this.renderToggle) }
        {
          this.state.color ?
            ['floor', 'accArrow', 'snapDot'].map(this.renderToggle)
          : null
        }
        {
          this.state.track ?

              { this.renderToggle('slowmo') }
              <button onClick={() => {console.log(this.state.track.lines)}}>Print lines</button>
              <button onClick={this.onTogglePlayback}>{ this.state.timer ? 'Stop' : 'Play'}</button>
              <button onClick={this.onPause}>Pause</button>
              <button onClick={() => this.setState({ frame: this.state.frame + 1 })}>Step forward</button>
              <button onClick={() => this.setState({ frame: Math.max(0, this.state.frame - 1) })}>Step backward</button>

            : null
        }
        {
          this.state.track ?
            <Display {...this.state} rider={this.getRider()} />
            : null
        }

    );
  }

});

module.exports = App;
<|endoftext|>


<commit_before>'use strict';

var React = require('react');
var Buffer = require('buffer');

var App = React.createClass({

  render() {
    return (

yo.

    );
  }

});

module.exports = App;
<commit_msg>implement reading .sols and displaying their data<commit_after>'use strict';

var savedLinesReader = require('../saved-lines-reader');
var React = require('react');
require('buffer');

var App = React.createClass({

  getInitialState() {
    return {
      tracks: [],
      track: null
    };
  },

  onSelect(e) {
    this.setState({
      track: this.state.tracks[e.target.value]
    })
  },

  handleFile(e) {
    var reader = new FileReader();
    var file = e.target.files[0];

    reader.onload = (upload) => {
      this.setState({
        tracks: savedLinesReader(new Buffer(new Uint8Array(upload.target.result))),
      });
    }

    reader.readAsArrayBuffer(file);
  },

  render() {
    return (

        Input a .sol file to view your tracks.
        <input type="file" onChange={this.handleFile} />
        {
          this.state.tracks.length > 0 ?
            <select defaultValue="" onChange={this.onSelect}>
              <option key="-1" value="" disabled>Select a track to render...</option>
              {
                this.state.tracks.map((track, i) =>
                  <option key={i} value={i}>{track.label}</option>
                )
              }
            </select>
            : null
        }
        {
          this.state.track ?

              { JSON.stringify(this.state.track) }

            : null
        }

    );
  }

});

module.exports = App;
<|endoftext|>


<commit_before>//jest.dontMock('../japan_income_tax');
jest.autoMockOff();

let { japan_income_tax } = require('../japan_income_tax.js');

describe('income tax', () => {

  it('should calculate tax', () => {
    let data = {
      income: 5000000,
      spouse: false,
      children16: 0,
      children19: 0
    };
    let tax = japan_income_tax(data);

    expect(tax).toEqual(214900);
  });

  it('should calculate tax with deduction', () => {
    let data = {
      income: 5000000,
      spouse: true,
      children16: 0,
      children19: 0
    };
    let tax = japan_income_tax(data);

    expect(tax).toEqual(176100);
  });

});

describe ('floor1000', () => {
  let { floor1000 } = require('../japan_income_tax.js');

  it('should calculate', () => {

    expect(floor1000(1)).toEqual(0);
    expect(floor1000(999)).toEqual(0);
    expect(floor1000(1000)).toEqual(1000);
    expect(floor1000(1001)).toEqual(1000);
    expect(floor1000(1999)).toEqual(1000);
    expect(floor1000(2001)).toEqual(2000);
  });

});
<commit_msg>テスト追加：住民税、ふるさと納税上限<commit_after>//jest.dontMock('../japan_income_tax');
jest.autoMockOff();

describe('income tax', () => {
  let { japan_income_tax } = require('../japan_income_tax.js');

  it('should calculate tax', () => {
    let data = {
      income: 5000000,
      spouse: false,
      children16: 0,
      children19: 0
    };
    let tax = japan_income_tax(data);

    expect(tax).toEqual(214900);
  });

  it('should calculate tax with deduction', () => {
    let data = {
      income: 5000000,
      spouse: true,
      children16: 0,
      children19: 0
    };
    let tax = japan_income_tax(data);

    expect(tax).toEqual(176100);
  });

});

describe('resident tax', () => {
  let { japan_resident_tax } = require('../japan_income_tax.js');

  it('should calculate tax', () => {
    let data = {
      income: 5000000,
      spouse: false,
      children16: 0,
      children19: 0
    };
    let tax = japan_resident_tax(data);

    expect(tax).toEqual(315500);
  });

  it('should calculate tax with deduction', () => {
    let data = {
      income: 5000000,
      spouse: true,
      children16: 0,
      children19: 0
    };
    let tax = japan_resident_tax(data);

    expect(tax).toEqual(282500);
  });

});

describe('furusato max', () => {
  let { furusato_tax_max } = require('../japan_income_tax.js');

  it('should calculate', () => {
    let data = {
      income: 5000000,
      spouse: false,
      children16: 0,
      children19: 0
    };
    let max = furusato_tax_max(data);

    expect(max).toEqual(80800);
  });

  it('should calculate it with deduction', () => {
    let data = {
      income: 5000000,
      spouse: true,
      children16: 0,
      children19: 0
    };
    let max = furusato_tax_max(data);

    expect(max).toEqual(72600);
  });

});

describe ('floor1000', () => {
  let { floor1000 } = require('../japan_income_tax.js');

  it('should calculate', () => {

    expect(floor1000(1)).toEqual(0);
    expect(floor1000(999)).toEqual(0);
    expect(floor1000(1000)).toEqual(1000);
    expect(floor1000(1001)).toEqual(1000);
    expect(floor1000(1999)).toEqual(1000);
    expect(floor1000(2001)).toEqual(2000);
  });

});

describe ('floor100', () => {
  let { floor100 } = require('../japan_income_tax.js');

  it('should calculate', () => {

    expect(floor100(1)).toEqual(0);
    expect(floor100(99)).toEqual(0);
    expect(floor100(100)).toEqual(100);
    expect(floor100(101)).toEqual(100);
    expect(floor100(199)).toEqual(100);
    expect(floor100(201)).toEqual(200);
  });

});
<|endoftext|>


<commit_before>/*
    A small plugin to help Foxy help his friends like Echidnabot
*/

let core = undefined;
let exec = require('child_process').execFile;

let CODEHAUS_Server = "215661302692052992";
const echidnasDir = "/home/vitaly/_Bots/echidnabot";
const minnieDir = "/home/vitaly/_Bots/minnie-marygold";

function isGranted(message)
{
    return (core.botConfig.myboss.indexOf(message.author.id) !== -1) || (message.author.id === "133426635998232577");
}

function knuxLog(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    if(!isGranted(message))
    {
        message.reply("Sorry, I can't help you, you are not allowed to use this command");
        return;
    }

    let linesNumber = (args === "" ? 25 : Number(args));

    exec('tail', ["-n", linesNumber.toString(), "knuxlog.log"], {cwd: echidnasDir}, function(err, data)
    {
        if(!err)
        {
            let s = data.toString();
            if(s.length > 1900)
                s = s.substr(s.length - 1900);
            message.reply("tail -n " + linesNumber + " knuxlog.log\n```\n" + s + "\n```\n");
        }
        else
        {
            message.reply("ERROR of tail -n 25 knuxlog.log```\n" + err + "\n\n" + data.toString() + "\n```\n");
        }
    });
}

function knuxFullLog(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    if(!isGranted(message))
    {
        message.reply("Sorry, I can't help you, you are not allowed to use this command");
        return;
    }

    exec('bzip2', ["-fk", echidnasDir + "/knuxlog.log"], {cwd: echidnasDir}, function(err, data)
    {
        if(!err)
            message.channel.sendFile(echidnasDir + "/knuxlog.log.bz2", "knuxlog.log.bz2").catch(core.msgSendError);
        else
            message.reply("ERROR of bzip2 -fk " + echidnasDir + "/knuxlog.log\n```\n" + err + "\n\n" + data.toString() + "\n```\n");
    });

}

function pokeBot(bot, message, botPath)
{
    if(!isGranted(message))
    {
        message.reply("Sorry, I can't help you, you are not allowed to use this command");
        return;
    }

    exec('git', ["pull", "origin", "master"], {cwd: botPath}, function(err, data)
    {
        if(!err)
            message.reply("git pull origin master\n```\n" + data.toString() + "\n```\n");
        else
        {
            message.reply("ERROR of git pull origin master```\n" + err + "\n\n" + data.toString() + "\n```\n");
            exec('git', ["merge", "--abort"], {cwd: botPath}, function(err, data){});
        }
    });
}

function knuxPoke(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    pokeBot(bot, message, echidnasDir);
}

function minniePoke(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    pokeBot(bot, message, minnieDir);
}

function systemDofBot(bot, message, botPath, botName, action)
{
    if(!isGranted(message))
    {
        message.reply("Sorry, I can't help you, you are not allowed to use this command");
        return;
    }

    exec('sudo', ["systemctl", action, botName], {cwd: botPath}, function(err, data)
    {
        let fullCommand = "systemctl " + action + " " + botName;
        if(!err)
            message.reply(fullCommand + "\n```\n" + data.toString() + "\n```\n");
        else
            message.reply("ERROR of " + fullCommand + "```\n" + err + "\n\n" + data.toString() + "\n```\n");
    });
}

function minnieStart(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-minnie", "start");
}

function minnieStop(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-minnie", "stop");
}

function minnieRestart(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-minnie", "restart");
}

function minnieStatus(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-minnie", "status");
}

function knuxStart(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-knux", "start");
}

function knuxStop(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-knux", "stop");
}

function knuxRestart(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-knux", "restart");
}

function knuxStatus(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-knux", "status");
}

function registerCommands(foxyCore)
{
    core = foxyCore;
    core.addCMD(["knuxlog",    knuxLog,           "Check out Knux's log tail. Has optional argument - a count of lines to print.", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["knuxlogfile",knuxFullLog,       "Get a complete Knux's log file.", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["knuxpoke",   knuxPoke,          "Poke Knux if he is asleep", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["minniepoke", minniePoke,        "Poke Minnie Marygold if she is asleep", [], true, [CODEHAUS_Server] ]);

    core.addCMD(["knux-start",   knuxStart,   "Start Knuckles", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["knux-stop",    knuxStop,    "Stop Knuckles", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["knux-restart", knuxRestart, "Restart Knuckles", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["knux-status",  knuxStatus,  "Show status of Knuckles", [], true, [CODEHAUS_Server] ]);

    core.addCMD(["minnie-start",   minnieStart,   "Start Minnie Marygold", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["minnie-stop",    minnieStop,    "Stop Minnie Marygold", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["minnie-restart", minnieRestart, "Restart Minnie Marygold", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["minnie-status",  minnieStatus,  "Show status of Minnie Marygold", [], true, [CODEHAUS_Server] ]);
}

module.exports =
{
    registerCommands:   registerCommands
};
<commit_msg>MyFriends: Fixed the typo of Minnie<commit_after>/*
    A small plugin to help Foxy help his friends like Echidnabot
*/

let core = undefined;
let exec = require('child_process').execFile;

let CODEHAUS_Server = "215661302692052992";
const echidnasDir = "/home/vitaly/_Bots/echidnabot";
const minnieDir = "/home/vitaly/_Bots/minnie-marigold";

function isGranted(message)
{
    return (core.botConfig.myboss.indexOf(message.author.id) !== -1) || (message.author.id === "133426635998232577");
}

function knuxLog(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    if(!isGranted(message))
    {
        message.reply("Sorry, I can't help you, you are not allowed to use this command");
        return;
    }

    let linesNumber = (args === "" ? 25 : Number(args));

    exec('tail', ["-n", linesNumber.toString(), "knuxlog.log"], {cwd: echidnasDir}, function(err, data)
    {
        if(!err)
        {
            let s = data.toString();
            if(s.length > 1900)
                s = s.substr(s.length - 1900);
            message.reply("tail -n " + linesNumber + " knuxlog.log\n```\n" + s + "\n```\n");
        }
        else
        {
            message.reply("ERROR of tail -n 25 knuxlog.log```\n" + err + "\n\n" + data.toString() + "\n```\n");
        }
    });
}

function knuxFullLog(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    if(!isGranted(message))
    {
        message.reply("Sorry, I can't help you, you are not allowed to use this command");
        return;
    }

    exec('bzip2', ["-fk", echidnasDir + "/knuxlog.log"], {cwd: echidnasDir}, function(err, data)
    {
        if(!err)
            message.channel.sendFile(echidnasDir + "/knuxlog.log.bz2", "knuxlog.log.bz2").catch(core.msgSendError);
        else
            message.reply("ERROR of bzip2 -fk " + echidnasDir + "/knuxlog.log\n```\n" + err + "\n\n" + data.toString() + "\n```\n");
    });

}

function pokeBot(bot, message, botPath)
{
    if(!isGranted(message))
    {
        message.reply("Sorry, I can't help you, you are not allowed to use this command");
        return;
    }

    exec('git', ["pull", "origin", "master"], {cwd: botPath}, function(err, data)
    {
        if(!err)
            message.reply("git pull origin master\n```\n" + data.toString() + "\n```\n");
        else
        {
            message.reply("ERROR of git pull origin master```\n" + err + "\n\n" + data.toString() + "\n```\n");
            exec('git', ["merge", "--abort"], {cwd: botPath}, function(err, data){});
        }
    });
}

function knuxPoke(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    pokeBot(bot, message, echidnasDir);
}

function minniePoke(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    pokeBot(bot, message, minnieDir);
}

function systemDofBot(bot, message, botPath, botName, action)
{
    if(!isGranted(message))
    {
        message.reply("Sorry, I can't help you, you are not allowed to use this command");
        return;
    }

    exec('sudo', ["systemctl", action, botName], {cwd: botPath}, function(err, data)
    {
        let fullCommand = "systemctl " + action + " " + botName;
        if(!err)
            message.reply(fullCommand + "\n```\n" + data.toString() + "\n```\n");
        else
            message.reply("ERROR of " + fullCommand + "```\n" + err + "\n\n" + data.toString() + "\n```\n");
    });
}

function minnieStart(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-minnie", "start");
}

function minnieStop(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-minnie", "stop");
}

function minnieRestart(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-minnie", "restart");
}

function minnieStatus(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-minnie", "status");
}

function knuxStart(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-knux", "start");
}

function knuxStop(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-knux", "stop");
}

function knuxRestart(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-knux", "restart");
}

function knuxStatus(/*Client*/ bot, /*Message*/ message, /*string*/ args)
{
    systemDofBot(bot, message, minnieDir, "discord-knux", "status");
}

function registerCommands(foxyCore)
{
    core = foxyCore;
    core.addCMD(["knuxlog",    knuxLog,           "Check out Knux's log tail. Has optional argument - a count of lines to print.", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["knuxlogfile",knuxFullLog,       "Get a complete Knux's log file.", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["knuxpoke",   knuxPoke,          "Poke Knux if he is asleep", [], true, [CODEHAUS_Server] ]);

    core.addCMD(["minniepoke", minniePoke,        "Poke Minnie Marigold if she is asleep", [], true, [CODEHAUS_Server] ]);

    core.addCMD(["knux-start",   knuxStart,   "Start Knuckles", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["knux-stop",    knuxStop,    "Stop Knuckles", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["knux-restart", knuxRestart, "Restart Knuckles", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["knux-status",  knuxStatus,  "Show status of Knuckles", [], true, [CODEHAUS_Server] ]);

    core.addCMD(["minnie-start",   minnieStart,   "Start Minnie Marigold", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["minnie-stop",    minnieStop,    "Stop Minnie Marigold", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["minnie-restart", minnieRestart, "Restart Minnie Marigold", [], true, [CODEHAUS_Server] ]);
    core.addCMD(["minnie-status",  minnieStatus,  "Show status of Minnie Marigold", [], true, [CODEHAUS_Server] ]);
}

module.exports =
{
    registerCommands:   registerCommands
};
<|endoftext|>