<commit_before>function set_curr_block(elem, currency, textname)
{
    elem.children('.currflag').attr('src', 'images/'.concat(currency).concat('_flag.png'));
    elem.children('.currname').text(textname);
    elem.children('.currbox_right').children('.currcode').text(currency);
}
function set_currency(elem, currency)
{
    switch(currency)
    {
        case 'aud':
            set_curr_block(elem, 'aud', 'Australian Dollar');
        break;

        case 'btc':
            set_curr_block(elem, 'btc', 'Bitcoin');
        break;
    }
}
function twin_currency(currency)
{
    switch(currency)
    {
        case 'btc':
            return 'aud';
        case 'aud':
        default:
            return 'btc';
    }
}

function set_currency_in(currency)
{
    ic = $('#incurrency');
    set_currency(ic, currency);

    if (!typed_price && currency in exchange_rates)
        $('#price').attr('value', exchange_rates[currency]);
}
function set_currency_out(currency)
{
    ic = $('#outcurrency');
    set_currency(ic, currency);
}

function rolldown(cs, ic)
{
    if (cs.css('visibility') == 'hidden') {
        cs.position({
            my: "left top",
            at: "left bottom",
            of: ic
        });
        cs.css('visibility', 'visible');
    }
    else
        cs.css('visibility', 'hidden');
}
function hide_rolldown(cs)
{
    cs.css('visibility', 'hidden');
}
function rolldown_in()
{
    rolldown($('#currsel_in'), '#incurrency');
    hide_rolldown($('#currsel_out'));
}
function rolldown_out()
{
    rolldown($('#currsel_out'), '#outcurrency');
    hide_rolldown($('#currsel_in'));
}

function select_currency_in(caller)
{
    $('#currsel_in').css('visibility', 'hidden');
    curr = jQuery('.currcode', caller).text();
    curr = curr.toLowerCase();
    set_currency_in(curr);
    set_currency_out(twin_currency(curr), false);
    $('#inamount').attr('value', '');
    typed_amount_in();
}
function select_currency_out(caller)
{
    $('#currsel_out').css('visibility', 'hidden');
    curr = jQuery('.currcode', caller).text();
    curr = curr.toLowerCase();
    set_currency_out(curr);
    set_currency_in(twin_currency(curr));
    $('#outamount').attr('value', '');
    typed_amount_out();
}

function typed_amount(this_name, change_name)
{
    this_obj = $('#' + this_name + 'amount');
    change_obj = $('#' + change_name + 'amount');
    price_obj = $('#price');

    price_text = price_obj.attr('value');
    this_text = this_obj.attr('value');

    if (!price_text || !this_text)
        return;

    price = parseFloat(price_text);
    this_amount = parseFloat(this_text);

    if (      price <= 0 || !isFinite(      price) || isNaN(      price) ||
        this_amount <= 0 || !isFinite(this_amount) || isNaN(this_amount)) {
        change_obj.attr('value', '');
        return;
    }

    a_curr = jQuery('.currcode', '#incurrency').text();
    if ((this_name == 'out' && a_curr == 'btc') ||
        (this_name == 'in'  && a_curr != 'btc'))
        price = 1.0/price;

    val = this_amount * price;

    // toFixed(2) rounds 0.235001 up to 0.24, meaning the order doesn't quite match
    // add on / take off 0.0049999 to make sure of a match
    if (this_name == 'out')
        val += 0.000049999;
    else
        val -= 0.000049999;

    val = val.toFixed(4)
    val = val.replace(/([.].*?)0+$/, '$1'); // remove trailing zeroes after the decimal point
    val = val.replace(/[.]$/, '');          // remove trailing decimal point
    change_obj.attr('value', val);
}

function isdefined( variable)
{
    return (typeof(window[variable]) == "undefined") ? false : true;
}

function is_typing(e)
{
    // sometimes 'e' is undefined?
    if (!isdefined(e)) return false;
    code = e.keyCode ? e.keyCode : e.charCode;
    return (code == 8 || code > 31);
}

function typed_amount_in(e)
{
    if (!is_typing(e)) return;
    typed_amount('in', 'out');
}

function typed_amount_out(e)
{
    if (!is_typing(e)) return;
    typed_amount('out', 'in');
}

function typed_amount_price(e)
{
    if (!is_typing(e)) return;
    typed_price = true;
    typed_amount('in', 'out');
}

function buy_clicked()
{
    curr_type = jQuery('.currcode', '#incurrency').text();
    want_curr_type = jQuery('.currcode', '#outcurrency').text();
    amount = $('#inamount').attr('value');
    want_amount = $('#outamount').attr('value');
    $("input[name='type']").val(curr_type);
    $("input[name='amount']").val(amount);
    if (amount == '' || want_amount == '' || isNaN(amount) || isNaN(want_amount)) {
        alert("Invalid amount specified.");
        return false;
    }
    $("input[name='want_type']").val(want_curr_type);
    $("input[name='want_amount']").val(want_amount);
    return true;
}

<commit_msg>Previous fix was wrong.  This really fixes it.<commit_after>function set_curr_block(elem, currency, textname)
{
    elem.children('.currflag').attr('src', 'images/'.concat(currency).concat('_flag.png'));
    elem.children('.currname').text(textname);
    elem.children('.currbox_right').children('.currcode').text(currency);
}
function set_currency(elem, currency)
{
    switch(currency)
    {
        case 'aud':
            set_curr_block(elem, 'aud', 'Australian Dollar');
        break;

        case 'btc':
            set_curr_block(elem, 'btc', 'Bitcoin');
        break;
    }
}
function twin_currency(currency)
{
    switch(currency)
    {
        case 'btc':
            return 'aud';
        case 'aud':
        default:
            return 'btc';
    }
}

function set_currency_in(currency)
{
    ic = $('#incurrency');
    set_currency(ic, currency);

    if (!typed_price && currency in exchange_rates)
        $('#price').attr('value', exchange_rates[currency]);
}
function set_currency_out(currency)
{
    ic = $('#outcurrency');
    set_currency(ic, currency);
}

function rolldown(cs, ic)
{
    if (cs.css('visibility') == 'hidden') {
        cs.position({
            my: "left top",
            at: "left bottom",
            of: ic
        });
        cs.css('visibility', 'visible');
    }
    else
        cs.css('visibility', 'hidden');
}
function hide_rolldown(cs)
{
    cs.css('visibility', 'hidden');
}
function rolldown_in()
{
    rolldown($('#currsel_in'), '#incurrency');
    hide_rolldown($('#currsel_out'));
}
function rolldown_out()
{
    rolldown($('#currsel_out'), '#outcurrency');
    hide_rolldown($('#currsel_in'));
}

function select_currency_in(caller)
{
    $('#currsel_in').css('visibility', 'hidden');
    curr = jQuery('.currcode', caller).text();
    curr = curr.toLowerCase();
    set_currency_in(curr);
    set_currency_out(twin_currency(curr), false);
    $('#inamount').attr('value', '');
    $('#outamount').attr('value', '');
}
function select_currency_out(caller)
{
    $('#currsel_out').css('visibility', 'hidden');
    curr = jQuery('.currcode', caller).text();
    curr = curr.toLowerCase();
    set_currency_out(curr);
    set_currency_in(twin_currency(curr));
    $('#outamount').attr('value', '');
    $('#inamount').attr('value', '');
}

function typed_amount(this_name, change_name)
{
    this_obj = $('#' + this_name + 'amount');
    change_obj = $('#' + change_name + 'amount');
    price_obj = $('#price');

    price_text = price_obj.attr('value');
    this_text = this_obj.attr('value');

    if (!price_text || !this_text)
        return;

    price = parseFloat(price_text);
    this_amount = parseFloat(this_text);

    if (      price <= 0 || !isFinite(      price) || isNaN(      price) ||
        this_amount <= 0 || !isFinite(this_amount) || isNaN(this_amount)) {
        change_obj.attr('value', '');
        return;
    }

    a_curr = jQuery('.currcode', '#incurrency').text();
    if ((this_name == 'out' && a_curr == 'btc') ||
        (this_name == 'in'  && a_curr != 'btc'))
        price = 1.0/price;

    val = this_amount * price;

    // toFixed(2) rounds 0.235001 up to 0.24, meaning the order doesn't quite match
    // add on / take off 0.0049999 to make sure of a match
    if (this_name == 'out')
        val += 0.000049999;
    else
        val -= 0.000049999;

    val = val.toFixed(4)
    val = val.replace(/([.].*?)0+$/, '$1'); // remove trailing zeroes after the decimal point
    val = val.replace(/[.]$/, '');          // remove trailing decimal point
    change_obj.attr('value', val);
}

function is_typing(e)
{
    code = e.keyCode ? e.keyCode : e.charCode;
    return (code == 8 || code > 31);
}

function typed_amount_in(e)
{
    if (!is_typing(e)) return;
    typed_amount('in', 'out');
}

function typed_amount_out(e)
{
    if (!is_typing(e)) return;
    typed_amount('out', 'in');
}

function typed_amount_price(e)
{
    if (!is_typing(e)) return;
    typed_price = true;
    typed_amount('in', 'out');
}

function buy_clicked()
{
    curr_type = jQuery('.currcode', '#incurrency').text();
    want_curr_type = jQuery('.currcode', '#outcurrency').text();
    amount = $('#inamount').attr('value');
    want_amount = $('#outamount').attr('value');
    $("input[name='type']").val(curr_type);
    $("input[name='amount']").val(amount);
    if (amount == '' || want_amount == '' || isNaN(amount) || isNaN(want_amount)) {
        alert("Invalid amount specified.");
        return false;
    }
    $("input[name='want_type']").val(want_curr_type);
    $("input[name='want_amount']").val(want_amount);
    return true;
}

<|endoftext|>


<commit_before>var loggedIn = false;

$(function() {
    // Animate stuff
    var delay = 150;
    for (i = 0; i < 3; i++) {
        $($('.features h2')[i]).transition({ opacity: 1, delay: (i*delay) }, 2000);
        $($('.features .circle')[i]).transition({ opacity: 1, scale: 1, delay: (300+i*delay) }, 500, 'snap');
        $($('.features .blurb')[i]).transition({ opacity: 1, delay: (i*delay) }, 2000);
    }

    // Feature listeners
    $('.show-feature').on('click', function(e) {
        e.preventDefault();
        console.log('hello');
        $($(this).attr('data-show')).slideToggle();
    });

    var tests = {
        user: function (val) {
            return val.length > 3 &&
                   val.length <= 16 &&
                   /^[0-9A-Za-z_-][0-9A-Za-z_.-]*[0-9A-Za-z_-]$/.test(val);
        },

        email: function (val) {
            return /^(?:\w+\.?)*\w+@(?:\w+\.)+\w+$/.test(val);
        },

        minLength: function (val, length) {
            return val.length >= length;
        },

        maxLength: function (val, length) {
            return val.length <= length;
        },

        equal: function (val1, val2) {
            return (val1 == val2);
        }
    };

    $('#login_form').isHappy({
        fields: {
            '#username': {
                required: true
            },
            '#password': {
                required: true
            }
        }
    });

    $('#registration_form').isHappy({
        fields: {
            '#reg_username': {
                required: true,
                test: tests.user
            },
            '#reg_password': {
                required: true
            },
            '#reg_password_2': {
                required: true,
                test: tests.equal,
                arg: function () {
                    return $('#reg_password').val();
                }
            },
            '#reg_email': {
                required: true,
                test: tests.email
            }
        }
    });

    // Landing page forms
    $('.landing .registration > div').on('click', function(e) {
        if (!$(this).hasClass('hidden')) return;

        $('.landing .registration > div').toggleClass('hidden');
        $(this).children('.widget').slideToggle();
        $('.landing .registration > div').not(this).children('.widget').slideToggle();
    });

    // Navigation forms
    var dropdown = $('.nav-extra-dropdown');

    $('.nav-extra').each(function() {
        if ($(this).parent().hasClass('active')) {
            if ($(this).hasClass('nav-extra-login'))
                $('#nav-extra-login').slideDown(200);
            else
                $('#nav-extra-register').slideDown(200);
            bindCloseNotifications();
            return false;
        }
    });

    $('.nav-extra').on('click', function(e) {
        e.preventDefault();
        e.stopPropagation();

        if (($(this).hasClass('nav-extra-login') && $('#nav-extra-login').is(":visible")) ||
            $(this).hasClass('nav-extra-register') && $('#nav-extra-register').is(":visible")) {
            closeNotifications();
            return false;
        }
        dropdown.slideUp(200);

        if ($(this).hasClass('nav-extra-login'))
            $('#nav-extra-login').slideDown(200);
        else
            $('#nav-extra-register').slideDown(200);
        $(this).parent().addClass('active');

        bindCloseNotifications();
    });

    function bindCloseNotifications() {
        $(document).bind('click.extra-hide', function(e) {
            if ($(e.target).closest('.nav-extra-dropdown').length != 0 && $(e.target).not('.nav-extra')) return true;
            closeNotifications();
        });
    }

    function closeNotifications() {
        dropdown.slideUp(200);
        $('.nav-extra').parent().removeClass('active');
        $('.nav-extra-dropdown .msg').remove();
    }
});<commit_msg>Removed extra details for each feature<commit_after>var loggedIn = false;

$(function() {
    // Animate stuff
    var delay = 150;
    for (i = 0; i < 3; i++) {
        $($('.features h2')[i]).transition({ opacity: 1, delay: (i*delay) }, 2000);
        $($('.features .circle')[i]).transition({ opacity: 1, scale: 1, delay: (300+i*delay) }, 500, 'snap');
        $($('.features .blurb')[i]).transition({ opacity: 1, delay: (i*delay) }, 2000);
    }

    var tests = {
        user: function (val) {
            return val.length > 3 &&
                   val.length <= 16 &&
                   /^[0-9A-Za-z_-][0-9A-Za-z_.-]*[0-9A-Za-z_-]$/.test(val);
        },

        email: function (val) {
            return /^(?:\w+\.?)*\w+@(?:\w+\.)+\w+$/.test(val);
        },

        minLength: function (val, length) {
            return val.length >= length;
        },

        maxLength: function (val, length) {
            return val.length <= length;
        },

        equal: function (val1, val2) {
            return (val1 == val2);
        }
    };

    $('#login_form').isHappy({
        fields: {
            '#username': {
                required: true
            },
            '#password': {
                required: true
            }
        }
    });

    $('#registration_form').isHappy({
        fields: {
            '#reg_username': {
                required: true,
                test: tests.user
            },
            '#reg_password': {
                required: true
            },
            '#reg_password_2': {
                required: true,
                test: tests.equal,
                arg: function () {
                    return $('#reg_password').val();
                }
            },
            '#reg_email': {
                required: true,
                test: tests.email
            }
        }
    });

    // Landing page forms
    $('.landing .registration > div').on('click', function(e) {
        if (!$(this).hasClass('hidden')) return;

        $('.landing .registration > div').toggleClass('hidden');
        $(this).children('.widget').slideToggle();
        $('.landing .registration > div').not(this).children('.widget').slideToggle();
    });

    // Navigation forms
    var dropdown = $('.nav-extra-dropdown');

    $('.nav-extra').each(function() {
        if ($(this).parent().hasClass('active')) {
            if ($(this).hasClass('nav-extra-login'))
                $('#nav-extra-login').slideDown(200);
            else
                $('#nav-extra-register').slideDown(200);
            bindCloseNotifications();
            return false;
        }
    });

    $('.nav-extra').on('click', function(e) {
        e.preventDefault();
        e.stopPropagation();

        if (($(this).hasClass('nav-extra-login') && $('#nav-extra-login').is(":visible")) ||
            $(this).hasClass('nav-extra-register') && $('#nav-extra-register').is(":visible")) {
            closeNotifications();
            return false;
        }
        dropdown.slideUp(200);

        if ($(this).hasClass('nav-extra-login'))
            $('#nav-extra-login').slideDown(200);
        else
            $('#nav-extra-register').slideDown(200);
        $(this).parent().addClass('active');

        bindCloseNotifications();
    });

    function bindCloseNotifications() {
        $(document).bind('click.extra-hide', function(e) {
            if ($(e.target).closest('.nav-extra-dropdown').length != 0 && $(e.target).not('.nav-extra')) return true;
            closeNotifications();
        });
    }

    function closeNotifications() {
        dropdown.slideUp(200);
        $('.nav-extra').parent().removeClass('active');
        $('.nav-extra-dropdown .msg').remove();
    }
});<|endoftext|>


<commit_before>// ==UserScript==
// @name         vgadblockblockblocker
// @namespace    http://github.com/epleterte
// @version      0.1
// @description  Blocks the adblock blocker
// @author       Christian Bryn
// @include      http://www.vg.no/*
// @match        http*://www.vg.no/*
// @grant        none
// @license      BSD-3
// ==/UserScript==

// put our function in a new script element
var script = document.createElement('script');

// method 1:
// override the function that inserts the unwanted ...content
script.innerHTML = 'window.__AB__ = function() { return true; }';

// method 2:
// probably better. probably disables the function that makes calls to the (german) adblock detector provider
script.innerHTML = 'var _0x9f3f = [];var _0xef99x1 = function() {};';

// append to head elements (making it the last)
document.getElementsByTagName('head')[0].appendChild(script);
<commit_msg>remove useless function return<commit_after>// ==UserScript==
// @name         vgadblockblockblocker
// @namespace    http://github.com/epleterte
// @version      0.1
// @description  Blocks the adblock blocker
// @author       Christian Bryn
// @include      http://www.vg.no/*
// @match        http*://www.vg.no/*
// @grant        none
// @license      BSD-3
// ==/UserScript==

// put our function in a new script element
var script = document.createElement('script');

// method 1:
// override the function that inserts the unwanted ...content
script.innerHTML = 'window.__AB__ = function() {}';

// method 2:
// probably better. probably disables the function that makes calls to the (german) adblock detector provider
script.innerHTML = 'var _0x9f3f = [];var _0xef99x1 = function() {};';

// append to head elements (making it the last)
document.getElementsByTagName('head')[0].appendChild(script);
<|endoftext|>


<commit_before>'use strict';

var _                 = require('mano').i18n.bind('View: Statistics')
  , db                = require('../db')
  , uncapitalize      = require('es5-ext/string/#/uncapitalize')
  , location          = require('mano/lib/client/location')
  , queryHandlerConf  = require('../apps/statistics/flow-query-conf')
  , setupQueryHandler = require('../utils/setup-client-query-handler')
  , copy              = require('es5-ext/object/copy')
  , ObservableValue   = require('observable-value')
  , assign            = require('es5-ext/object/assign')
  , Pagination        = require('./components/pagination')
  , modes             = require('../utils/statistics-flow-group-modes')
  , selectService     = require('./components/filter-bar/select-service')
  , selectCertificate = require('./components/filter-bar/select-certificate')
  , selectPeriodMode  = require('./components/filter-bar/select-period-mode')
  , itemsPerPage      = require('../conf/objects-list-items-per-page')
  , serviceQuery      = require('../apps-common/query-conf/service')
  , certificateQuery  = require('../apps-common/query-conf/certificate')
  , stepStatusQuery   = require('../apps-common/query-conf/processing-step-status')
  , pageQuery         = require('../utils/query/date-constrained-page')
  , copyDbDate        = require('../utils/copy-db-date')
  , queryServer       = require('./utils/statistics-flow-query-server')
  , processingSteps   = require('../processing-steps-meta')
  , getDynamicUrl     = require('./utils/get-dynamic-url')
  , getStepLabelByShortPath = require('../utils/get-step-label-by-short-path')
  , incrementDateByTimeUnit = require('../utils/increment-date-by-time-unit')
  , floorToTimeUnit         = require('../utils/floor-to-time-unit')
  , calculateDurationByMode = require('../utils/calculate-duration-by-mode')
  , dateFromToBlock         = require('./components/filter-bar/select-date-range-safe-fallback')
  , reduceResult            = require('../utils/statistics-flow-reduce-processing-step')
  , filterData              = require('../utils/statistics-flow-roles-filter-result');

exports._parent        = require('./statistics-flow');
exports._customFilters = Function.prototype;

exports['flow-nav']                = { class: { 'submitted-menu-item-active': true } };
exports['flow-by-role-nav'] = { class: { 'pills-nav-active': true } };

var serviceToCertLegacyMatch = { '': [] };

var getServiceName = function (ServiceType) {
	return uncapitalize.call(
		ServiceType.__id__.slice('BusinessProcess'.length)
	);
};

db.BusinessProcess.extensions.forEach(function (ServiceType) {
	ServiceType.prototype.certificates.map.forEach(function (certificate) {
		if (!serviceToCertLegacyMatch[getServiceName(ServiceType)]) {
			serviceToCertLegacyMatch[getServiceName(ServiceType)] = [];
		}
		serviceToCertLegacyMatch[getServiceName(ServiceType)].push('certificate-' + certificate.key);
		serviceToCertLegacyMatch[''].push('certificate-' + certificate.key);
	});
});

var stepStatuses = {};
['pending', 'approved', 'sentBack', 'rejected', 'paused'].forEach(function (stepName) {
	// sanity check
	if (!db.ProcessingStepStatus.members.has(stepName)) {
		return;
	}
	stepStatuses[stepName] = db.ProcessingStepStatus.meta[stepName];
});

exports['statistics-main'] = function () {
	var queryHandler, data = new ObservableValue({})
	  , pagination = new Pagination('/flow/by-role/'), handlerConf, params;

	handlerConf = queryHandlerConf.slice(0);
	handlerConf.push(pageQuery, serviceQuery, certificateQuery, stepStatusQuery);
	queryHandler = setupQueryHandler(handlerConf,
		location, '/flow/by-role/');

	params = queryHandler._handlers.map(function (handler) {
		return handler.name;
	});

	queryHandler.on('query', function (query) {
		var serverQuery = copy(query), dateFrom, dateTo, mode
		  , currentDate, offset, timeUnitsCount = 0, durationInTimeUnits, page;
		dateFrom = query.dateFrom;
		dateTo   = query.dateTo || new db.Date();
		mode     = query.mode;
		page     = query.page;

		durationInTimeUnits = calculateDurationByMode(dateFrom, dateTo, mode);
		if (query.pageCount > 1) {
			offset = { from: ((page - 1) * itemsPerPage) };
			offset.to = offset.from;
			if ((durationInTimeUnits - offset.from) < itemsPerPage) {
				offset.to += durationInTimeUnits - offset.from;
			} else {
				offset.to += itemsPerPage;
			}
			offset.to -= 1;

			currentDate = copyDbDate(dateFrom);
			floorToTimeUnit(currentDate, mode);
			while (timeUnitsCount <= offset.to) {
				if (timeUnitsCount === offset.from && query.page > 1) {
					dateFrom = copyDbDate(currentDate);
				}
				if (timeUnitsCount === offset.to && query.page < query.pageCount) {
					dateTo = incrementDateByTimeUnit(copyDbDate(currentDate), mode);
					dateTo.setUTCDate(dateTo.getUTCDate() - 1);
				}
				timeUnitsCount++;
				incrementDateByTimeUnit(currentDate, mode);
			}
		}
		serverQuery.dateFrom = dateFrom.toJSON();
		serverQuery.dateTo = dateTo.toJSON();

		delete serverQuery.service;
		delete serverQuery.page;
		delete serverQuery.certificate;
		delete serverQuery.status;
		delete serverQuery.pageCount;

		queryServer(serverQuery).done(function (responseData) {
			data.value = filterData(reduceResult(responseData),
				assign(query, { dateFrom: dateFrom, dateTo: dateTo }));
			pagination.count.value   = query.pageCount;
			pagination.current.value = query.page;
		});
	});

	div({ class: 'block-pull-up' },
		form({ action: '/flow/by-role/', autoSubmit: true },
			section({ class: 'date-period-selector-positioned-on-submenu' }, dateFromToBlock()),
			section({ class: 'section-primary users-table-filter-bar display-flex flex-wrap' },
				div(
					div({ class: 'users-table-filter-bar-status' },
						selectService({ label: _("All services") })),
					div({ class: 'users-table-filter-bar-status' },
						selectCertificate(),
						legacy('selectMatch', 'service-select', serviceToCertLegacyMatch)),
					div({ class: 'users-table-filter-bar-status' },
						select(
							{ id: 'step-status', name: 'status' },
							list(Object.keys(stepStatuses), function (status) {
								if (status === 'pending') {
									return;
								}
								return option({
									id: 'status-' + status,
									value: status,
									selected: location.query.get('status').map(function (value) {
										var selected = (status ? (value === status) : (value == null));
										return selected ? 'selected' : null;
									})
								}, stepStatuses[status].label);
							})
						))
				),
				selectPeriodMode(),
				div(
					div(
						a({
							class: 'users-table-filter-bar-print',
							href: getDynamicUrl('/flow-roles-data.pdf', { only: params }),
							target: '_blank'
						}, span({ class: 'fa fa-print' }), " ", _("Print pdf"))
					),
					div(
						a({
							class: 'users-table-filter-bar-print',
							href: getDynamicUrl('/flow-roles-data.csv', { only: params }),
							target: '_blank'
						}, span({ class: 'fa fa-print' }), " ", _("Print csv"))
					)
				),
				p({ class: 'submit' }, input({ type: 'submit' })))),

		section({ class: 'pad-if-pagination' }, pagination),
		br(),
		section({ class: "section-primary statistics-table-scrollable" },
			data.map(function (result) {
				var mode = modes.get(location.query.mode || 'daily');
				return table({ class: 'statistics-table' },
					thead(
						th({ class: 'statistics-table-number' }, mode.labelNoun),
						list(Object.keys(processingSteps), function (shortStepPath) {
							return th({ class: 'statistics-table-number' },
								getStepLabelByShortPath(shortStepPath));
						})
					),
					tbody({
						onEmpty: tr(td({ class: 'empty', colspan: Object.keys(processingSteps).length },
							_("No data for this criteria")))
					}, Object.keys(result), function (key) {
						return tr(
							td(key),
							Object.keys(result[key]).length ?
									list(Object.keys(result[key]), function (step) {
										return td({ class: 'statistics-table-number' },
											result[key][step] == null ? _("N/A") : result[key][step]);
									}) : td({
								class: 'statistics-table-info',
								colspan: Object.keys(processingSteps).length
							}, _("Nothing to report for this period"))
						);
					}));
			})));
};
<commit_msg>fix very silly mistake<commit_after>'use strict';

var _                 = require('mano').i18n.bind('View: Statistics')
  , db                = require('../db')
  , uncapitalize      = require('es5-ext/string/#/uncapitalize')
  , location          = require('mano/lib/client/location')
  , queryHandlerConf  = require('../apps/statistics/flow-query-conf')
  , setupQueryHandler = require('../utils/setup-client-query-handler')
  , copy              = require('es5-ext/object/copy')
  , ObservableValue   = require('observable-value')
  , assign            = require('es5-ext/object/assign')
  , Pagination        = require('./components/pagination')
  , modes             = require('../utils/statistics-flow-group-modes')
  , selectService     = require('./components/filter-bar/select-service')
  , selectCertificate = require('./components/filter-bar/select-certificate')
  , selectPeriodMode  = require('./components/filter-bar/select-period-mode')
  , itemsPerPage      = require('../conf/objects-list-items-per-page')
  , serviceQuery      = require('../apps-common/query-conf/service')
  , certificateQuery  = require('../apps-common/query-conf/certificate')
  , stepStatusQuery   = require('../apps-common/query-conf/processing-step-status')
  , pageQuery         = require('../utils/query/date-constrained-page')
  , copyDbDate        = require('../utils/copy-db-date')
  , queryServer       = require('./utils/statistics-flow-query-server')
  , processingSteps   = require('../processing-steps-meta')
  , getDynamicUrl     = require('./utils/get-dynamic-url')
  , getStepLabelByShortPath = require('../utils/get-step-label-by-short-path')
  , incrementDateByTimeUnit = require('../utils/increment-date-by-time-unit')
  , floorToTimeUnit         = require('../utils/floor-to-time-unit')
  , calculateDurationByMode = require('../utils/calculate-duration-by-mode')
  , dateFromToBlock         = require('./components/filter-bar/select-date-range-safe-fallback')
  , reduceResult            = require('../utils/statistics-flow-reduce-processing-step')
  , filterData              = require('../utils/statistics-flow-roles-filter-result');

exports._parent        = require('./statistics-flow');
exports._customFilters = Function.prototype;

exports['flow-nav']                = { class: { 'submitted-menu-item-active': true } };
exports['flow-by-role-nav'] = { class: { 'pills-nav-active': true } };

var serviceToCertLegacyMatch = { '': [] };

var getServiceName = function (ServiceType) {
	return uncapitalize.call(
		ServiceType.__id__.slice('BusinessProcess'.length)
	);
};

db.BusinessProcess.extensions.forEach(function (ServiceType) {
	ServiceType.prototype.certificates.map.forEach(function (certificate) {
		if (!serviceToCertLegacyMatch[getServiceName(ServiceType)]) {
			serviceToCertLegacyMatch[getServiceName(ServiceType)] = [];
		}
		serviceToCertLegacyMatch[getServiceName(ServiceType)].push('certificate-' + certificate.key);
		serviceToCertLegacyMatch[''].push('certificate-' + certificate.key);
	});
});

var stepStatuses = {};
['approved', 'sentBack', 'rejected', 'paused'].forEach(function (stepName) {
	// sanity check
	if (!db.ProcessingStepStatus.members.has(stepName)) {
		return;
	}
	stepStatuses[stepName] = db.ProcessingStepStatus.meta[stepName];
});

exports['statistics-main'] = function () {
	var queryHandler, data = new ObservableValue({})
	  , pagination = new Pagination('/flow/by-role/'), handlerConf, params;

	handlerConf = queryHandlerConf.slice(0);
	handlerConf.push(pageQuery, serviceQuery, certificateQuery, stepStatusQuery);
	queryHandler = setupQueryHandler(handlerConf,
		location, '/flow/by-role/');

	params = queryHandler._handlers.map(function (handler) {
		return handler.name;
	});

	queryHandler.on('query', function (query) {
		var serverQuery = copy(query), dateFrom, dateTo, mode
		  , currentDate, offset, timeUnitsCount = 0, durationInTimeUnits, page;
		dateFrom = query.dateFrom;
		dateTo   = query.dateTo || new db.Date();
		mode     = query.mode;
		page     = query.page;

		durationInTimeUnits = calculateDurationByMode(dateFrom, dateTo, mode);
		if (query.pageCount > 1) {
			offset = { from: ((page - 1) * itemsPerPage) };
			offset.to = offset.from;
			if ((durationInTimeUnits - offset.from) < itemsPerPage) {
				offset.to += durationInTimeUnits - offset.from;
			} else {
				offset.to += itemsPerPage;
			}
			offset.to -= 1;

			currentDate = copyDbDate(dateFrom);
			floorToTimeUnit(currentDate, mode);
			while (timeUnitsCount <= offset.to) {
				if (timeUnitsCount === offset.from && query.page > 1) {
					dateFrom = copyDbDate(currentDate);
				}
				if (timeUnitsCount === offset.to && query.page < query.pageCount) {
					dateTo = incrementDateByTimeUnit(copyDbDate(currentDate), mode);
					dateTo.setUTCDate(dateTo.getUTCDate() - 1);
				}
				timeUnitsCount++;
				incrementDateByTimeUnit(currentDate, mode);
			}
		}
		serverQuery.dateFrom = dateFrom.toJSON();
		serverQuery.dateTo = dateTo.toJSON();

		delete serverQuery.service;
		delete serverQuery.page;
		delete serverQuery.certificate;
		delete serverQuery.status;
		delete serverQuery.pageCount;

		queryServer(serverQuery).done(function (responseData) {
			data.value = filterData(reduceResult(responseData),
				assign(query, { dateFrom: dateFrom, dateTo: dateTo }));
			pagination.count.value   = query.pageCount;
			pagination.current.value = query.page;
		});
	});

	div({ class: 'block-pull-up' },
		form({ action: '/flow/by-role/', autoSubmit: true },
			section({ class: 'date-period-selector-positioned-on-submenu' }, dateFromToBlock()),
			section({ class: 'section-primary users-table-filter-bar display-flex flex-wrap' },
				div(
					div({ class: 'users-table-filter-bar-status' },
						selectService({ label: _("All services") })),
					div({ class: 'users-table-filter-bar-status' },
						selectCertificate(),
						legacy('selectMatch', 'service-select', serviceToCertLegacyMatch)),
					div({ class: 'users-table-filter-bar-status' },
						select(
							{ id: 'step-status', name: 'status' },
							list(Object.keys(stepStatuses), function (status) {
								return option({
									id: 'status-' + status,
									value: status,
									selected: location.query.get('status').map(function (value) {
										var selected = (status ? (value === status) : (value == null));
										return selected ? 'selected' : null;
									})
								}, stepStatuses[status].label);
							})
						))
				),
				selectPeriodMode(),
				div(
					div(
						a({
							class: 'users-table-filter-bar-print',
							href: getDynamicUrl('/flow-roles-data.pdf', { only: params }),
							target: '_blank'
						}, span({ class: 'fa fa-print' }), " ", _("Print pdf"))
					),
					div(
						a({
							class: 'users-table-filter-bar-print',
							href: getDynamicUrl('/flow-roles-data.csv', { only: params }),
							target: '_blank'
						}, span({ class: 'fa fa-print' }), " ", _("Print csv"))
					)
				),
				p({ class: 'submit' }, input({ type: 'submit' })))),

		section({ class: 'pad-if-pagination' }, pagination),
		br(),
		section({ class: "section-primary statistics-table-scrollable" },
			data.map(function (result) {
				var mode = modes.get(location.query.mode || 'daily');
				return table({ class: 'statistics-table' },
					thead(
						th({ class: 'statistics-table-number' }, mode.labelNoun),
						list(Object.keys(processingSteps), function (shortStepPath) {
							return th({ class: 'statistics-table-number' },
								getStepLabelByShortPath(shortStepPath));
						})
					),
					tbody({
						onEmpty: tr(td({ class: 'empty', colspan: Object.keys(processingSteps).length },
							_("No data for this criteria")))
					}, Object.keys(result), function (key) {
						return tr(
							td(key),
							Object.keys(result[key]).length ?
									list(Object.keys(result[key]), function (step) {
										return td({ class: 'statistics-table-number' },
											result[key][step] == null ? _("N/A") : result[key][step]);
									}) : td({
								class: 'statistics-table-info',
								colspan: Object.keys(processingSteps).length
							}, _("Nothing to report for this period"))
						);
					}));
			})));
};
<|endoftext|>


<commit_before>import createDebug from 'debug'
import eventToPromise from 'event-to-promise'
import find from 'lodash.find'
import forEach from 'lodash.foreach'
import got from 'got'
import map from 'lodash.map'
import omit from 'lodash.omit'
import unzip from '@julien-f/unzip'
import {PassThrough} from 'stream'
import {promisify} from 'bluebird'
import {Xapi as XapiBase} from 'xen-api'

import {debounce} from './decorators'
import {JsonRpcError} from './api-errors'
import {parseXml, pFinally} from './utils'

const debug = createDebug('xo:xapi')

// ===================================================================

const gotPromise = promisify(got)

const wrapError = error => {
  const e = new Error(error[0])
  e.code = error[0]
  e.params = error.slice(1)
  return e
}

// ===================================================================

export default class Xapi extends XapiBase {
  constructor (...args) {
    super(...args)

    const objectsWatchers = this._objectWatchers = Object.create(null)
    const taskWatchers = this._taskWatchers = Object.create(null)

    // TODO: This is necessary to get UUIDs for host.patches.
    //
    // It will no longer be useful when using xen-api >= 0.5.
    this._refsToUuids = Object.create(null)

    const onAddOrUpdate = objects => {
      forEach(objects, object => {
        const {
          $id: id,
          $ref: ref,
          uuid
        } = object

        if (ref && uuid) {
          this._refsToUuids[ref] = uuid
        }

        // Watched object.
        if (id in objectsWatchers) {
          objectsWatchers[id].resolve(object)
          delete objectsWatchers[id]
        }
        if (ref in objectsWatchers) {
          objectsWatchers[ref].resolve(object)
          delete objectsWatchers[ref]
        }

        // Watched task.
        if (ref in taskWatchers) {
          const {status} = object

          if (status === 'success') {
            taskWatchers[ref].resolve(object.result)
          } else if (status === 'failure') {
            taskWatchers[ref].reject(wrapError(object.error_info))
          } else {
            return
          }

          delete taskWatchers[ref]
        }
      })
    }
    this.objects.on('add', onAddOrUpdate)
    this.objects.on('update', onAddOrUpdate)
  }

  // FIXME: remove this backported methods when xen-api >= 0.5
  getObject (idOrUuidOrRef, defaultValue) {
    const {_objects: {all: objects}} = this
    const object = (
      // if there is an UUID, it is also the $id.
      objects[idOrUuidOrRef] ||
      objects[this._refsToUuids[idOrUuidOrRef]]
    )

    if (object) return object

    if (arguments.length > 1) return defaultValue

    throw new Error('there is not object can be matched to ' + idOrUuidOrRef)
  }
  getObjectByRef (ref, defaultValue) {
    const {
      _refsToUuids: refsToUuids,

      // Objects ids are already UUIDs if they have one.
      _objects: {all: objectsByUuids}
    } = this

    if (ref in refsToUuids) {
      return objectsByUuids[refsToUuids[ref]]
    }

    if (arguments.length > 1) {
      return defaultValue
    }

    throw new Error('there is no object with the ref ' + ref)
  }
  getObjectByUuid (uuid, defaultValue) {
    const {
      // Objects ids are already UUIDs if they have one.
      _objects: {all: objectsByUuids}
    } = this

    if (uuid in objectsByUuids) {
      return objectsByUuids[uuid]
    }

    if (arguments.length > 1) {
      return defaultValue
    }

    throw new Error('there is no object with the UUID ' + uuid)
  }

  // =================================================================

  // Wait for an object to appear or to be updated.
  //
  // TODO: implements a timeout.
  _waitObject (idOrUuidOrRef) {
    let watcher = this._objectWatchers[idOrUuidOrRef]
    if (!watcher) {
      let resolve, reject
      const promise = new Promise((resolve_, reject_) => {
        resolve = resolve_
        reject = reject_
      })

      // Register the watcher.
      watcher = this._objectWatchers[idOrUuidOrRef] = {
        promise,
        resolve,
        reject
      }
    }

    return watcher.promise
  }

  // Returns the objects if already presents or waits for it.
  async _getOrWaitObject (idOrUuidOrRef) {
    return (
      this.getObject(idOrUuidOrRef, undefined) ||
      this._waitObject(idOrUuidOrRef)
    )
  }

  // =================================================================

  // Create a task.
  //
  // Returns the task object from the Xapi.
  async _createTask (name, description = '') {
    const ref = await this.call('task.create', name, description)
    debug('task created: %s', name)

    pFinally(this._watchTask(ref), () => {
      this.call('task.destroy', ref).then(() => {
        debug('task destroyed: %s', name)
      })
    })

    return this._getOrWaitObject(ref)
  }

  // Waits for a task to be resolved.
  _watchTask (ref) {
    // If a task object is passed, unpacked the ref.
    if (typeof ref === 'object' && ref.$ref) ref = ref.$ref

    let watcher = this._taskWatchers[ref]
    if (!watcher) {
      let resolve, reject
      const promise = new Promise((resolve_, reject_) => {
        resolve = resolve_
        reject = reject_
      })

      // Register the watcher.
      watcher = this._taskWatchers[ref] = {
        promise,
        resolve,
        reject
      }
    }

    return watcher.promise
  }

  // =================================================================

  // FIXME: should be static
  @debounce(24 * 60 * 60 * 1000)
  async _getXenUpdates () {
    const [body, {statusCode}] = await gotPromise(
      'http://updates.xensource.com/XenServer/updates.xml'
    )

    if (statusCode !== 200) {
      throw new JsonRpcError('cannot fetch patches list from Citrix')
    }

    const {patchdata: data} = parseXml(body)

    const patches = Object.create(null)
    forEach(data.patches.patch, patch => {
      patches[patch.uuid] = {
        date: patch.timestamp,
        description: patch['name-description'],
        documentationUrl: patch.url,
        guidance: patch['after-apply-guidance'],
        name: patch['name-label'],
        url: patch['patch-url'],

        // TODO: what does it mean, should we handle it?
        // version: patch.version,
      }
    })

    const resolveVersionPatches = function (uuids) {
      const versionPatches = Object.create(null)

      forEach(uuids, ({uuid}) => {
        versionPatches[uuid] = patches[uuid]
      })

      return versionPatches
    }

    const versions = Object.create(null)
    let latestVersion
    forEach(data.serverversions.version, version => {
      versions[version.value] = {
        date: version.timestamp,
        name: version.name,
        id: version.value,
        documentationUrl: version.url,
        patches: resolveVersionPatches(version.patch)
      }

      if (version.latest) {
        latestVersion = versions[version.value]
      }
    })

    return {
      patches,
      latestVersion,
      versions
    }
  }

  // =================================================================

  async listMissingPoolPatchesOnHost (hostId) {
    const {
      software_version: {product_version: version},
      patches
    } = this.getObject(hostId)
    console.log
    return omit(
      (await this._getXenUpdates()).versions[version].patches,

      // TODO: simplify when we start to use xen-api >= 0.5
      map(patches, ref => {
        const hostPatch = this.objects.all[this._refsToUuids[ref]]
        return this._refsToUuids[hostPatch.pool_patch]
      })
    )
  }

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

  async _uploadPoolPatch (stream, length) {
    const task = await this._createTask('Patch upload from XO')

    // TODO: Update when xen-api >= 0.5
    const poolMaster = this.objects.all[this._refsToUuids[this.pool.master]]

    const [, patchRef] = await Promise.all([
      gotPromise('http://' + poolMaster.address + '/pool_patch_upload', {
        method: 'put',
        body: stream,
        query: {
          session_id: this.sessionId,
          task_id: task.$ref
        },
        headers: {
          'content-length': length
        }
      }),
      this._watchTask(task)
    ])

    return this._getOrWaitObject(patchRef)
  }

  async _getOrUploadPoolPatch (uuid) {
    try {
      return this.getObjectByUuid(uuid)
    } catch (error) {}

    debug('downloading patch %s', uuid)

    const patchInfo = (await this._getXenUpdates()).patches[uuid]

    const PATCH_RE = /\.xsupdate$/
    const proxy = new PassThrough()
    got(patchInfo.url).on('error', error => {
      // TODO: better error handling
      console.error(error)
    }).pipe(unzip.Parse()).on('entry', entry => {
      if (PATCH_RE.test(entry.path)) {
        proxy.emit('length', entry.size)
        entry.pipe(proxy)
      } else {
        entry.autodrain()
      }
    }).on('error', error => {
      // TODO: better error handling
      console.error(error)
    })

    const length = await eventToPromise(proxy, 'length')
    return this._uploadPoolPatch(proxy, length)
  }

  async installPoolPatchOnHost (patchUuid, hostId) {
    const patch = await this._getOrUploadPoolPatch(patchUuid)
    const host = this.getObject(hostId)

    debug('installing patch %s', patchUuid)

    await this.call('pool_patch.apply', patch.$ref, host.$ref)
  }

  async installPoolPatchOnAllHosts (patchUuid) {
    const patch = await this._getOrUploadPoolPatch(patchUuid)

    await this.call('pool_patch.pool_apply', patch.$ref)
  }

  // =================================================================

  async _doDockerAction (vmId, action, containerId) {
    const vm = this.getObject(vmId)
    const host = this.getObject(vm.resident_on)

    let params = {
      vmuuid: vm.uuid
    }

    if (containerId) {
      params.container = containerId
    }
    return await this.call('host.call_plugin', host.$ref, 'xscontainer', action, params)
  }

  async registerDockerContainer (vmId) {
    await this._doDockerAction(vmId, 'register')
  }

  async deregisterDockerContainer (vmId) {
    await this._doDockerAction(vmId, 'deregister')
  }

  async startDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, containerId, 'start')
  }

  async stopDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, containerId, 'stop')
  }

  async restartDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, containerId, 'restart')
  }

  async pauseDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, containerId, 'pause')
  }

  async unpauseDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, containerId, 'unpause')
  }

  // =================================================================

}
<commit_msg>Fix docker methods.<commit_after>import createDebug from 'debug'
import eventToPromise from 'event-to-promise'
import find from 'lodash.find'
import forEach from 'lodash.foreach'
import got from 'got'
import map from 'lodash.map'
import omit from 'lodash.omit'
import unzip from '@julien-f/unzip'
import {PassThrough} from 'stream'
import {promisify} from 'bluebird'
import {Xapi as XapiBase} from 'xen-api'

import {debounce} from './decorators'
import {JsonRpcError} from './api-errors'
import {parseXml, pFinally} from './utils'

const debug = createDebug('xo:xapi')

// ===================================================================

const gotPromise = promisify(got)

const wrapError = error => {
  const e = new Error(error[0])
  e.code = error[0]
  e.params = error.slice(1)
  return e
}

// ===================================================================

export default class Xapi extends XapiBase {
  constructor (...args) {
    super(...args)

    const objectsWatchers = this._objectWatchers = Object.create(null)
    const taskWatchers = this._taskWatchers = Object.create(null)

    // TODO: This is necessary to get UUIDs for host.patches.
    //
    // It will no longer be useful when using xen-api >= 0.5.
    this._refsToUuids = Object.create(null)

    const onAddOrUpdate = objects => {
      forEach(objects, object => {
        const {
          $id: id,
          $ref: ref,
          uuid
        } = object

        if (ref && uuid) {
          this._refsToUuids[ref] = uuid
        }

        // Watched object.
        if (id in objectsWatchers) {
          objectsWatchers[id].resolve(object)
          delete objectsWatchers[id]
        }
        if (ref in objectsWatchers) {
          objectsWatchers[ref].resolve(object)
          delete objectsWatchers[ref]
        }

        // Watched task.
        if (ref in taskWatchers) {
          const {status} = object

          if (status === 'success') {
            taskWatchers[ref].resolve(object.result)
          } else if (status === 'failure') {
            taskWatchers[ref].reject(wrapError(object.error_info))
          } else {
            return
          }

          delete taskWatchers[ref]
        }
      })
    }
    this.objects.on('add', onAddOrUpdate)
    this.objects.on('update', onAddOrUpdate)
  }

  // FIXME: remove this backported methods when xen-api >= 0.5
  getObject (idOrUuidOrRef, defaultValue) {
    const {_objects: {all: objects}} = this
    const object = (
      // if there is an UUID, it is also the $id.
      objects[idOrUuidOrRef] ||
      objects[this._refsToUuids[idOrUuidOrRef]]
    )

    if (object) return object

    if (arguments.length > 1) return defaultValue

    throw new Error('there is not object can be matched to ' + idOrUuidOrRef)
  }
  getObjectByRef (ref, defaultValue) {
    const {
      _refsToUuids: refsToUuids,

      // Objects ids are already UUIDs if they have one.
      _objects: {all: objectsByUuids}
    } = this

    if (ref in refsToUuids) {
      return objectsByUuids[refsToUuids[ref]]
    }

    if (arguments.length > 1) {
      return defaultValue
    }

    throw new Error('there is no object with the ref ' + ref)
  }
  getObjectByUuid (uuid, defaultValue) {
    const {
      // Objects ids are already UUIDs if they have one.
      _objects: {all: objectsByUuids}
    } = this

    if (uuid in objectsByUuids) {
      return objectsByUuids[uuid]
    }

    if (arguments.length > 1) {
      return defaultValue
    }

    throw new Error('there is no object with the UUID ' + uuid)
  }

  // =================================================================

  // Wait for an object to appear or to be updated.
  //
  // TODO: implements a timeout.
  _waitObject (idOrUuidOrRef) {
    let watcher = this._objectWatchers[idOrUuidOrRef]
    if (!watcher) {
      let resolve, reject
      const promise = new Promise((resolve_, reject_) => {
        resolve = resolve_
        reject = reject_
      })

      // Register the watcher.
      watcher = this._objectWatchers[idOrUuidOrRef] = {
        promise,
        resolve,
        reject
      }
    }

    return watcher.promise
  }

  // Returns the objects if already presents or waits for it.
  async _getOrWaitObject (idOrUuidOrRef) {
    return (
      this.getObject(idOrUuidOrRef, undefined) ||
      this._waitObject(idOrUuidOrRef)
    )
  }

  // =================================================================

  // Create a task.
  //
  // Returns the task object from the Xapi.
  async _createTask (name, description = '') {
    const ref = await this.call('task.create', name, description)
    debug('task created: %s', name)

    pFinally(this._watchTask(ref), () => {
      this.call('task.destroy', ref).then(() => {
        debug('task destroyed: %s', name)
      })
    })

    return this._getOrWaitObject(ref)
  }

  // Waits for a task to be resolved.
  _watchTask (ref) {
    // If a task object is passed, unpacked the ref.
    if (typeof ref === 'object' && ref.$ref) ref = ref.$ref

    let watcher = this._taskWatchers[ref]
    if (!watcher) {
      let resolve, reject
      const promise = new Promise((resolve_, reject_) => {
        resolve = resolve_
        reject = reject_
      })

      // Register the watcher.
      watcher = this._taskWatchers[ref] = {
        promise,
        resolve,
        reject
      }
    }

    return watcher.promise
  }

  // =================================================================

  // FIXME: should be static
  @debounce(24 * 60 * 60 * 1000)
  async _getXenUpdates () {
    const [body, {statusCode}] = await gotPromise(
      'http://updates.xensource.com/XenServer/updates.xml'
    )

    if (statusCode !== 200) {
      throw new JsonRpcError('cannot fetch patches list from Citrix')
    }

    const {patchdata: data} = parseXml(body)

    const patches = Object.create(null)
    forEach(data.patches.patch, patch => {
      patches[patch.uuid] = {
        date: patch.timestamp,
        description: patch['name-description'],
        documentationUrl: patch.url,
        guidance: patch['after-apply-guidance'],
        name: patch['name-label'],
        url: patch['patch-url'],

        // TODO: what does it mean, should we handle it?
        // version: patch.version,
      }
    })

    const resolveVersionPatches = function (uuids) {
      const versionPatches = Object.create(null)

      forEach(uuids, ({uuid}) => {
        versionPatches[uuid] = patches[uuid]
      })

      return versionPatches
    }

    const versions = Object.create(null)
    let latestVersion
    forEach(data.serverversions.version, version => {
      versions[version.value] = {
        date: version.timestamp,
        name: version.name,
        id: version.value,
        documentationUrl: version.url,
        patches: resolveVersionPatches(version.patch)
      }

      if (version.latest) {
        latestVersion = versions[version.value]
      }
    })

    return {
      patches,
      latestVersion,
      versions
    }
  }

  // =================================================================

  async listMissingPoolPatchesOnHost (hostId) {
    const {
      software_version: {product_version: version},
      patches
    } = this.getObject(hostId)
    console.log
    return omit(
      (await this._getXenUpdates()).versions[version].patches,

      // TODO: simplify when we start to use xen-api >= 0.5
      map(patches, ref => {
        const hostPatch = this.objects.all[this._refsToUuids[ref]]
        return this._refsToUuids[hostPatch.pool_patch]
      })
    )
  }

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

  async _uploadPoolPatch (stream, length) {
    const task = await this._createTask('Patch upload from XO')

    // TODO: Update when xen-api >= 0.5
    const poolMaster = this.objects.all[this._refsToUuids[this.pool.master]]

    const [, patchRef] = await Promise.all([
      gotPromise('http://' + poolMaster.address + '/pool_patch_upload', {
        method: 'put',
        body: stream,
        query: {
          session_id: this.sessionId,
          task_id: task.$ref
        },
        headers: {
          'content-length': length
        }
      }),
      this._watchTask(task)
    ])

    return this._getOrWaitObject(patchRef)
  }

  async _getOrUploadPoolPatch (uuid) {
    try {
      return this.getObjectByUuid(uuid)
    } catch (error) {}

    debug('downloading patch %s', uuid)

    const patchInfo = (await this._getXenUpdates()).patches[uuid]

    const PATCH_RE = /\.xsupdate$/
    const proxy = new PassThrough()
    got(patchInfo.url).on('error', error => {
      // TODO: better error handling
      console.error(error)
    }).pipe(unzip.Parse()).on('entry', entry => {
      if (PATCH_RE.test(entry.path)) {
        proxy.emit('length', entry.size)
        entry.pipe(proxy)
      } else {
        entry.autodrain()
      }
    }).on('error', error => {
      // TODO: better error handling
      console.error(error)
    })

    const length = await eventToPromise(proxy, 'length')
    return this._uploadPoolPatch(proxy, length)
  }

  async installPoolPatchOnHost (patchUuid, hostId) {
    const patch = await this._getOrUploadPoolPatch(patchUuid)
    const host = this.getObject(hostId)

    debug('installing patch %s', patchUuid)

    await this.call('pool_patch.apply', patch.$ref, host.$ref)
  }

  async installPoolPatchOnAllHosts (patchUuid) {
    const patch = await this._getOrUploadPoolPatch(patchUuid)

    await this.call('pool_patch.pool_apply', patch.$ref)
  }

  // =================================================================

  async _doDockerAction (vmId, action, containerId) {
    const vm = this.getObject(vmId)
    const host = this.getObject(vm.resident_on)

    return await this.call('host.call_plugin', host.$ref, 'xscontainer', action, {
      vmuuid: vm.uuid,
      container: containerId
    })
  }

  async registerDockerContainer (vmId) {
    await this._doDockerAction(vmId, 'register')
  }

  async deregisterDockerContainer (vmId) {
    await this._doDockerAction(vmId, 'deregister')
  }

  async startDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'start', containerId)
  }

  async stopDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'stop', containerId)
  }

  async restartDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'restart', containerId)
  }

  async pauseDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'pause', containerId)
  }

  async unpauseDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'unpause', containerId)
  }

  // =================================================================

}
<|endoftext|>


<commit_before>/* eslint-disable max-nested-callbacks,no-unused-expressions,handle-callback-err */
'use strict';

var fs = require('fs');
var path = require('path');
var expect = require('chai').expect;
var rimraf = require('rimraf');
var moment = require('moment');
var winston = require('winston');
var MemoryStream = require('./memory-stream');
var randomString = require('./random-string');
var DailyRotateFile = require('../daily-rotate-file');

function sendLogItem(transport, level, message, meta, cb) { // eslint-disable-line max-params
    var logger = winston.createLogger({
        transports: [transport]
    });

    transport.on('logged', function () {
        if (cb) {
            cb(null, true);
        }
    });

    logger.info({
        level: level,
        message: message
    });
}

describe('winston/transports/daily-rotate-file', function () {
    beforeEach(function () {
        this.stream = new MemoryStream();
        this.transport = new DailyRotateFile({
            json: true,
            stream: this.stream
        });
    });

    it('should have the proper methods defined', function () {
        var transport = new DailyRotateFile({stream: new MemoryStream()});
        expect(transport).to.be.instanceOf(DailyRotateFile);
        expect(transport).to.respondTo('log');
        expect(transport).to.respondTo('query');
    });

    it('should not allow invalid characters in the filename', function () {
        expect(function () {
            // eslint-disable-next-line no-new
            new DailyRotateFile({
                filename: 'test\0log.log'
            });
        }).to.throw();
    });

    it('should not allow invalid characters in the dirname', function () {
        expect(function () {
            // eslint-disable-next-line no-new
            new DailyRotateFile({
                dirname: 'C:\\application<logs>',
                filename: 'test_%DATE%.log'
            });
        }).to.throw();
    });

    it('should write to the stream', function (done) {
        var self = this;
        sendLogItem(this.transport, 'info', 'this message should write to the stream', {}, function (err, logged) {
            expect(err).to.be.null;
            expect(logged).to.be.true;
            var logEntry = JSON.parse(self.stream.toString());
            expect(logEntry.level).to.equal('info');
            expect(logEntry.message).to.equal('this message should write to the stream');
            done();
        });
    });

    describe('when passed metadata', function () {
        var circular = {};
        circular.metadata = circular;

        var params = {
            no: {},
            object: {metadata: true},
            primitive: 'metadata',
            circular: circular
        };

        Object.keys(params).forEach(function (param) {
            it('should accept log messages with ' + param + ' metadata', function (done) {
                sendLogItem(this.transport, 'info', 'test log message', params[param], function (err, logged) {
                    expect(err).to.be.null;
                    expect(logged).to.be.true;
                    // TODO parse the metadata value to make sure its set properly
                    done();
                });
            });
        });
    });

    describe('when using a filename or dirname', function () {
        var logDir = path.join(__dirname, 'logs');
        var now = moment().utc().format('YYYY-MM-DD-HH');
        var filename = path.join(logDir, 'application-' + now + '.testlog');
        var options = {
            json: true,
            dirname: logDir,
            filename: 'application-%DATE%',
            datePattern: 'YYYY-MM-DD-HH',
            utc: true,
            extension: '.testlog'
        };

        beforeEach(function (done) {
            var self = this;
            rimraf(logDir, function () {
                self.transport = new DailyRotateFile(options);
                done();
            });
        });

        it('should write to the file', function (done) {
            this.transport.on('finish', function () {
                var logEntries = fs.readFileSync(filename).toString().split('\n').slice(0, -1);
                expect(logEntries.length).to.equal(1);

                var logEntry = JSON.parse(logEntries[0]);
                expect(logEntry.level).to.equal('info');
                expect(logEntry.message).to.equal('this message should write to the file');
                done();
            });

            sendLogItem(this.transport, 'info', 'this message should write to the file', {}, function (err, logged) {
                expect(err).to.be.null;
                expect(logged).to.be.true;
            });

            this.transport.close();
        });

        it('should not allow the stream to be set', function () {
            var opts = Object.assign({}, options);
            opts.stream = new MemoryStream();
            expect(function () {
                var transport = new DailyRotateFile(opts);
                expect(transport).to.not.be.null;
            }).to.throw();
        });

        it('should raise the new event for a new log file', function (done) {
            this.transport.on('new', function (newFile) {
                expect(newFile).to.equal(filename);
                done();
            });

            sendLogItem(this.transport, 'info', 'this message should write to the file');
            this.transport.close();
        });

        it('should raise the logRemoved event when pruning old log files', function (done) {
            var opts = Object.assign({}, options);
            opts.maxSize = '1k';
            opts.maxFiles = 1;

            this.transport = new DailyRotateFile(opts);

            this.transport.on('logRemoved', function (removedFilename) {
                expect(removedFilename).to.equal(filename);
                done();
            });

            sendLogItem(this.transport, 'info', randomString(1056));
            sendLogItem(this.transport, 'info', randomString(1056));
            this.transport.close();
        });

        describe('when setting zippedArchive', function () {
            it('should archive the log after rotating', function (done) {
                var opts = Object.assign({}, options);
                opts.zippedArchive = true;
                opts.maxSize = '1k';

                this.transport = new DailyRotateFile(opts);

                this.transport.on('finish', function () {
                    fs.readdir(logDir, function (err, files) {
                        expect(files.filter(function (file) {
                            return path.extname(file) === '.gz';
                        }).length).to.equal(1);
                        done();
                    });
                });
                sendLogItem(this.transport, 'info', randomString(1056));
                sendLogItem(this.transport, 'info', randomString(1056));
                this.transport.close();
            });
        });

        describe('query', function () {
            it('should call callback when no files are present', function () {
                this.transport.query(function (err, results) {
                    expect(results).to.not.be.null;
                    expect(results.length).to.equal(0);
                });
            });

            it('should raise error when calling with stream', function () {
                expect(function () {
                    var transport = new DailyRotateFile({stream: new MemoryStream()});
                    transport.query(null);
                }).to.throw();
            });

            it('should raise error when calling with json set to false', function () {
                expect(function () {
                    var opts = Object.assign({}, options);
                    opts.json = false;
                    var transport = new DailyRotateFile(opts);
                    transport.query(null);
                }).to.throw();
            });

            it('should return log entries that match the query', function (done) {
                sendLogItem(this.transport, 'info', randomString(1056));
                sendLogItem(this.transport, 'info', randomString(1056));
                sendLogItem(this.transport, 'info', randomString(1056));
                sendLogItem(this.transport, 'info', randomString(1056));

                var self = this;
                this.transport.on('finish', function () {
                    self.transport.query(function (err, results) {
                        expect(results).to.not.be.null;
                        expect(results.length).to.equal(4);
                        done();
                    });
                });

                this.transport.close();
            });

            it('should search within archived files', function (done) {
                var opts = Object.assign({}, options);
                opts.zippedArchive = true;
                opts.maxSize = '1k';

                this.transport = new DailyRotateFile(opts);

                sendLogItem(this.transport, 'info', randomString(1056));
                sendLogItem(this.transport, 'info', randomString(1056));

                var self = this;

                self.transport.on('archive', function () {
                    self.transport.query(function (err, results) {
                        expect(results).to.not.be.null;
                        expect(results.length).to.equal(2);
                        done();
                    });
                });
            });
        });
    });
});
<commit_msg>remove winston logger from unit tests to address side effects<commit_after>/* eslint-disable max-nested-callbacks,no-unused-expressions,handle-callback-err */
'use strict';

var fs = require('fs');
var path = require('path');
var expect = require('chai').expect;
var rimraf = require('rimraf');
var moment = require('moment');
var winston = require('winston');
var MemoryStream = require('./memory-stream');
var randomString = require('./random-string');
var DailyRotateFile = require('../daily-rotate-file');

function sendLogItem(transport, level, message, meta, cb) { // eslint-disable-line max-params
    transport.on('logged', function () {
        if (cb) {
            cb(null, true);
        }
    });

    const info = { level: level, message: message };
    transport.log(winston.format.json().transform(info));
}

describe('winston/transports/daily-rotate-file', function () {
    beforeEach(function () {
        this.stream = new MemoryStream();
        this.transport = new DailyRotateFile({
            stream: this.stream
        });
    });

    it('should have the proper methods defined', function () {
        var transport = new DailyRotateFile({stream: new MemoryStream()});
        expect(transport).to.be.instanceOf(DailyRotateFile);
        expect(transport).to.respondTo('log');
        expect(transport).to.respondTo('query');
    });

    it('should not allow invalid characters in the filename', function () {
        expect(function () {
            // eslint-disable-next-line no-new
            new DailyRotateFile({
                filename: 'test\0log.log'
            });
        }).to.throw();
    });

    it('should not allow invalid characters in the dirname', function () {
        expect(function () {
            // eslint-disable-next-line no-new
            new DailyRotateFile({
                dirname: 'C:\\application<logs>',
                filename: 'test_%DATE%.log'
            });
        }).to.throw();
    });

    it('should write to the stream', function (done) {
        var self = this;
        sendLogItem(this.transport, 'info', 'this message should write to the stream', {}, function (err, logged) {
            expect(err).to.be.null;
            expect(logged).to.be.true;
            var logEntry = JSON.parse(self.stream.toString());
            expect(logEntry.level).to.equal('info');
            expect(logEntry.message).to.equal('this message should write to the stream');
            done();
        });
    });

    describe('when passed metadata', function () {
        var circular = {};
        circular.metadata = circular;

        var params = {
            no: {},
            object: {metadata: true},
            primitive: 'metadata',
            circular: circular
        };

        Object.keys(params).forEach(function (param) {
            it('should accept log messages with ' + param + ' metadata', function (done) {
                sendLogItem(this.transport, 'info', 'test log message', params[param], function (err, logged) {
                    expect(err).to.be.null;
                    expect(logged).to.be.true;
                    // TODO parse the metadata value to make sure its set properly
                    done();
                });
            });
        });
    });

    describe('when using a filename or dirname', function () {
        var logDir = path.join(__dirname, 'logs');
        var now = moment().utc().format('YYYY-MM-DD-HH');
        var filename = path.join(logDir, 'application-' + now + '.testlog');
        var options = {
            json: true,
            dirname: logDir,
            filename: 'application-%DATE%',
            datePattern: 'YYYY-MM-DD-HH',
            utc: true,
            extension: '.testlog'
        };

        beforeEach(function (done) {
            var self = this;
            rimraf(logDir, function () {
                self.transport = new DailyRotateFile(options);
                done();
            });
        });

        it('should write to the file', function (done) {
            this.transport.on('finish', function () {
                var logEntries = fs.readFileSync(filename).toString().split('\n').slice(0, -1);
                expect(logEntries.length).to.equal(1);

                var logEntry = JSON.parse(logEntries[0]);
                expect(logEntry.level).to.equal('info');
                expect(logEntry.message).to.equal('this message should write to the file');
                done();
            });

            sendLogItem(this.transport, 'info', 'this message should write to the file', {}, function (err, logged) {
                expect(err).to.be.null;
                expect(logged).to.be.true;
            });

            this.transport.close();
        });

        it('should not allow the stream to be set', function () {
            var opts = Object.assign({}, options);
            opts.stream = new MemoryStream();
            expect(function () {
                var transport = new DailyRotateFile(opts);
                expect(transport).to.not.be.null;
            }).to.throw();
        });

        it('should raise the new event for a new log file', function (done) {
            this.transport.on('new', function (newFile) {
                expect(newFile).to.equal(filename);
                done();
            });

            sendLogItem(this.transport, 'info', 'this message should write to the file');
            this.transport.close();
        });

        it('should raise the logRemoved event when pruning old log files', function (done) {
            var opts = Object.assign({}, options);
            opts.maxSize = '1k';
            opts.maxFiles = 1;

            this.transport = new DailyRotateFile(opts);

            this.transport.on('logRemoved', function (removedFilename) {
                expect(removedFilename).to.equal(filename);
                done();
            });

            sendLogItem(this.transport, 'info', randomString(1056));
            sendLogItem(this.transport, 'info', randomString(1056));
            this.transport.close();
        });

        describe('when setting zippedArchive', function () {
            it('should archive the log after rotating', function (done) {
                var opts = Object.assign({}, options);
                opts.zippedArchive = true;
                opts.maxSize = '1k';

                this.transport = new DailyRotateFile(opts);

                this.transport.on('finish', function () {
                    fs.readdir(logDir, function (err, files) {
                        expect(files.filter(function (file) {
                            return path.extname(file) === '.gz';
                        }).length).to.equal(1);
                        done();
                    });
                });
                sendLogItem(this.transport, 'info', randomString(1056));
                sendLogItem(this.transport, 'info', randomString(1056));
                this.transport.close();
            });
        });

        describe('query', function () {
            it('should call callback when no files are present', function () {
                this.transport.query(function (err, results) {
                    expect(results).to.not.be.null;
                    expect(results.length).to.equal(0);
                });
            });

            it('should raise error when calling with stream', function () {
                expect(function () {
                    var transport = new DailyRotateFile({stream: new MemoryStream()});
                    transport.query(null);
                }).to.throw();
            });

            it('should raise error when calling with json set to false', function () {
                expect(function () {
                    var opts = Object.assign({}, options);
                    opts.json = false;
                    var transport = new DailyRotateFile(opts);
                    transport.query(null);
                }).to.throw();
            });

            it('should return log entries that match the query', function (done) {
                sendLogItem(this.transport, 'info', randomString(1056));
                sendLogItem(this.transport, 'info', randomString(1056));
                sendLogItem(this.transport, 'info', randomString(1056));
                sendLogItem(this.transport, 'info', randomString(1056));

                var self = this;
                this.transport.on('finish', function () {
                    self.transport.query(function (err, results) {
                        expect(results).to.not.be.null;
                        expect(results.length).to.equal(4);
                        done();
                    });
                });

                this.transport.close();
            });

            it('should search within archived files', function (done) {
                var opts = Object.assign({}, options);
                opts.zippedArchive = true;
                opts.maxSize = '1k';

                this.transport = new DailyRotateFile(opts);

                sendLogItem(this.transport, 'info', randomString(1056));
                sendLogItem(this.transport, 'info', randomString(1056));

                var self = this;

                self.transport.on('archive', function () {
                    self.transport.query(function (err, results) {
                        expect(results).to.not.be.null;
                        expect(results.length).to.equal(2);
                        done();
                    });
                });
            });
        });
    });
});
<|endoftext|>


<commit_before>import * as tt from 'typescript-definition-tester'

describe('TypeScript definitions', () => {
  it('should compile against index.d.ts', (done) => {
    tt.compileDirectory(
      __dirname + '/typescript',
      fileName => fileName.match(/\.ts$/),
      () => done()
    )
  })
})
<commit_msg>Disable timeout for TypeScript definitions tests<commit_after>import * as tt from 'typescript-definition-tester'

describe('TypeScript definitions', function() {
  this.timeout(0)

  it('should compile against index.d.ts', (done) => {
    tt.compileDirectory(
      __dirname + '/typescript',
      fileName => fileName.match(/\.ts$/),
      () => done()
    )
  })
})
<|endoftext|>


<commit_before>// This is a karma config file. For more details see
//   http://karma-runner.github.io/0.13/config/configuration-file.html
// we are also using it with karma-webpack
//   https://github.com/webpack/karma-webpack

var path = require('path')
var merge = require('webpack-merge')
var baseConfig = require('../../build/webpack.base.conf')
var utils = require('../../build/utils')
var projectRoot = path.resolve(__dirname, '../../')

var webpackConfig = merge(baseConfig, {
  // use inline sourcemap for karma-sourcemap-loader
  module: {
    loaders: utils.styleLoaders()
  },
  devtool: '#inline-source-map',
  vue: {
    loaders: {
      js: 'isparta'
    }
  }
})

// no need for app entry during tests
delete webpackConfig.entry

// make sure isparta loader is applied before eslint
webpackConfig.module.preLoaders = webpackConfig.module.preLoaders || []
webpackConfig.module.preLoaders.unshift({
  test: /\.js$/,
  loader: 'isparta',
  include: projectRoot,
  exclude: /test\/unit|node_modules/
})

// only apply babel for test files when using isparta
webpackConfig.module.loaders.some(function (loader, i) {
  if (loader.loader === 'babel') {
    loader.include = /test\/unit/
    return true
  }
})

module.exports = function (config) {
  config.set({
    // to run in additional browsers:
    // 1. install corresponding karma launcher
    //    http://karma-runner.github.io/0.13/config/browsers.html
    // 2. add it to the `browsers` array below.
    browsers: ['PhantomJS'],
    frameworks: ['mocha', 'sinon-chai'],
    reporters: ['spec', 'coverage'],
    files: ['./index.js'],
    preprocessors: {
      './index.js': ['webpack', 'sourcemap']
    },
    webpack: webpackConfig,
    webpackMiddleware: {
      noInfo: true
    },
    coverageReporter: {
      dir: './coverage',
      reporters: [
        { type: 'lcov', subdir: '.' },
        { type: 'text-summary' }
      ]
    }
  })
}
<commit_msg>Array.includes polyfill for Phantom<commit_after>// This is a karma config file. For more details see
//   http://karma-runner.github.io/0.13/config/configuration-file.html
// we are also using it with karma-webpack
//   https://github.com/webpack/karma-webpack

var path = require('path')
var merge = require('webpack-merge')
var baseConfig = require('../../build/webpack.base.conf')
var utils = require('../../build/utils')
var projectRoot = path.resolve(__dirname, '../../')

var webpackConfig = merge(baseConfig, {
  // use inline sourcemap for karma-sourcemap-loader
  module: {
    loaders: utils.styleLoaders()
  },
  devtool: '#inline-source-map',
  vue: {
    loaders: {
      js: 'isparta'
    }
  }
})

// no need for app entry during tests
delete webpackConfig.entry

// make sure isparta loader is applied before eslint
webpackConfig.module.preLoaders = webpackConfig.module.preLoaders || []
webpackConfig.module.preLoaders.unshift({
  test: /\.js$/,
  loader: 'isparta',
  include: projectRoot,
  exclude: /test\/unit|node_modules/
})

// only apply babel for test files when using isparta
webpackConfig.module.loaders.some(function (loader, i) {
  if (loader.loader === 'babel') {
    loader.include = /test\/unit/
    return true
  }
})

module.exports = function (config) {
  config.set({
    // to run in additional browsers:
    // 1. install corresponding karma launcher
    //    http://karma-runner.github.io/0.13/config/browsers.html
    // 2. add it to the `browsers` array below.
    browsers: ['PhantomJS'],
    frameworks: ['mocha', 'sinon-chai'],
    reporters: ['spec', 'coverage'],
    files: [
      '../../node_modulOes/phantomjs-polyfill-includes/includes-polyfill.js',
      './index.js'
    ],
    preprocessors: {
      './index.js': ['webpack', 'sourcemap']
    },
    webpack: webpackConfig,
    webpackMiddleware: {
      noInfo: true
    },
    coverageReporter: {
      dir: './coverage',
      reporters: [
        { type: 'lcov', subdir: '.' },
        { type: 'text-summary' }
      ]
    }
  })
}
<|endoftext|>


<commit_before>/*jslint white: true*/
/*global module */
module.exports = function (config) {
    'use strict';
    config.set({
        basePath: '../../',
        frameworks: ['jasmine', 'requirejs'],
        plugins: [
            'karma-jasmine',
            // 'karma-chrome-launcher',
            'karma-phantomjs-launcher',
            'karma-requirejs',
            'karma-coverage'
        ],
        preprocessors: {
            'kbase-extension/static/kbase/js/**/*.js': ['coverage']
        },
        files: [
            // {pattern: 'test/unit/spec/**/*.js', included: false},
            {pattern: 'test/unit/spec/appWidgets/input/dynamicDropdownInputSpec.js', included: false},
            {pattern: 'kbase-extension/static/**/*.css', included: false, served: true},
            {pattern: 'kbase-extension/static/kbase/templates/**/*.html', included: false, served: true},
            {pattern: 'kbase-extension/static/kbase/config/**/*.json', included: false, served: true},
            {pattern: 'kbase-extension/static/**/*.js', included: false, served: true},
            {pattern: 'kbase-extension/static/**/*.gif', included: false, served: true},
            'kbase-extension/static/narrative_paths.js',
            {pattern: 'test/unit/testConfig.json', included: false, served: true, nocache: true},
            {pattern: 'test/*.tok', included: false, served: true, nocache: true},
            {pattern: 'test/data/**/*', included: false, served: true},
            'test/unit/testUtil.js',
            'test/unit/test-main.js'
        ],
        exclude: [
            'kbase-extension/static/buildTools/*.js',
            'kbase-extension/static/ext_components/**/test/**/*.js',
            'kbase-extension/static/kbase/js/patched-components/**/*'
        ],
        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['progress', 'coverage'],
        coverageReporter: {
            type: 'html',
            dir: 'js-coverage/',
            reporters: [{
                type: 'html',
                subdir: 'html'
            }, {
                type: 'lcov',
                subdir: 'lcov'
            }],
            includeAllSources: true
        },
        // web server port
        port: 9876,
        // enable / disable colors in the output (reporters and logs)
        colors: true,
        // level of logging
        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
        logLevel: config.LOG_INFO,
        // enable / disable watching file and executing tests whenever any file changes
        autoWatch: false,
        // start these browsers
        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
        browsers: ['PhantomJS'],
        // Continuous Integration mode
        // if true, Karma captures browsers, runs the tests and exits
        // phantomjsLauncher: {
        //     options: {
        //         settings: {
        //             webSecurityEnabled: false
        //         }
        //     }
        // },
        singleRun: true,
        proxies: {
            '/narrative/static/': '/base/kbase-extension/static/',
            '/narrative/static/base': 'http://localhost:9999/narrative/static/base',
            '/narrative/static/notebook': 'http://localhost:9999/narrative/static/notebook',
            '/narrative/static/components': 'http://localhost:9999/narrative/static/components',
            '/narrative/static/services': 'http://localhost:9999/narrative/static/services',
            '/static/kbase/config': '/base/kbase-extension/static/kbase/config',
            '/test/': '/base/test/'
        }

    });
};
<commit_msg>turn off single-test mode<commit_after>/*jslint white: true*/
/*global module */
module.exports = function (config) {
    'use strict';
    config.set({
        basePath: '../../',
        frameworks: ['jasmine', 'requirejs'],
        plugins: [
            'karma-jasmine',
            // 'karma-chrome-launcher',
            'karma-phantomjs-launcher',
            'karma-requirejs',
            'karma-coverage'
        ],
        preprocessors: {
            'kbase-extension/static/kbase/js/**/*.js': ['coverage']
        },
        files: [
            {pattern: 'test/unit/spec/**/*.js', included: false},
            {pattern: 'kbase-extension/static/**/*.css', included: false, served: true},
            {pattern: 'kbase-extension/static/kbase/templates/**/*.html', included: false, served: true},
            {pattern: 'kbase-extension/static/kbase/config/**/*.json', included: false, served: true},
            {pattern: 'kbase-extension/static/**/*.js', included: false, served: true},
            {pattern: 'kbase-extension/static/**/*.gif', included: false, served: true},
            'kbase-extension/static/narrative_paths.js',
            {pattern: 'test/unit/testConfig.json', included: false, served: true, nocache: true},
            {pattern: 'test/*.tok', included: false, served: true, nocache: true},
            {pattern: 'test/data/**/*', included: false, served: true},
            'test/unit/testUtil.js',
            'test/unit/test-main.js'
        ],
        exclude: [
            'kbase-extension/static/buildTools/*.js',
            'kbase-extension/static/ext_components/**/test/**/*.js',
            'kbase-extension/static/kbase/js/patched-components/**/*'
        ],
        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['progress', 'coverage'],
        coverageReporter: {
            type: 'html',
            dir: 'js-coverage/',
            reporters: [{
                type: 'html',
                subdir: 'html'
            }, {
                type: 'lcov',
                subdir: 'lcov'
            }],
            includeAllSources: true
        },
        // web server port
        port: 9876,
        // enable / disable colors in the output (reporters and logs)
        colors: true,
        // level of logging
        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
        logLevel: config.LOG_INFO,
        // enable / disable watching file and executing tests whenever any file changes
        autoWatch: false,
        // start these browsers
        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
        browsers: ['PhantomJS'],
        // Continuous Integration mode
        // if true, Karma captures browsers, runs the tests and exits
        // phantomjsLauncher: {
        //     options: {
        //         settings: {
        //             webSecurityEnabled: false
        //         }
        //     }
        // },
        singleRun: true,
        proxies: {
            '/narrative/static/': '/base/kbase-extension/static/',
            '/narrative/static/base': 'http://localhost:9999/narrative/static/base',
            '/narrative/static/notebook': 'http://localhost:9999/narrative/static/notebook',
            '/narrative/static/components': 'http://localhost:9999/narrative/static/components',
            '/narrative/static/services': 'http://localhost:9999/narrative/static/services',
            '/static/kbase/config': '/base/kbase-extension/static/kbase/config',
            '/test/': '/base/test/'
        }

    });
};
<|endoftext|>