<commit_before>/* Read the Docs - Documentation promotions */

var constants = require('./doc-embed/constants');

module.exports = {
    Promo: Promo
};

function Promo (id, text, link, image, theme, display_type, pixel) {
    this.id = id;
    this.text = text;
    this.link = link;
    this.image = image;
    this.theme = theme || constants.THEME_RTD;
    this.display_type = display_type || constants.PROMO_TYPES.LEFTNAV;
    this.pixel = pixel;
    this.promo = null;

    // Handler when a promo receives a click
    this.click_handler = function () {
        if (_gaq) {
            _gaq.push(
                ['rtfd._setAccount', 'UA-17997319-1'],
                ['rtfd._trackEvent', 'Promo', 'Click', self.id]
            );
        }
    };
}

Promo.prototype.create = function () {
    var self = this,
        menu,
        promo_class;
    if (this.theme == constants.THEME_RTD) {
        menu = this.get_sphinx_rtd_theme_promo_selector();
        promo_class = this.display_type === constants.PROMO_TYPES.FOOTER ? 'rtd-pro-footer' : 'wy-menu';
    }
    else if (this.theme == constants.THEME_ALABASTER) {
        menu = this.get_alabaster_promo_selector();
        promo_class = this.display_type === constants.PROMO_TYPES.FOOTER ? 'rtd-pro-footer' : 'alabaster';
    }

    if (typeof(menu) != 'undefined') {
        this.place_promo(menu, promo_class);
    }
}

Promo.prototype.place_promo = function (selector, promo_class) {
    var self = this;

    // Add elements
    var promo = $('
')
        .attr('class', 'rtd-pro ' + promo_class);

    // Promo info
    var promo_about = $('
')
        .attr('class', 'rtd-pro-about');
    var promo_about_link = $('')
        .attr('href', 'https://readthedocs.org/sustainability/advertising/')
        .appendTo(promo_about);
    $('').text('Sponsored ').appendTo(promo_about_link);
    var promo_about_icon = $('')
        .attr('class', 'fa fa-info-circle')
        .appendTo(promo_about_link);
    promo_about.appendTo(promo);

    // Promo image
    if (self.pixel) {
        var pixel = $('')
            .attr('style', 'display: none;')
            .attr('src', self.image)
            .appendTo(promo);
    } else {
        // Use a first-party tracking pixel,
        // so we can still count the number of times this is displayed
        var promo_image_link = $('')
            .attr('class', 'rtd-pro-image-wrapper')
            .attr('href', self.link)
            .attr('target', '_blank')
            .on('click', this.click_handler);
        var promo_image = $('')
            .attr('class', 'rtd-pro-image')
            .attr('src', self.image)
            .appendTo(promo_image_link);
        promo.append(promo_image_link);
    }

    // Create link with callback
    var promo_text = $('')
        .html(self.text);
    $(promo_text).find('a').each(function () {
        $(this)
            .attr('class', 'rtd-pro-link')
            .attr('href', self.link)
            .attr('target', '_blank')
            .on('click', this.click_handler);
    });
    promo.append(promo_text);

    var copy_text = $(
    '
' +
    'Ads served ethically' +
    '
'
    )
    promo.append(copy_text);

    promo.appendTo(selector);

    promo.wrapper = $('
')
        .attr('class', 'rtd-pro-wrapper')
        .appendTo(selector);

    return promo;
};

Promo.prototype.get_alabaster_promo_selector = function () {
    // Return a jQuery selector where the promo goes on the Alabaster theme
    var self = this,
        selector;

    if (self.display_type === constants.PROMO_TYPES.FOOTER) {
        selector = $('
')
            .attr('class', 'rtd-pro-footer-wrapper body')
            .appendTo('div.bodywrapper');
        $('
').insertBefore(selector);
        $('
').insertAfter(selector);
    } else {
        selector = $('div.sphinxsidebar > div.sphinxsidebarwrapper');
    }

    if (selector.length) {
        return selector;
    }
};

Promo.prototype.get_sphinx_rtd_theme_promo_selector = function () {
    // Return a jQuery selector where the promo goes on the RTD theme
    var self = this,
        selector;

    if (self.display_type === constants.PROMO_TYPES.FOOTER) {
        selector = $('
')
            .attr('class', 'rtd-pro-footer-wrapper')
            .insertBefore('footer hr');
        $('
').insertBefore(selector);
    } else {
        selector = $('nav.wy-nav-side > div.wy-side-scroll');
    }

    if (selector.length) {
        return selector;
    }
};

// Position promo
Promo.prototype.display = function () {
    var promo = this.promo,
        self = this;

    if (! promo) {
        promo = this.promo = this.create();
    }

    // Promo still might not exist yet
    if (promo) {
        promo.show();
    }
};

Promo.prototype.disable = function () {
};

// Variant factory method
Promo.from_variants = function (variants) {
    if (variants.length == 0) {
        return null;
    }
    var chosen = Math.floor(Math.random() * variants.length),
        variant = variants[chosen],
        text = variant.text,
        link = variant.link,
        image = variant.image,
        id = variant.id;
    return new Promo(id, text, link, image);
};
<commit_msg>Clean up comment<commit_after>/* Read the Docs - Documentation promotions */

var constants = require('./doc-embed/constants');

module.exports = {
    Promo: Promo
};

function Promo (id, text, link, image, theme, display_type, pixel) {
    this.id = id;
    this.text = text;
    this.link = link;
    this.image = image;
    this.theme = theme || constants.THEME_RTD;
    this.display_type = display_type || constants.PROMO_TYPES.LEFTNAV;
    this.pixel = pixel;
    this.promo = null;

    // Handler when a promo receives a click
    this.click_handler = function () {
        if (_gaq) {
            _gaq.push(
                ['rtfd._setAccount', 'UA-17997319-1'],
                ['rtfd._trackEvent', 'Promo', 'Click', self.id]
            );
        }
    };
}

Promo.prototype.create = function () {
    var self = this,
        menu,
        promo_class;
    if (this.theme == constants.THEME_RTD) {
        menu = this.get_sphinx_rtd_theme_promo_selector();
        promo_class = this.display_type === constants.PROMO_TYPES.FOOTER ? 'rtd-pro-footer' : 'wy-menu';
    }
    else if (this.theme == constants.THEME_ALABASTER) {
        menu = this.get_alabaster_promo_selector();
        promo_class = this.display_type === constants.PROMO_TYPES.FOOTER ? 'rtd-pro-footer' : 'alabaster';
    }

    if (typeof(menu) != 'undefined') {
        this.place_promo(menu, promo_class);
    }
}

Promo.prototype.place_promo = function (selector, promo_class) {
    var self = this;

    // Add elements
    var promo = $('
')
        .attr('class', 'rtd-pro ' + promo_class);

    // Promo info
    var promo_about = $('
')
        .attr('class', 'rtd-pro-about');
    var promo_about_link = $('')
        .attr('href', 'https://readthedocs.org/sustainability/advertising/')
        .appendTo(promo_about);
    $('').text('Sponsored ').appendTo(promo_about_link);
    var promo_about_icon = $('')
        .attr('class', 'fa fa-info-circle')
        .appendTo(promo_about_link);
    promo_about.appendTo(promo);

    // Promo image
    if (self.pixel) {
        // Use a first-party tracking pixel for text ads,
        // so we can still count the number of times they are displayed
        var pixel = $('')
            .attr('style', 'display: none;')
            .attr('src', self.image)
            .appendTo(promo);
    } else {
        var promo_image_link = $('')
            .attr('class', 'rtd-pro-image-wrapper')
            .attr('href', self.link)
            .attr('target', '_blank')
            .on('click', this.click_handler);
        var promo_image = $('')
            .attr('class', 'rtd-pro-image')
            .attr('src', self.image)
            .appendTo(promo_image_link);
        promo.append(promo_image_link);
    }

    // Create link with callback
    var promo_text = $('')
        .html(self.text);
    $(promo_text).find('a').each(function () {
        $(this)
            .attr('class', 'rtd-pro-link')
            .attr('href', self.link)
            .attr('target', '_blank')
            .on('click', this.click_handler);
    });
    promo.append(promo_text);

    var copy_text = $(
    '
' +
    'Ads served ethically' +
    '
'
    )
    promo.append(copy_text);

    promo.appendTo(selector);

    promo.wrapper = $('
')
        .attr('class', 'rtd-pro-wrapper')
        .appendTo(selector);

    return promo;
};

Promo.prototype.get_alabaster_promo_selector = function () {
    // Return a jQuery selector where the promo goes on the Alabaster theme
    var self = this,
        selector;

    if (self.display_type === constants.PROMO_TYPES.FOOTER) {
        selector = $('
')
            .attr('class', 'rtd-pro-footer-wrapper body')
            .appendTo('div.bodywrapper');
        $('
').insertBefore(selector);
        $('
').insertAfter(selector);
    } else {
        selector = $('div.sphinxsidebar > div.sphinxsidebarwrapper');
    }

    if (selector.length) {
        return selector;
    }
};

Promo.prototype.get_sphinx_rtd_theme_promo_selector = function () {
    // Return a jQuery selector where the promo goes on the RTD theme
    var self = this,
        selector;

    if (self.display_type === constants.PROMO_TYPES.FOOTER) {
        selector = $('
')
            .attr('class', 'rtd-pro-footer-wrapper')
            .insertBefore('footer hr');
        $('
').insertBefore(selector);
    } else {
        selector = $('nav.wy-nav-side > div.wy-side-scroll');
    }

    if (selector.length) {
        return selector;
    }
};

// Position promo
Promo.prototype.display = function () {
    var promo = this.promo,
        self = this;

    if (! promo) {
        promo = this.promo = this.create();
    }

    // Promo still might not exist yet
    if (promo) {
        promo.show();
    }
};

Promo.prototype.disable = function () {
};

// Variant factory method
Promo.from_variants = function (variants) {
    if (variants.length == 0) {
        return null;
    }
    var chosen = Math.floor(Math.random() * variants.length),
        variant = variants[chosen],
        text = variant.text,
        link = variant.link,
        image = variant.image,
        id = variant.id;
    return new Promo(id, text, link, image);
};
<|endoftext|>


<commit_before>/*
  All Emoncms code is released under the GNU Affero General Public License.
  See COPYRIGHT.txt and LICENSE.txt.
    ---------------------------------------------------------------------
    Part of the OpenEnergyMonitor project:
    http://openenergymonitor.org

    Author: Trystan Lea: trystan.lea@googlemail.com
    Enhancements done by: Andreas Messerli firefox7518@gmail.com
    kWPeriod widget instigated by: Daniel Bates @danbates2
    If you have any questions please get in touch, try the forums here:
    http://openenergymonitor.org/emon/forum
 */

var kwhperiod_cache = []
var kwhperiod_lastupdate = 0
var kwhperiod_lastvalue = 0

 function addOption(widget, optionKey, optionType, optionName, optionHint, optionData)
{
  widget["options"    ].push(optionKey);
  widget["optionstype"].push(optionType);
  widget["optionsname"].push(optionName);
  widget["optionshint"].push(optionHint);
  widget["optionsdata"].push(optionData);
}

function kwhperiod_widgetlist()
{
  var widgets =
  {
    "kwhperiod":
    {
      "offsetx":-40,"offsety":-30,"width":120,"height":60,
      "menu":"Widgets",
      "options":    [],
      "optionstype":[],
      "optionsname":[],
      "optionshint":[],
      "optionsdata":[]
    }
  };

  var decimalsDropBoxOptions = [        // Options for the type combobox. Each item is [typeID, "description"]
        [-1,   _Tr("Automatic")],
        [0,    "0"],
        [1,    "1"],
        [2,    "2"],
        [3,    "3"],
        [4,    "4"],
        [5,    "5"],
        [6,    "6"]
    ];

  var periodDropBoxOptions = [        // Options for the type combobox. Each item is [typeID, "description"]
        [0,   "Hour (useage in hour just been)"],
        [1,   "Day (since midnight + offset)"],
        [2,   "Week (7 days exactly"],
        [3,   "Month (28 days exactly)"],
        [4,   "Year (usage in one year exactly"]
    ];

	var fontoptions = [
					[9, "Arial Black"],
					[8, "Arial Narrow"],
					[7, "sans-serif"],
					[6, "Helvetica Neue"],
					[5, "Helvetica"],
					[4, "Comic Sans MS"],
					[3, "Courier New"],
					[2, "Arial"],
					[1, "Georgia"],
					[0, "Impact"]
				];

	var fstyleoptions = [
					[2, _Tr("Normal")],
					[1, _Tr("Italic")],
					[0, _Tr("Oblique")]
				];

	var fweightoptions = [
					[1, _Tr("Bold")],
					[0, _Tr("Normal")]
				];

	var sizeoptions = [
					[14, "18"], // set size 18 to the top position to be the default value for creating new kwhperiod widgets otherwise size 40 would be always the default
					[13, "40"],
					[12, "36"],
					[11, "32"],
					[10, "28"],
					[9, "24"],
					[8, "22"],
					[7, "20"],
					[6, "18"],
					[5, "16"],
					[4, "14"],
					[3, "12"],
					[2, "10"],
					[1, "8"],
					[0, "6"]
				];

  var alignmentOptions = [
    ["center", _Tr("Center")],
    ["left", _Tr("Left")],
    ["right", _Tr("Right")]
  ];

	addOption(widgets["kwhperiod"], "feedid",   "feedid",  _Tr("Feed"),     _Tr("Feed value"),      []);
	addOption(widgets["kwhperiod"], "period",   "dropbox",  _Tr("Period"),     _Tr("Period range"), periodDropBoxOptions);
	addOption(widgets["kwhperiod"], "offset",    "value",   _Tr("Period offset"),    _Tr("Period offset hours, 'day' period only"),   []);
	addOption(widgets["kwhperiod"], "prepend",    "value",   _Tr("Prepend Text"),    _Tr("Prepend Text"),   []);
	addOption(widgets["kwhperiod"], "append",  "value", _Tr("Append Text"), _Tr("Append Text (Units)"), []);
	addOption(widgets["kwhperiod"], "decimals", "dropbox", _Tr("Decimals"), _Tr("Decimals to show"), decimalsDropBoxOptions);
	addOption(widgets["kwhperiod"], "colour",   "colour_picker",  _Tr("Colour"),     _Tr("Colour used for display"),      []);
	addOption(widgets["kwhperiod"], "font",     "dropbox",  _Tr("Font"),     _Tr("Font used for display"),     fontoptions);
	addOption(widgets["kwhperiod"], "fstyle",   "dropbox", _Tr("Font style"), _Tr("Font style used for display"),    fstyleoptions);
	addOption(widgets["kwhperiod"], "fweight",  "dropbox", _Tr("Font weight"), _Tr("Font weight used for display"),    fweightoptions);
	addOption(widgets["kwhperiod"], "size",   	"dropbox", _Tr("Size"), _Tr("Text size in px to use"),    sizeoptions);
	addOption(widgets["kwhperiod"], "align",    "dropbox", _Tr("Alignment"), _Tr("Alignment"), alignmentOptions);
	addOption(widgets["kwhperiod"], "timeout",  "value",   _Tr("Timeout"),    _Tr("Timeout without feed update in seconds (empty is never)"),   []);
	addOption(widgets["kwhperiod"], "errormessagedisplayed",    "value",  _Tr("Error Message"),   _Tr("Error message displayed when timeout is reached"),   []);

	return widgets;
}

function draw_kwhperiod(kwhperiod,font,fstyle,fweight,width,height,prepend,val,append,colour,decimals,size,align,errorCode,errorMessage)
{
    colour = colour || "4444CC";
    size = size || "8";
    font = font || "5";
    fstyle = fstyle || "2";
    fweight = fweight || "1";
    align = align || "center";

    var fontsize;

    if (size === "0"){fontsize = 6;}
    if (size === "1"){fontsize = 8;}
    if (size === "2"){fontsize = 10;}
    if (size === "3"){fontsize = 12;}
    if (size === "4"){fontsize = 14;}
    if (size === "5"){fontsize = 16;}
    if (size === "6"){fontsize = 18;}
    if (size === "7"){fontsize = 20;}
    if (size === "8"){fontsize = 22;}
    if (size === "9"){fontsize = 24;}
    if (size === "10"){fontsize = 28;}
    if (size === "11"){fontsize = 32;}
    if (size === "12"){fontsize = 36;}
    if (size === "13"){fontsize = 40;}
    if (size === "14"){fontsize = 18;}  //default value so that not size 40 is always the default

    var fontname;

    if (font === "0"){fontname = "Impact";}
    if (font === "1"){fontname = "Georgia";}
    if (font === "2"){fontname = "Arial";}
    if (font === "3"){fontname = "Courier New";}
    if (font === "4"){fontname = "Comic Sans MS";}
    if (font === "5"){fontname = "Helvetica";}
    if (font === "6"){fontname = "Helvetica Neue";}
    if (font === "7"){fontname = "sans-serif";}
    if (font === "8"){fontname = "Arial Narrow";}
    if (font === "9"){fontname = "Arial Black";}

    var fontstyle;

    if (fstyle === "0"){fontstyle = "oblique";}
    if (fstyle === "1"){fontstyle = "italic";}
    if (fstyle === "2"){fontstyle = "normal";}

    var fontweight;

    if (fweight === "0"){fontweight = "normal";}
    if (fweight === "1"){fontweight = "bold";}

    if (decimals<0)
    {
        if (val>=100){
            val = val.toFixed(0);
        }
        else if (val>=10){
            val = val.toFixed(1);
        }
        else if (val<=-100){
            val = val.toFixed(0);
        }
        else if (val<=-10){
            val = val.toFixed(1);
        }
        else {
            val = val.toFixed(2);
        }
        val = parseFloat(val);
    }
    else
    {
        val = val.toFixed(decimals);
    }

    if (colour.indexOf("#") === -1) {			// Fix missing "#" on colour if needed
        colour = "#" + colour;
    }

    kwhperiod.css({
        "color":colour,
        "font":fontstyle+" "+ fontweight+" "+ fontsize+"px "+fontname,"text-align":align,
        "line-height":height+"px"
    });

    if (errorCode === "1")
    {
        kwhperiod.html(errorMessage);
    }
    else
    {
        kwhperiod.html(prepend+val+append);
    }
}

function kwhperiod_draw()
{
    $(".kwhperiod").each(function(index)
    {
        var kwhperiod = $(this);
        var errorMessage = $(this).attr("errormessagedisplayed");
        if (errorMessage === "" || errorMessage === undefined){            //Error Message parameter is empty
          errorMessage = "Feed Timeout";
        }
        var errorTimeout = kwhperiod.attr("timeout");
        if (errorTimeout === "" || errorTimeout === undefined){           //Timeout parameter is empty
            errorTimeout = 0;
        }

        var font = kwhperiod.attr("font");
        var feedid = kwhperiod.attr("feedid");
        if (assocfeed[feedid]!=undefined) feedid = assocfeed[feedid]; // convert tag:name to feedid
        if (associd[feedid] === undefined) { console.log("Review config for feed id of " + kwhperiod.attr("class")); return; }
        var val = associd[feedid]["value"] * 1;

        var offset = kwhperiod.attr("offset") * 1;
        if (offset===undefined) offset = 0;
        if (isNaN(offset)) offset = 0;

        var period = kwhperiod.attr("period") * 1;
        if (period===undefined) period = 1; // "day" period default
        if (isNaN(period)) period = 1;

        var now = new Date();

        // Pull in value at given time to subtract (HOUR)
        if (period===0) {
            //	var now = new Date();
            now.setHours(now.getHours() - 1);
            var period_time = now.getTime()/1000;

            if ((period_time-kwhperiod_lastupdate)>60.0) {
                kwhperiod_lastupdate = period_time
                var result = feed.get_value(feedid, period_time*1000);
                kwhperiod_lastvalue = result[1];
            }
            val -= kwhperiod_lastvalue
        }

        // Pull in value at given time to subtract (DAY + offset)
        else if (period===1) {
            now.setHours(0,0,0,0);
            var period_time = now.getTime()/3600000 + offset;

            if (kwhperiod_cache[period_time]==undefined) {
                var result = feed.get_value(feedid, period_time * 3600000);
                kwhperiod_cache[period_time] = result[1];
            }
            val -= kwhperiod_cache[period_time]
        }

        // Pull in value at given time to subtract (WEEK)
        else if (period===2) {
            now.setDate(now.getDate() - 7);
	    now.setSeconds(0,0);
            var period_time = now.getTime();

            if (kwhperiod_cache[period_time]==undefined) {
                var result = feed.get_value(feedid, period_time);
                kwhperiod_cache[period_time] = result[1];
            }
            val -= kwhperiod_cache[period_time]
        }

        // Pull in value at given time to subtract (MONTH)
        else if (period===3) {
            now.setDate(now.getDate() - 28);
	    now.setSeconds(0,0);
            var period_time = now.getTime();

            if (kwhperiod_cache[period_time]==undefined) {
                var result = feed.get_value(feedid, period_time);
                kwhperiod_cache[period_time] = result[1];
            }
            val -= kwhperiod_cache[period_time]
        }

        // Pull in value at given time to subtract (YEAR)
        else if (period===4) {
            now.setDate(now.getDate() - 365);
	    now.setSeconds(0,0);
            var period_time = now.getTime();

            if (kwhperiod_cache[period_time]==undefined) {
                var result = feed.get_value(feedid, period_time);
                kwhperiod_cache[period_time] = result[1];
            }
            val -= kwhperiod_cache[period_time]
        }

        if (val===undefined) {val = 0;}
        if (isNaN(val))  {val = 0;}

	var latest_feedtime = (associd[feedid]["time"] * 1);
	var errorCode = "0";

	var unix_now = Date.now() / 1000;
	var errorTime = parseInt(latest_feedtime) + parseInt(errorTimeout);
//	console.log(unix_now - errorTime);

	if (errorTimeout > 0 && unix_now >= errorTime)
        {
	  errorCode = "1";
        }
	//console.log(errorCode);

        var size = kwhperiod.attr("size");

        var decimals = kwhperiod.attr("decimals");

        if (decimals===undefined) {decimals = -1};

        // backwards compatibility
        var unitend = kwhperiod.attr("unitend");
        var units = kwhperiod.attr("units");

        // new options
        var prepend = kwhperiod.attr("prepend");
        var append = kwhperiod.attr("append");

        // check if new options are undefined: use old
        if (prepend==undefined && append==undefined) {
            if (unitend!=undefined && units!=undefined) {
                if (unitend ==="0") {
                    append = units;
                    prepend = ""
                } else if (unitend ==="1") {
                    prepend = units;
                    append = ""
                }
            } else {
                prepend = ""
                append = ""
            }
        }

        draw_kwhperiod(
            kwhperiod,
            kwhperiod.attr("font"),
            kwhperiod.attr("fstyle"),
            kwhperiod.attr("fweight"),
            kwhperiod.width(),
            kwhperiod.height(),
            prepend,
            val,
            append,
            kwhperiod.attr("colour"),
            kwhperiod.attr("decimals"),
            kwhperiod.attr("size"),
            kwhperiod.attr("align"),
            errorCode,
            errorMessage
        );
    });
}

function kwhperiod_init()
{
	$(".kwhperiod").html("");
	kwhperiod_draw();
}
function kwhperiod_slowupdate()
{
	kwhperiod_draw();
}
function kwhperiod_fastupdate()
{
	//kwhperiod_draw();
}
<commit_msg>Update kwhperiod_render.js<commit_after>/*
  All Emoncms code is released under the GNU Affero General Public License.
  See COPYRIGHT.txt and LICENSE.txt.
    ---------------------------------------------------------------------
    Part of the OpenEnergyMonitor project:
    http://openenergymonitor.org

    Author: Trystan Lea: trystan.lea@googlemail.com
    Enhancements done by: Andreas Messerli firefox7518@gmail.com
    kWhPeriod widget implemented by: Daniel Bates dgbates@mail.uk
    If you have any questions please get in touch, try the forums here:
    http://openenergymonitor.org/emon/forum
 */

var kwhperiod_cache = []
var kwhperiod_lastupdate = 0
var kwhperiod_lastvalue = 0

 function addOption(widget, optionKey, optionType, optionName, optionHint, optionData)
{
  widget["options"    ].push(optionKey);
  widget["optionstype"].push(optionType);
  widget["optionsname"].push(optionName);
  widget["optionshint"].push(optionHint);
  widget["optionsdata"].push(optionData);
}

function kwhperiod_widgetlist()
{
  var widgets =
  {
    "kwhperiod":
    {
      "offsetx":-40,"offsety":-30,"width":120,"height":60,
      "menu":"Widgets",
      "options":    [],
      "optionstype":[],
      "optionsname":[],
      "optionshint":[],
      "optionsdata":[]
    }
  };

  var decimalsDropBoxOptions = [        // Options for the type combobox. Each item is [typeID, "description"]
        [-1,   _Tr("Automatic")],
        [0,    "0"],
        [1,    "1"],
        [2,    "2"],
        [3,    "3"],
        [4,    "4"],
        [5,    "5"],
        [6,    "6"]
    ];

  var periodDropBoxOptions = [        // Options for the type combobox. Each item is [typeID, "description"]
        [0,   "Hour (useage in hour just been)"],
        [1,   "Day (since midnight + offset)"],
        [2,   "Week (7 days exactly"],
        [3,   "Month (28 days exactly)"],
        [4,   "Year (usage in one year exactly"]
    ];

	var fontoptions = [
					[9, "Arial Black"],
					[8, "Arial Narrow"],
					[7, "sans-serif"],
					[6, "Helvetica Neue"],
					[5, "Helvetica"],
					[4, "Comic Sans MS"],
					[3, "Courier New"],
					[2, "Arial"],
					[1, "Georgia"],
					[0, "Impact"]
				];

	var fstyleoptions = [
					[2, _Tr("Normal")],
					[1, _Tr("Italic")],
					[0, _Tr("Oblique")]
				];

	var fweightoptions = [
					[1, _Tr("Bold")],
					[0, _Tr("Normal")]
				];

	var sizeoptions = [
					[14, "18"], // set size 18 to the top position to be the default value for creating new kwhperiod widgets otherwise size 40 would be always the default
					[13, "40"],
					[12, "36"],
					[11, "32"],
					[10, "28"],
					[9, "24"],
					[8, "22"],
					[7, "20"],
					[6, "18"],
					[5, "16"],
					[4, "14"],
					[3, "12"],
					[2, "10"],
					[1, "8"],
					[0, "6"]
				];

  var alignmentOptions = [
    ["center", _Tr("Center")],
    ["left", _Tr("Left")],
    ["right", _Tr("Right")]
  ];

	addOption(widgets["kwhperiod"], "feedid",   "feedid",  _Tr("Feed"),     _Tr("Feed value"),      []);
	addOption(widgets["kwhperiod"], "period",   "dropbox",  _Tr("Period"),     _Tr("Period range"), periodDropBoxOptions);
	addOption(widgets["kwhperiod"], "offset",    "value",   _Tr("Period offset"),    _Tr("Period offset hours, 'day' period only"),   []);
	addOption(widgets["kwhperiod"], "prepend",    "value",   _Tr("Prepend Text"),    _Tr("Prepend Text"),   []);
	addOption(widgets["kwhperiod"], "append",  "value", _Tr("Append Text"), _Tr("Append Text (Units)"), []);
	addOption(widgets["kwhperiod"], "decimals", "dropbox", _Tr("Decimals"), _Tr("Decimals to show"), decimalsDropBoxOptions);
	addOption(widgets["kwhperiod"], "colour",   "colour_picker",  _Tr("Colour"),     _Tr("Colour used for display"),      []);
	addOption(widgets["kwhperiod"], "font",     "dropbox",  _Tr("Font"),     _Tr("Font used for display"),     fontoptions);
	addOption(widgets["kwhperiod"], "fstyle",   "dropbox", _Tr("Font style"), _Tr("Font style used for display"),    fstyleoptions);
	addOption(widgets["kwhperiod"], "fweight",  "dropbox", _Tr("Font weight"), _Tr("Font weight used for display"),    fweightoptions);
	addOption(widgets["kwhperiod"], "size",   	"dropbox", _Tr("Size"), _Tr("Text size in px to use"),    sizeoptions);
	addOption(widgets["kwhperiod"], "align",    "dropbox", _Tr("Alignment"), _Tr("Alignment"), alignmentOptions);
	addOption(widgets["kwhperiod"], "timeout",  "value",   _Tr("Timeout"),    _Tr("Timeout without feed update in seconds (empty is never)"),   []);
	addOption(widgets["kwhperiod"], "errormessagedisplayed",    "value",  _Tr("Error Message"),   _Tr("Error message displayed when timeout is reached"),   []);

	return widgets;
}

function draw_kwhperiod(kwhperiod,font,fstyle,fweight,width,height,prepend,val,append,colour,decimals,size,align,errorCode,errorMessage)
{
    colour = colour || "4444CC";
    size = size || "8";
    font = font || "5";
    fstyle = fstyle || "2";
    fweight = fweight || "1";
    align = align || "center";

    var fontsize;

    if (size === "0"){fontsize = 6;}
    if (size === "1"){fontsize = 8;}
    if (size === "2"){fontsize = 10;}
    if (size === "3"){fontsize = 12;}
    if (size === "4"){fontsize = 14;}
    if (size === "5"){fontsize = 16;}
    if (size === "6"){fontsize = 18;}
    if (size === "7"){fontsize = 20;}
    if (size === "8"){fontsize = 22;}
    if (size === "9"){fontsize = 24;}
    if (size === "10"){fontsize = 28;}
    if (size === "11"){fontsize = 32;}
    if (size === "12"){fontsize = 36;}
    if (size === "13"){fontsize = 40;}
    if (size === "14"){fontsize = 18;}  //default value so that not size 40 is always the default

    var fontname;

    if (font === "0"){fontname = "Impact";}
    if (font === "1"){fontname = "Georgia";}
    if (font === "2"){fontname = "Arial";}
    if (font === "3"){fontname = "Courier New";}
    if (font === "4"){fontname = "Comic Sans MS";}
    if (font === "5"){fontname = "Helvetica";}
    if (font === "6"){fontname = "Helvetica Neue";}
    if (font === "7"){fontname = "sans-serif";}
    if (font === "8"){fontname = "Arial Narrow";}
    if (font === "9"){fontname = "Arial Black";}

    var fontstyle;

    if (fstyle === "0"){fontstyle = "oblique";}
    if (fstyle === "1"){fontstyle = "italic";}
    if (fstyle === "2"){fontstyle = "normal";}

    var fontweight;

    if (fweight === "0"){fontweight = "normal";}
    if (fweight === "1"){fontweight = "bold";}

    if (decimals<0)
    {
        if (val>=100){
            val = val.toFixed(0);
        }
        else if (val>=10){
            val = val.toFixed(1);
        }
        else if (val<=-100){
            val = val.toFixed(0);
        }
        else if (val<=-10){
            val = val.toFixed(1);
        }
        else {
            val = val.toFixed(2);
        }
        val = parseFloat(val);
    }
    else
    {
        val = val.toFixed(decimals);
    }

    if (colour.indexOf("#") === -1) {			// Fix missing "#" on colour if needed
        colour = "#" + colour;
    }

    kwhperiod.css({
        "color":colour,
        "font":fontstyle+" "+ fontweight+" "+ fontsize+"px "+fontname,"text-align":align,
        "line-height":height+"px"
    });

    if (errorCode === "1")
    {
        kwhperiod.html(errorMessage);
    }
    else
    {
        kwhperiod.html(prepend+val+append);
    }
}

function kwhperiod_draw()
{
    $(".kwhperiod").each(function(index)
    {
        var kwhperiod = $(this);
        var errorMessage = $(this).attr("errormessagedisplayed");
        if (errorMessage === "" || errorMessage === undefined){            //Error Message parameter is empty
          errorMessage = "Feed Timeout";
        }
        var errorTimeout = kwhperiod.attr("timeout");
        if (errorTimeout === "" || errorTimeout === undefined){           //Timeout parameter is empty
            errorTimeout = 0;
        }

        var font = kwhperiod.attr("font");
        var feedid = kwhperiod.attr("feedid");
        if (assocfeed[feedid]!=undefined) feedid = assocfeed[feedid]; // convert tag:name to feedid
        if (associd[feedid] === undefined) { console.log("Review config for feed id of " + kwhperiod.attr("class")); return; }
        var val = associd[feedid]["value"] * 1;

        var offset = kwhperiod.attr("offset") * 1;
        if (offset===undefined) offset = 0;
        if (isNaN(offset)) offset = 0;

        var period = kwhperiod.attr("period") * 1;
        if (period===undefined) period = 1; // "day" period default
        if (isNaN(period)) period = 1;

        var now = new Date();

        // Pull in value at given time to subtract (HOUR)
        if (period===0) {
            //	var now = new Date();
            now.setHours(now.getHours() - 1);
            var period_time = now.getTime()/1000;

            if ((period_time-kwhperiod_lastupdate)>60.0) {
                kwhperiod_lastupdate = period_time
                var result = feed.get_value(feedid, period_time*1000);
                kwhperiod_lastvalue = result[1];
            }
            val -= kwhperiod_lastvalue
        }

        // Pull in value at given time to subtract (DAY + offset)
        else if (period===1) {
            now.setHours(0,0,0,0);
            var period_time = now.getTime()/3600000 + offset;

            if (kwhperiod_cache[period_time]==undefined) {
                var result = feed.get_value(feedid, period_time * 3600000);
                kwhperiod_cache[period_time] = result[1];
            }
            val -= kwhperiod_cache[period_time]
        }

        // Pull in value at given time to subtract (WEEK)
        else if (period===2) {
            now.setDate(now.getDate() - 7);
	    now.setSeconds(0,0);
            var period_time = now.getTime();

            if (kwhperiod_cache[period_time]==undefined) {
                var result = feed.get_value(feedid, period_time);
                kwhperiod_cache[period_time] = result[1];
            }
            val -= kwhperiod_cache[period_time]
        }

        // Pull in value at given time to subtract (MONTH)
        else if (period===3) {
            now.setDate(now.getDate() - 28);
	    now.setSeconds(0,0);
            var period_time = now.getTime();

            if (kwhperiod_cache[period_time]==undefined) {
                var result = feed.get_value(feedid, period_time);
                kwhperiod_cache[period_time] = result[1];
            }
            val -= kwhperiod_cache[period_time]
        }

        // Pull in value at given time to subtract (YEAR)
        else if (period===4) {
            now.setDate(now.getDate() - 365);
	    now.setSeconds(0,0);
            var period_time = now.getTime();

            if (kwhperiod_cache[period_time]==undefined) {
                var result = feed.get_value(feedid, period_time);
                kwhperiod_cache[period_time] = result[1];
            }
            val -= kwhperiod_cache[period_time]
        }

        if (val===undefined) {val = 0;}
        if (isNaN(val))  {val = 0;}

	var latest_feedtime = (associd[feedid]["time"] * 1);
	var errorCode = "0";

	var unix_now = Date.now() / 1000;
	var errorTime = parseInt(latest_feedtime) + parseInt(errorTimeout);
//	console.log(unix_now - errorTime);

	if (errorTimeout > 0 && unix_now >= errorTime)
        {
	  errorCode = "1";
        }
	//console.log(errorCode);

        var size = kwhperiod.attr("size");

        var decimals = kwhperiod.attr("decimals");

        if (decimals===undefined) {decimals = -1};

        // backwards compatibility
        var unitend = kwhperiod.attr("unitend");
        var units = kwhperiod.attr("units");

        // new options
        var prepend = kwhperiod.attr("prepend");
        var append = kwhperiod.attr("append");

        // check if new options are undefined: use old
        if (prepend==undefined && append==undefined) {
            if (unitend!=undefined && units!=undefined) {
                if (unitend ==="0") {
                    append = units;
                    prepend = ""
                } else if (unitend ==="1") {
                    prepend = units;
                    append = ""
                }
            } else {
                prepend = ""
                append = ""
            }
        }

        draw_kwhperiod(
            kwhperiod,
            kwhperiod.attr("font"),
            kwhperiod.attr("fstyle"),
            kwhperiod.attr("fweight"),
            kwhperiod.width(),
            kwhperiod.height(),
            prepend,
            val,
            append,
            kwhperiod.attr("colour"),
            kwhperiod.attr("decimals"),
            kwhperiod.attr("size"),
            kwhperiod.attr("align"),
            errorCode,
            errorMessage
        );
    });
}

function kwhperiod_init()
{
	$(".kwhperiod").html("");
	kwhperiod_draw();
}
function kwhperiod_slowupdate()
{
	kwhperiod_draw();
}
function kwhperiod_fastupdate()
{
	//kwhperiod_draw();
}
<|endoftext|>


<commit_before>/*
* This JavaScript file implements everything authentication
* related in the 123done demo. This includes interacting
* with the Persona API, the 123done server, and updating
* the UI to reflect sign-in state.
*/

$(document).ready(function() {
  window.loggedInEmail = null;

  // now check with the server to get our current login state
  $.get('/api/auth_status', function(data) {
    loggedInEmail = JSON.parse(data).email;

    function updateUI(email) {
      $("ul.loginarea li").css('display', 'none');
      if (email) {
        console.log(email);
        $('#loggedin span').text(email);
        $('#loggedin').css('display', 'block');
        $("#splash").hide();
        $("#lists").slideDown(500);
      } else {
        $('#loggedin span').text('');
        $('#loggedout').css('display', 'block');
        $("#splash").show();
        $("#lists").hide();

      }
      $("button").removeAttr('disabled').css('opacity', '1');
    }

    function updateListArea(email) {
      $("section.todo ul").css('display', 'none');
      $("section.todo form").css('display', 'none');
      if (email) {
        $('#addform').css('display', 'block');
        $('#todolist').css('display', 'block');
        $('#donelist').css('display', 'block');
      } else {
        $('#signinhere').css('display', 'block');
      }
    }

    var logout = function() {
      loggedInEmail = null;
      updateUI(loggedInEmail);
      updateListArea(loggedInEmail);

      $("#splash").show();
      $("#lists").hide();

      // clear items from the dom at logout
      $("#todolist > li").remove();
      State.save();

      // don't display the warning icon at logout time, but wait until the user
      // makes a change to her tasks
      $("#dataState > div").css('display', 'none');

      // upon logout, make an api request to tear the user's session down
      $.post('/api/logout');
    };

    function authenticate (endpoint, flow) {
      if (window.location.href.indexOf('iframe') > -1) {
        $.getJSON('/api/' + endpoint)
          .done(function (data) {
            var relierClient = new FxaRelierClient(data.client_id, {
              oauthHost: data.oauth_uri,
              contentHost: data.content_uri
            });

            relierClient.auth[flow]({
              ui: 'lightbox',
              state: data.state,
              scope: data.scope,
              redirectUri: data.redirect_uri
            }).then(function (result) {
              document.location.href = result.redirect;
            }, function (err) {
              console.log('iframe auth err: %s', JSON.stringify(err));
            });
        });
      } else {
        $.getJSON('/api/' + endpoint)
          .done(function (data) {
            var relierClient = new FxaRelierClient(data.client_id, {
              oauthHost: data.oauth_uri,
              contentHost: data.content_uri
            });

            relierClient.auth[flow]({
              ui: 'redirect',
              state: data.state,
              scope: data.scope,
              redirectUri: data.redirect_uri
            });
        });
      }
    }

    $('button.signin').click(function(ev) {
      authenticate('login', 'signIn');
    });

    $('button.signup').click(function(ev) {
      authenticate('signup', 'signUp');
    });

    $('button.sign-choose').click(function(ev) {
      authenticate('best_choice', 'bestChoice');
    });

    // upon click of logout link navigator.id.logout()
    $("#logout").click(function(ev) {
      ev.preventDefault();
      logout();
    });

    updateUI(loggedInEmail);
    updateListArea(loggedInEmail);
    // display current saved state
    State.load();

  });
});
<commit_msg>fix(app): add class ready on document.ready<commit_after>/*
* This JavaScript file implements everything authentication
* related in the 123done demo. This includes interacting
* with the Persona API, the 123done server, and updating
* the UI to reflect sign-in state.
*/

$(document).ready(function() {
  window.loggedInEmail = null;

  // now check with the server to get our current login state
  $.get('/api/auth_status', function(data) {
    loggedInEmail = JSON.parse(data).email;

    function updateUI(email) {
      $("ul.loginarea li").css('display', 'none');
      if (email) {
        console.log(email);
        $('#loggedin span').text(email);
        $('#loggedin').css('display', 'block');
        $("#splash").hide();
        $("#lists").slideDown(500);
      } else {
        $('#loggedin span').text('');
        $('#loggedout').css('display', 'block');
        $("#splash").show();
        $("#lists").hide();

      }
      $("button").removeAttr('disabled').css('opacity', '1');
    }

    function updateListArea(email) {
      $("section.todo ul").css('display', 'none');
      $("section.todo form").css('display', 'none');
      if (email) {
        $('#addform').css('display', 'block');
        $('#todolist').css('display', 'block');
        $('#donelist').css('display', 'block');
      } else {
        $('#signinhere').css('display', 'block');
      }
    }

    var logout = function() {
      loggedInEmail = null;
      updateUI(loggedInEmail);
      updateListArea(loggedInEmail);

      $("#splash").show();
      $("#lists").hide();

      // clear items from the dom at logout
      $("#todolist > li").remove();
      State.save();

      // don't display the warning icon at logout time, but wait until the user
      // makes a change to her tasks
      $("#dataState > div").css('display', 'none');

      // upon logout, make an api request to tear the user's session down
      $.post('/api/logout');
    };

    function authenticate (endpoint, flow) {
      if (window.location.href.indexOf('iframe') > -1) {
        $.getJSON('/api/' + endpoint)
          .done(function (data) {
            var relierClient = new FxaRelierClient(data.client_id, {
              oauthHost: data.oauth_uri,
              contentHost: data.content_uri
            });

            relierClient.auth[flow]({
              ui: 'lightbox',
              state: data.state,
              scope: data.scope,
              redirectUri: data.redirect_uri
            }).then(function (result) {
              document.location.href = result.redirect;
            }, function (err) {
              console.log('iframe auth err: %s', JSON.stringify(err));
            });
        });
      } else {
        $.getJSON('/api/' + endpoint)
          .done(function (data) {
            var relierClient = new FxaRelierClient(data.client_id, {
              oauthHost: data.oauth_uri,
              contentHost: data.content_uri
            });

            relierClient.auth[flow]({
              ui: 'redirect',
              state: data.state,
              scope: data.scope,
              redirectUri: data.redirect_uri
            });
        });
      }
    }

    $('button.signin').click(function(ev) {
      authenticate('login', 'signIn');
    });

    $('button.signup').click(function(ev) {
      authenticate('signup', 'signUp');
    });

    $('button.sign-choose').click(function(ev) {
      authenticate('best_choice', 'bestChoice');
    });

    // upon click of logout link navigator.id.logout()
    $("#logout").click(function(ev) {
      ev.preventDefault();
      logout();
    });

    updateUI(loggedInEmail);
    updateListArea(loggedInEmail);
    // display current saved state
    State.load();
    $('body').addClass('ready');
  });
});
<|endoftext|>


<commit_before>import expect from 'expect';
import * as actions from '../../actions/TodoActions';
import * as types from '../../constants/ActionTypes';

describe('Actions::Search', () => {
  it('should create an action', () => {
    const text = 'Finish docs';
    const expectedAction = {
      type: types.SEARCH_CONTENT,
      text
    };
    expect(actions.searchByTitle(text)).toEqual(expectedAction);
  });
});
<commit_msg>remove search test which moved to utils<commit_after><|endoftext|>


<commit_before>// Top level Webpack configuration for running a development environment
// from the command line via devServer.js

const webpack = require('webpack');
const postCssImport = require('postcss-import');
const autoprefixer = require('autoprefixer');
const postCssCustomProperties = require('postcss-custom-properties');
const postCssCalc = require('postcss-calc');
const postCssNesting = require('postcss-nesting');
const postCssCustomMedia = require('postcss-custom-media');
const postCssMediaMinMax = require('postcss-media-minmax');
const postCssColorFunction = require('postcss-color-function');

const base = require('./webpack.config.base');
const cli = require('./webpack.config.cli');

const devConfig = Object.assign({}, base, cli, {
  devtool: 'inline-source-map',
  mode: 'development',
});

devConfig.entry.unshift('webpack-hot-middleware/client');

devConfig.plugins = devConfig.plugins.concat([
  new webpack.HotModuleReplacementPlugin(),
]);

devConfig.module.rules.push({
  test: /\.css$/,
  use: [
    {
      loader: 'style-loader',
      options: {
        sourceMap: true,
      },
    },
    {
      loader: 'css-loader',
      options: {
        localIdentName: '[local]---[hash:base64:5]',
        modules: true,
        sourceMap: true,
        importLoaders: 1,
      },
    },
    {
      loader: 'postcss-loader',
      options: {
        plugins: () => [
          postCssImport(),
          autoprefixer(),
          postCssCustomProperties({
            preserve: false
          }),
          postCssCalc(),
          postCssNesting(),
          postCssCustomMedia(),
          postCssMediaMinMax(),
          postCssColorFunction(),
        ],
        sourceMap: true,
      },
    },
  ],
});

module.exports = devConfig;
<commit_msg>Fixed dev build memory leak<commit_after>// Top level Webpack configuration for running a development environment
// from the command line via devServer.js

const webpack = require('webpack');
const postCssImport = require('postcss-import');
const autoprefixer = require('autoprefixer');
const postCssCustomProperties = require('postcss-custom-properties');
const postCssCalc = require('postcss-calc');
const postCssNesting = require('postcss-nesting');
const postCssCustomMedia = require('postcss-custom-media');
const postCssMediaMinMax = require('postcss-media-minmax');
const postCssColorFunction = require('postcss-color-function');

const base = require('./webpack.config.base');
const cli = require('./webpack.config.cli');

const devConfig = Object.assign({}, base, cli, {
  devtool: 'inline-source-map',
  mode: 'development',
});

// Override filename to remove the hash in development due to memory issues (STCOR-296)
devConfig.output.filename = 'bundle.js';

devConfig.entry.unshift('webpack-hot-middleware/client');

devConfig.plugins = devConfig.plugins.concat([
  new webpack.HotModuleReplacementPlugin(),
]);

devConfig.module.rules.push({
  test: /\.css$/,
  use: [
    {
      loader: 'style-loader',
      options: {
        sourceMap: true,
      },
    },
    {
      loader: 'css-loader',
      options: {
        localIdentName: '[local]---[hash:base64:5]',
        modules: true,
        sourceMap: true,
        importLoaders: 1,
      },
    },
    {
      loader: 'postcss-loader',
      options: {
        plugins: () => [
          postCssImport(),
          autoprefixer(),
          postCssCustomProperties({
            preserve: false
          }),
          postCssCalc(),
          postCssNesting(),
          postCssCustomMedia(),
          postCssMediaMinMax(),
          postCssColorFunction(),
        ],
        sourceMap: true,
      },
    },
  ],
});

module.exports = devConfig;
<|endoftext|>


<commit_before>'use strict';

/**
 * Provides a validation function to verify socket options.
 *
 * @param {object}   params - Defines an object hash of required and optional parameters including the following:
 * {string}   host - host name / port.
 * {boolean}  ssl - (optional) Indicates if an SSL connection is requested; default (false).
 * {object}   serializer - (optional) An instance of an object which conforms to JSON for serialization; default (JSON).
 * {boolean}  autoConnect - (optional) Indicates if socket should connect on construction; default (true).
 * {boolean}  autoReconnect - (optional) Indicates if socket should reconnect on socket closed; default (true).
 * {integer}  reconnectInterval - (optional) Indicates socket reconnect inteveral; default (10000) milliseconds.
 * {string}   protocol - (optional) Defines the websocket protocol; default (undefined).
 * {string}   websocketPath - (optional) Defines the websocket path; default (`websocket`).
 * {string}   sockjsPath - (optional) Defines the sockjs path; default (`sockjs`).
 * @return {object}
 */
export default function validateSocketOptions(params = {})
{
   if (typeof params.host !== 'string')
   {
      throw new TypeError('validateSocketOptions - `params.host` is not a string.');
   }

   if (typeof params.ssl !== 'boolean')
   {
      throw new TypeError('validateSocketOptions - `params.ssl` is not a boolean.');
   }

   if (typeof params.serializer !== 'object' || typeof params.serializer.stringify !== 'function' ||
    typeof params.serializer.parse !== 'function')
   {
      throw new TypeError('validateSocketOptions - `serializer` does not conform to the JSON API.');
   }

   if (typeof params.autoConnect !== 'boolean')
   {
      throw new TypeError('validateSocketOptions - `params.autoConnect` is not a boolean.');
   }

   if (typeof params.autoReconnect !== 'boolean')
   {
      throw new TypeError('validateSocketOptions - `params.autoReconnect` is not a boolean.');
   }

   if (!Number.isInteger(params.reconnectInterval))
   {
      throw new TypeError('validateSocketOptions - `params.reconnectInterval` is not an integer.');
   }

   if (typeof params.SocketConstructor !== 'function')
   {
      throw new TypeError('validateSocketOptions - `params.SocketConstructor` is not an constructor function.');
   }

   if (typeof options.endpoint !== 'string')
   {
      throw new Error('ctor - `options.endpoint` is missing or not a string.');
   }

   if (typeof params.type !== 'string')
   {
      throw new TypeError('validateSocketOptions - `params.type` is not a string.');
   }

   switch (params.type)
   {
      case 'sockjs':
         if (typeof params.sockjsPath !== 'string')
         {
            throw new TypeError('validateSocketOptions - `params.sockjsPath` is not a string.');
         }
         break;

      case 'websocket':
         if (typeof params.websocketPath !== 'string')
         {
            throw new TypeError('validateSocketOptions - `params.websocketPath` is not a string.');
         }

         // Optionally verify params.protocol if it exists.
         if (params.protocol && typeof params.protocol !== 'string')
         {
            throw new TypeError('validateSocketOptions - `params.protocol` is not a string.');
         }
         break;

      default:
         throw new TypeError('validateSocketOptions - `params.type` is not valid; must be `sockjs` or `websocket`.');
         break;
   }

   return true;
}<commit_msg>Added validateSocketOptions<commit_after>'use strict';

/**
 * Provides a validation function to verify socket options.
 *
 * @param {object}   params - Defines an object hash of required and optional parameters including the following:
 * {string}   host - host name / port.
 * {boolean}  ssl - (optional) Indicates if an SSL connection is requested; default (false).
 * {object}   serializer - (optional) An instance of an object which conforms to JSON for serialization; default (JSON).
 * {boolean}  autoConnect - (optional) Indicates if socket should connect on construction; default (true).
 * {boolean}  autoReconnect - (optional) Indicates if socket should reconnect on socket closed; default (true).
 * {integer}  reconnectInterval - (optional) Indicates socket reconnect inteveral; default (10000) milliseconds.
 * {string}   protocol - (optional) Defines the websocket protocol; default (undefined).
 * {string}   websocketPath - (optional) Defines the websocket path; default (`websocket`).
 * {string}   sockjsPath - (optional) Defines the sockjs path; default (`sockjs`).
 * @return {object}
 */
export default function validateSocketOptions(params = {})
{
   if (typeof params.host !== 'string')
   {
      throw new TypeError('validateSocketOptions - `params.host` is not a string.');
   }

   if (typeof params.ssl !== 'boolean')
   {
      throw new TypeError('validateSocketOptions - `params.ssl` is not a boolean.');
   }

   if (typeof params.serializer !== 'object' || typeof params.serializer.stringify !== 'function' ||
    typeof params.serializer.parse !== 'function')
   {
      throw new TypeError('validateSocketOptions - `serializer` does not conform to the JSON API.');
   }

   if (typeof params.autoConnect !== 'boolean')
   {
      throw new TypeError('validateSocketOptions - `params.autoConnect` is not a boolean.');
   }

   if (typeof params.autoReconnect !== 'boolean')
   {
      throw new TypeError('validateSocketOptions - `params.autoReconnect` is not a boolean.');
   }

   if (!Number.isInteger(params.reconnectInterval))
   {
      throw new TypeError('validateSocketOptions - `params.reconnectInterval` is not an integer.');
   }

   if (typeof params.SocketConstructor !== 'function')
   {
      throw new TypeError('validateSocketOptions - `params.SocketConstructor` is not an constructor function.');
   }

   if (typeof params.endpoint !== 'string')
   {
      throw new Error('ctor - `options.endpoint` is missing or not a string.');
   }

   if (typeof params.type !== 'string')
   {
      throw new TypeError('validateSocketOptions - `params.type` is not a string.');
   }

   switch (params.type)
   {
      case 'sockjs':
         if (typeof params.sockjsPath !== 'string')
         {
            throw new TypeError('validateSocketOptions - `params.sockjsPath` is not a string.');
         }
         break;

      case 'websocket':
         if (typeof params.websocketPath !== 'string')
         {
            throw new TypeError('validateSocketOptions - `params.websocketPath` is not a string.');
         }

         // Optionally verify params.protocol if it exists.
         if (params.protocol && typeof params.protocol !== 'string')
         {
            throw new TypeError('validateSocketOptions - `params.protocol` is not a string.');
         }
         break;

      default:
         throw new TypeError('validateSocketOptions - `params.type` is not valid; must be `sockjs` or `websocket`.');
         break;
   }

   return true;
}<|endoftext|>


<commit_before>function MonitorCtrl($scope, $http, $routeParams, $log, $sce, expvar) {
    $scope.active = true;
    $scope.monitoredIndexes = {};

    var tv = 1000;
    var top = "/stats/";
    var updateInterval = null;
    var isoDateFormatter = function(x) { return ISODateString(new Date(x*1000)); };
    var byteSizeFormatter = function(y) { return Humanize.fileSize(y); };
    var nanosecondFormatter = function(y) {
        if (y > 1000000) {
            return Humanize.toFixed(y/1000000) + " ms";
        } else {
            return y + " ns";
        }
    };
    var intFormatter = function(y) {
        return Humanize.compactInteger(y);
    };

    var updateData = function() {
        expvar.pollExpvar();

        indexesSeen = {};
        indxs = expvar.getDynamicDataKeys("indexes");
        for (var idxIndex in indxs) {
            idxname = indxs[idxIndex];
            if ($scope.monitoredIndexes[idxname] === undefined) {
                // a new index
                $scope.monitoredIndexes[idxname] = monitorIndex(idxname);
            }
            indexesSeen[idxname] = true;
        }

        for (var monitoredIdxName in $scope.monitoredIndexes) {
            if (indexesSeen[monitoredIdxName] !== true) {
                $log.info("stop monitoring index: " + monitoredIdxName);
                removeIndex($scope.monitoredIndexes[monitoredIdxName]);
                delete $scope.monitoredIndexes[monitoredIdxName];
            }
        }

        for (var i in $scope.metrics) {
            category = $scope.metrics[i];
            for (var k in category.metrics) {
                metric = category.metrics[k];
                redrawMetric(metric);
            }
        }

        for (var idxName in $scope.monitoredIndexes) {
            idx = $scope.monitoredIndexes[idxName];
            if (idx !== undefined) {
                for(var j in idx.metrics) {
                    metric = idx.metrics[j];
                    redrawMetric(metric);
                }
            }
        }
    };

    function monitorIndex(name) {
        $log.info("start monitoring index: " + name);
        idx = {
            metrics: [
                {
                    name: name+"updates",
                    display: "Updates",
                    path: top + "indexes/" + name  + "/index/updates",
                    type: "rate",
                    color: "steelblue",
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: intFormatter
                },
                {
                    name: name+"deletes",
                    display: "Deletes",
                    path: top + "indexes/"+ name  +"/index/deletes",
                    type: "rate",
                    color: "steelblue",
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: intFormatter
                },
                {
                    name: name+"indexanalysistime",
                    display: "Analysis/Index Time",
                    series: [
                        {
                            display: "Index",
                            name: name+"indextime",
                            path: top + "indexes/"+ name  +"/index/index_time",
                            type: "rate",
                            color: "red",
                        },
                        {
                            display: "Analysis",
                            name: name+"analysistime",
                            path: top + "indexes/" + name  + "/index/analysis_time",
                            type: "rate",
                            color: "green",
                        }
                    ],
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: nanosecondFormatter,
                    legend: true
                },
                {
                    name: name+"searches",
                    display: "Searches",
                    path: top + "indexes/"+ name  +"/searches",
                    type: "rate",
                    color: "steelblue",
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: intFormatter
                },
                {
                    name: name+"searchtime",
                    display: "Search Time",
                    path: top + "indexes/"+ name  +"/search_time",
                    type: "rate",
                    color: "steelblue",
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: nanosecondFormatter
                },
            ]
        };

        indexDivName = "index" + idify(name);
        indexPanel =
            '
' +
            '
' +
            '  ' + name + '' +
            '
' +
            '

' +
            '
';
        $(indexPanel).insertBefore('#indexchartend');

        for (var i in idx.metrics) {
            metric = idx.metrics[i];
            mname = idify(metric.name);

            divContent =
                '
' + metric.display + '
' +
                '

';

            $(divContent).appendTo('#'+indexDivName);

            if (metric.legend) {
                legendDivName = "legend" + idify(name);
                legendContent = '

';
                $(legendContent).appendTo('#'+indexDivName);
            }

            // ask the expvar service to track this metric for us
            if (metric.path !== undefined) {
                expvar.addMetric(metric.name, metric.path);
            } else if (metric.series !== undefined) {
                for (var si in metric.series) {
                    sm = metric.series[si];

                    var swatch = document.createElement('div');
                    swatch.className = 'swatch';
                    swatch.style.backgroundColor = sm.color;
                    $(swatch).appendTo('#'+legendDivName);

                    var label = document.createElement('div');
                    label.className = 'label';
                    label.innerHTML = sm.display;
                    $(label).appendTo('#'+legendDivName);

                    expvar.addMetric(sm.name, sm.path);
                }
            }

            // build chart
            addGraph(metric);
        }

        return idx;
    }

    function removeIndex(index) {
        for (var i in index.metrics) {
            metric = index.metrics[i];
            mname = idify(metric.name);
            expvar.removeMetric(metric.name);
            $("#header" + mname).remove();
            $("#"+mname).remove();
            $("#panel"+name).remove();
        }
    }

    function redrawMetric(metric) {
        graph = metric.graph;
        if (!graph || !graph.series) {
            return;
        }

        if (metric.series !== undefined) {
            var seriesData = [];
            for (var si in metric.series) {
                sm = metric.series[si];
                if (sm.type == "value") {
                    currentValue = expvar.getMetricCurrentValue(sm.name);
                    seriesData.push(currentValue);
                } else if (sm.type == "rate") {
                    currentRate = expvar.getMetricCurrentRate(sm.name);
                    seriesData.push(currentRate);
                    $log.info("name: " + sm.name + " " + currentRate);
                    $log.info(seriesData);
                }
            }
            graph.series.addData(seriesData);
        } else {
            var d = {};
            if (metric.type == "value") {
                currentValue = expvar.getMetricCurrentValue(metric.name);
                d[metric.name]= currentValue;
            } else if (metric.type == "rate") {
                currentRate = expvar.getMetricCurrentRate(metric.name);
                d[metric.name]= currentRate;
            }
            graph.series.addData(d);
        }

        // redraw
        graph.render();
    }

    $scope.metrics = {
        "memory": {
            "display": "Memory",
            metrics: [
                {
                    name: "alloc",
                    display: "Memory Allocated",
                    path: "/memstats/Alloc",
                    type: "value",
                    color: "steelblue",
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: byteSizeFormatter
                },
                {
                    name: "pauseTotalNs",
                    display: "Garbage Collection Time",
                    path: "/memstats/PauseTotalNs",
                    type: "rate",
                    color: "steelblue",
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: nanosecondFormatter,
                }
            ]
        }
    };

    expvar.addDynamicDataPath("indexes", top + "indexes");

    for (var categoryName in $scope.metrics) {
        category = $scope.metrics[categoryName];

        divName = "cat" + categoryName;
        panel = '

'+ category.display + '

';
        $(panel).insertBefore('#chartend');

        for (var i in category.metrics) {
            metric = category.metrics[i];
            mname = idify(metric.name);

            divContent = '
'+metric.display+'

';

            $(divContent).appendTo("#"+divName);

            // ask the expvar service to track this metric for us
            expvar.addMetric(metric.name, metric.path);

            // build chart
            addGraph(metric);
        }
    }

    function addGraph(metric) {
        mname = idify(metric.name);

        var seriesData = [];
        if (metric.series !== undefined) {
            for (var si in metric.series) {
                sm = metric.series[si];
                seriesData.push({
                    name: sm.name,
                    color: sm.color
                });
            }
        } else {
            seriesData.push({
                name: metric.name,
                color: metric.color
            });
        }

        $log.info("seriesdata");
        $log.info(seriesData);
        $log.info("seriesdataend");

        var graph = new Rickshaw.Graph({
            element: document.querySelector("#"+mname),
            width: "800",
            height: "75",
            renderer: "area",
            series: new Rickshaw.Series.FixedDuration(seriesData,
            undefined,
            {
                timeInterval: tv,
                maxDataPoints: 600,
                timeBase: new Date().getTime() / 1000
            })
        });

        // store the graph object inside the metric
        metric.graph = graph;

        // y-axis ticks
        if (metric.yaxis) {
            var yAxis = new Rickshaw.Graph.Axis.Y({
                graph: graph,
                tickFormat: metric.yaxis,
            });

            yAxis.render();
        }

        var xAxis = new Rickshaw.Graph.Axis.X({
            graph: graph,
            pixelsPerTick: 1000
        });
        xAxis.render();

        // set up the hover
        var hoverDetail = new Rickshaw.Graph.HoverDetail( {
            graph: graph,
            formatter: function(series, x, y, formattedX, formattedY, d) {
                var date = '' + formattedX + '';
                var content =  formattedY + '
' + date;
                return content;
            }
        });

        if (metric.xformatter) {
            hoverDetail.xFormatter = metric.xformatter;
        }
        if (metric.yformatter) {
            hoverDetail.yFormatter = metric.yformatter;
        }

        // render it
        graph.render();
    }

    // setup data updates
    updateInterval = setInterval(updateData, tv);
    $scope.$on("$destroy", function(){
        clearInterval(updateInterval);
    });

    function ISODateString(d){
        function pad(n){return n<10 ? '0'+n : n;}
        return d.getUTCFullYear()+'-' +
            pad(d.getUTCMonth()+1)+'-' +
            pad(d.getUTCDate())+'T' +
            pad(d.getUTCHours())+':' +
            pad(d.getUTCMinutes())+':' +
            pad(d.getUTCSeconds())+'Z';
    }

    function idify(s) {
        return s.replace(/\./g, '-');
    }
}
<commit_msg>idify for category div<commit_after>function MonitorCtrl($scope, $http, $routeParams, $log, $sce, expvar) {
    $scope.active = true;
    $scope.monitoredIndexes = {};

    var tv = 1000;
    var top = "/stats/";
    var updateInterval = null;
    var isoDateFormatter = function(x) { return ISODateString(new Date(x*1000)); };
    var byteSizeFormatter = function(y) { return Humanize.fileSize(y); };
    var nanosecondFormatter = function(y) {
        if (y > 1000000) {
            return Humanize.toFixed(y/1000000) + " ms";
        } else {
            return y + " ns";
        }
    };
    var intFormatter = function(y) {
        return Humanize.compactInteger(y);
    };

    var updateData = function() {
        expvar.pollExpvar();

        indexesSeen = {};
        indxs = expvar.getDynamicDataKeys("indexes");
        for (var idxIndex in indxs) {
            idxname = indxs[idxIndex];
            if ($scope.monitoredIndexes[idxname] === undefined) {
                // a new index
                $scope.monitoredIndexes[idxname] = monitorIndex(idxname);
            }
            indexesSeen[idxname] = true;
        }

        for (var monitoredIdxName in $scope.monitoredIndexes) {
            if (indexesSeen[monitoredIdxName] !== true) {
                $log.info("stop monitoring index: " + monitoredIdxName);
                removeIndex($scope.monitoredIndexes[monitoredIdxName]);
                delete $scope.monitoredIndexes[monitoredIdxName];
            }
        }

        for (var i in $scope.metrics) {
            category = $scope.metrics[i];
            for (var k in category.metrics) {
                metric = category.metrics[k];
                redrawMetric(metric);
            }
        }

        for (var idxName in $scope.monitoredIndexes) {
            idx = $scope.monitoredIndexes[idxName];
            if (idx !== undefined) {
                for(var j in idx.metrics) {
                    metric = idx.metrics[j];
                    redrawMetric(metric);
                }
            }
        }
    };

    function monitorIndex(name) {
        $log.info("start monitoring index: " + name);
        idx = {
            metrics: [
                {
                    name: name+"updates",
                    display: "Updates",
                    path: top + "indexes/" + name  + "/index/updates",
                    type: "rate",
                    color: "steelblue",
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: intFormatter
                },
                {
                    name: name+"deletes",
                    display: "Deletes",
                    path: top + "indexes/"+ name  +"/index/deletes",
                    type: "rate",
                    color: "steelblue",
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: intFormatter
                },
                {
                    name: name+"indexanalysistime",
                    display: "Analysis/Index Time",
                    series: [
                        {
                            display: "Index",
                            name: name+"indextime",
                            path: top + "indexes/"+ name  +"/index/index_time",
                            type: "rate",
                            color: "red",
                        },
                        {
                            display: "Analysis",
                            name: name+"analysistime",
                            path: top + "indexes/" + name  + "/index/analysis_time",
                            type: "rate",
                            color: "green",
                        }
                    ],
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: nanosecondFormatter,
                    legend: true
                },
                {
                    name: name+"searches",
                    display: "Searches",
                    path: top + "indexes/"+ name  +"/searches",
                    type: "rate",
                    color: "steelblue",
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: intFormatter
                },
                {
                    name: name+"searchtime",
                    display: "Search Time",
                    path: top + "indexes/"+ name  +"/search_time",
                    type: "rate",
                    color: "steelblue",
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: nanosecondFormatter
                },
            ]
        };

        indexDivName = "index" + idify(name);
        indexPanel =
            '
' +
            '
' +
            '  ' + name + '' +
            '
' +
            '

' +
            '
';
        $(indexPanel).insertBefore('#indexchartend');

        for (var i in idx.metrics) {
            metric = idx.metrics[i];
            mname = idify(metric.name);

            divContent =
                '
' + metric.display + '
' +
                '

';

            $(divContent).appendTo('#'+indexDivName);

            if (metric.legend) {
                legendDivName = "legend" + idify(name);
                legendContent = '

';
                $(legendContent).appendTo('#'+indexDivName);
            }

            // ask the expvar service to track this metric for us
            if (metric.path !== undefined) {
                expvar.addMetric(metric.name, metric.path);
            } else if (metric.series !== undefined) {
                for (var si in metric.series) {
                    sm = metric.series[si];

                    var swatch = document.createElement('div');
                    swatch.className = 'swatch';
                    swatch.style.backgroundColor = sm.color;
                    $(swatch).appendTo('#'+legendDivName);

                    var label = document.createElement('div');
                    label.className = 'label';
                    label.innerHTML = sm.display;
                    $(label).appendTo('#'+legendDivName);

                    expvar.addMetric(sm.name, sm.path);
                }
            }

            // build chart
            addGraph(metric);
        }

        return idx;
    }

    function removeIndex(index) {
        for (var i in index.metrics) {
            metric = index.metrics[i];
            mname = idify(metric.name);
            expvar.removeMetric(metric.name);
            $("#header" + mname).remove();
            $("#"+mname).remove();
            $("#panel"+name).remove();
        }
    }

    function redrawMetric(metric) {
        graph = metric.graph;
        if (!graph || !graph.series) {
            return;
        }

        if (metric.series !== undefined) {
            var seriesData = [];
            for (var si in metric.series) {
                sm = metric.series[si];
                if (sm.type == "value") {
                    currentValue = expvar.getMetricCurrentValue(sm.name);
                    seriesData.push(currentValue);
                } else if (sm.type == "rate") {
                    currentRate = expvar.getMetricCurrentRate(sm.name);
                    seriesData.push(currentRate);
                    $log.info("name: " + sm.name + " " + currentRate);
                    $log.info(seriesData);
                }
            }
            graph.series.addData(seriesData);
        } else {
            var d = {};
            if (metric.type == "value") {
                currentValue = expvar.getMetricCurrentValue(metric.name);
                d[metric.name]= currentValue;
            } else if (metric.type == "rate") {
                currentRate = expvar.getMetricCurrentRate(metric.name);
                d[metric.name]= currentRate;
            }
            graph.series.addData(d);
        }

        // redraw
        graph.render();
    }

    $scope.metrics = {
        "memory": {
            "display": "Memory",
            metrics: [
                {
                    name: "alloc",
                    display: "Memory Allocated",
                    path: "/memstats/Alloc",
                    type: "value",
                    color: "steelblue",
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: byteSizeFormatter
                },
                {
                    name: "pauseTotalNs",
                    display: "Garbage Collection Time",
                    path: "/memstats/PauseTotalNs",
                    type: "rate",
                    color: "steelblue",
                    yaxis: Rickshaw.Fixtures.Number.formatKMBT,
                    xformatter: isoDateFormatter,
                    yformatter: nanosecondFormatter,
                }
            ]
        }
    };

    expvar.addDynamicDataPath("indexes", top + "indexes");

    for (var categoryName in $scope.metrics) {
        category = $scope.metrics[categoryName];

        divName = "cat" + idify(categoryName);
        panel =
            '
' +
            '
' +
            '  ' +
            category.display +
            '  ' +
            '
' +
            '
' +
            '
' +
            '
';
        $(panel).insertBefore('#chartend');

        for (var i in category.metrics) {
            metric = category.metrics[i];
            mname = idify(metric.name);

            divContent = '
'+metric.display+'

';

            $(divContent).appendTo("#"+divName);

            // ask the expvar service to track this metric for us
            expvar.addMetric(metric.name, metric.path);

            // build chart
            addGraph(metric);
        }
    }

    function addGraph(metric) {
        mname = idify(metric.name);

        var seriesData = [];
        if (metric.series !== undefined) {
            for (var si in metric.series) {
                sm = metric.series[si];
                seriesData.push({
                    name: sm.name,
                    color: sm.color
                });
            }
        } else {
            seriesData.push({
                name: metric.name,
                color: metric.color
            });
        }

        $log.info("seriesdata");
        $log.info(seriesData);
        $log.info("seriesdataend");

        var graph = new Rickshaw.Graph({
            element: document.querySelector("#"+mname),
            width: "800",
            height: "75",
            renderer: "area",
            series: new Rickshaw.Series.FixedDuration(seriesData,
            undefined,
            {
                timeInterval: tv,
                maxDataPoints: 600,
                timeBase: new Date().getTime() / 1000
            })
        });

        // store the graph object inside the metric
        metric.graph = graph;

        // y-axis ticks
        if (metric.yaxis) {
            var yAxis = new Rickshaw.Graph.Axis.Y({
                graph: graph,
                tickFormat: metric.yaxis,
            });

            yAxis.render();
        }

        var xAxis = new Rickshaw.Graph.Axis.X({
            graph: graph,
            pixelsPerTick: 1000
        });
        xAxis.render();

        // set up the hover
        var hoverDetail = new Rickshaw.Graph.HoverDetail( {
            graph: graph,
            formatter: function(series, x, y, formattedX, formattedY, d) {
                var date = '' + formattedX + '';
                var content =  formattedY + '
' + date;
                return content;
            }
        });

        if (metric.xformatter) {
            hoverDetail.xFormatter = metric.xformatter;
        }
        if (metric.yformatter) {
            hoverDetail.yFormatter = metric.yformatter;
        }

        // render it
        graph.render();
    }

    // setup data updates
    updateInterval = setInterval(updateData, tv);
    $scope.$on("$destroy", function(){
        clearInterval(updateInterval);
    });

    function ISODateString(d){
        function pad(n){return n<10 ? '0'+n : n;}
        return d.getUTCFullYear()+'-' +
            pad(d.getUTCMonth()+1)+'-' +
            pad(d.getUTCDate())+'T' +
            pad(d.getUTCHours())+':' +
            pad(d.getUTCMinutes())+':' +
            pad(d.getUTCSeconds())+'Z';
    }

    function idify(s) {
        return s.replace(/\./g, '-');
    }
}
<|endoftext|>


<commit_before>Tabs = new Meteor.Collection('tabs');

if (Meteor.isClient) {
    Meteor.subscribe('tabs');

    function extractData(form) {
        return _.reduce($(form).serializeArray(), function (memo, item) {
            memo[item.name] = item.value;
            return memo;
        }, {});
    }

    Template.tabs.tabs = function () {
        return Tabs.find();
    }

    Template.newTab.events({
        'submit': function (e, tmpl) {
            var tab = extractData(e.currentTarget);
            tab.total = Number(tab.total);
            Tabs.insert(tab);
            return false;
        }
    });

    Template.tab.events({
        'click li': function (e, tmpl) {
            Session.set('selectedTab', tmpl.data);
        }
    });

    Template.editTab.tab = function () {
        return Session.get('selectedTab');
    };

    Template.editTab.events({
        'submit': function (e, tmpl) {
            var tab = extractData(e.currentTarget);
            Tabs.update({_id: tab._id}, {
                $set: {name: tab.name, total: tab.total}
            });
            return false;
        }
    });
}

if (Meteor.isServer) {
    console.log('started server');

    Meteor.publish('tabs', function (id) {
        console.log('subscribing to tabs', id);
        return Tabs.find();
    });

    Meteor.methods({
        'addTab': function (tab1, tab2, tab3) {
            console.log('attempting to add a tab');
            console.log(arguments);
            if (_.isObject(tab1)) {
                Tabs.insert(tab1);
            }
            if (_.isObject(tab2)) {
                Tabs.insert(tab2);
            }
            if (_.isObject(tab3)) {
                Tabs.insert(tab3);
            }
            return true;
        }
    });

    Meteor.startup(function () {
        // code to run on server at startup
    });

    Meteor.onConnection(function (conn) {
        console.log(conn);
        conn.onClose(function () {
            console.log('connection to ', conn.id, ' closed');
        });
    });

    Tabs.allow({
        insert: function () {
            return true;
        },
        update: function () {
            return true;
        },
        remove: function () {
            return false;
        }
    })

}
<commit_msg>fixed number format in update<commit_after>Tabs = new Meteor.Collection('tabs');

if (Meteor.isClient) {
    Meteor.subscribe('tabs');

    function extractData(form) {
        return _.reduce($(form).serializeArray(), function (memo, item) {
            memo[item.name] = item.value;
            return memo;
        }, {});
    }

    Template.tabs.tabs = function () {
        return Tabs.find();
    }

    Template.newTab.events({
        'submit': function (e, tmpl) {
            var tab = extractData(e.currentTarget);
            tab.total = Number(tab.total);
            Tabs.insert(tab);
            return false;
        }
    });

    Template.tab.events({
        'click li': function (e, tmpl) {
            Session.set('selectedTab', tmpl.data);
        }
    });

    Template.editTab.tab = function () {
        return Session.get('selectedTab');
    };

    Template.editTab.events({
        'submit': function (e, tmpl) {
            var tab = extractData(e.currentTarget);
            tab.total = Number(tab.total);
            Tabs.update({_id: tab._id}, {
                $set: {name: tab.name, total: tab.total}
            });
            return false;
        }
    });
}

if (Meteor.isServer) {
    console.log('started server');

    Meteor.publish('tabs', function (id) {
        console.log('subscribing to tabs', id);
        return Tabs.find();
    });

    Meteor.methods({
        'addTab': function (tab1, tab2, tab3) {
            console.log('attempting to add a tab');
            console.log(arguments);
            if (_.isObject(tab1)) {
                Tabs.insert(tab1);
            }
            if (_.isObject(tab2)) {
                Tabs.insert(tab2);
            }
            if (_.isObject(tab3)) {
                Tabs.insert(tab3);
            }
            return true;
        }
    });

    Meteor.startup(function () {
        // code to run on server at startup
    });

    Meteor.onConnection(function (conn) {
        console.log(conn);
        conn.onClose(function () {
            console.log('connection to ', conn.id, ' closed');
        });
    });

    Tabs.allow({
        insert: function () {
            return true;
        },
        update: function () {
            return true;
        },
        remove: function () {
            return false;
        }
    })

}
<|endoftext|>