<commit_before>'use strict';

//var ref = require('../lib/reference')('v3');

var vc;

module.exports = function(v3) {
    //v3.version = 3.1;
    vc = v3.constants;
    v3.layers.forEach(convertLayer);
    return v3;
};

var newTypes = {
    point: 'Point',
    line: 'LineString',
    polygon: 'Polygon'
};

function convertLayer(layer) {
    var render = layer.render;

    if (!render) return;

    if (layer.filter && layer.filter.$type) {
        layer.filter.$type = newTypes[layer.filter.$type];
    }

    if (render.type === 'text' || render.type === 'icon') {
        render.type = 'symbol';

        rename(render, 'icon-spacing', 'symbol-min-distance');
        rename(render, 'text-min-distance', 'symbol-min-distance');
        rename(render, 'icon-allow-overlap', 'symbol-allow-overlap');
        rename(render, 'text-allow-overlap', 'symbol-allow-overlap');
        rename(render, 'icon-ignore-placement', 'symbol-ignore-placement');
        rename(render, 'text-ignore-placement', 'symbol-ignore-placement');

        if (layer.style && layer.style['icon-rotate-anchor']) {
            render['symbol-rotation-alignment'] = layer.style['icon-rotate-anchor'];
            delete layer.style['icon-rotate-anchor'];
        }

        if (render['text-path' === 'curve']) {
            render['symbol-rotation-alignment'] = 'map';
            render.placement = 'line';
        }

        var convertHalo = function(haloWidth, textSize) {
            return Number(((6 - haloWidth * 8) * textSize / 24).toFixed(2));
        }

        // convert text-halo-width to pixels
        for (var classname in layer) {
            if (classname.indexOf('style') == 0) {
                var style = layer[classname];
                if (style['text-halo-width']) {
                    // handle 3 cases: text-size as constant, text-size as #, no text-size but max-text-size
                    var textSize = (typeof(style['text-size']) == 'string' &&
                                        style['text-size'].indexOf('@') != -1) ?
                                    vc[style['text-size']] :
                                    (style['text-size'] ?
                                        style['text-size'] :
                                        layer.render['text-max-size']);

                    if (typeof(textSize) == 'number') {
                        style['text-halo-width'] = convertHalo(style['text-halo-width'], textSize)
                    } else if (textSize && textSize['stops']) {
                        var stops = []
                        textSize['stops'].forEach(function(stop) {
                            stops.push([stop[0], convertHalo(style['text-halo-width'], stop[1])]);
                        })
                        style['text-halo-width'] = {
                            "fn": "stops",
                            "stops": stops
                        }
                    }
                }
            }
        }

        if (layer.style && layer.style['text-halo-blur']) {
        }

        delete render['text-path'];
    }
    if (layer.layers) layer.layers.forEach(convertLayer);
}

function rename(render, from, to) {
    if (render[from]) {
        render[to] = render[from];
        delete render[from];
    }
}
<commit_msg>travis-ify JS<commit_after>'use strict';

//var ref = require('../lib/reference')('v3');

var vc;

module.exports = function(v3) {
    //v3.version = 3.1;
    vc = v3.constants;
    v3.layers.forEach(convertLayer);
    return v3;
};

var newTypes = {
    point: 'Point',
    line: 'LineString',
    polygon: 'Polygon'
};

function convertLayer(layer) {
    var render = layer.render;

    if (!render) return;

    if (layer.filter && layer.filter.$type) {
        layer.filter.$type = newTypes[layer.filter.$type];
    }

    if (render.type === 'text' || render.type === 'icon') {
        render.type = 'symbol';

        rename(render, 'icon-spacing', 'symbol-min-distance');
        rename(render, 'text-min-distance', 'symbol-min-distance');
        rename(render, 'icon-allow-overlap', 'symbol-allow-overlap');
        rename(render, 'text-allow-overlap', 'symbol-allow-overlap');
        rename(render, 'icon-ignore-placement', 'symbol-ignore-placement');
        rename(render, 'text-ignore-placement', 'symbol-ignore-placement');

        if (layer.style && layer.style['icon-rotate-anchor']) {
            render['symbol-rotation-alignment'] = layer.style['icon-rotate-anchor'];
            delete layer.style['icon-rotate-anchor'];
        }

        if (render['text-path' === 'curve']) {
            render['symbol-rotation-alignment'] = 'map';
            render.placement = 'line';
        }

        var convertHalo = function(haloWidth, textSize) {
            return Number(((6 - haloWidth * 8) * textSize / 24).toFixed(2));
        };

        // convert text-halo-width to pixels
        for (var classname in layer) {
            if (classname.indexOf('style') === 0) {
                var style = layer[classname];
                if (style['text-halo-width']) {
                    // handle 3 cases: text-size as constant, text-size as #, no text-size but max-text-size
                    var textSize = (typeof(style['text-size']) == 'string' &&
                                        style['text-size'].indexOf('@') != -1) ?
                                    vc[style['text-size']] :
                                    (style['text-size'] ?
                                        style['text-size'] :
                                        layer.render['text-max-size']);

                    // handle text-size numbers and functions
                    if (typeof(textSize) == 'number') {
                        style['text-halo-width'] = convertHalo(style['text-halo-width'], textSize);
                    } else if (textSize && textSize.stops) {
                        var stops = [];
                        for (var stop in textSize.stops) {
                            stops.push(
                                [textSize.stops[stop][0],
                                convertHalo(style['text-halo-width'], textSize.stops[stop][1])]
                            );
                        }
                        style['text-halo-width'] = {
                            "fn": "stops",
                            "stops": stops
                        };
                    }
                }
            }
        }

        if (layer.style && layer.style['text-halo-blur']) {
        }

        delete render['text-path'];
    }
    if (layer.layers) layer.layers.forEach(convertLayer);
}

function rename(render, from, to) {
    if (render[from]) {
        render[to] = render[from];
        delete render[from];
    }
}
<|endoftext|>


<commit_before>//HV control panel
(function(){

    xtag.register('widget-rateBar', {
        extends: 'div',
        lifecycle: {
            created: function() {
                var barTitle = document.createElement('h2')

                ////////////////////
                //build the DOM
                ////////////////////
                barTitle.setAttribute('id', this.id + 'Title');
                barTitle.innerHTML = 'Click on a rate or threshold channel to get started.';
                this.appendChild(barTitle);
                this.UIdeployed = false;

                this.addEventListener('postADC', function(evt){
                    this.updateRates(evt.detail);
                }, false);

            },
            inserted: function() {},
            removed: function() {},
            attributeChanged: function() {}
        },
        events: {

        },
        accessors: {
            'MIDAS':{
                attribute: {} //this just needs to be declared
            }
        },
        methods: {
            'updateRates' : function(customEventData){
                document.getElementById(this.id + 'Title').innerHTML = customEventData.channel
                if(!this.UIdeployed){
                    this.setUpUI();
                    this.UIdeployed = true;
                }
            },

            'setUpUI' : function(){
                var control = document.createElement('div'),
                    mainSections = ['ADCstatusPane', 'ADC', 'trig', 'pulseHeight', 'time', 'waveform', 'simulation', 'misc'],
                    mainSectionDivs = [],
                    mainSectionTitles = ['MSCB Node Info', 'ADC Control', 'Triggering', 'Pulse Height Eval.', 'Time Eval.', 'Waveform Readout', 'Simulation Pulse', 'Miscellaneous'],
                    mainSectionH3 = [],
                    mainLists = [],
                    statusIDs = ['ctrl', 'rev', 'serial', 'cpu_temp', 'cc_lock', 'cc_freq', 'hw_sw_m', 'hw_id', 'hw_time', 'sw_id', 'sw_time', 'uptime', 'dac_ch', 'ref_clk', 'ch_en', 'ch_aa'],
                    ADCitemTitles = ['DC Offset:', 'ADC Chan:', 'Trim:', 'Polarity:'],
                    triggeringItemTitles = ['Channel:', 'Hit Thresh:', 'Trig Thresh', 'Differentiation:', 'Integration:', 'Delay:', 'Pole Cxn:', 'BLR Control:'],
                    pulseheightItemTitles = ['Integration:', 'Differentiation:', 'Delay:', 'Pole Cxn 1:', 'Pole Cxn 2:', 'Baseline Rest:', 'Gain:', 'Pileup Algo:'],
                    timeItemTitles = ['CFD Delay:', 'CFD Fraction:'],
                    waveformItemTitles = ['', 'Pretrigger:', 'Samples:', 'Decimation:', 'Filter WF:'],
                    listItem, items, input, label, p,
                    id, step,
                    i;

                //wrapper for ADC UI
                control.setAttribute('id', 'control');
                this.appendChild(control);

                //main sections
                for(i=0; i<mainSections.length; i++){
                    mainSectionDivs[i] = document.createElement('div');
                    mainSectionDivs[i].setAttribute('id', mainSections[i]);
                    mainSectionDivs[i].setAttribute('class', 'collapse');

                    mainSectionH3[i] = document.createElement('h3');
                    mainSectionH3[i].setAttribute('class', 'sectionHead');
                    mainSectionH3[i].onclick = toggleSection.bind(mainSectionH3[i], mainSections[i]);
                    mainSectionH3[i].innerHTML = String.fromCharCode(0x25B6) + ' ' +mainSectionTitles[i];
                    mainSectionDivs[i].appendChild(mainSectionH3[i]);

                    mainLists[i] = document.createElement('ul');
                    mainSectionDivs[i].appendChild(mainLists[i]);

                    control.appendChild(mainSectionDivs[i]);
                }

                ////////////////////////////
                //ADC status pane elements
                ////////////////////////////
                for(i=0; i<statusIDs.length; i++){
                    listItem = document.createElement('li');
                    listItem.setAttribute('id', statusIDs[i]);
                    mainLists[0].appendChild(listItem);
                }

                //////////////////////////
                //ADC pane elements
                //////////////////////////
                items = [];
                for(i=0; i<ADCitemTitles.length; i++){
                    listItem = document.createElement('li');
                    mainLists[1].appendChild(listItem);
                    label = document.createElement('label');
                    label.innerHTML = ADCitemTitles[i];
                    listItem.appendChild(label);
                    items.push(listItem);
                }

                input = document.createElement('input');
                setAttributes(input, {
                    "id" : "a_dcofst",
                    "type" : "range",
                    "step" : 1,
                    "min" : 0,
                    "max" : 4095,
                });
                input.oninput = this.updateADC.bind(input, 'a_dcofst');
                items[0].appendChild(input);
                label = document.createElement('label');
                label.setAttribute('id', 'dcofstLabel');
                label.innerHTML = 'mV';
                items[0].appendChild(label);

                radioArray(items[1], ['Enabled', 'Disabled'], [true, false], 'a_off');
                document.getElementById('a_off0').onchange = this.updateADC.bind(document.getElementById('a_off0'), 'a_off');
                document.getElementById('a_off1').onchange = this.updateADC.bind(document.getElementById('a_off1'), 'a_off');

                input = document.createElement('input');
                setAttributes(input, {
                    "id" : "a_trim",
                    "type" : "number",
                    "step" : 1,
                    "class" : "stdin"
                });
                input.onchange = this.updateADC.bind(input, 'a_trim');
                items[2].appendChild(input);

                radioArray(items[3], ['Positive', 'Negative'], [true, false], 'a_pol');
                document.getElementById('a_pol0').onchange = this.updateADC.bind(document.getElementById('a_pol0'), 'a_pol');
                document.getElementById('a_pol1').onchange = this.updateADC.bind(document.getElementById('a_pol1'), 'a_pol');

                ////////////////////////////////
                //Triggering pane elements
                ////////////////////////////////
                items = [];
                for(i=0; i<triggeringItemTitles.length; i++){
                    listItem = document.createElement('li');
                    mainLists[2].appendChild(listItem);
                    label = document.createElement('label');
                    label.innerHTML = triggeringItemTitles[i];
                    listItem.appendChild(label);
                    items.push(listItem);
                }

                radioArray(items[0], ['Enabled', 'Disabled'], [true, false], 't_off');
                document.getElementById('t_off0').onchange = this.updateADC.bind(document.getElementById('t_off0'), 't_off');
                document.getElementById('t_off1').onchange = this.updateADC.bind(document.getElementById('t_off1'), 't_off');

                id = ['t_hthresh', 't_thresh', 't_diff', 't_int', 't_delay', 't_polcor', 't_blrctl'];
                step = ["any", "any", 1, 1, 1, "any", "any"];

                for(i=0; i<id.length; i++){
                    input = document.createElement('input');
                    setAttributes(input, {
                        "id" : id[i],
                        "type" : "number",
                        "step" : step[i],
                        "class" : "stdin"
                    });
                    input.onchange = this.updateADC.bind(input, id[i]);
                    items[i+1].appendChild(input);
                }

                /////////////////////////////////
                //pulse height pane elements
                /////////////////////////////////
                items = [];
                for(i=0; i<pulseheightItemTitles.length; i++){
                    listItem = document.createElement('li');
                    mainLists[3].appendChild(listItem);
                    label = document.createElement('label');
                    label.innerHTML = pulseheightItemTitles[i];
                    listItem.appendChild(label);
                    items.push(listItem);
                }

                id = ['p_int', 'p_diff', 'p_delay', 'p_polec1', 'p_polec2', 'p_bsr', 'p_gain', 'p_pactrl'];
                step = [1,1,1,"any","any","any","any", 1];

                for(i=0; i<id.length; i++){
                    input = document.createElement('input');
                    setAttributes(input, {
                        "id" : id[i],
                        "type" : "number",
                        "step" : step[i],
                        "class" : "stdin"
                    });
                    input.onchange = this.updateADC.bind(input, id[i]);
                    items[i].appendChild(input);
                }

                ///////////////////////////////
                //Time eval pane elements
                ///////////////////////////////
                items = [];
                for(i=0; i<timeItemTitles.length; i++){
                    listItem = document.createElement('li');
                    mainLists[4].appendChild(listItem);
                    label = document.createElement('label');
                    label.innerHTML = timeItemTitles[i];
                    listItem.appendChild(label);
                    items.push(listItem);
                }

                id = ['cfd_dly', 'cfd_frac'];
                step = [1,"any"];

                for(i=0; i<id.length; i++){
                    input = document.createElement('input');
                    setAttributes(input, {
                        "id" : id[i],
                        "type" : "number",
                        "step" : step[i],
                        "class" : "stdin"
                    });
                    input.onchange = this.updateADC.bind(input, id[i]);
                    items[i].appendChild(input);
                }

                //////////////////////////////
                //Waveform pane elements
                //////////////////////////////
                items = [];
                for(i=1; i<waveformItemTitles.length; i++){
                    listItem = document.createElement('li');
                    mainLists[5].appendChild(listItem);
                    label = document.createElement('label');
                    label.innerHTML = triggeringItemTitles[i];
                    listItem.appendChild(label);
                    items.push(listItem);
                }

                radioArray(items[0], ['Enabled', 'Disabled'], [true, false], 'wrf_supp');
                document.getElementById('wrf_supp0').onchange = this.updateADC.bind(document.getElementById('wrf_supp0'), 'wrf_supp');
                document.getElementById('wrf_supp1').onchange = this.updateADC.bind(document.getElementById('wrf_supp1'), 'wrf_supp');

                id = ['wrf_pret', 'wrf_smpl', 'wrf_dec'];
                step = [1,1,1];

                for(i=0; i<id.length; i++){
                    input = document.createElement('input');
                    setAttributes(input, {
                        "id" : id[i],
                        "type" : "number",
                        "step" : step[i],
                        "class" : "stdin"
                    });
                    input.onchange = this.updateADC.bind(input, id[i]);
                    items[i+1].appendChild(input);
                }

                radioArray(items[4], ['Enabled', 'Disabled'], [true, false], 'wrf_off');
                document.getElementById('wrf_supp0').onchange = this.updateADC.bind(document.getElementById('wrf_off0'), 'wrf_off');
                document.getElementById('wrf_supp1').onchange = this.updateADC.bind(document.getElementById('wrf_off1'), 'wrf_off');

            },

            'updateADC' : function(var_name){
                console.log(var_name)
            }
        }
    });

})();

function toggleSection(id){
    var section = document.getElementById(id)

    if(section.className == 'collapse'){
        section.className = 'expand'
        this.innerHTML = String.fromCharCode(0x25BC) + this.innerHTML.slice(this.innerHTML.indexOf(' '));
    }
    else{
        section.className = 'collapse'
        this.innerHTML = String.fromCharCode(0x25B6) + this.innerHTML.slice(this.innerHTML.indexOf(' '));
    }
}<commit_msg>setting up ADC control UI<commit_after>//HV control panel
(function(){

    xtag.register('widget-rateBar', {
        extends: 'div',
        lifecycle: {
            created: function() {
                var barTitle = document.createElement('h2')

                ////////////////////
                //build the DOM
                ////////////////////
                barTitle.setAttribute('id', this.id + 'Title');
                barTitle.innerHTML = 'Click on a rate or threshold channel to get started.';
                this.appendChild(barTitle);
                this.UIdeployed = false;

                this.addEventListener('postADC', function(evt){
                    this.updateRates(evt.detail);
                }, false);

            },
            inserted: function() {},
            removed: function() {},
            attributeChanged: function() {}
        },
        events: {

        },
        accessors: {
            'MIDAS':{
                attribute: {} //this just needs to be declared
            }
        },
        methods: {
            'updateRates' : function(customEventData){
                document.getElementById(this.id + 'Title').innerHTML = customEventData.channel
                if(!this.UIdeployed){
                    this.setUpUI();
                    this.UIdeployed = true;
                }
            },

            'setUpUI' : function(){
                var control = document.createElement('div'),
                    mainSections = ['ADCstatusPane', 'ADC', 'trig', 'pulseHeight', 'time', 'waveform', 'simulation', 'misc'],
                    mainSectionDivs = [],
                    mainSectionTitles = ['MSCB Node Info', 'ADC Control', 'Triggering', 'Pulse Height Eval.', 'Time Eval.', 'Waveform Readout', 'Simulation Pulse', 'Miscellaneous'],
                    mainSectionH3 = [],
                    mainLists = [],
                    statusIDs = ['ctrl', 'rev', 'serial', 'cpu_temp', 'cc_lock', 'cc_freq', 'hw_sw_m', 'hw_id', 'hw_time', 'sw_id', 'sw_time', 'uptime', 'dac_ch', 'ref_clk', 'ch_en', 'ch_aa'],
                    ADCitemTitles = ['DC Offset:', 'ADC Chan:', 'Trim:', 'Polarity:'],
                    triggeringItemTitles = ['Channel:', 'Hit Thresh:', 'Trig Thresh:', 'Differentiation:', 'Integration:', 'Delay:', 'Pole Cxn:', 'BLR Control:'],
                    pulseheightItemTitles = ['Integration:', 'Differentiation:', 'Delay:', 'Pole Cxn 1:', 'Pole Cxn 2:', 'Baseline Rest:', 'Gain:', 'Pileup Algo:'],
                    timeItemTitles = ['CFD Delay:', 'CFD Fraction:'],
                    waveformItemTitles = ['', 'Pretrigger:', 'Samples:', 'Decimation:', 'Filter WF:'],
                    simulationItemTitles = ['', 'Pulse Height:', 'Risetime:', 'Falltime:', 'Rate:', 'Period:'],
                    miscItemTitles = ['Fixed Deadtime:', 'Detector Type:'],
                    listItem, items, input, label, p,
                    id, step,
                    i;

                //wrapper for ADC UI
                control.setAttribute('id', 'control');
                this.appendChild(control);

                //main sections
                for(i=0; i<mainSections.length; i++){
                    mainSectionDivs[i] = document.createElement('div');
                    mainSectionDivs[i].setAttribute('id', mainSections[i]);
                    mainSectionDivs[i].setAttribute('class', 'collapse');

                    mainSectionH3[i] = document.createElement('h3');
                    mainSectionH3[i].setAttribute('class', 'sectionHead');
                    mainSectionH3[i].onclick = toggleSection.bind(mainSectionH3[i], mainSections[i]);
                    mainSectionH3[i].innerHTML = String.fromCharCode(0x25B6) + ' ' +mainSectionTitles[i];
                    mainSectionDivs[i].appendChild(mainSectionH3[i]);

                    mainLists[i] = document.createElement('ul');
                    mainSectionDivs[i].appendChild(mainLists[i]);

                    control.appendChild(mainSectionDivs[i]);
                }

                ////////////////////////////
                //ADC status pane elements
                ////////////////////////////
                for(i=0; i<statusIDs.length; i++){
                    listItem = document.createElement('li');
                    listItem.setAttribute('id', statusIDs[i]);
                    mainLists[0].appendChild(listItem);
                }

                //////////////////////////
                //ADC pane elements
                //////////////////////////
                items = [];
                for(i=0; i<ADCitemTitles.length; i++){
                    listItem = document.createElement('li');
                    mainLists[1].appendChild(listItem);
                    label = document.createElement('label');
                    label.innerHTML = ADCitemTitles[i];
                    listItem.appendChild(label);
                    items.push(listItem);
                }

                input = document.createElement('input');
                setAttributes(input, {
                    "id" : "a_dcofst",
                    "type" : "range",
                    "step" : 1,
                    "min" : 0,
                    "max" : 4095,
                });
                input.oninput = this.updateADC.bind(input, 'a_dcofst');
                items[0].appendChild(input);
                label = document.createElement('label');
                label.setAttribute('id', 'dcofstLabel');
                label.innerHTML = 'mV';
                items[0].appendChild(label);

                radioArray(items[1], ['Enabled', 'Disabled'], [true, false], 'a_off');
                document.getElementById('a_off0').onchange = this.updateADC.bind(document.getElementById('a_off0'), 'a_off');
                document.getElementById('a_off1').onchange = this.updateADC.bind(document.getElementById('a_off1'), 'a_off');

                input = document.createElement('input');
                setAttributes(input, {
                    "id" : "a_trim",
                    "type" : "number",
                    "step" : 1,
                    "class" : "stdin"
                });
                input.onchange = this.updateADC.bind(input, 'a_trim');
                items[2].appendChild(input);

                radioArray(items[3], ['Positive', 'Negative'], [true, false], 'a_pol');
                document.getElementById('a_pol0').onchange = this.updateADC.bind(document.getElementById('a_pol0'), 'a_pol');
                document.getElementById('a_pol1').onchange = this.updateADC.bind(document.getElementById('a_pol1'), 'a_pol');

                ////////////////////////////////
                //Triggering pane elements
                ////////////////////////////////
                items = [];
                for(i=0; i<triggeringItemTitles.length; i++){
                    listItem = document.createElement('li');
                    mainLists[2].appendChild(listItem);
                    label = document.createElement('label');
                    label.innerHTML = triggeringItemTitles[i];
                    listItem.appendChild(label);
                    items.push(listItem);
                }

                radioArray(items[0], ['Enabled', 'Disabled'], [true, false], 't_off');
                document.getElementById('t_off0').onchange = this.updateADC.bind(document.getElementById('t_off0'), 't_off');
                document.getElementById('t_off1').onchange = this.updateADC.bind(document.getElementById('t_off1'), 't_off');

                id = ['t_hthresh', 't_thresh', 't_diff', 't_int', 't_delay', 't_polcor', 't_blrctl'];
                step = ["any", "any", 1, 1, 1, "any", "any"];

                for(i=0; i<id.length; i++){
                    input = document.createElement('input');
                    setAttributes(input, {
                        "id" : id[i],
                        "type" : "number",
                        "step" : step[i],
                        "class" : "stdin"
                    });
                    input.onchange = this.updateADC.bind(input, id[i]);
                    items[i+1].appendChild(input);
                }

                /////////////////////////////////
                //pulse height pane elements
                /////////////////////////////////
                items = [];
                for(i=0; i<pulseheightItemTitles.length; i++){
                    listItem = document.createElement('li');
                    mainLists[3].appendChild(listItem);
                    label = document.createElement('label');
                    label.innerHTML = pulseheightItemTitles[i];
                    listItem.appendChild(label);
                    items.push(listItem);
                }

                id = ['p_int', 'p_diff', 'p_delay', 'p_polec1', 'p_polec2', 'p_bsr', 'p_gain', 'p_pactrl'];
                step = [1,1,1,"any","any","any","any", 1];

                for(i=0; i<id.length; i++){
                    input = document.createElement('input');
                    setAttributes(input, {
                        "id" : id[i],
                        "type" : "number",
                        "step" : step[i],
                        "class" : "stdin"
                    });
                    input.onchange = this.updateADC.bind(input, id[i]);
                    items[i].appendChild(input);
                }

                ///////////////////////////////
                //Time eval pane elements
                ///////////////////////////////
                items = [];
                for(i=0; i<timeItemTitles.length; i++){
                    listItem = document.createElement('li');
                    mainLists[4].appendChild(listItem);
                    label = document.createElement('label');
                    label.innerHTML = timeItemTitles[i];
                    listItem.appendChild(label);
                    items.push(listItem);
                }

                id = ['cfd_dly', 'cfd_frac'];
                step = [1,"any"];

                for(i=0; i<id.length; i++){
                    input = document.createElement('input');
                    setAttributes(input, {
                        "id" : id[i],
                        "type" : "number",
                        "step" : step[i],
                        "class" : "stdin"
                    });
                    input.onchange = this.updateADC.bind(input, id[i]);
                    items[i].appendChild(input);
                }

                //////////////////////////////
                //Waveform pane elements
                //////////////////////////////
                items = [];
                for(i=1; i<waveformItemTitles.length; i++){
                    listItem = document.createElement('li');
                    mainLists[5].appendChild(listItem);
                    label = document.createElement('label');
                    label.innerHTML = waveformItemTitles[i];
                    listItem.appendChild(label);
                    items.push(listItem);
                }

                radioArray(items[0], ['Enabled', 'Disabled'], [true, false], 'wrf_supp');
                document.getElementById('wrf_supp0').onchange = this.updateADC.bind(document.getElementById('wrf_supp0'), 'wrf_supp');
                document.getElementById('wrf_supp1').onchange = this.updateADC.bind(document.getElementById('wrf_supp1'), 'wrf_supp');

                id = ['wrf_pret', 'wrf_smpl', 'wrf_dec'];
                step = [1,1,1];

                for(i=0; i<id.length; i++){
                    input = document.createElement('input');
                    setAttributes(input, {
                        "id" : id[i],
                        "type" : "number",
                        "step" : step[i],
                        "class" : "stdin"
                    });
                    input.onchange = this.updateADC.bind(input, id[i]);
                    items[i+1].appendChild(input);
                }

                radioArray(items[4], ['Enabled', 'Disabled'], [true, false], 'wrf_off');
                document.getElementById('wrf_supp0').onchange = this.updateADC.bind(document.getElementById('wrf_off0'), 'wrf_off');
                document.getElementById('wrf_supp1').onchange = this.updateADC.bind(document.getElementById('wrf_off1'), 'wrf_off');

                //////////////////////////////
                //Simulation pane elements
                //////////////////////////////
                items = [];
                for(i=1; i<simulationItemTitles.length; i++){
                    listItem = document.createElement('li');
                    mainLists[6].appendChild(listItem);
                    label = document.createElement('label');
                    label.innerHTML = simulationItemTitles[i];
                    listItem.appendChild(label);
                    items.push(listItem);
                }

                radioArray(items[0], ['Enabled', 'Disabled'], [true, false], 'sim_ena');
                document.getElementById('sim_ena0').onchange = this.updateADC.bind(document.getElementById('sim_ena0'), 'sim_ena');
                document.getElementById('sim_ena1').onchange = this.updateADC.bind(document.getElementById('sim_ena1'), 'sim_ena');

                id = ['sim_phgt', 'sim_rise', 'sim_fall', 'sim_rate'];
                step = ["any", "any", "any", "any"];

                for(i=0; i<id.length; i++){
                    input = document.createElement('input');
                    setAttributes(input, {
                        "id" : id[i],
                        "type" : "number",
                        "step" : step[i],
                        "class" : "stdin"
                    });
                    input.onchange = this.updateADC.bind(input, id[i]);
                    items[i+1].appendChild(input);
                }

                radioArray(items[5], ['Random', 'Fixed'], [true, false], 'sim_rand');
                document.getElementById('sim_rand0').onchange = this.updateADC.bind(document.getElementById('sim_rand0'), 'sim_rand');
                document.getElementById('sim_rand1').onchange = this.updateADC.bind(document.getElementById('sim_rand1'), 'sim_rand');

                ///////////////////////////////
                //Misc pane elements
                ///////////////////////////////
                items = [];
                for(i=0; i<miscItemTitles.length; i++){
                    listItem = document.createElement('li');
                    mainLists[7].appendChild(listItem);
                    label = document.createElement('label');
                    label.innerHTML = miscItemTitles[i];
                    listItem.appendChild(label);
                    items.push(listItem);
                }

                id = ['fix_dead', 'det_type'];
                step = [1,1];

                for(i=0; i<id.length; i++){
                    input = document.createElement('input');
                    setAttributes(input, {
                        "id" : id[i],
                        "type" : "number",
                        "step" : step[i],
                        "class" : "stdin"
                    });
                    input.onchange = this.updateADC.bind(input, id[i]);
                    items[i].appendChild(input);
                }

            },

            'updateADC' : function(var_name){
                console.log(var_name)
            }
        }
    });

})();

function toggleSection(id){
    var section = document.getElementById(id)

    if(section.className == 'collapse'){
        section.className = 'expand'
        this.innerHTML = String.fromCharCode(0x25BC) + this.innerHTML.slice(this.innerHTML.indexOf(' '));
    }
    else{
        section.className = 'collapse'
        this.innerHTML = String.fromCharCode(0x25B6) + this.innerHTML.slice(this.innerHTML.indexOf(' '));
    }
}<|endoftext|>


<commit_before>'use strict';

//////////////////////////////////////////////////////////////////////////////
// REQUIRED
//////////////////////////////////////////////////////////////////////////////

var gulp = require('gulp');
var path = require('path');
var cm = require('./lib/common');

var publish = require('./lib/publish');
var build = require('./lib/build');

//////////////////////////////////////////////////////////////////////////////
// TASKS
//////////////////////////////////////////////////////////////////////////////

gulp.task('clean', function(done) {

  var rimraf = require('gulp-rimraf');
  var DIR = cm.component_publisher_dir;
  gulp.src(DIR + '/**').pipe(rimraf())
  .on('end', done);
});

gulp.task('build_gh-pages', build.ghpages);
gulp.task('build_bower', build.bower);
gulp.task('build_subbower', function(done){
  var moduleNames = Object.keys(cm.public.subcomponents);
  var almostDone = cm._.after(moduleNames.length, done);
  for (var i = 0, n = moduleNames.length; i < n ; i++){
    build.subbower(moduleNames[i], cm.public.subcomponents[moduleNames[i]])(almostDone);
  }
});

var allowPushOnRepo = (process.env.TRAVIS == 'true') && (process.env.TRAVIS_PULL_REQUEST == 'false') && (process.env.TRAVIS_BRANCH == 'develop') && true;
gulp.task('publish_gh-pages', function(cb){
  if (process.env.TRAVIS){
    publish.apply(this, [{
      tag:  false,
      push: allowPushOnRepo,
      message: 'Travis commit : build ' + process.env.TRAVIS_BUILD_NUMBER
    }, cb]);
  }else{
    publish.apply(this, [cb]);
  }
});

gulp.task('publish_bower', function(cb){
  if (process.env.TRAVIS){
    publish.apply(this, [
    {
      push: allowPushOnRepo,
      message: 'Travis commit : build ' + process.env.TRAVIS_BUILD_NUMBER
    }, cb]);
  }else{
    publish.apply(this, [cb]);
  }
});

gulp.task('publish_subbower', function(done){
  var moduleNames = Object.keys(cm.public.subcomponents);
  var almostDone = cm._.after(moduleNames.length, done);
  for (var i = 0, n = moduleNames.length; i < n ; i++){
    var mName = moduleNames[i];
    publish.apply(this, [{
      branch: 'bower-' + mName,
      cloneLocation: path.resolve(path.join(process.cwd(), cm.PUBLISH_DIR, mName)),
      dirSrc: path.resolve(path.join(process.cwd(), cm.BUILD_DIR, mName)),
      message: 'Travis commit : build ' + process.env.TRAVIS_BUILD_NUMBER,
      push: allowPushOnRepo,
      tag: mName + '-' + cm.pkg.version
    }, almostDone]);
  }
});

function prefixedBranchedTasks(prefix){

  gulp.task(prefix, function(cb){
    if (!this.env.branch )
      throw new Error('\nJust say want you want to ' + prefix + ' like\n' + prefix + ' --branch=bower');

    // TODO test if exist ?
    gulp.run(prefix + '_' + this.env.branch, cb);
  });

}
prefixedBranchedTasks('build');
prefixedBranchedTasks('publish');

<commit_msg>fix(subbower): make publisher works on subbower directories<commit_after>'use strict';

//////////////////////////////////////////////////////////////////////////////
// REQUIRED
//////////////////////////////////////////////////////////////////////////////

var gulp = require('gulp');
var path = require('path');
var cm = require('./lib/common');

var publish = require('./lib/publish');
var build = require('./lib/build');

//////////////////////////////////////////////////////////////////////////////
// TASKS
//////////////////////////////////////////////////////////////////////////////

gulp.task('clean', function(done) {

  var rimraf = require('gulp-rimraf');
  var DIR = cm.component_publisher_dir;
  gulp.src(DIR + '/**').pipe(rimraf())
  .on('end', done);
});

gulp.task('build_gh-pages', build.ghpages);
gulp.task('build_bower', build.bower);
gulp.task('build_subbower', function(done){
  var moduleNames = Object.keys(cm.public.subcomponents);
  var almostDone = cm._.after(moduleNames.length, done);
  for (var i = 0, n = moduleNames.length; i < n ; i++){
    build.subbower(moduleNames[i], cm.public.subcomponents[moduleNames[i]])(almostDone);
  }
});

var allowPushOnRepo = (process.env.TRAVIS == 'true') && (process.env.TRAVIS_PULL_REQUEST == 'false') && (process.env.TRAVIS_BRANCH == 'develop') && true;
gulp.task('publish_gh-pages', function(cb){
  if (process.env.TRAVIS){
    publish.apply(this, [{
      tag:  false,
      push: allowPushOnRepo,
      message: 'Travis commit : build ' + process.env.TRAVIS_BUILD_NUMBER
    }, cb]);
  }else{
    publish.apply(this, [cb]);
  }
});

gulp.task('publish_bower', function(cb){
  if (process.env.TRAVIS){
    publish.apply(this, [
    {
      push: allowPushOnRepo,
      message: 'Travis commit : build ' + process.env.TRAVIS_BUILD_NUMBER
    }, cb]);
  }else{
    publish.apply(this, [cb]);
  }
});

gulp.task('publish_subbower', function(done){
  var moduleNames = Object.keys(cm.public.subcomponents);
  var almostDone = cm._.after(moduleNames.length, done);
  for (var i = 0, n = moduleNames.length; i < n ; i++){
    var mName = moduleNames[i];
    publish.apply(this, [{
      branch: 'bower-' + mName,
      cloneLocation: path.resolve(path.join(process.cwd(), cm.PUBLISH_DIR, 'subbower', mName)),
      dirSrc: path.resolve(path.join(process.cwd(), cm.BUILD_DIR, 'subbower', mName)),
      message: 'Travis commit : build ' + process.env.TRAVIS_BUILD_NUMBER,
      push: allowPushOnRepo,
      tag: mName + '-' + cm.pkg.version
    }, almostDone]);
  }
});

function prefixedBranchedTasks(prefix){

  gulp.task(prefix, function(cb){
    if (!this.env.branch )
      throw new Error('\nJust say want you want to ' + prefix + ' like\n' + prefix + ' --branch=bower');

    // TODO test if exist ?
    gulp.run(prefix + '_' + this.env.branch, cb);
  });

}
prefixedBranchedTasks('build');
prefixedBranchedTasks('publish');

<|endoftext|>


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

module.exports = Class('Request', Object, {
    constructor: function (req, res) {
        this.limit = 1024 * 1024 * 10; // 10MB
        this.req = req;
        this.res = res;
        this.session = null;

        if (req.headers) {
            this.handleHeaders();
        }
    },
    handleHeaders: function () {
        var xforward = 'x-forwarded-for';
        var referer = 'referer';

        var headers = this.req.headers;

        if (xforward in headers) {
            this.ipaddress = headers[xforward];
        } else {
            this.ipaddress = this.req.connection.remoteAddress;
        }

        if (referer in headers) {
            this.referer = headers[referer];
        } else {
            this.referer = '';
        }

        this.query = url.parse(this.req.url, true);

        this.query_string = this.query.search;
        this.query_params = this.query.query;
    },
    handleData: function (data) {
        if ('data' in this) {
            this.data = Buffer.concat([ this.data, data ]);
        } else {
            this.data = data;
        }

        if (this.data.length > this.limit) {
            this.res.writeHead(404,
                {
                    'Content-Type': 'text/html; charset=utf-8'
                }
            );

            this.res.end();
        }
    },
    write: function (data) {
        try {
            if (data instanceof Buffer) {
                this.res.write(data);
            } else if (data instanceof Object) {
                this.res.write(JSON.stringify(data));
            } else {
                this.res.write(data);
            }
        } catch (e) {

        }
    },
    parseDataPost: function () {
        if (this.req.method == 'POST' &&
            this.data &&
            'content-type' in this.req.headers &&
            this.req.headers['content-type'].toLowerCase().indexOf('application/x-www-form-urlencoded') == 0) {

            this.post = querystring.parse(this.data.toString());
        }
    },
    parseDataJson: function () {
        log(this.data);
        var json = JSON.parse(this.data);

        log(json);
    }
});
<commit_msg>debug<commit_after>var querystring = require('querystring');
var url = require('url');

module.exports = Class('Request', Object, {
    constructor: function (req, res) {
        this.limit = 1024 * 1024 * 10; // 10MB
        this.req = req;
        this.res = res;
        this.session = null;

        if (req.headers) {
            this.handleHeaders();
        }
    },
    handleHeaders: function () {
        var xforward = 'x-forwarded-for';
        var referer = 'referer';

        var headers = this.req.headers;

        if (xforward in headers) {
            this.ipaddress = headers[xforward];
        } else {
            this.ipaddress = this.req.connection.remoteAddress;
        }

        if (referer in headers) {
            this.referer = headers[referer];
        } else {
            this.referer = '';
        }

        this.query = url.parse(this.req.url, true);

        this.query_string = this.query.search;
        this.query_params = this.query.query;
    },
    handleData: function (data) {
        if ('data' in this) {
            this.data = Buffer.concat([ this.data, data ]);
        } else {
            this.data = data;
        }

        if (this.data.length > this.limit) {
            this.res.writeHead(404,
                {
                    'Content-Type': 'text/html; charset=utf-8'
                }
            );

            this.res.end();
        }
    },
    write: function (data) {
        try {
            if (data instanceof Buffer) {
                this.res.write(data);
            } else if (data instanceof Object) {
                this.res.write(JSON.stringify(data));
            } else {
                this.res.write(data);
            }
        } catch (e) {
            console.log(e);
        }
    },
    parseDataPost: function () {
        if (this.req.method == 'POST' &&
            this.data &&
            'content-type' in this.req.headers &&
            this.req.headers['content-type'].toLowerCase().indexOf('application/x-www-form-urlencoded') == 0) {

            this.post = querystring.parse(this.data.toString());
        }
    },
    parseDataJson: function () {
        log(this.data);
        var json = JSON.parse(this.data);

        log(json);
    }
});
<|endoftext|>


<commit_before>// MongoDB stuff
// Created by Fredrik A. Madsen-Malmo

// Imports
var mongo = require('mongodb').MongoClient;
var assert = require('assert');
var Promise = require('promise');

// Mongo config
var PORT = 27017 || process.env.MONGOPORT;
var HOST = 'localhost' || process.env.MONGOHOST;
var DB = 'serverstatus' || process.env.MONGODB;

var URL = 'mongodb://' + HOST + ':' + PORT + '/' + DB;

// Base function
var WEEKDAYS = [
    'Sunday',
    'Monday',
    'Tuesday',
    'Wednesday',
    'Thursday',
    'Friday',
    'Saturday'
];

/**
 * Connects to the database and calls the anon function provided
 * @param  {Function}  Func Anon function to call
 * @return {null}      No return value
 */
var connect = function (func) {
    mongo.connect(URL, function (err, db) {
        if (err) {
            throw err;
        }

        assert.equal(null, err);
        func(db);
    });
};

// DB functions

/**
 * Callback used for the isert function
 * @param  {Object}   err     This is the Error object that describes the error encountered
 * @param  {Object}   result  This is the result, contains all info about the insert
 * @param  {Object}   db      The database object, here I use it to close the db
 * @param  {Function} resolve This is the function to be called when the script completes
 * @param  {Function} reject  This is the function to be called if the script fails
 * @return {Object}           Resolve or Reject
 */
function insertCallback (err, result, db, resolve, reject) {
    if (err) {
        reject(err);
    }

    assert.equal(err, null);

    db.close();
    resolve(result);
}

/**
 * Insert an entry into the db
 * @param  {String}   mode  either 'temp' or 'load'; what kind of entry
 * @param  {String}    value the value to insert.
 * @return {Function} A promise with the value passed in
 */
var insert = function (mode, value) {
    return new Promise(function (resolve, reject) {
        connect(function (db) {
            if (mode.toLowerCase() == 'temp') {
                db.collection('temp').insertOne({
                    "time": new Date(),
                    "temp": (parseFloat(value.replace(',', '.')))
                }, function(err, result){insertCallback(err, result, db, resolve, reject);});
            } else if (mode.toLowerCase() == 'load') {
                db.collection('load').insertOne({
                    "time": new Date(),
                    "load": ((parseFloat(value) / 4) * 100)
                }, function(err, result){insertCallback(err, result, db, resolve, reject);});
            } else {
                db.close();
                reject('Invalid input');
            }
        });
    });
};

/**
 * Gets the 20 last entries of one mode
 * @param  {String} mode The type of entry to retrieve
 * @return {Function}    Returns either a resolve or reject function
 */
var realtime = function (mode) {
    var latest = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var cursor = db.collection(mode).find({  }).limit(20).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    // Push [hh:mm:ss, temp|load] to latest
                    latest.push([doc.time.toTimeString().substr(0, 8),
                                 (doc.temp || doc.load)]);
                } else {
                    resolve(latest);
                    db.close();
                }
            });
        });
    });
};

/**
 * Get's the average temperature for the 20 last minutes
 * @param  {String} What type of entry to retrieve
 * @return {Array}  Two-dimentional array with HH:MM and temp|load:float
 */
var minute = function (mode) {
    var minutes = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var count = -1;
            var prev = -1;
            var count_internal = 2;

            var cursor = db.collection(mode).find({}).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    if (count <= 20 && doc.time.getMinutes() == prev) {
                        // Push [hh:mm:ss, temp|load] to minutes
                        minutes[count] = [doc.time.toTimeString().substr(0, 5),
                                          (minutes[count][1] + (doc.temp || doc.load)) / 2];
                        count_internal++;
                    } else if (doc.time.getMinutes() != prev) {
                        count++;
                        prev = doc.time.getMinutes();
                        // Push [hh:mm:ss, temp|load] to minutes
                        minutes[count] = [doc.time.toTimeString().substr(0,5),
                                          0 + (doc.temp || doc.load)];
                        count_internal = 2;
                    } else {
                        resolve(minutes);
                        db.close();
                    }
                } else {
                    resolve(minutes);
                    db.close();
                }
            });
        });
    });
};

/**
 * Get's the average temperature for the last 10 hours
 * @param  {String} What type of entry to retrieve
 * @return {Array}  Two-dimentional array with Weekday date, hour:00
 */
var hour = function(mode) {
    var hours = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var count = -1;
            var prev = -1;
            var count_internal = 2;

            var cursor = db.collection(mode).find({}).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    if (count <= 10 && doc.time.getHours() == prev) {
                        // Push [hh:mm:ss, temp|load] to hours
                        hours[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + ', ' +
                                        doc.time.toTimeString().substr(0,2) + ':00',
                                        (hours[count][1] + (doc.temp || doc.load)) / 2];
                        count_internal++;
                    } else if (doc.time.getHours() != prev) {
                        count++;
                        prev = doc.time.getHours();
                        // Push [hh:mm:ss, temp|load] to hours
                        hours[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + ', ' +
                                        doc.time.toTimeString().substr(0,2) + ':00',
                                        0 + (doc.temp || doc.load)];
                        count_internal = 2;
                    } else {
                        resolve(hours);
                        db.close();
                    }
                } else {
                    resolve(hours);
                    db.close();
                }
            });
        });
    });
};

/**
 * Get's the average temperature for the last week
 * @param  {String} What type of entry to retrieve
 * @return {Array}  Two-dimentional array with Weekday date/month
 */
var day = function(mode) {
    var days = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var count = -1;
            var prev = -1;
            var count_internal = 2;

            var cursor = db.collection(mode).find({}).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    if (count <= 7 && doc.time.getDate() == prev) {
                        // Push [hh:mm:ss, temp|load] to days
                        days[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + '/' +
                                        (doc.time.getMonth() + 1),
                                        (days[count][1] + (doc.temp || doc.load)) / 2];
                        count_internal++;
                    } else if (doc.time.getDate() != prev) {
                        count++;
                        prev = doc.time.getDate();
                        // Push [hh:mm:ss, temp|load] to days
                        days[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + '/' +
                                        (doc.time.getMonth() + 1),
                                        0 + (doc.temp || doc.load)];
                        count_internal = 2;
                    } else {
                        resolve(days);
                        db.close();
                    }
                } else {
                    resolve(days);
                    db.close();
                }
            });
        });
    });
};

// Exports

module.exports = {
    insert: insert,
    realtime: realtime,
    minute: minute,
    hour: hour,
    day: day
};
<commit_msg>fixed so that it shows proper count<commit_after>// MongoDB stuff
// Created by Fredrik A. Madsen-Malmo

// Imports
var mongo = require('mongodb').MongoClient;
var assert = require('assert');
var Promise = require('promise');

// Mongo config
var PORT = 27017 || process.env.MONGOPORT;
var HOST = 'localhost' || process.env.MONGOHOST;
var DB = 'serverstatus' || process.env.MONGODB;

var URL = 'mongodb://' + HOST + ':' + PORT + '/' + DB;

// Base function
var WEEKDAYS = [
    'Sunday',
    'Monday',
    'Tuesday',
    'Wednesday',
    'Thursday',
    'Friday',
    'Saturday'
];

/**
 * Connects to the database and calls the anon function provided
 * @param  {Function}  Func Anon function to call
 * @return {null}      No return value
 */
var connect = function (func) {
    mongo.connect(URL, function (err, db) {
        if (err) {
            throw err;
        }

        assert.equal(null, err);
        func(db);
    });
};

// DB functions

/**
 * Callback used for the isert function
 * @param  {Object}   err     This is the Error object that describes the error encountered
 * @param  {Object}   result  This is the result, contains all info about the insert
 * @param  {Object}   db      The database object, here I use it to close the db
 * @param  {Function} resolve This is the function to be called when the script completes
 * @param  {Function} reject  This is the function to be called if the script fails
 * @return {Object}           Resolve or Reject
 */
function insertCallback (err, result, db, resolve, reject) {
    if (err) {
        reject(err);
    }

    assert.equal(err, null);

    db.close();
    resolve(result);
}

/**
 * Insert an entry into the db
 * @param  {String}   mode  either 'temp' or 'load'; what kind of entry
 * @param  {String}    value the value to insert.
 * @return {Function} A promise with the value passed in
 */
var insert = function (mode, value) {
    return new Promise(function (resolve, reject) {
        connect(function (db) {
            if (mode.toLowerCase() == 'temp') {
                db.collection('temp').insertOne({
                    "time": new Date(),
                    "temp": (parseFloat(value.replace(',', '.')))
                }, function(err, result){insertCallback(err, result, db, resolve, reject);});
            } else if (mode.toLowerCase() == 'load') {
                db.collection('load').insertOne({
                    "time": new Date(),
                    "load": ((parseFloat(value) / 4) * 100)
                }, function(err, result){insertCallback(err, result, db, resolve, reject);});
            } else {
                db.close();
                reject('Invalid input');
            }
        });
    });
};

/**
 * Gets the 20 last entries of one mode
 * @param  {String} mode The type of entry to retrieve
 * @return {Function}    Returns either a resolve or reject function
 */
var realtime = function (mode) {
    var latest = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var cursor = db.collection(mode).find({  }).limit(20).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    // Push [hh:mm:ss, temp|load] to latest
                    latest.push([doc.time.toTimeString().substr(0, 8),
                                 (doc.temp || doc.load)]);
                } else {
                    resolve(latest);
                    db.close();
                }
            });
        });
    });
};

/**
 * Get's the average temperature for the 20 last minutes
 * @param  {String} What type of entry to retrieve
 * @return {Array}  Two-dimentional array with HH:MM and temp|load:float
 */
var minute = function (mode) {
    var minutes = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var count = -1;
            var prev = -1;
            var count_internal = 2;

            var cursor = db.collection(mode).find({}).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    if (count <= 20 && doc.time.getMinutes() == prev) {
                        // Push [hh:mm:ss, temp|load] to minutes
                        minutes[count] = [doc.time.toTimeString().substr(0, 5),
                                          (minutes[count][1] + (doc.temp || doc.load)) / 2];
                        count_internal++;
                    } else if (count <= 20 && doc.time.getMinutes() != prev) {
                        count++;
                        prev = doc.time.getMinutes();
                        // Push [hh:mm:ss, temp|load] to minutes
                        minutes[count] = [doc.time.toTimeString().substr(0,5),
                                          0 + (doc.temp || doc.load)];
                        count_internal = 2;
                    } else {
                        resolve(minutes);
                        db.close();
                    }
                } else {
                    resolve(minutes);
                    db.close();
                }
            });
        });
    });
};

/**
 * Get's the average temperature for the last 10 hours
 * @param  {String} What type of entry to retrieve
 * @return {Array}  Two-dimentional array with Weekday date, hour:00
 */
var hour = function(mode) {
    var hours = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var count = -1;
            var prev = -1;
            var count_internal = 2;

            var cursor = db.collection(mode).find({}).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    if (count <= 10 && doc.time.getHours() == prev) {
                        // Push [hh:mm:ss, temp|load] to hours
                        hours[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + ', ' +
                                        doc.time.toTimeString().substr(0,2) + ':00',
                                        (hours[count][1] + (doc.temp || doc.load)) / 2];
                        count_internal++;
                    } else if (count <= 10 && doc.time.getHours() != prev) {
                        count++;
                        prev = doc.time.getHours();
                        // Push [hh:mm:ss, temp|load] to hours
                        hours[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + ', ' +
                                        doc.time.toTimeString().substr(0,2) + ':00',
                                        0 + (doc.temp || doc.load)];
                        count_internal = 2;
                    } else {
                        resolve(hours);
                        db.close();
                    }
                } else {
                    resolve(hours);
                    db.close();
                }
            });
        });
    });
};

/**
 * Get's the average temperature for the last week
 * @param  {String} What type of entry to retrieve
 * @return {Array}  Two-dimentional array with Weekday date/month
 */
var day = function(mode) {
    var days = [];

    return new Promise(function (resolve, reject) {
        connect(function (db) {
            var count = -1;
            var prev = -1;
            var count_internal = 2;

            var cursor = db.collection(mode).find({}).sort({time:-1});

            cursor.each(function (err, doc) {
                if (err) {
                    reject(err);
                }

                assert.equal(err, null);

                if (doc !== null) {
                    if (count <= 7 && doc.time.getDate() == prev) {
                        // Push [hh:mm:ss, temp|load] to days
                        days[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + '/' +
                                        (doc.time.getMonth() + 1),
                                        (days[count][1] + (doc.temp || doc.load)) / 2];
                        count_internal++;
                    } else if (count <= 7 && doc.time.getDate() != prev) {
                        count++;
                        prev = doc.time.getDate();
                        // Push [hh:mm:ss, temp|load] to days
                        days[count] = [WEEKDAYS[doc.time.getDay()] + ' ' +
                                        doc.time.getDate() + '/' +
                                        (doc.time.getMonth() + 1),
                                        0 + (doc.temp || doc.load)];
                        count_internal = 2;
                    } else {
                        resolve(days);
                        db.close();
                    }
                } else {
                    resolve(days);
                    db.close();
                }
            });
        });
    });
};

// Exports

module.exports = {
    insert: insert,
    realtime: realtime,
    minute: minute,
    hour: hour,
    day: day
};
<|endoftext|>


<commit_before>
'use strict';

(function () {
  var Dispatcher = function () {
    this._listeners = [];
    this._maxListeners = 10;
  };

  Dispatcher.prototype._parseListener = function (dependencies, listener) {
    var newListener = {
      fn: listener
    };

    if(typeof dependencies == 'function') {
      newListener.fn = dependencies;
    } else if(Array.isArray(dependencies)) {
      newListener.dependencies = dependencies;
    } else if(typeof dependencies == 'string') {
      newListener.dependencies = [dependencies];
    } else throw new Error('EventHandler is not a function.');

    return newListener;
  };

  Dispatcher.prototype.removeAllListeners = function (eventName) {
    if(eventName || eventName == 0) return this.off(eventName);
    this._listeners = [];
  };

    // some other time
  Dispatcher.prototype.setMaxListeners = function (num) {
    this._maxListeners = num;
  };

  Dispatcher.prototype.on = function (eventName, dependencies, listener) {
    if(this.listeners(eventName).length >= this._maxListeners)
      return;

    listener = this._parseListener(dependencies, listener);
    listener.eventName = eventName;
    this._listeners.push(listener);
    if(eventName != 'newListener')
      this.emit('newListener', listener.fn);
  };

  Dispatcher.prototype.once = function (eventName, dependencies, listener) {
    if(this.listeners(eventName).length >= this._maxListeners)
      return;

    listener = this._parseListener(dependencies, listener);
    listener.eventName = eventName;
    listener.once = true;
    this._listeners.push(listener);
    if(eventName != 'newListener')
      this.emit('newListener', listener.fn);
  };

  Dispatcher.prototype.off = function (eventName, listener) {
    if(typeof eventName === 'undefined') return;
    if(listener) {
      var i = this._listeners.length;
      while(i--) {
        if(eventName == this._listeners[i].eventName && this._listeners[i].fn === listener) {
          this.emit('removeListener', this._listeners[i].fn);
          this._listeners.splice(i, 1);
        }
      }
    }
    else {
      var i = this._listeners.length;
      while(i--) {
        if(eventName == this._listeners[i].eventName) {
          this.emit('removeListener', this._listeners[i].fn)
          this._listeners.splice(i, 1);
        }
      }
    }
  };

  Dispatcher.prototype.listeners = function (eventName) {
    if(!eventName)
      return this._listeners;

    var eventParts = eventName.split('.')
      , eventName = eventParts[0]
      , namespace = eventParts[1] ? '.' + eventParts[1] : null
      , _match
      , results = [];

    if(namespace)
      _match = this._matchWithNamespace;
    else
      _match = this._matchEvent;

    if(typeof this._listeners.filter == 'function')
      return this._listeners.filter(function (listener) {
        return _match(eventName, listener.eventName, namespace);
      });
    else {
      for(var i = 0; i < this._listeners; i++) {
        if(_match(eventName, listener.eventName, namespace))
          results.push(listener);
      }
      return results;
    }
  };

  Dispatcher.prototype._matchWithNamespace = function (eventName, listenerEventName, namespace) {
    return eventName == listenerEventName || eventName.indexOf(listenerEventName + ':') == 0
    || listenerEventName == namespace || listenerEventName == '*'
    || eventName.indexOf(listenerEventName.substring(0, listenerEventName.indexOf('.')) + ':') == 0;
  };

  Dispatcher.prototype._matchEvent = function (eventName, listenerEventName) {
    return eventName == listenerEventName || eventName.indexOf(listenerEventName + ':') == 0
    || listenerEventName.indexOf(eventName + '.') == 0 || listenerEventName == '*'
    || eventName.indexOf(listenerEventName.substring(0, listenerEventName.indexOf('.')) + ':') == 0;
  };

  Dispatcher.prototype._matchArray = function (listenerArray, eventName) {
    var _match, listener;

    // check for namespace
    if(eventName.indexOf('.') != -1) {
      var eventParts = eventName.split('.')
        , eventName = eventParts[0]
        , namespace = eventParts[1] ? '.' + eventParts[1] : null
      _match = this._matchWithNamespace;
    } else {
      _match = this._matchEvent;
    }

    while(listener = listenerArray.pop()) {
      if(_match(eventName, listener.eventName, namespace) || listener.eventName.substring(listener.eventName.indexOf('.')) == namespace && listener.eventName != '*')
        return true;
    }

    return false;
  };

  Dispatcher.prototype._deferredLoop = function (deferredListeners, waitingAsync, context) {
    var deferredLength, listener, promise, dependent
      , _this = this
      , deadlockCounter = 0;

    deferredLength = deadlockCounter = deferredListeners.length;

    while(listener = deferredListeners.pop()) {
      if(deadlockCounter == 0) {
        if(!waitingAsync) {
            throw new Error('Deadlock!');
        } else {
          return;
        }
      }
      dependent = false;

      if(!listener.dependencies) {
        deferredListeners.unshift(listener);
        deadlockCounter--;
        continue;
      }

      for(var j = 0; j < listener.dependencies.length; j++) {
        dependent = _this._matchArray(deferredListeners.slice(), listener.dependencies[j]) ? true : dependent;
      }

      if(!dependent) {
        // run listener
        promise = listener.fn(context);

        if(promise && promise.then) {
          waitingAsync++;
          deferredListeners.unshift(listener);

          // run promise
          promise.then(function () {
            waitingAsync--;
            _this._deferredLoop(deferredListeners, waitingAsync, context);
          });
        }

      } else {
        deferredListeners.unshift(listener);
      }

      if(deferredListeners.length == deferredLength)
        deadlockCounter--;
      else
        deferredLength = deadlockCounter = deferredListeners.length;
    }
  };

  Dispatcher.prototype.emit = function (eventName) {
    if(!eventName) {
      throw new Error('Nothing to emit.');
    }

    // common variables
    var deferredListeners = []
      , listenerArray = this._listeners.slice()
      , waitingAsync = 0
      , _this = this
      , context = {
        arguments: typeof arguments == 'object' ? Array.prototype.slice.call(arguments, 1) : [],
        event: eventName
      }
      , listener, _match, promise;

    // check for namespace
    if(eventName.indexOf('.') != -1) {
      var eventParts = eventName.split('.')
        , eventName = eventParts[0]
        , namespace = eventParts[1] ? '.' + eventParts[1] : null;
      _match = _this._matchWithNamespace;
    } else {
      _match = _this._matchEvent;
    }

    if(!eventName) {
      throw new Error('Nothing to emit.');
    }

    while(listener = listenerArray.pop()) {
      // check if current listener matches
      if(_match(eventName, listener.eventName, namespace)) {
        // dependencies
        if(listener.dependencies) {
          deferredListeners.push(listener);
          continue;
        }

        // run listener
        promise = listener.fn(context);

        if(promise && promise.then) {
          waitingAsync++;
          deferredListeners.push(listener);

          // run promise
          promise.then(function () {
            waitingAsync--;
            _this._deferredLoop(deferredListeners, waitingAsync, context);
          });
        }

        // remove one time listeners
        if(listener.once)
          _this._listeners.splice(listenerArray.length, 1);
      }
    }

    // check if there is callback dependency
    if(deferredListeners.length > 0)
      _this._deferredLoop(deferredListeners, waitingAsync, context);
  };

  Dispatcher.prototype.removeListener = Dispatcher.off;
  Dispatcher.prototype.addListener = Dispatcher.on;

  if (typeof define === 'function' && define.amd) {
     // AMD. Register as an anonymous module.
    define(function() {
      return Dispatcher;
    });
  } else if (typeof exports === 'object') {
    // CommonJS
    module.exports = Dispatcher;
  }
  else {
    // Browser global.
    window.Dispatcher = Dispatcher;
  }
})();
<commit_msg>fixing a bug occurred when both browserify and requirejs are used<commit_after>
'use strict';

(function () {
  var Dispatcher = function () {
    this._listeners = [];
    this._maxListeners = 10;
  };

  Dispatcher.prototype._parseListener = function (dependencies, listener) {
    var newListener = {
      fn: listener
    };

    if(typeof dependencies == 'function') {
      newListener.fn = dependencies;
    } else if(Array.isArray(dependencies)) {
      newListener.dependencies = dependencies;
    } else if(typeof dependencies == 'string') {
      newListener.dependencies = [dependencies];
    } else throw new Error('EventHandler is not a function.');

    return newListener;
  };

  Dispatcher.prototype.removeAllListeners = function (eventName) {
    if(eventName || eventName == 0) return this.off(eventName);
    this._listeners = [];
  };

    // some other time
  Dispatcher.prototype.setMaxListeners = function (num) {
    this._maxListeners = num;
  };

  Dispatcher.prototype.on = function (eventName, dependencies, listener) {
    if(this.listeners(eventName).length >= this._maxListeners)
      return;

    listener = this._parseListener(dependencies, listener);
    listener.eventName = eventName;
    this._listeners.push(listener);
    if(eventName != 'newListener')
      this.emit('newListener', listener.fn);
  };

  Dispatcher.prototype.once = function (eventName, dependencies, listener) {
    if(this.listeners(eventName).length >= this._maxListeners)
      return;

    listener = this._parseListener(dependencies, listener);
    listener.eventName = eventName;
    listener.once = true;
    this._listeners.push(listener);
    if(eventName != 'newListener')
      this.emit('newListener', listener.fn);
  };

  Dispatcher.prototype.off = function (eventName, listener) {
    if(typeof eventName === 'undefined') return;
    if(listener) {
      var i = this._listeners.length;
      while(i--) {
        if(eventName == this._listeners[i].eventName && this._listeners[i].fn === listener) {
          this.emit('removeListener', this._listeners[i].fn);
          this._listeners.splice(i, 1);
        }
      }
    }
    else {
      var i = this._listeners.length;
      while(i--) {
        if(eventName == this._listeners[i].eventName) {
          this.emit('removeListener', this._listeners[i].fn)
          this._listeners.splice(i, 1);
        }
      }
    }
  };

  Dispatcher.prototype.listeners = function (eventName) {
    if(!eventName)
      return this._listeners;

    var eventParts = eventName.split('.')
      , eventName = eventParts[0]
      , namespace = eventParts[1] ? '.' + eventParts[1] : null
      , _match
      , results = [];

    if(namespace)
      _match = this._matchWithNamespace;
    else
      _match = this._matchEvent;

    if(typeof this._listeners.filter == 'function')
      return this._listeners.filter(function (listener) {
        return _match(eventName, listener.eventName, namespace);
      });
    else {
      for(var i = 0; i < this._listeners; i++) {
        if(_match(eventName, listener.eventName, namespace))
          results.push(listener);
      }
      return results;
    }
  };

  Dispatcher.prototype._matchWithNamespace = function (eventName, listenerEventName, namespace) {
    return eventName == listenerEventName || eventName.indexOf(listenerEventName + ':') == 0
    || listenerEventName == namespace || listenerEventName == '*'
    || eventName.indexOf(listenerEventName.substring(0, listenerEventName.indexOf('.')) + ':') == 0;
  };

  Dispatcher.prototype._matchEvent = function (eventName, listenerEventName) {
    return eventName == listenerEventName || eventName.indexOf(listenerEventName + ':') == 0
    || listenerEventName.indexOf(eventName + '.') == 0 || listenerEventName == '*'
    || eventName.indexOf(listenerEventName.substring(0, listenerEventName.indexOf('.')) + ':') == 0;
  };

  Dispatcher.prototype._matchArray = function (listenerArray, eventName) {
    var _match, listener;

    // check for namespace
    if(eventName.indexOf('.') != -1) {
      var eventParts = eventName.split('.')
        , eventName = eventParts[0]
        , namespace = eventParts[1] ? '.' + eventParts[1] : null
      _match = this._matchWithNamespace;
    } else {
      _match = this._matchEvent;
    }

    while(listener = listenerArray.pop()) {
      if(_match(eventName, listener.eventName, namespace) || listener.eventName.substring(listener.eventName.indexOf('.')) == namespace && listener.eventName != '*')
        return true;
    }

    return false;
  };

  Dispatcher.prototype._deferredLoop = function (deferredListeners, waitingAsync, context) {
    var deferredLength, listener, promise, dependent
      , _this = this
      , deadlockCounter = 0;

    deferredLength = deadlockCounter = deferredListeners.length;

    while(listener = deferredListeners.pop()) {
      if(deadlockCounter == 0) {
        if(!waitingAsync) {
            throw new Error('Deadlock!');
        } else {
          return;
        }
      }
      dependent = false;

      if(!listener.dependencies) {
        deferredListeners.unshift(listener);
        deadlockCounter--;
        continue;
      }

      for(var j = 0; j < listener.dependencies.length; j++) {
        dependent = _this._matchArray(deferredListeners.slice(), listener.dependencies[j]) ? true : dependent;
      }

      if(!dependent) {
        // run listener
        promise = listener.fn(context);

        if(promise && promise.then) {
          waitingAsync++;
          deferredListeners.unshift(listener);

          // run promise
          promise.then(function () {
            waitingAsync--;
            _this._deferredLoop(deferredListeners, waitingAsync, context);
          });
        }

      } else {
        deferredListeners.unshift(listener);
      }

      if(deferredListeners.length == deferredLength)
        deadlockCounter--;
      else
        deferredLength = deadlockCounter = deferredListeners.length;
    }
  };

  Dispatcher.prototype.emit = function (eventName) {
    if(!eventName) {
      throw new Error('Nothing to emit.');
    }

    // common variables
    var deferredListeners = []
      , listenerArray = this._listeners.slice()
      , waitingAsync = 0
      , _this = this
      , context = {
        arguments: typeof arguments == 'object' ? Array.prototype.slice.call(arguments, 1) : [],
        event: eventName
      }
      , listener, _match, promise;

    // check for namespace
    if(eventName.indexOf('.') != -1) {
      var eventParts = eventName.split('.')
        , eventName = eventParts[0]
        , namespace = eventParts[1] ? '.' + eventParts[1] : null;
      _match = _this._matchWithNamespace;
    } else {
      _match = _this._matchEvent;
    }

    if(!eventName) {
      throw new Error('Nothing to emit.');
    }

    while(listener = listenerArray.pop()) {
      // check if current listener matches
      if(_match(eventName, listener.eventName, namespace)) {
        // dependencies
        if(listener.dependencies) {
          deferredListeners.push(listener);
          continue;
        }

        // run listener
        promise = listener.fn(context);

        if(promise && promise.then) {
          waitingAsync++;
          deferredListeners.push(listener);

          // run promise
          promise.then(function () {
            waitingAsync--;
            _this._deferredLoop(deferredListeners, waitingAsync, context);
          });
        }

        // remove one time listeners
        if(listener.once)
          _this._listeners.splice(listenerArray.length, 1);
      }
    }

    // check if there is callback dependency
    if(deferredListeners.length > 0)
      _this._deferredLoop(deferredListeners, waitingAsync, context);
  };

  Dispatcher.prototype.removeListener = Dispatcher.off;
  Dispatcher.prototype.addListener = Dispatcher.on;

  if (typeof exports === 'object') {
    // CommonJS
    module.exports = Dispatcher;
  }
  else if (typeof define === 'function' && define.amd) {
     // AMD. Register as an anonymous module.
    define(function() {
      return Dispatcher;
    });
  }
  else {
    // Browser global.
    window.Dispatcher = Dispatcher;
  }
})();
<|endoftext|>


<commit_before>import config from 'config';
import _ from 'lodash';
import Promise from 'bluebird';
import juice from 'juice';
import nodemailer from 'nodemailer';
import debugLib from 'debug';
import templates from './emailTemplates';
import activities from '../constants/activities';
import {isEmailInternal} from './utils';
import crypto from 'crypto';
import fs from 'fs';

const debug = debugLib('email');

const render = (template, data) => {

  let text, filepath;
  data.logoNotSvg = data.group && data.group.logo && !data.group.logo.endsWith('.svg');
  data = _.merge({}, data);
  delete data.config;
  data.config = { host: config.host };

  if (templates[`${template}.text`]) {
    text = templates[`${template}.text`](data);
  }
  const html = juice(templates[template](data));
  const slug = data.group && data.group.slug || data.recipient && data.recipient.username;

  // When in preview mode, we export an HTML version of the email in `/tmp/:template.:slug.html`
  if (process.env.DEBUG && process.env.DEBUG.match(/preview/)) {
    filepath = `/tmp/${template}.${slug}.html`;
    const script = `<script>data=${JSON.stringify(data)};</script>`;
    fs.writeFileSync(filepath, `${html}\n\n${script}`);
    console.log(`Preview email template: file://${filepath}`);
    if (text) {
      filepath = `/tmp/${template}.${slug}.txt`;
      fs.writeFileSync(filepath, text);
      console.log(`Preview email template: file://${filepath}`);
    }
  }

  // When in development mode, we log the data used to compile the template
  // (useful to get login token without sending an email)
  if (process.env.NODE_ENV === 'development' && process.env.DEBUG && process.env.DEBUG.match(/email/)) {
    console.log(`Rendering ${template} with data`, data);
  }

  return {text, html};
};

const generateUnsubscribeToken = (email, groupSlug, type) => {
  const uid = `${email}.${groupSlug}.${type}.${config.keys.opencollective.secret}`;
  const token = crypto.createHash('md5').update(uid).digest("hex");
  return token;
}

/*
 * Gets the body from a string (usually a template)
 */
const getTemplateAttributes = (str) => {
  let index = 0;
  const lines = str.split('\n');
  const attributes = {};
  let tokens;
  do {
    tokens = lines[index++].match(/^([a-z]+):(.+)/i);
    if (tokens) {
      attributes[tokens[1].toLowerCase()] = tokens[2].replace(/<br( \/)?>/g,'\n').trim();
    }
  } while (tokens);

  attributes.body = lines.slice(index).join('\n').trim();
  return attributes;
};

/*
 * sends an email message to a recipient with given subject and body
 */
const sendMessage = (recipients, subject, html, options = {}) => {
  options.bcc = options.bcc || `ops@opencollective.com`;

  if (!_.isArray(recipients)) recipients = [ recipients ];

  recipients = recipients.filter(recipient => {
    if (!recipient || !recipient.match(/.+@.+\..+/)) {
      debug(`${recipient} is an invalid email address, skipping`);
      return false;
    }
    // if not in production, only send out emails to bcc'd opencollective address
    if (process.env.NODE_ENV !== 'production' && !isEmailInternal(recipient)) {
      debug(`${recipient} is an external email address, skipping in development environment`);
      return false;
    } else {
      return true;
    }
  });

  if (process.env.NODE_ENV === 'staging') {
    subject = `[STAGING] ${subject}`;
  } else if (process.env.NODE_ENV !== 'production'){
    subject = `[TESTING] ${subject}`;
  }

  if (process.env.ONLY) {
    debug("Only sending email to ", process.env.ONLY);
    recipients = [process.env.ONLY];
  }

  debug(`sending email to ${recipients.join(', ')}`);
  if (recipients.length === 0) {
    debug("No recipient to send to, only sending to bcc", options.bcc);
  }

  if (config.mailgun.user) {
    const mailgun = nodemailer.createTransport({
      service: 'Mailgun',
      auth: {
        user: config.mailgun.user,
        pass: config.mailgun.password
      }
    });

    return new Promise((resolve, reject) => {
      let to;
      if (recipients.length > 0) {
        to = recipients.join(', ');
      }
      const from = options.from || config.email.from;
      const bcc = options.bcc;
      const text = options.text;
      debug("mailgun> sending email to ", to,"bcc", bcc, "text", text);
      mailgun.sendMail({ from, to, bcc, subject, text, html }, (err, info) => {
        if (err) {
          return reject(err);
        } else {
          return resolve(info);
        }
      })
    });
  } else {
    console.warn("Warning: No mail sent - Mailgun is not configured");
    return Promise.resolve();
  }
};

const getNotificationLabel = (template, recipient) => {

  template = template.replace('.text', '');

  const notificationTypeLabels = {
    'group.monthlyreport': 'monthly reports',
    'user.yearlyreport': 'yearly reports',
    'group.transaction.created': 'notifications of new transactions for this collective',
    'group.expense.created': 'notifications of new expenses submitted to this collective',
    'email.approve': 'notifications of new emails pending approval',
    'email.message': recipient
  }

  return notificationTypeLabels[template];
};

/*
 * Given a template, recipient and data, generates email.
 */
const generateEmailFromTemplate = (template, recipient, data, options = {}) => {

  if (template === 'thankyou') {
    if (data.group.name.match(/WWCode/i))
      template += '.wwcode';
    if (data.group.name.match(/ispcwa/i))
      template += '.ispcwa';
    if (data.group.slug === 'brusselstogether')
      template = 'thankyou.brusselstogether';
    if (_.contains(['lesbarbares', 'nuitdebout', 'laprimaire'], data.group.slug)) {
      template += '.fr';

      if (data.group.slug === 'laprimaire')
        template = 'thankyou.laprimaire';

      // xdamman: hack
      switch (data.interval) {
        case 'month':
          data.interval = 'mois';
          break;
        case 'year':
          data.interval = 'an';
          break;
      }
    }
  }

  if (template === 'group.transaction.created') {
    template = (data.transaction.amount > 0) ? 'group.donation.created' : 'group.expense.paid';
    if (data.user && data.user.twitterHandle) {
      const groupMention = (data.group.twitterHandle) ? `@${data.group.twitterHandle}` : data.group.name;
      const text = `Hi @${data.user.twitterHandle} thanks for your donation to ${groupMention} https://opencollective.com/${data.group.slug} 🎉😊`;
      data.tweet = {
        text,
        encoded: encodeURIComponent(text)
      };
    }
  }

  const slug = (data.group && data.group.slug) ? data.group.slug : 'undefined';

  data.unsubscribeUrl = `${config.host.website}/api/services/email/unsubscribe/${encodeURIComponent(options.bcc || recipient)}/${slug}/${options.type || template}/${generateUnsubscribeToken(options.bcc || recipient, slug, options.type || template)}`;
  data.notificationTypeLabel = getNotificationLabel(template, recipient);
  data.config = config;
  data.utm = `utm_source=opencollective&utm_campaign=${template}&utm_medium=email`;

  if (!templates[template]) {
    return Promise.reject(new Error("Invalid email template"));
  }
  return Promise.resolve(render(template, data));
};

/*
 * Given a template, recipient and data, generates email and sends it.
 * Deprecated. Should use sendMessageFromActivity() for sending new emails.
 */
const generateEmailFromTemplateAndSend = (template, recipient, data, options = {}) => {
  return generateEmailFromTemplate(template, recipient, data, options)
    .then(renderedTemplate => {
      const attributes = getTemplateAttributes(renderedTemplate.html);
      options.text = renderedTemplate.text;
      return emailLib.sendMessage(recipient, attributes.subject, attributes.body, options)
    });
};

/*
 * Given an activity, it sends out an email to the right people and right template
 */
const sendMessageFromActivity = (activity, notification) => {
  const data = activity.data;
  switch (activity.type) {
    case activities.GROUP_TRANSACTION_CREATED:
      return generateEmailFromTemplateAndSend('group.transaction.created', notification.User.email, data);
    case activities.GROUP_EXPENSE_CREATED:
      data.actions = {
        approve: notification.User.generateLoginLink(`/${data.group.slug}/expenses/${data.expense.id}/approve`),
        reject: notification.User.generateLoginLink(`/${data.group.slug}/expenses/${data.expense.id}/reject`)
      };
      return generateEmailFromTemplateAndSend('group.expense.created', notification.User.email, data);
    case activities.GROUP_EXPENSE_APPROVED:
      data.actions = {
        view: notification.User.generateLoginLink(`/${data.group.slug}/transactions/expenses#exp${data.expense.id}`)
      }
      return generateEmailFromTemplateAndSend('group.expense.approved.for.host', notification.User.email, data);
    default:
      return Promise.resolve();
  }
}

const emailLib = {
  render,
  getTemplateAttributes,
  sendMessage,
  generateEmailFromTemplate,
  send: generateEmailFromTemplateAndSend,
  sendMessageFromActivity
};

export default emailLib;
<commit_msg>Update email.js<commit_after>import config from 'config';
import _ from 'lodash';
import Promise from 'bluebird';
import juice from 'juice';
import nodemailer from 'nodemailer';
import debugLib from 'debug';
import templates from './emailTemplates';
import activities from '../constants/activities';
import {isEmailInternal} from './utils';
import crypto from 'crypto';
import fs from 'fs';

const debug = debugLib('email');

const render = (template, data) => {

  let text, filepath;
  data.logoNotSvg = data.group && data.group.logo && !data.group.logo.endsWith('.svg');
  data = _.merge({}, data);
  delete data.config;
  data.config = { host: config.host };

  if (templates[`${template}.text`]) {
    text = templates[`${template}.text`](data);
  }
  const html = juice(templates[template](data));
  const slug = data.group && data.group.slug || data.recipient && data.recipient.username;

  // When in preview mode, we export an HTML version of the email in `/tmp/:template.:slug.html`
  if (process.env.DEBUG && process.env.DEBUG.match(/preview/)) {
    filepath = `/tmp/${template}.${slug}.html`;
    const script = `<script>data=${JSON.stringify(data)};</script>`;
    fs.writeFileSync(filepath, `${html}\n\n${script}`);
    console.log(`Preview email template: file://${filepath}`);
    if (text) {
      filepath = `/tmp/${template}.${slug}.txt`;
      fs.writeFileSync(filepath, text);
      console.log(`Preview email template: file://${filepath}`);
    }
  }

  // When in development mode, we log the data used to compile the template
  // (useful to get login token without sending an email)
  if (process.env.NODE_ENV === 'development' && process.env.DEBUG && process.env.DEBUG.match(/email/)) {
    console.log(`Rendering ${template} with data`, data);
  }

  return {text, html};
};

const generateUnsubscribeToken = (email, groupSlug, type) => {
  const uid = `${email}.${groupSlug}.${type}.${config.keys.opencollective.secret}`;
  const token = crypto.createHash('md5').update(uid).digest("hex");
  return token;
}

/*
 * Gets the body from a string (usually a template)
 */
const getTemplateAttributes = (str) => {
  let index = 0;
  const lines = str.split('\n');
  const attributes = {};
  let tokens;
  do {
    tokens = lines[index++].match(/^([a-z]+):(.+)/i);
    if (tokens) {
      attributes[tokens[1].toLowerCase()] = tokens[2].replace(/<br( \/)?>/g,'\n').trim();
    }
  } while (tokens);

  attributes.body = lines.slice(index).join('\n').trim();
  return attributes;
};

/*
 * sends an email message to a recipient with given subject and body
 */
const sendMessage = (recipients, subject, html, options = {}) => {
  options.bcc = options.bcc || `ops@opencollective.com`;

  if (!_.isArray(recipients)) recipients = [ recipients ];

  recipients = recipients.filter(recipient => {
    if (!recipient || !recipient.match(/.+@.+\..+/)) {
      debug(`${recipient} is an invalid email address, skipping`);
      return false;
    }
    // if not in production, only send out emails to bcc'd opencollective address
    if (process.env.NODE_ENV !== 'production' && !isEmailInternal(recipient)) {
      debug(`${recipient} is an external email address, skipping in development environment`);
      return false;
    } else {
      return true;
    }
  });

  if (process.env.NODE_ENV === 'staging') {
    subject = `[STAGING] ${subject}`;
  } else if (process.env.NODE_ENV !== 'production'){
    subject = `[TESTING] ${subject}`;
  }

  if (process.env.ONLY) {
    debug("Only sending email to ", process.env.ONLY);
    recipients = [process.env.ONLY];
  }

  debug(`sending email to ${recipients.join(', ')}`);
  if (recipients.length === 0) {
    debug("No recipient to send to, only sending to bcc", options.bcc);
  }

  if (config.mailgun.user) {
    const mailgun = nodemailer.createTransport({
      service: 'Mailgun',
      auth: {
        user: config.mailgun.user,
        pass: config.mailgun.password
      }
    });

    return new Promise((resolve, reject) => {
      let to;
      if (recipients.length > 0) {
        to = recipients.join(', ');
      }
      const from = options.from || config.email.from;
      const bcc = options.bcc;
      const text = options.text;
      debug("mailgun> sending email to ", to,"bcc", bcc, "text", text);
      mailgun.sendMail({ from, to, bcc, subject, text, html }, (err, info) => {
        if (err) {
          return reject(err);
        } else {
          return resolve(info);
        }
      })
    });
  } else {
    console.warn("Warning: No mail sent - Mailgun is not configured");
    return Promise.resolve();
  }
};

const getNotificationLabel = (template, recipient) => {

  template = template.replace('.text', '');

  const notificationTypeLabels = {
    'group.monthlyreport': 'monthly reports',
    'user.yearlyreport': 'yearly reports',
    'group.transaction.created': 'notifications of new transactions for this collective',
    'group.expense.created': 'notifications of new expenses submitted to this collective',
    'email.approve': 'notifications of new emails pending approval',
    'email.message': recipient
  }

  return notificationTypeLabels[template];
};

/*
 * Given a template, recipient and data, generates email.
 */
const generateEmailFromTemplate = (template, recipient, data, options = {}) => {

  if (template === 'thankyou') {
    if (data.group.name.match(/WWCode/i))
      template += '.wwcode';
    if (data.group.name.match(/ispcwa/i))
      template += '.ispcwa';
    if (data.group.slug === 'brusselstogether')
      template = 'thankyou.brusselstogether';
    if (_.contains(['lesbarbares', 'nuitdebout', 'laprimaire'], data.group.slug)) {
      template += '.fr';

      if (data.group.slug === 'laprimaire')
        template = 'thankyou.laprimaire';

      // xdamman: hack
      switch (data.interval) {
        case 'month':
          data.interval = 'mois';
          break;
        case 'year':
          data.interval = 'an';
          break;
      }
    }
  }

  if (template === 'group.transaction.created') {
    template = (data.transaction.amount > 0) ? 'group.donation.created' : 'group.expense.paid';
    if (data.user && data.user.twitterHandle) {
      const groupMention = (data.group.twitterHandle) ? `@${data.group.twitterHandle}` : data.group.name;
      const text = `Hi @${data.user.twitterHandle} thanks for your donation to ${groupMention} https://opencollective.com/${data.group.slug} 🎉😊`;
      data.tweet = {
        text,
        encoded: encodeURIComponent(text)
      };
    }
  }

  const slug = (data.group && data.group.slug) ? data.group.slug : 'undefined';

  data.unsubscribeUrl = `${config.host.website}/api/services/email/unsubscribe/${encodeURIComponent(options.bcc || recipient)}/${slug}/${options.type || template}/${generateUnsubscribeToken(options.bcc || recipient, slug, options.type || template)}`;
  data.notificationTypeLabel = getNotificationLabel(template, recipient);
  data.config = config;
  data.utm = `utm_source=opencollective&utm_campaign=${template}&utm_medium=email`;

  if (!templates[template]) {
    return Promise.reject(new Error("Invalid email template"));
  }
  return Promise.resolve(render(template, data));
};

/*
 * Given a template, recipient and data, generates email and sends it.
 * Deprecated. Should use sendMessageFromActivity() for sending new emails.
 */
const generateEmailFromTemplateAndSend = (template, recipient, data, options = {}) => {
  return generateEmailFromTemplate(template, recipient, data, options)
    .then(renderedTemplate => {
      const attributes = getTemplateAttributes(renderedTemplate.html);
      options.text = renderedTemplate.text;
      return emailLib.sendMessage(recipient, attributes.subject, attributes.body, options)
    });
};

/*
 * Given an activity, it sends out an email to the right people and right template
 */
const sendMessageFromActivity = (activity, notification) => {
  const data = activity.data;
  switch (activity.type) {
    case activities.GROUP_TRANSACTION_CREATED:
      return generateEmailFromTemplateAndSend('group.transaction.created', notification.User.email, data);
    case activities.GROUP_EXPENSE_CREATED:
      data.actions = {
        approve: notification.User.generateLoginLink(`/${data.group.slug}/expenses/${data.expense.id}/approve`),
        reject: notification.User.generateLoginLink(`/${data.group.slug}/expenses/${data.expense.id}/reject`)
      };
      return generateEmailFromTemplateAndSend('group.expense.created', notification.User.email, data);
    case activities.GROUP_EXPENSE_APPROVED:
      data.actions = {
        viewExpenseUrl: notification.User.generateLoginLink(`/${data.group.slug}/transactions/expenses#exp${data.expense.id}`)
      }
      return generateEmailFromTemplateAndSend('group.expense.approved.for.host', notification.User.email, data);
    default:
      return Promise.resolve();
  }
}

const emailLib = {
  render,
  getTemplateAttributes,
  sendMessage,
  generateEmailFromTemplate,
  send: generateEmailFromTemplateAndSend,
  sendMessageFromActivity
};

export default emailLib;
<|endoftext|>