<commit_before>/********************************************************************************************************
 * Name: UML to YANG Mapping Tool
 * Copyright 2015 CAICT (China Academy of Information and Communication Technology (former China Academy of Telecommunication Research)). All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License").
 *
 * This tool is developed according to the mapping rules defined in onf2015.261_Mapping_Gdls_UML-YANG.08 by OpenNetworkFoundation(ONF) IMP group.
 *
 * file: \model\yang\type.js
 *
 * The above copyright information should be included in all distribution, reproduction or derivative works of this software.
 *
 ****************************************************************************************************/

var Util = require('./util.js');

function type(name, id, path, range, length, descrip, units, fileName) {
    this.name = name;
    this.id = id;
    this.description = descrip;
    this.path = path;
    this.range = range;
    this.length = length;
    this.children = [];
    this.units = units;
    this.fileName = fileName;
}
type.prototype.writeNode = function (layer) {
    var PRE = '';
    var k = layer;
    while (k-- > 0) {
        PRE += '\t';
    }
    if(parseInt(this.name[0]) != -1 && parseInt(this.name[0]) >= 0){
        var first = this.name[0];
        switch (first){
            case '0' :
                this.name = this.name.replace(/^0/g, "Zero");
                break;
            case '1' :
                this.name = this.name.replace(/^1/g, "One");
                break;
            case '2' :
                this.name = this.name.replace(/^2/g, "Two");
                break;
            case '3' :
                this.name = this.name.replace(/^3/g, "Three");
                break;
            case '4' :
                this.name = this.name.replace(/^4/g, "Four");
                break;
            case '5' :
                this.name = this.name.replace(/^5/g, "Five");
                break;
            case '6' :
                this.name = this.name.replace(/^6/g, "Six");
                break;
            case '7' :
                this.name = this.name.replace(/^7/g, "Seven");
                break;
            case '8' :
                this.name = this.name.replace(/^8/g, "Eight");
                break;
            case '9' :
                this.name = this.name.replace(/^9/g, "Nine");
                break;
        }
    }
    var name = "type " + this.name;
   /* if (this.name !== "enumeration") {
        name += ";";
    }*/
    var s = "";
    if(this.path || this.range || this.length || this.children.length){
        s = " {\r\n";
        var regex  = /[^0-9/./*]/;
        if(this.range){
            /*if(regex.test(this.range) == true){
                if(this.range.indexOf('*') !== -1){
                    this.range = this.range.replace('*', "max");
                }
                this.description = "range " + this.range + "\r\n" + this.description;
                this.description = this.description.replace(/\r\n$/g, "");
                this.range == undefined;
                console.warn("Warning: The range of id = \"" + this.id + "\"doesn't match the RFC 6020! We will put this range into description. Please recheck it.");
            }else{
                this.range = this.range.replace(/\r+\n\s*!/g, '\r\n' + PRE + '\t\t');
                s += PRE + "\trange ";
                s += "\"" + this.range + "\"" + ";\r\n";
            }*/
            s += PRE + "\trange ";
            s += "\"" + this.range + "\"" + ";\r\n";
        }

        if(this.description){
            this.description = this.description.replace(/\r+\n\s*/g, '\r\n' + PRE + '\t\t');
            s += PRE + "\tdescription \"" + this.description + "\";\r\n";
        }
        if (this.children.length) {
            if(typeof this.children[0] == "object"){                //enum
                for(var i = 0; i < this.children.length; i++){
                    s += this.children[i].writeNode(layer + 1);
                }
            }else{
                for (var i = 0; i < this.children.length; i++) {
                    s += PRE + "\t";
                    s += this.children[i] + ";\r\n";
                }
            }
        }
        if(this.path){
            s += PRE + "\t";
            s += Util.yangifyName(this.path) + ";\r\n";
        }

        s = s + PRE + "}";
    }
    else{
        s=";";
    }
    //var s = PRE + name + s + "\r\n";
    s = PRE + Util.yangifyName(name) + s + "\r\n";
    return s;

};
module.exports = type;
<commit_msg>handling integer<commit_after>/********************************************************************************************************
 * Name: UML to YANG Mapping Tool
 * Copyright 2015 CAICT (China Academy of Information and Communication Technology (former China Academy of Telecommunication Research)). All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License").
 *
 * This tool is developed according to the mapping rules defined in onf2015.261_Mapping_Gdls_UML-YANG.08 by OpenNetworkFoundation(ONF) IMP group.
 *
 * file: \model\yang\type.js
 *
 * The above copyright information should be included in all distribution, reproduction or derivative works of this software.
 *
 ****************************************************************************************************/

var Util = require('./util.js');

function type(name, id, path, range, length, unsigned, units, descrip, fileName) {
    this.name = name;
    this.id = id;
    this.description = descrip;
    this.path = path;
    this.range = range;
    this.length = length;
    this.unsigned = unsigned;
    this.units = units;
    this.fileName = fileName;
    this.children = [];
};
type.prototype.getTypeName = function() {
    if (this.name !== 'integer') {
        return this.name;
    }
    var result = 'int';
    if (this.length) {
      result = result + this.length;
    } else {
      result = result + '64';
    }
    if (this.unsinged) {
        result = 'u' + result;
    }
    return result;
};
type.prototype.writeNode = function (layer) {
    var PRE = '';
    var k = layer;
    while (k-- > 0) {
        PRE += '\t';
    }
    if(parseInt(this.name[0]) != -1 && parseInt(this.name[0]) >= 0){
        var first = this.name[0];
        switch (first){
            case '0' :
                this.name = this.name.replace(/^0/g, "Zero");
                break;
            case '1' :
                this.name = this.name.replace(/^1/g, "One");
                break;
            case '2' :
                this.name = this.name.replace(/^2/g, "Two");
                break;
            case '3' :
                this.name = this.name.replace(/^3/g, "Three");
                break;
            case '4' :
                this.name = this.name.replace(/^4/g, "Four");
                break;
            case '5' :
                this.name = this.name.replace(/^5/g, "Five");
                break;
            case '6' :
                this.name = this.name.replace(/^6/g, "Six");
                break;
            case '7' :
                this.name = this.name.replace(/^7/g, "Seven");
                break;
            case '8' :
                this.name = this.name.replace(/^8/g, "Eight");
                break;
            case '9' :
                this.name = this.name.replace(/^9/g, "Nine");
                break;
        }
    }
    var name = "type " + this.name;
   /* if (this.name !== "enumeration") {
        name += ";";
    }*/
    var s = "";
    if(this.path || this.range || this.length || this.children.length){
        s = " {\r\n";
        var regex  = /[^0-9/./*]/;
        if(this.range){
            /*if(regex.test(this.range) == true){
                if(this.range.indexOf('*') !== -1){
                    this.range = this.range.replace('*', "max");
                }
                this.description = "range " + this.range + "\r\n" + this.description;
                this.description = this.description.replace(/\r\n$/g, "");
                this.range == undefined;
                console.warn("Warning: The range of id = \"" + this.id + "\"doesn't match the RFC 6020! We will put this range into description. Please recheck it.");
            }else{
                this.range = this.range.replace(/\r+\n\s*!/g, '\r\n' + PRE + '\t\t');
                s += PRE + "\trange ";
                s += "\"" + this.range + "\"" + ";\r\n";
            }*/
            s += PRE + "\trange ";
            s += "\"" + this.range + "\"" + ";\r\n";
        }

        if(this.description){
            this.description = this.description.replace(/\r+\n\s*/g, '\r\n' + PRE + '\t\t');
            s += PRE + "\tdescription \"" + this.description + "\";\r\n";
        }
        if (this.children.length) {
            if(typeof this.children[0] == "object"){                //enum
                for(var i = 0; i < this.children.length; i++){
                    s += this.children[i].writeNode(layer + 1);
                }
            }else{
                for (var i = 0; i < this.children.length; i++) {
                    s += PRE + "\t";
                    s += this.children[i] + ";\r\n";
                }
            }
        }
        if(this.path){
            s += PRE + "\t";
            s += Util.yangifyName(this.path) + ";\r\n";
        }

        s = s + PRE + "}";
    }
    else{
        s=";";
    }
    //var s = PRE + name + s + "\r\n";
    s = PRE + Util.yangifyName(name) + s + "\r\n";
    return s;

};
module.exports = type;
<|endoftext|>


<commit_before>/*
 * JS函数扩展
 * 作者：zoeDylan
 * 描述：收集网络上各种高性能、实用性高、兼容解决等JS功能，方便平时开发
 * 修改：2016-05-03
 * ##更新说明：
 * 1. 添加_cookie函数
 * 2. 之前未添加下划线(`_`)的函数全部添加下划线(`_`)
 * 3. 去除`zoe`和`zoeDylan`的全局函数添加
 *
 */

/*
 * 随机值
 * min:最小值
 * max:最大值
 * randomNum(10,20);获取10到20的值
 * randomNum(10);获取0-10的值
 * randomNum(1.0,10);获取0-10的值(小数)
 */
function _randomNum(min, max) {
    if (typeof (max) == 'undefined') {
        max = min;
        min = 0;
    }
    return Math.random() * (max - min) + min;
}

/*
 * 随机字符串
 * 默认32位字符
 * len:返回字符串长度
 * char:指定字符串
 */
function _randomString(length, chars) {
    length = length || 32;

    chars = chars || 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';    /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
    var pwd = '';
    for (i = 0; i < length; i++) {
        pwd += chars.charAt(randomNum(chars.length));
    }
    return pwd;
}

/*
 * 随机颜色值
 * 返回：#XXXXXX(16进制)
 */
function _randomColor() {
    return "#" + ("00000" + ((Math.random() * 16777215 + 0.5) >> 0).toString(16)).slice(-6);
}

/*
 * 去字符串首尾空格
 */
String.prototype.trim = function () {
    var str = this,
    whitespace = ' \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000';
    for (var i = 0, len = str.length; i < len; i++) {
        if (whitespace.indexOf(str.charAt(i)) === -1) {
            str = str.substring(i);
            break;
        }
    }
    for (i = str.length - 1; i >= 0; i--) {
        if (whitespace.indexOf(str.charAt(i)) === -1) {
            str = str.substring(0, i + 1);
            break;
        }
    }
    return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
}

/*
 * cookie处理，默认get、set、clear使用html5的localStorage,没有的情况下使用cookie
 *
 */
var _cookie = (function () {
    var cookie = {};
    cookie.html5 = window.localStorage ? true : false;

    cookie.setCookie = function (name, cvalue, exdays) {
        var d = new Date();
        exdays = exdays || 100000;
        d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
        var expires = "expires=" + d.toUTCString();
        document.cookie = cname + "=" + cvalue + "; " + expires;
    }
    cookie.getCookie = function (name) {
         name = name + "=";
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) != -1) {
                return c.substring(name.length, c.length)
            }
        }
        return null;
    }
    cookie.clearCookie = function (name) {
        setCookie(name, "", -1);
    }
    cookie.deleteCookie = cookie.clearCookie;
    cookie.getAllCookie = function () {
        var all = {};
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            c = c.split('=');
            all[c[0]] = c[1];
        }
        return all;
    }
    cookie.clearAllCookie = function () {
        var keys = document.cookie.match(/[^ =;]+(?=\=)/g);
        if (keys) {
            for (var i = keys.length; i--;)
                document.cookie = keys[i] + '=0;expires=' + new Date(0).toUTCString()
        }
    }
    cookie.deleteAllCookie = cookie.clearAllCookie;

    if (cookie.html5) {
        cookie.set = function (name, val) {
            window.localStorage.setItem(name, val);
        }
        cookie.get = function (name) {
            return window.localStorage.getItem(name);
        }
        cookie.clear = function (name) {
            window.localStorage.removeItem(name);
        }
        cookie.delete = cookie.clear;
        cookie.getAll = function () {
            var all = {};
            for (var i = 0; i < window.localStorage.length; i++) {
                var nowK = window.localStorage.key(i);
                all[nowK] = window.localStorage.getItem(nowK);
            }
            return all;
        }
        cookie.clearAll = function () {
            for (var i = 0; i < window.localStorage.length; i++) {
                var nowK = window.localStorage.key(i);
                window.localStorage.removeItem(nowK);
            }
        }
        cookie.deleteAll = cookie.clearAll;
    } else {
        cookie.set = cookie.setCookie;
        cookie.get = cookie.getCookie;
        cookie.clear = cookie.clearCookie;
        cookie.delete = cookie.clear;
        cookie.getAll = cookie.getAllCookie;
        cookie.clearAll = cookie.clearAllCookie;
        cookie.deleteAll = cookie.clearAll;
    }

    return cookie;
})();

//是否是手机号
function _isPhone(val) {
    return /^1[3|4|5|7|8][0-9]\d{8}$/.test(val);
}

//是否是邮箱号
function _isEmail(val) {
    return /^[0-9a-z][a-z0-9\._-]{1,}@[a-z0-9-]{1,}[a-z0-9]\.[a-z\.]{1,}[a-z]$/.test(val)
}<commit_msg>随机数修改<commit_after>/*
 * JS函数扩展
 * 作者：zoeDylan
 * 描述：收集网络上各种高性能、实用性高、兼容解决等JS功能，方便平时开发
 * 修改：2016-05-03
 * ##更新说明：
 * 1. 添加_cookie函数
 * 2. 之前未添加下划线(`_`)的函数全部添加下划线(`_`)
 * 3. 去除`zoe`和`zoeDylan`的全局函数添加
 *
 */

/*
 * 随机值
 * min:最小值
 * max:最大值
 * noInt:是否返回小数
 * randomNum(10,20);获取10到20的值
 * randomNum(10);获取0-10的值
 *
 */
function _randomNum(min, max, noInt) {
    if (typeof (max) == 'undefined') {
        max = min;
        min = 0;
    }
    return noInt ? Math.random() * (max - min) + min : parseInt(Math.random() * (max - min) + min);
}

/*
 * 随机字符串
 * 默认32位字符
 * len:返回字符串长度
 * char:指定字符串
 */
function _randomString(length, chars) {
    length = length || 32;

    chars = chars || 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';    /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
    var pwd = '';
    for (i = 0; i < length; i++) {
        pwd += chars.charAt(randomNum(chars.length));
    }
    return pwd;
}

/*
 * 随机颜色值
 * 返回：#XXXXXX(16进制)
 */
function _randomColor() {
    return "#" + ("00000" + ((Math.random() * 16777215 + 0.5) >> 0).toString(16)).slice(-6);
}

/*
 * 去字符串首尾空格
 */
String.prototype.trim = function () {
    var str = this,
    whitespace = ' \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000';
    for (var i = 0, len = str.length; i < len; i++) {
        if (whitespace.indexOf(str.charAt(i)) === -1) {
            str = str.substring(i);
            break;
        }
    }
    for (i = str.length - 1; i >= 0; i--) {
        if (whitespace.indexOf(str.charAt(i)) === -1) {
            str = str.substring(0, i + 1);
            break;
        }
    }
    return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
}

/*
 * cookie处理，默认get、set、clear使用html5的localStorage,没有的情况下使用cookie
 *
 */
var _cookie = (function () {
    var cookie = {};
    cookie.html5 = window.localStorage ? true : false;

    cookie.setCookie = function (name, cvalue, exdays) {
        var d = new Date();
        exdays = exdays || 100000;
        d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
        var expires = "expires=" + d.toUTCString();
        document.cookie = cname + "=" + cvalue + "; " + expires;
    }
    cookie.getCookie = function (name) {
         name = name + "=";
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) != -1) {
                return c.substring(name.length, c.length)
            }
        }
        return null;
    }
    cookie.clearCookie = function (name) {
        setCookie(name, "", -1);
    }
    cookie.deleteCookie = cookie.clearCookie;
    cookie.getAllCookie = function () {
        var all = {};
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            c = c.split('=');
            all[c[0]] = c[1];
        }
        return all;
    }
    cookie.clearAllCookie = function () {
        var keys = document.cookie.match(/[^ =;]+(?=\=)/g);
        if (keys) {
            for (var i = keys.length; i--;)
                document.cookie = keys[i] + '=0;expires=' + new Date(0).toUTCString()
        }
    }
    cookie.deleteAllCookie = cookie.clearAllCookie;

    if (cookie.html5) {
        cookie.set = function (name, val) {
            window.localStorage.setItem(name, val);
        }
        cookie.get = function (name) {
            return window.localStorage.getItem(name);
        }
        cookie.clear = function (name) {
            window.localStorage.removeItem(name);
        }
        cookie.delete = cookie.clear;
        cookie.getAll = function () {
            var all = {};
            for (var i = 0; i < window.localStorage.length; i++) {
                var nowK = window.localStorage.key(i);
                all[nowK] = window.localStorage.getItem(nowK);
            }
            return all;
        }
        cookie.clearAll = function () {
            for (var i = 0; i < window.localStorage.length; i++) {
                var nowK = window.localStorage.key(i);
                window.localStorage.removeItem(nowK);
            }
        }
        cookie.deleteAll = cookie.clearAll;
    } else {
        cookie.set = cookie.setCookie;
        cookie.get = cookie.getCookie;
        cookie.clear = cookie.clearCookie;
        cookie.delete = cookie.clear;
        cookie.getAll = cookie.getAllCookie;
        cookie.clearAll = cookie.clearAllCookie;
        cookie.deleteAll = cookie.clearAll;
    }

    return cookie;
})();

//是否是手机号
function _isPhone(val) {
    return /^1[3|4|5|7|8][0-9]\d{8}$/.test(val);
}

//是否是邮箱号
function _isEmail(val) {
    return /^[0-9a-z][a-z0-9\._-]{1,}@[a-z0-9-]{1,}[a-z0-9]\.[a-z\.]{1,}[a-z]$/.test(val)
}<|endoftext|>


<commit_before>dc.lineChart = function(parent) {
    var chart = dc.coordinateGridChart({});

    chart.transitionDuration(500);

    chart.subRender = function(){
        if (chart.dataAreSet()) {
            chart.plotData();
        }

        return chart;
    };

    chart.redraw = function() {
        chart.plotData();
        chart.redrawBrush(chart.g());
        if (chart.elasticY())
            chart.renderYAxis(chart.g());
        return chart;
    };

    chart.plotData = function() {
        chart.g().datum(chart.group().all());

        var path = chart.selectAll("path.line");

        if (path.empty())
            path = chart.g().append("path")
                .attr("class", "line");

        var line = d3.svg.line()
            .x(function(d) {
                return chart.x()(chart.xValue()(d));
            })
            .y(function(d) {
                return chart.y()(chart.yValue()(d));
            });

        path = path
            .attr("transform", "translate(" + chart.margins().left + "," + chart.margins().top + ")");

        dc.transition(path, chart.transitionDuration(), function(t) {
            t.ease("linear")
        }).attr("d", line);
    }

    chart.redrawBrush = function(g) {
        chart._redrawBrush(g);

        fadeDeselectedArea();
    }

    function fadeDeselectedArea() {

    }

    function isSubChart(parent) {
        return (parent instanceof Object);
    }

    dc.registerChart(chart);

    return isSubChart(parent)?chart:chart.anchor(parent);
};
<commit_msg>removed redraw function from line chart<commit_after>dc.lineChart = function(parent) {
    var chart = dc.coordinateGridChart({});

    chart.transitionDuration(500);

    chart.subRender = function(){
        if (chart.dataAreSet()) {
            chart.plotData();
        }

        return chart;
    };

    chart.plotData = function() {
        chart.g().datum(chart.group().all());

        var path = chart.selectAll("path.line");

        if (path.empty())
            path = chart.g().append("path")
                .attr("class", "line");

        var line = d3.svg.line()
            .x(function(d) {
                return chart.x()(chart.xValue()(d));
            })
            .y(function(d) {
                return chart.y()(chart.yValue()(d));
            });

        path = path
            .attr("transform", "translate(" + chart.margins().left + "," + chart.margins().top + ")");

        dc.transition(path, chart.transitionDuration(), function(t) {
            t.ease("linear")
        }).attr("d", line);
    }

    chart.redrawBrush = function(g) {
        chart._redrawBrush(g);

        fadeDeselectedArea();
    }

    function fadeDeselectedArea() {

    }

    function isSubChart(parent) {
        return (parent instanceof Object);
    }

    dc.registerChart(chart);

    return isSubChart(parent)?chart:chart.anchor(parent);
};
<|endoftext|>


<commit_before>/**
 * @author Adam Meadows [@job13er](https://github.com/job13er)
 * @copyright 2015 Cyan, Inc. All rights reserved.
 */

'use strict';

/* global expect */

/**
 * @typedef Resolver
 * @param {Function} resolve - resolve the promise
 * @param {Function} reject - reject the promise
 * @param {Function} notify - notify of progress on the promise
 */

var _ = require('lodash');
var Q = require('q');

/** @exports testUtils */
var ns = {};

/**
 * Create a Promise that can be resolved by the given resolver object
 * @param {Resolver} resolver - the reference of the resolver to update (methods don't have to exist)
 * @returns {Q.Promise} the promise that is created
 */
ns.makePromise = function (resolver) {
    /* eslint-disable new-cap */
    return Q.Promise(function (resolve, reject, notify) {
        resolver.resolve = resolve;
        resolver.reject = reject;
        resolver.notify = notify;
    });
    /* eslint-enable new-cap */
};

// ------------------------------------------------------------------------------------------------
// Waiting
// ------------------------------------------------------------------------------------------------

/**
 * Use setTimeout to give up control flow for the given number of milliseconds
 * This is useful when you want to give a promise a chance to be resolved before continuing
 * @param {Function} done - the jasmine async done() method from the spec
 * @param {Number} [milliseconds=0] - the time to wait
 * @param {Function} [callback] - will be called before done() so you can expect() stuff
 * @param {Function} [timeoutFn] - optional replacement to setTimeout (for testing in nodejs)
 */
ns.wait = function (done, milliseconds, callback, timeoutFn) {
    if (!milliseconds) {
        milliseconds = 0;
    }

    if (timeoutFn === undefined ) {
        timeoutFn = setTimeout;
    }

    timeoutFn(function () {
        if (callback) {
            callback();
        }
        done();
    }, milliseconds);
};

/**
 * Call done() once the given promise is resolved
 * @param {Function} done - the jasmine async done() method from the spec
 * @param {Q.promise} promise - wait till this is resolved before calling done()
 * @param {Function} [callback] - will be called before done() on resolution so you can expect() stuff
 * @param {Function} [errback] - will be called before done() on rejection so you can expect() stuff
 */
ns.waitForPromise = function (done, promise, callback, errback) {
    promise.then(
        function (data) {
            if (callback) {
                callback(data);
            }
            done();
        },
        function (err) {
            if (errback) {
                errback(err);
            }
            done();
        }
    ).done();
};

// ------------------------------------------------------------------------------------------------
// E2E Test Utilities
// ------------------------------------------------------------------------------------------------

ns.e2e = {

    /**
     * @typedef Screenshot
     * @property {String} name - should be dash-separated as it will be used as part of a filename
     * @property {String} [elem] - the jQuery selector for element to screenshot (i.e. 'body' or '.navbar')
     * @property {Number} [width] - the fixed pixel width of the screenshot
     * @property {Number} [height] - the fixed pixel height of the screenshot
     * @property {Number} [x] - take screenshot at exact x,y position (requires width/height)
     * @property {Number} [y] - take screenshot at exact x,y position (requires width/height)
     * @property {String[]|Object[]} [exclude] - an array of selectors or objects with x,y values which span a polygon
     */

    /**
     * @typedef TestConfig
     * @property {Object} selenium - selenium server info
     * @property {String} selenium.host - the hostname of the selenium server
     * @property {Number} selenium.port - the port number for the selenium server
     * @property {String} selenium.browser - the browser to use with selenium
     * @property {Object} http - http-server info
     * @property {String} http.host - the http-server hostname
     * @property {Number} http.port - the http-server port
     * @property {String} http.entryPoint - the URL path we want to start at
     * @property {String} selniumServer - backward-compatible selenium server URL for older projects
     * @property {String} url - backward-compatible http-server URL (including port)
     */

    /**
     * Initialize webdriverio and webdrivercss (should be called in your beforeEach())
     * @param {Object} webdriverio - the webdriverio module [require('webdriverio')]
     * @param {Object} webdrivercss - the webdrivercss module [require('webdrivercss')]
     * @param {TestConfig} testConfig - the config for these specs
     * @param {Object} [wdIoOpts] - the webdriverio options defaults will be used if not provided
     * @param {Object} [wdCssOpts] - the webdrivercss options defaults will be used if not provided
     * @returns {WebdriverIoClient} a webdriverio client instance
     */
    init: function (webdriverio, webdrivercss, testConfig, wdIoOpts, wdCssOpts) {
        if (wdIoOpts === undefined) {
            wdIoOpts = {};
        }

        if (wdCssOpts === undefined) {
            wdCssOpts = {};
        }

        _.defaults(wdIoOpts, {
            desiredCapabilities: {browserName: testConfig.selenium.browser},
            host: testConfig.selenium.host,
            port: testConfig.selenium.port,
            logLevel: 'silent',
        });

        _.defaults(wdCssOpts, {
            screenshotRoot: 'spec/e2e/screenshots',
            failedComparisonsRoot: 'spec/e2e/screenshots/diff',
            misMatchTolerance: 0.1,
        });

        var client = webdriverio.remote(wdIoOpts);
        client.init();
        webdrivercss.init(client, wdCssOpts);
        this.addCommands(client);

        return client;
    },

    /**
     * Add the 'verifyScreenshots' command to the webdriverio client
     * @param {WebdriverIoClient} client - the webdriverio client
     */
    addCommands: function (client) {
        client.addCommand('verifyScreenshots', function (name, screenshots) {

            // this is a little odd, but webdriverio adds an additional callback argument at the end for chaining
            // http://webdriver.io/guide/usage/customcommands.html
            var callback = arguments[arguments.length - 1];

            var screenshotsCopy = _.clone(screenshots);
            client.webdrivercss(name, screenshotsCopy, function (err, res) {
                expect(err).toBeFalsy();
                _.forEach(screenshots, function (screenshot) {
                    var result = res[screenshot.name][0];
                    var msg = 'Visual difference found for "' + screenshot.name + '" \n';
                    expect(result.isWithinMisMatchTolerance).toBeTruthy(msg + JSON.stringify(result, null, 4));
                });
            });

            callback();
        });
    },

    /**
     * Construc the base URL from the testConfig
     * @param {TestConfig} testConfig - the e2ee spec configuration
     * @param {String} [extra] - extra URL path
     * @returns {String} the full URL
     */
    getUrl: function (testConfig, extra) {
        var http = testConfig.http;
        var entryPoint = http.entryPoint;

        // Prevent double backslash in URL
        if (entryPoint.length !== 0 && entryPoint[0] === '/') {
            entryPoint = entryPoint.substring(1);
        }

        var url = 'http://' + http.host + ':' + http.port + '/' + entryPoint;
        if (extra) {
            // Prevent double backslash in URL
            if (url[url.length - 1] === '/' && extra[0] === '/') {
                extra = extra.substring(1);
            }

            url = url + extra;
        }

        return url;
    },
};

module.exports = ns;
<commit_msg>Update index.js<commit_after>/**
 * @author Adam Meadows [@job13er](https://github.com/job13er)
 * @copyright 2015 Cyan, Inc. All rights reserved.
 */

'use strict';

/* global expect */

/**
 * @typedef Resolver
 * @param {Function} resolve - resolve the promise
 * @param {Function} reject - reject the promise
 * @param {Function} notify - notify of progress on the promise
 */

var _ = require('lodash');
var Q = require('q');

/** @exports testUtils */
var ns = {};

/**
 * Create a Promise that can be resolved by the given resolver object
 * @param {Resolver} resolver - the reference of the resolver to update (methods don't have to exist)
 * @returns {Q.Promise} the promise that is created
 */
ns.makePromise = function (resolver) {
    /* eslint-disable new-cap */
    return Q.Promise(function (resolve, reject, notify) {
        resolver.resolve = resolve;
        resolver.reject = reject;
        resolver.notify = notify;
    });
    /* eslint-enable new-cap */
};

// ------------------------------------------------------------------------------------------------
// Waiting
// ------------------------------------------------------------------------------------------------

/**
 * Use setTimeout to give up control flow for the given number of milliseconds
 * This is useful when you want to give a promise a chance to be resolved before continuing
 * @param {Function} done - the jasmine async done() method from the spec
 * @param {Number} [milliseconds=0] - the time to wait
 * @param {Function} [callback] - will be called before done() so you can expect() stuff
 * @param {Function} [timeoutFn] - optional replacement to setTimeout (for testing in nodejs)
 */
ns.wait = function (done, milliseconds, callback, timeoutFn) {
    if (!milliseconds) {
        milliseconds = 0;
    }

    if (timeoutFn === undefined ) {
        timeoutFn = setTimeout;
    }

    timeoutFn(function () {
        if (callback) {
            callback();
        }
        done();
    }, milliseconds);
};

/**
 * Call done() once the given promise is resolved
 * @param {Function} done - the jasmine async done() method from the spec
 * @param {Q.promise} promise - wait till this is resolved before calling done()
 * @param {Function} [callback] - will be called before done() on resolution so you can expect() stuff
 * @param {Function} [errback] - will be called before done() on rejection so you can expect() stuff
 */
ns.waitForPromise = function (done, promise, callback, errback) {
    promise.then(
        function (data) {
            if (callback) {
                callback(data);
            }
            done();
        },
        function (err) {
            if (errback) {
                errback(err);
            }
            done();
        }
    ).done();
};

// ------------------------------------------------------------------------------------------------
// E2E Test Utilities
// ------------------------------------------------------------------------------------------------

ns.e2e = {

    /**
     * @typedef Screenshot
     * @property {String} name - should be dash-separated as it will be used as part of a filename
     * @property {String} [elem] - the jQuery selector for element to screenshot (i.e. 'body' or '.navbar')
     * @property {Number} [width] - the fixed pixel width of the screenshot
     * @property {Number} [height] - the fixed pixel height of the screenshot
     * @property {Number} [x] - take screenshot at exact x,y position (requires width/height)
     * @property {Number} [y] - take screenshot at exact x,y position (requires width/height)
     * @property {String[]|Object[]} [exclude] - an array of selectors or objects with x,y values which span a polygon
     */

    /**
     * @typedef TestConfig
     * @property {Object} selenium - selenium server info
     * @property {String} selenium.host - the hostname of the selenium server
     * @property {Number} selenium.port - the port number for the selenium server
     * @property {String} selenium.browser - the browser to use with selenium
     * @property {Object} http - http-server info
     * @property {String} http.host - the http-server hostname
     * @property {Number} http.port - the http-server port
     * @property {String} http.entryPoint - the URL path we want to start at
     * @property {String} selniumServer - backward-compatible selenium server URL for older projects
     * @property {String} url - backward-compatible http-server URL (including port)
     */

    /**
     * Initialize webdriverio and webdrivercss (should be called in your beforeEach())
     * @param {Object} webdriverio - the webdriverio module [require('webdriverio')]
     * @param {Object} webdrivercss - the webdrivercss module [require('webdrivercss')]
     * @param {TestConfig} testConfig - the config for these specs
     * @param {Object} [wdIoOpts] - the webdriverio options defaults will be used if not provided
     * @param {Object} [wdCssOpts] - the webdrivercss options defaults will be used if not provided
     * @returns {WebdriverIoClient} a webdriverio client instance
     */
    init: function (webdriverio, webdrivercss, testConfig, wdIoOpts, wdCssOpts) {
        if (wdIoOpts === undefined) {
            wdIoOpts = {};
        }

        if (wdCssOpts === undefined) {
            wdCssOpts = {};
        }

        _.defaults(wdIoOpts, {
            desiredCapabilities: {browserName: testConfig.selenium.browser},
            host: testConfig.selenium.host,
            port: testConfig.selenium.port,
            logLevel: 'silent',
        });

        _.defaults(wdCssOpts, {
            screenshotRoot: 'spec/e2e/screenshots',
            failedComparisonsRoot: 'spec/e2e/screenshots/diff',
            misMatchTolerance: 0.1,
        });

        var client = webdriverio.remote(wdIoOpts);
        client.init();
        webdrivercss.init(client, wdCssOpts);
        this.addCommands(client);

        return client;
    },

    /**
     * Add the 'verifyScreenshots' command to the webdriverio client
     * @param {WebdriverIoClient} client - the webdriverio client
     */
    addCommands: function (client) {
        client.addCommand('verifyScreenshots', function (name, screenshots) {

            // this is a little odd, but webdriverio adds an additional callback argument at the end for chaining
            // http://webdriver.io/guide/usage/customcommands.html
            var callback = arguments[arguments.length - 1];

            var screenshotsCopy = _.clone(screenshots);
            client.webdrivercss(name, screenshotsCopy, function (err, res) {
                expect(err).toBeFalsy();
                _.forEach(screenshots, function (screenshot) {
                    var result = res[screenshot.name][0];
                    var msg = 'Visual difference found for "' + screenshot.name + '" \n';
                    expect(result.isWithinMisMatchTolerance).toBeTruthy(msg + JSON.stringify(result, null, 4));
                });
            });

            callback();
        });
    },

    /**
     * Construc the base URL from the testConfig
     * @param {TestConfig} testConfig - the e2ee spec configuration
     * @param {String} [extra] - extra URL path
     * @returns {String} the full URL
     */
    getUrl: function (testConfig, extra) {
        var http = testConfig.http;
        var entryPoint = http.entryPoint;

        // Prevent double forward slash in URL
        if (entryPoint.length !== 0 && entryPoint[0] === '/') {
            entryPoint = entryPoint.substring(1);
        }

        var url = 'http://' + http.host + ':' + http.port + '/' + entryPoint;
        if (extra) {
            // Prevent double forward slash in URL
            if (url[url.length - 1] === '/' && extra[0] === '/') {
                extra = extra.substring(1);
            }

            url = url + extra;
        }

        return url;
    },
};

module.exports = ns;
<|endoftext|>


<commit_before>import FS from "fs";
import Path from "path";
import _ from "lodash-fp";
import { log } from "../helpers";

export const title = "Day 20: Infinite Elves and Infinite Houses";

export function getPresentCounts(target, increment, limit) {
    const max = target / increment;

    return _.reduce((houses, multiple) => {
        const multiples = _.map((index) => {
            return multiple + (index * multiple);
        }, _.range(0, Math.floor(max / multiple)));

        _.forEach((x) => {
            houses[x] = (houses[x] || 0) + (multiple * increment);
        }, limit ? multiples.slice(0, limit) : multiples);

        return houses;
    }, {}, _.range(1, max + 1));
}

export function getLowestHouseNumber(target, increment = 10, limit) {
    const counts = getPresentCounts(target, increment, limit);

    return _.compose(
        _.get("house"),
        _.first,
        _.sortByAll(["house", "presents"]),
        _.filter(({presents}) => presents >= target),
        _.map((index) => {
            const key = parseInt(index, 10);

            return  {
                house: key,
                presents: counts[key]
            };
        })
    )(Object.keys(counts)) || null;
}

export function run() {
    const inputPath = Path.join(__dirname, "input.txt");
    const input = _.parseInt(10, FS.readFileSync(inputPath, "utf-8").trim());

    console.log("Given infinite houses and 10 presents per delivery, what is the lowest house number of the house to get at least as many presents as the number in your puzzle input?", getLowestHouseNumber(input));
    console.log("Given 50 houses and 11 presents per delivery, what is the new lowest house number of the house to get at least as many presents as the number in your puzzle input?", getLowestHouseNumber(input, 11, 50));
}
<commit_msg>Improved the efficiency of getPresentCounts. - When a limit is passsed, truncating is done when mapping over each possible multiple, rather than slicing after. - Removed 'helpers' as a dependency.<commit_after>import FS from "fs";
import Path from "path";
import _ from "lodash-fp";

export const title = "Day 20: Infinite Elves and Infinite Houses";

export function getPresentCounts(target, increment, limit) {
    const max = target / increment;

    return _.reduce((houses, multiple) => {
        const count = Math.floor(max / multiple);
        const multiples = _.map((index) => {
            return multiple + (index * multiple);
        }, _.range(0, limit ? Math.min(limit, count) : count));

        _.forEach((x) => {
            houses[x] = (houses[x] || 0) + (multiple * increment);
        }, multiples);

        return houses;
    }, {}, _.range(1, max + 1));
}

export function getLowestHouseNumber(target, increment = 10, limit) {
    const counts = getPresentCounts(target, increment, limit);

    return _.compose(
        _.get("house"),
        _.first,
        _.sortByAll(["house", "presents"]),
        _.filter(({presents}) => presents >= target),
        _.map((index) => {
            const key = parseInt(index, 10);

            return  {
                house: key,
                presents: counts[key]
            };
        })
    )(Object.keys(counts)) || null;
}

export function run() {
    const inputPath = Path.join(__dirname, "input.txt");
    const input = _.parseInt(10, FS.readFileSync(inputPath, "utf-8").trim());

    console.log("Given infinite houses and 10 presents per delivery, what is the lowest house number of the house to get at least as many presents as the number in your puzzle input?", getLowestHouseNumber(input));
    console.log("Given 50 houses and 11 presents per delivery, what is the new lowest house number of the house to get at least as many presents as the number in your puzzle input?", getLowestHouseNumber(input, 11, 50));
}
<|endoftext|>


<commit_before>/*
 * django-scribbler
 * Source: https://github.com/mlavin/django-scribbler
 * Docs: http://django-scribbler.readthedocs.org/
 *
 * Copyright 2012, Mark Lavin
 * BSD License
 *
*/

require.config({
    paths: {
        jquery: 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min',
        codemirror: '../libs/codemirror-compressed'
    },
    shim: {
        codemirror: {
            exports: 'CodeMirror'
        }
    }
});

require(['jquery', 'codemirror'], function($, CodeMirror) {
    var ScribbleEditor = {
        visible: false,
        rendering: false,
        errorLine: null,
        element: null,
        controls: {},
        current: {},
        editor: null,
        scribbles: null,
        init: function() {
            console.log('init');
            this.scribbles = $('.scribble-wrapper.with-controls');
            if (this.scribbles.length > 0) {
                this.element = $('

');
                this.buildControls();
                $('body').append(this.element);
                // Initialize CodeMirror editor
                var options = {
                    mode: "text/html",
                    tabMode: "indent",
                    lineNumbers: true,
                    onChange: function(editor) {ScribbleEditor.submitPreview();}
                };
                this.editor = CodeMirror(
                    document.getElementById("scribbleEditorContainer"),
                    options
                );
                // Bind editor to the scribbles
                this.scribbles.each(function(i, elem) {
                    // Bind event handlers for each scribble
                    $(elem).click(function(e) {
                        e.preventDefault();
                        ScribbleEditor.open($(this));
                    });
                });
            }
        },
        buildControls: function() {
            // Build control bar
            var footerControls = $('

').addClass('controls clearfix');
            // Close button
            this.controls.close = $('Close')
            .attr({title: 'Close', href: '#'})
            .addClass('close')
            .click(function(e) {
                e.preventDefault();
                ScribbleEditor.close();
            });
            // Save button
            this.controls.save = $('Save')
            .attr({title: 'Save', href: "#"})
            .addClass('btn save').click(function(e) {
                e.preventDefault();
                ScribbleEditor.submitSave();
            });
            // Error message
            this.controls.errors = $('')
            .addClass('error-msg');
            footerControls.append(
                this.controls.errors,
                this.controls.close,
                this.controls.save
            );
            this.element.append(footerControls);
        },
        open: function(scribble) {
            this.current.content = $('.scribble-content.original', scribble);
            this.current.preview = $('.scribble-content.preview', scribble);
            this.current.form = $('.scribble-form', scribble);
            this.current.can_save = this.current.form.data('save');
            this.current.can_delete = this.current.form.data('delete');
            this.element.show();
            this.element.animate({height: '300px'}, 500);
            if (this.current.can_save) {
                this.controls.save.show();
                this.editor.setOption('readOnly', false);
                this.editor.setValue($('[name$=content]', this.current.form).val());
            } else {
                this.controls.save.hide();
                this.editor.setOption('readOnly', true);
                this.editor.setValue('You do not have permission to edit this content.');
            }
            this.editor.focus();
            this.visible = true;
        },
        close: function() {
            this.current.preview.hide();
            this.current.content.show();
            $('[name$=content]', this.current.form).val(this.editor.getValue());
            this.current = {};
            this.editor.setValue('');
            this.element.animate({height: 0}, 500);
            this.visible = false;
        },
        submitPreview: function() {
            if (this.current.form && !this.rendering && !this.editor.getOption('readOnly')) {
                this.rendering = true;
                // Submit the form and display the preview
                $.post(
                    this.current.form.attr('action'),
                    this.getFormData(),
                    function(response) {
                        ScribbleEditor.renderPreview(response);
                    },
                    'json'
                );
            }
        },
        renderPreview: function(response) {
            if (this.errorLine !== null) {
                this.editor.setLineClass(this.errorLine, null, null);
            }
            this.controls.errors.html('');
            if (response.valid) {
                this.current.preview.html(response.html);
                this.current.preview.show();
                this.current.content.hide();
                this.controls.save.show();
            } else {
                this.errorLine = response.error.line - 1;
                this.editor.setLineClass(this.errorLine, null, "activeline");
                this.controls.errors.html("Error: " + response.error.message);
                this.controls.save.hide();
            }
            this.rendering = false;
        },
        getFormData: function() {
            var result = {};
            var prefix = '';
            if (this.current.form) {
                prefix = this.current.form.data('prefix');
                $(':input', this.current.form).each(function(i, input) {
                    var inputName = $(input).attr('name').replace(prefix + '-', '');
                    var inputValue = $(input).val();
                    if (inputName === 'content') {
                        result[inputName] = ScribbleEditor.editor.getValue();
                    } else {
                        result[inputName] = inputValue;
                    }
                });
            }
            return result;
        },
        submitSave: function() {
            if (this.current.form && !this.errorLine) {
                // Submit the form and change current content
                $.post(
                    this.current.form.data('save'),
                    this.getFormData(),
                    function(response) {
                        ScribbleEditor.renderSave(response);
                    },
                    'json'
                );
            }
        },
        renderSave: function(response) {
            if (response.valid) {
                this.current.form.data('save', response.url);
                this.current.content.html(this.current.preview.html());
                this.close();
            } else {
                this.controls.errors.html("Error: Content is not valid");
            }
        }
    };

    $(document).ready(function(){ScribbleEditor.init();});
});
<commit_msg>Remove debugging console statement.<commit_after>/*
 * django-scribbler
 * Source: https://github.com/mlavin/django-scribbler
 * Docs: http://django-scribbler.readthedocs.org/
 *
 * Copyright 2012, Mark Lavin
 * BSD License
 *
*/

require.config({
    paths: {
        jquery: 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min',
        codemirror: '../libs/codemirror-compressed'
    },
    shim: {
        codemirror: {
            exports: 'CodeMirror'
        }
    }
});

require(['jquery', 'codemirror'], function($, CodeMirror) {
    var ScribbleEditor = {
        visible: false,
        rendering: false,
        errorLine: null,
        element: null,
        controls: {},
        current: {},
        editor: null,
        scribbles: null,
        init: function() {
            this.scribbles = $('.scribble-wrapper.with-controls');
            if (this.scribbles.length > 0) {
                this.element = $('

');
                this.buildControls();
                $('body').append(this.element);
                // Initialize CodeMirror editor
                var options = {
                    mode: "text/html",
                    tabMode: "indent",
                    lineNumbers: true,
                    onChange: function(editor) {ScribbleEditor.submitPreview();}
                };
                this.editor = CodeMirror(
                    document.getElementById("scribbleEditorContainer"),
                    options
                );
                // Bind editor to the scribbles
                this.scribbles.each(function(i, elem) {
                    // Bind event handlers for each scribble
                    $(elem).click(function(e) {
                        e.preventDefault();
                        ScribbleEditor.open($(this));
                    });
                });
            }
        },
        buildControls: function() {
            // Build control bar
            var footerControls = $('

').addClass('controls clearfix');
            // Close button
            this.controls.close = $('Close')
            .attr({title: 'Close', href: '#'})
            .addClass('close')
            .click(function(e) {
                e.preventDefault();
                ScribbleEditor.close();
            });
            // Save button
            this.controls.save = $('Save')
            .attr({title: 'Save', href: "#"})
            .addClass('btn save').click(function(e) {
                e.preventDefault();
                ScribbleEditor.submitSave();
            });
            // Error message
            this.controls.errors = $('')
            .addClass('error-msg');
            footerControls.append(
                this.controls.errors,
                this.controls.close,
                this.controls.save
            );
            this.element.append(footerControls);
        },
        open: function(scribble) {
            this.current.content = $('.scribble-content.original', scribble);
            this.current.preview = $('.scribble-content.preview', scribble);
            this.current.form = $('.scribble-form', scribble);
            this.current.can_save = this.current.form.data('save');
            this.current.can_delete = this.current.form.data('delete');
            this.element.show();
            this.element.animate({height: '300px'}, 500);
            if (this.current.can_save) {
                this.controls.save.show();
                this.editor.setOption('readOnly', false);
                this.editor.setValue($('[name$=content]', this.current.form).val());
            } else {
                this.controls.save.hide();
                this.editor.setOption('readOnly', true);
                this.editor.setValue('You do not have permission to edit this content.');
            }
            this.editor.focus();
            this.visible = true;
        },
        close: function() {
            this.current.preview.hide();
            this.current.content.show();
            $('[name$=content]', this.current.form).val(this.editor.getValue());
            this.current = {};
            this.editor.setValue('');
            this.element.animate({height: 0}, 500);
            this.visible = false;
        },
        submitPreview: function() {
            if (this.current.form && !this.rendering && !this.editor.getOption('readOnly')) {
                this.rendering = true;
                // Submit the form and display the preview
                $.post(
                    this.current.form.attr('action'),
                    this.getFormData(),
                    function(response) {
                        ScribbleEditor.renderPreview(response);
                    },
                    'json'
                );
            }
        },
        renderPreview: function(response) {
            if (this.errorLine !== null) {
                this.editor.setLineClass(this.errorLine, null, null);
            }
            this.controls.errors.html('');
            if (response.valid) {
                this.current.preview.html(response.html);
                this.current.preview.show();
                this.current.content.hide();
                this.controls.save.show();
            } else {
                this.errorLine = response.error.line - 1;
                this.editor.setLineClass(this.errorLine, null, "activeline");
                this.controls.errors.html("Error: " + response.error.message);
                this.controls.save.hide();
            }
            this.rendering = false;
        },
        getFormData: function() {
            var result = {};
            var prefix = '';
            if (this.current.form) {
                prefix = this.current.form.data('prefix');
                $(':input', this.current.form).each(function(i, input) {
                    var inputName = $(input).attr('name').replace(prefix + '-', '');
                    var inputValue = $(input).val();
                    if (inputName === 'content') {
                        result[inputName] = ScribbleEditor.editor.getValue();
                    } else {
                        result[inputName] = inputValue;
                    }
                });
            }
            return result;
        },
        submitSave: function() {
            if (this.current.form && !this.errorLine) {
                // Submit the form and change current content
                $.post(
                    this.current.form.data('save'),
                    this.getFormData(),
                    function(response) {
                        ScribbleEditor.renderSave(response);
                    },
                    'json'
                );
            }
        },
        renderSave: function(response) {
            if (response.valid) {
                this.current.form.data('save', response.url);
                this.current.content.html(this.current.preview.html());
                this.close();
            } else {
                this.controls.errors.html("Error: Content is not valid");
            }
        }
    };

    $(document).ready(function(){ScribbleEditor.init();});
});
<|endoftext|>


<commit_before>module.exports = config => {
  // load external cdn dependencies
  const cdns = Object.values(require('../package.json').cdnDependencies);
  // add angular mocks
  const externalFiles = [
    ...cdns,
    'https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.3/angular-mocks.js',
  ];

  // entry file that bundles all the test files
  const testEntryFile = './other/tests.js';

  const webpackConfig = require('../webpack.config');
  const webpackJsLoader = webpackConfig.module.loaders.filter(loader => {
    return loader.loader === 'babel';
  });

  config.set({
    frameworks: ['mocha', 'chai', 'sinon'],
    files: [
      ...externalFiles,
      testEntryFile
    ],
    preprocessors: {
      [testEntryFile]: ['webpack', 'sourcemap']
    },
    webpack: {
      module: {
        loaders: webpackJsLoader
      },
      devtool: 'inline-source-map'
    },
    webpackMiddleware: {
      noInfo: true
    },
    // how the test success/failure status is reported:
    reporters: ['dots'],
    logLevel: config.LOG_ERROR,
    browsers: ['PhantomJS', 'Chrome', 'Firefox', 'Safari'],
    plugins: [
      'karma-phantomjs-launcher',
      'karma-sourcemap-loader',
      'karma-chrome-launcher',
      'karma-firefox-launcher',
      'karma-safari-launcher',
      'karma-mocha',
      'karma-chai',
      'karma-sinon',
      'karma-webpack'
    ]
  });
};
<commit_msg>refactor(karma.conf): add support for all webpack loaders<commit_after>module.exports = config => {
  // load external cdn dependencies
  const cdns = Object.values(require('../package.json').cdnDependencies);
  // add angular mocks
  const externalFiles = [
    ...cdns,
    'https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.3/angular-mocks.js',
  ];

  // entry file that bundles all the test files
  const testEntryFile = './other/tests.js';

  const webpackConfig = require('../webpack.config');
  const webpackLoaders = webpackConfig.module.loaders;

  config.set({
    frameworks: ['mocha', 'chai', 'sinon'],
    files: [
      ...externalFiles,
      testEntryFile
    ],
    preprocessors: {
      [testEntryFile]: ['webpack', 'sourcemap']
    },
    webpack: {
      module: {
        loaders: webpackLoaders
      },
      devtool: 'inline-source-map'
    },
    webpackMiddleware: {
      noInfo: true
    },
    // how the test success/failure status is reported:
    reporters: ['dots'],
    logLevel: config.LOG_ERROR,
    browsers: ['PhantomJS', 'Chrome', 'Firefox', 'Safari'],
    plugins: [
      'karma-phantomjs-launcher',
      'karma-sourcemap-loader',
      'karma-chrome-launcher',
      'karma-firefox-launcher',
      'karma-safari-launcher',
      'karma-mocha',
      'karma-chai',
      'karma-sinon',
      'karma-webpack'
    ]
  });
};
<|endoftext|>


<commit_before>const CopyWebpackPlugin = require('copy-webpack-plugin')
const path = require('path')

const entryFilePath = './src/client/app.js'
const appDir = path.join(path.resolve('.'), '/public/assets') // let as an absolute path
const assetsFromDir = './src/client/resources/html' // relative to this webpack config file path
const assetsToDir = '../' // relative to appDir

module.exports = {
  entry: {
    app : entryFilePath
  },
  output: {
    path: appDir,
    publicPath: 'assets/',
    filename: 'app.js'
  },
  module: {
    loaders: [{
        test: /\.js$/,
        loader: 'babel',
        exclude: /node_modules/
      },{
        test: /\.vue$/,
        loader: 'vue',
        exclude: /node_modules/
      },{
        test: /\.(jpe?g|png|gif|svg|eot|woff|ttf|svg|woff2)$/,
        loader: "file?name=[name].[ext]"
      },{
        test: /\.css$/,
        loader: "style-loader!css-loader",
        exclude: /node_modules/
      }]
  },
  plugins : [
    new CopyWebpackPlugin([{
      from : assetsFromDir,
      to : assetsToDir
    }])
  ]
}<commit_msg>better webpack config<commit_after>const CopyWebpackPlugin = require('copy-webpack-plugin')
const path = require('path')

const entryFilePath = './src/client/app.js'
const appDir = path.join(path.resolve('.'), '/public/assets') // let as an absolute path
const assetsFromDir = './src/client/resources/html' // relative to this webpack config file path
const assetsToDir = '../' // relative to appDir

module.exports = {
  entry: {
    app : entryFilePath
  },
  output: {
    path: appDir,
    publicPath: 'assets/',
    filename: 'app.js'
  },
  module: {
    loaders: [{
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },{
        test: /\.vue$/,
        loader: 'vue-loader',
        exclude: /node_modules/
      },{
        test: /\.(jpe?g|png|gif|svg|eot|woff|ttf|svg|woff2)$/,
        loader: "file-loader?name=[name].[ext]"
      },{
        test: /\.css$/,
        loader: "style-loader!css-loader",
        exclude: /node_modules/
      }]
  },
  plugins : [
    new CopyWebpackPlugin([{
      from : assetsFromDir,
      to : assetsToDir
    }])
  ],
  resolve: {
    alias: {
      vue: 'vue/dist/vue.js'
    }
  }
}<|endoftext|>


<commit_before>// abstract class for individual tool views.  Basically just a set of defaults.
// extend this to make a new tool.

$( function () {
	mw.pageTriage.ToolView = Backbone.View.extend( {
		// These things will probably be overridden with static values.  You can use a function
		// if you want to, though.
		//
		id: 'mwe-pt-info-abstract',
		icon: 'icon_skip.png', // icon to display in the toolbar
		title: 'Abstract tool view', // the title for the flyout window
		scrollable: false, // should the output of render be in a scrollable div?

		// should the content be re-rendered every time the tool is opened, or just rendered the first time?
		reRender: false,

		// These things will likely be overridden with functions.
		//
		// function that returns the number of items to display in an icon badge
		// if null, badge won't be displayed.
		badgeCount: function () {
			return null;
		},

		// function to bind to the icon's click handler
		// if not defined, runs render() and inserts the result into a flyout instead
		// useful for the "next" button, for example
		click: function () {
			if ( this.visible ) {
				this.hide();
			} else {
				this.show();
			}
		},

		// generate the stuff that goes in this tool's flyout.
		render: function () {
			this.$tel.html = 'this is some example html';
		},

		// if you override initialize, make sure you preserve eventBus
		initialize: function ( options ) {
			this.eventBus = options.eventBus;
		},

		// ***********************************************************
		// from here down is stuff you probably won't want to override
		tagName: 'div',
		className: 'mwe-pt-tool',
		chromeTemplate: mw.pageTriage.viewUtil.template( { view: 'toolbar', template: 'toolView.html' } ),
		visible: false,
		rendered: false,

		show: function () {
			var flyoutOffset;

			// trigger an event here saying which tool is being opened.
			this.eventBus.trigger( 'showTool', this );

			// close this tool if another tool is opened.
			this.eventBus.bind( 'showTool', function ( tool ) {
				if ( tool !== this ) {
					this.hide();
				}
			}, this );

			// swap the icon
			this.setIcon( 'active' );

			if ( this.reRender || !this.rendered ) {
				// render the content
				this.render();
				this.rendered = true;
			}

			// show the tool flyout
			this.$el.find( '.mwe-pt-tool-flyout' ).show();
			this.$el.find( '.mwe-pt-tool-pokey' ).show();
			this.visible = true;

			// If the toolbar has been dragged to the other side of the screen
			// make sure the flyout opens in the opposite direction.
			flyoutOffset = this.$el.find( '.mwe-pt-tool-flyout' ).outerWidth() + 8;
			if (
				(
					// For LTR, calculate the value from the left
					$( 'body' ).css( 'direction' ) === 'ltr' &&
					$( '#mwe-pt-toolbar' ).offset().left < flyoutOffset
				) ||
				(
					// For RTL, calculate the value from the right (body width - left offset)
					$( 'body' ).css( 'direction' ) === 'rtl' &&
					( $( 'body' ).outerWidth() - $( '#mwe-pt-toolbar' ).offset().left ) < flyoutOffset
				)
			) {
				this.$el.find( '.mwe-pt-tool-flyout' ).removeClass( 'mwe-pt-tool-flyout-not-flipped' );
				this.$el.find( '.mwe-pt-tool-pokey' ).removeClass( 'mwe-pt-tool-pokey-not-flipped' );
				this.$el.find( '.mwe-pt-tool-flyout' ).addClass( 'mwe-pt-tool-flyout-flipped' );
				this.$el.find( '.mwe-pt-tool-pokey' ).addClass( 'mwe-pt-tool-pokey-flipped' );
			} else {
				this.$el.find( '.mwe-pt-tool-flyout' ).removeClass( 'mwe-pt-tool-flyout-flipped' );
				this.$el.find( '.mwe-pt-tool-pokey' ).removeClass( 'mwe-pt-tool-pokey-flipped' );
				this.$el.find( '.mwe-pt-tool-flyout' ).addClass( 'mwe-pt-tool-flyout-not-flipped' );
				this.$el.find( '.mwe-pt-tool-pokey' ).addClass( 'mwe-pt-tool-pokey-not-flipped' );
			}

			// remove the hover action
			this.$icon.unbind( 'mouseenter mouseleave' );
		},

		hide: function () {
			var that = this;

			// swap the icon
			this.setIcon( 'normal' );

			// hide the div
			this.$el.find( '.mwe-pt-tool-flyout' ).hide();
			this.$el.find( '.mwe-pt-tool-pokey' ).hide();
			this.visible = false;

			// this listener is only needed when the tool is open
			this.eventBus.unbind( 'showTool', null, this );

			// re-add the hover action
			this.$icon.hover(
				function () {
					that.setIcon( 'hover' );
				},
				function () {
					that.setIcon( 'normal' );
				}
			);
		},

		place: function () {
			var iconPath,
				that = this;

			if ( this.disabled ) {
				return null;
			}

			if ( this.specialIcon ) {
				iconPath = this.iconPath( 'special' );
			} else {
				iconPath = this.iconPath( 'normal' );
			}

			// return the HTML for the closed up version of this tool.
			this.$el.html( this.chromeTemplate( {
				id: this.id,
				title: this.title,
				iconPath: iconPath
			} ) );

			this.$icon = this.$el.find( '.mwe-pt-tool-icon' );

			// bind a click handler to open it.
			this.$icon.click( function () {
				that.click();
			} );

			// and a hover action.
			this.$icon.hover(
				function () {
					that.setIcon( 'hover' );
				},
				function () {
					that.setIcon( 'normal' );
				}
			);

			if ( this.tooltip ) {
				this.$icon.attr( 'title', mw.msg( this.tooltip ) );
			}

			// set up an event for the close button
			this.$el.find( '.mwe-pt-tool-close' ).click( function () {
				that.hide();
			} );

			// $tel is the "tool element".  put stuff that goes in the tool there.
			this.$tel = this.$el.find( '.mwe-pt-tool-content' );

			if ( this.model ) {
				// If this view works with a model, wait until
				// the model is loaded to set the badge.
				this.model.bind( 'change', this.setBadge, this );
			} else {
				// If no model, set the badge right away
				this.setBadge();
			}

			return this.$el;
		},

		disable: function () {
			this.$icon.unbind( 'mouseenter mouseleave click' );
			this.setIcon( 'disabled' );
			this.$icon.css( 'cursor', 'default' );
		},

		iconPath: function ( dir ) {
			return mw.config.get( 'wgExtensionAssetsPath' ) +
				'/PageTriage/modules/ext.pageTriage.views.toolbar/images/icons/' +
				dir +
				'/' +
				this.icon;
		},

		setIcon: function ( dir ) {
			this.$icon.attr( 'src', this.iconPath( dir ) );
		},

		setBadge: function () {
			var badgeCount = this.badgeCount();
			if ( badgeCount ) {
				this.$el.find( '.mwe-pt-tool-icon-container' ).badge( badgeCount );
			}
		},

		/**
		 * Count the number of properties in an object
		 */
		objectPropCount: function ( obj ) {
			var key,
				count = 0;
			for ( key in obj ) {
				if ( obj.hasOwnProperty( key ) ) {
					count++;
				}
			}
			return count;
		}

	} );
} );
<commit_msg>Change use of deprecated jQuery.fn.hover() to on()<commit_after>// abstract class for individual tool views.  Basically just a set of defaults.
// extend this to make a new tool.

$( function () {
	mw.pageTriage.ToolView = Backbone.View.extend( {
		// These things will probably be overridden with static values.  You can use a function
		// if you want to, though.
		//
		id: 'mwe-pt-info-abstract',
		icon: 'icon_skip.png', // icon to display in the toolbar
		title: 'Abstract tool view', // the title for the flyout window
		scrollable: false, // should the output of render be in a scrollable div?

		// should the content be re-rendered every time the tool is opened, or just rendered the first time?
		reRender: false,

		// These things will likely be overridden with functions.
		//
		// function that returns the number of items to display in an icon badge
		// if null, badge won't be displayed.
		badgeCount: function () {
			return null;
		},

		// function to bind to the icon's click handler
		// if not defined, runs render() and inserts the result into a flyout instead
		// useful for the "next" button, for example
		click: function () {
			if ( this.visible ) {
				this.hide();
			} else {
				this.show();
			}
		},

		// generate the stuff that goes in this tool's flyout.
		render: function () {
			this.$tel.html = 'this is some example html';
		},

		// if you override initialize, make sure you preserve eventBus
		initialize: function ( options ) {
			this.eventBus = options.eventBus;
		},

		// ***********************************************************
		// from here down is stuff you probably won't want to override
		tagName: 'div',
		className: 'mwe-pt-tool',
		chromeTemplate: mw.pageTriage.viewUtil.template( { view: 'toolbar', template: 'toolView.html' } ),
		visible: false,
		rendered: false,

		show: function () {
			var flyoutOffset;

			// trigger an event here saying which tool is being opened.
			this.eventBus.trigger( 'showTool', this );

			// close this tool if another tool is opened.
			this.eventBus.bind( 'showTool', function ( tool ) {
				if ( tool !== this ) {
					this.hide();
				}
			}, this );

			// swap the icon
			this.setIcon( 'active' );

			if ( this.reRender || !this.rendered ) {
				// render the content
				this.render();
				this.rendered = true;
			}

			// show the tool flyout
			this.$el.find( '.mwe-pt-tool-flyout' ).show();
			this.$el.find( '.mwe-pt-tool-pokey' ).show();
			this.visible = true;

			// If the toolbar has been dragged to the other side of the screen
			// make sure the flyout opens in the opposite direction.
			flyoutOffset = this.$el.find( '.mwe-pt-tool-flyout' ).outerWidth() + 8;
			if (
				(
					// For LTR, calculate the value from the left
					$( 'body' ).css( 'direction' ) === 'ltr' &&
					$( '#mwe-pt-toolbar' ).offset().left < flyoutOffset
				) ||
				(
					// For RTL, calculate the value from the right (body width - left offset)
					$( 'body' ).css( 'direction' ) === 'rtl' &&
					( $( 'body' ).outerWidth() - $( '#mwe-pt-toolbar' ).offset().left ) < flyoutOffset
				)
			) {
				this.$el.find( '.mwe-pt-tool-flyout' ).removeClass( 'mwe-pt-tool-flyout-not-flipped' );
				this.$el.find( '.mwe-pt-tool-pokey' ).removeClass( 'mwe-pt-tool-pokey-not-flipped' );
				this.$el.find( '.mwe-pt-tool-flyout' ).addClass( 'mwe-pt-tool-flyout-flipped' );
				this.$el.find( '.mwe-pt-tool-pokey' ).addClass( 'mwe-pt-tool-pokey-flipped' );
			} else {
				this.$el.find( '.mwe-pt-tool-flyout' ).removeClass( 'mwe-pt-tool-flyout-flipped' );
				this.$el.find( '.mwe-pt-tool-pokey' ).removeClass( 'mwe-pt-tool-pokey-flipped' );
				this.$el.find( '.mwe-pt-tool-flyout' ).addClass( 'mwe-pt-tool-flyout-not-flipped' );
				this.$el.find( '.mwe-pt-tool-pokey' ).addClass( 'mwe-pt-tool-pokey-not-flipped' );
			}

			// remove the hover action
			this.$icon.unbind( 'mouseenter mouseleave' );
		},

		hide: function () {
			var that = this;

			// swap the icon
			this.setIcon( 'normal' );

			// hide the div
			this.$el.find( '.mwe-pt-tool-flyout' ).hide();
			this.$el.find( '.mwe-pt-tool-pokey' ).hide();
			this.visible = false;

			// this listener is only needed when the tool is open
			this.eventBus.unbind( 'showTool', null, this );

			// re-add the hover action
			this.$icon.hover(
				function () {
					that.setIcon( 'hover' );
				},
				function () {
					that.setIcon( 'normal' );
				}
			);
		},

		place: function () {
			var iconPath,
				that = this;

			if ( this.disabled ) {
				return null;
			}

			if ( this.specialIcon ) {
				iconPath = this.iconPath( 'special' );
			} else {
				iconPath = this.iconPath( 'normal' );
			}

			// return the HTML for the closed up version of this tool.
			this.$el.html( this.chromeTemplate( {
				id: this.id,
				title: this.title,
				iconPath: iconPath
			} ) );

			this.$icon = this.$el.find( '.mwe-pt-tool-icon' );

			// bind a click handler to open it.
			this.$icon.click( function () {
				that.click();
			} );

			// and a hover action.
			this.$icon.on( {
				mouseenter: function () {
					that.setIcon( 'hover' );
				},
				mouseleaver: function () {
					that.setIcon( 'normal' );
				}
			} );

			if ( this.tooltip ) {
				this.$icon.attr( 'title', mw.msg( this.tooltip ) );
			}

			// set up an event for the close button
			this.$el.find( '.mwe-pt-tool-close' ).click( function () {
				that.hide();
			} );

			// $tel is the "tool element".  put stuff that goes in the tool there.
			this.$tel = this.$el.find( '.mwe-pt-tool-content' );

			if ( this.model ) {
				// If this view works with a model, wait until
				// the model is loaded to set the badge.
				this.model.bind( 'change', this.setBadge, this );
			} else {
				// If no model, set the badge right away
				this.setBadge();
			}

			return this.$el;
		},

		disable: function () {
			this.$icon.unbind( 'mouseenter mouseleave click' );
			this.setIcon( 'disabled' );
			this.$icon.css( 'cursor', 'default' );
		},

		iconPath: function ( dir ) {
			return mw.config.get( 'wgExtensionAssetsPath' ) +
				'/PageTriage/modules/ext.pageTriage.views.toolbar/images/icons/' +
				dir +
				'/' +
				this.icon;
		},

		setIcon: function ( dir ) {
			this.$icon.attr( 'src', this.iconPath( dir ) );
		},

		setBadge: function () {
			var badgeCount = this.badgeCount();
			if ( badgeCount ) {
				this.$el.find( '.mwe-pt-tool-icon-container' ).badge( badgeCount );
			}
		},

		/**
		 * Count the number of properties in an object
		 */
		objectPropCount: function ( obj ) {
			var key,
				count = 0;
			for ( key in obj ) {
				if ( obj.hasOwnProperty( key ) ) {
					count++;
				}
			}
			return count;
		}

	} );
} );
<|endoftext|>


<commit_before>import { version } from '../package.json'
import Vue from 'vue'

import 'github-markdown-css'
import './style/tsplus.less'
import './icons/iconfont.js' // from http://www.iconfont.cn h5 仓库
import './util/rem'
import './util/prototype' // 原型拓展

import Message from './plugins/message/'
import AsyncImage from './components/FeedCard/v-async-image.js'

import imgCropper from '@/plugins/imgCropper'
import lstore from '@/plugins/lstore/index.js'

import Ajax from './api/api.js'
import mixin from './mixin.js'
import * as filters from './filters.js'
import components from './components.js'

import store from './stores/'
import router from './routers/'
import i18n from './i18n'
import App from './app'
import bus from './bus'
import './registerServiceWorker'
import './vendor'

import * as WebIM from '@/vendor/easemob'

export { version }

Vue.mixin(mixin)

components.forEach(component => {
  Vue.component(component.name, component)
})

Vue.config.productionTip = false

Vue.prototype.$http = Ajax
Vue.prototype.$Message = Message
Vue.prototype.$MessageBundle = filters.plusMessageFirst
Vue.prototype.$bus = bus

Vue.use(AsyncImage)
Vue.use(imgCropper)
Vue.use(lstore)

for (const k in filters) {
  Vue.filter(k, filters[k])
}
if (!window.initUrl) {
  window.initUrl = window.location.href.replace(/(\/$)/, '')
}

/* eslint-disable no-new */
new Vue({
  store,
  router,
  i18n,
  created () {
    WebIM.openWebIM()
  },
  render: h => h(App),
}).$mount('#app')

// Exposed versions
/* eslint-disable no-console */
console.info(
  `%cWelcome to Plus(ThinkSNS+)! Release %c v${version} `,
  'color: #00A9E0;',
  'background:#35495e; padding: 1px; border-radius: 3px; color: #fff;'
)
console.info(
  `%cDevelopment by SlimKit Group 👉 https://github.com/slimkit \nApache-2.0 Licensed | Copyright © ${new Date().getFullYear()} Chengdu ZhiYiChuangXiang Technology Co., Ltd. All rights reserved.`,
  'color: #00A9E0;'
)
<commit_msg>fix(chore): 恢复 moblink<commit_after>import { version } from '../package.json'
import { ENABLE_MOBLINK } from '@/constants/app'

import Vue from 'vue'

import 'github-markdown-css'
import './style/tsplus.less'
import './icons/iconfont.js' // from http://www.iconfont.cn h5 仓库
import './util/rem'
import './util/prototype' // 原型拓展

import Message from './plugins/message/'
import AsyncImage from './components/FeedCard/v-async-image.js'

import imgCropper from '@/plugins/imgCropper'
import lstore from '@/plugins/lstore/index.js'

import Ajax from './api/api.js'
import mixin from './mixin.js'
import * as filters from './filters.js'
import components from './components.js'

import store from './stores/'
import router from './routers/'
import i18n from './i18n'
import App from './app'
import bus from './bus'
import './registerServiceWorker'
import './vendor'

import * as WebIM from '@/vendor/easemob'

export { version }

Vue.mixin(mixin)

components.forEach(component => {
  Vue.component(component.name, component)
})

Vue.config.productionTip = false

Vue.prototype.$http = Ajax
Vue.prototype.$Message = Message
Vue.prototype.$MessageBundle = filters.plusMessageFirst
Vue.prototype.$bus = bus

Vue.use(AsyncImage)
Vue.use(imgCropper)
Vue.use(lstore)

for (const k in filters) {
  Vue.filter(k, filters[k])
}
if (!window.initUrl) {
  window.initUrl = window.location.href.replace(/(\/$)/, '')
}

// 加载 moblink 用于引导打开 APP
if (ENABLE_MOBLINK) {
  window.addEventListener('load', () => {
    const key = process.env.VUE_APP_MOBLINK_KEY || ''
    const script = document.createElement('script')
    script.type = 'text/javascript'
    script.src = `//f.moblink.mob.com/3.0.1/moblink.js?appkey=${key}`
    script.onload = () => {
      // eslint-disable-next-line
      MobLink({ path: location.href })
    }
    document.querySelector('body').appendChild(script)
  })
}

/* eslint-disable no-new */
new Vue({
  store,
  router,
  i18n,
  created () {
    WebIM.openWebIM()
  },
  render: h => h(App),
}).$mount('#app')

// Exposed versions
/* eslint-disable no-console */
console.info(
  `%cWelcome to Plus(ThinkSNS+)! Release %c v${version} `,
  'color: #00A9E0;',
  'background:#35495e; padding: 1px; border-radius: 3px; color: #fff;'
)
console.info(
  `%cDevelopment by SlimKit Group 👉 https://github.com/slimkit \nApache-2.0 Licensed | Copyright © ${new Date().getFullYear()} Chengdu ZhiYiChuangXiang Technology Co., Ltd. All rights reserved.`,
  'color: #00A9E0;'
)
<|endoftext|>