<commit_before>'use strict';

var cheerio = require('cheerio');
var fs = require('fs');
var tokens = require('./login/tokens');
var util = require('util');

// Open the sessions database
var Datastore = require('nedb');
var sessionDB = new Datastore({filename: './db/sessions.db', autoload: true});

// Automatically compact the DB every 5 minutes
sessionDB.persistence.setAutocompactionInterval(300000);

var config = require('./config').getConfig();
var filteredConfig = require('./config').getFilteredConfig();

exports.authCheck = function (req, res, next) {
    if (!config.login.enabled) {
        return next();
    }

    var allowed = (req.user !== undefined) ? req.user.allowed : false;
    var provider = (req.user !== undefined) ? req.user.provider : 'none';
    var providerAllowed = (provider !== 'none') ? config.login[provider].enabled : false;

    if (req.query.key || req.cookies.socketToken) {
        tokens.find({token: req.query.key || req.cookies.socketToken}, function (err, token) {
            if (err) throw err;
            if (token) next();
            else {
                req.session.returnTo = req.url;
                res.redirect('/login');
            }
        });
    } else if (req.isAuthenticated() && allowed && providerAllowed) {
        // Create token
        tokens.findOrCreate({provider: provider, id: req.user.id}, function(err, token) {
            if (err) throw err;

            // To set a cookie on localhost, domain must be "null"
            var domain = config.host === 'localhost'
                ? null
                : '.' + config.host;
            res.cookie('socketToken', token, {domain: domain});
            next();
        });
    } else {
        req.session.returnTo = req.url;
        res.redirect('/login');
    }
};

exports.findSession = function(params, cb) {
    params = params || {};
    sessionDB.findOne(params, function (err, doc) {
        if (err) cb(err);
        else cb(null, doc);
    });
};

exports.injectScripts = function (pathOrHtml, resourceType, opts, cb) {
    opts = opts || {};

    // Graphics only pass the path to the html file.
    // Panels and dialogs pass a cached HTML string.
    if (resourceType === 'graphic') {
        fs.readFile(pathOrHtml, inject);
    } else {
        inject(null, pathOrHtml);
    }

    function inject(err, html) {
        var $ = cheerio.load(html);

        // Everything needs the shims and config
        var scripts = [
            '<script src="/components/observe-shim/lib/observe-shim.js"></script>',
            '<script src="/shims/WeakMap.js"></script>',
            '<script>window.ncgConfig = ' + JSON.stringify(filteredConfig) + ';</script>'
        ];

        var styles = [];

        if (resourceType === 'panel' || resourceType === 'dialog') {
            // Panels and dialogs can grab the API from the dashboard
            scripts.push('<script>window.NodeCG = window.top.NodeCG</script>');

            // Both panels and dialogs need the main default style framework
            scripts.push('<link rel="import" href="/dashboard/style/nodecg-styles.html">');

            // They both also need to reference the dashboard window's socket, rather than make their own
            scripts.push('<script>window.socket = parent.socket;</script>');

            // Likewise, they both need the contentWindow portion of the iframeResizer
            scripts.push('<script src="/components/iframe-resizer/js/iframeResizer.contentWindow.min.js"></script>');

            // Panels need the default panel styles and the dialog_opener
            if (resourceType === 'panel') {
                styles.push('<link rel="stylesheet" href="/dashboard/style/panel.css">');
                scripts.push('<script src="/dashboard/dialog_opener.js"></script>');
            }

            // Dialogs need the default dialog styles and the dialog_helper
            else if (resourceType === 'dialog') {
                styles.push('<link rel="stylesheet" href="/dashboard/style/dialog.css">');
                scripts.push('<script src="/dashboard/dialog_helper.js"></script>');
            }
        }

        else if (resourceType === 'graphic') {
            // Graphics need to create their own socket
            scripts.push('<script src="/socket.io/socket.io.js"></script>');

            // Graphics must include the API script themselves before attempting to make an instance of it
            scripts.push('<script src="/nodecg-api.js"></script>');

            // If login security is enabled, graphics must provide a valid token when they connect to the socket
            // They also need cookies-js and a helper to manage URL query strings
            var socketScript;
            if (config.login.enabled) {
                scripts.push('<script src="/components/cookies-js/dist/cookies.min.js"></script>');
                scripts.push('<script src="/login/QueryString.js"></script>');
                socketScript =
                    '<script>\n' +
                    'var token = qs["key"] || Cookies.get("socketToken");\n' +
                    'var socket = io.connect("//%s/",{query: "token=" + token});\n' +
                    '</script>';
            } else {
                socketScript = '<script>var socket = io.connect("//%s/");</script>';
            }
            scripts.push(util.format(socketScript, filteredConfig.baseURL));
        }

        else {
            throw new Error('Invalid resourceType "' + resourceType + '"');
        }

        // Inject a small script to create a NodeCG API instance, if requested.
        if (opts.createApiInstance) {
            var partialBundle = {
                name: opts.createApiInstance.name,
                config: opts.createApiInstance.config
            };

            scripts.push(
                util.format('<script>window.nodecg = new NodeCG(%s, window.socket);</script>',
                    JSON.stringify(partialBundle))
            );
        }

        // Inject the scripts required for singleInstance behavior, if requested.
        if (opts.singleInstance) {
            scripts.push('<script src="/instance/client_heart.js"></script>');
        }

        scripts = scripts.join('\n');

        // Put our scripts before their first script or HTML import.
        // If they have no scripts or imports, put our scripts at the end of <body>.
        var theirScriptsAndImports = $('script, link[rel="import"]');
        if (theirScriptsAndImports.length > 0) {
            theirScriptsAndImports.first().before(scripts);
        } else {
            $('body').append(scripts);
        }

        // Inject the needed stylesheets, if any.
        // If there are <script> tags in the head, inject before them.
        // Otherwise, add at the end of the <head>.
        if (styles.length > 0) {
            styles = styles.join('\n');

            var headScripts = $('head').find('script');
            if (headScripts.length > 0) {
                headScripts.first().before(styles);
            } else {
                $('head').append(styles);
            }
        }

        cb($.html());
    }
};

exports.versionCompare = function (v1, v2, options) {
    var lexicographical = options && options.lexicographical;
    var zeroExtend = options && options.zeroExtend;
    var v1parts = v1.split('.');
    var v2parts = v2.split('.');

    function isValidPart(x) { return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x); }
    if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) { return NaN; }
    if (zeroExtend) {
        while (v1parts.length < v2parts.length) v1parts.push('0');
        while (v2parts.length < v1parts.length) v2parts.push('0');
    }
    if (!lexicographical) {
        v1parts = v1parts.map(Number);
        v2parts = v2parts.map(Number);
    }
    for (var i = 0; i < v1parts.length; ++i) {
        if (v2parts.length === i) { return 1; }
        if (v1parts[i] === v2parts[i]) { continue; }
        else if (v1parts[i] > v2parts[i]) { return 1; }
        else { return -1; }
    }
    if (v1parts.length !== v2parts.length) { return -1; }
    return 0;
};

module.exports = exports;
<commit_msg>[util] Fix script injection causing malfunctions in singleInstance graphics<commit_after>'use strict';

var cheerio = require('cheerio');
var fs = require('fs');
var tokens = require('./login/tokens');
var util = require('util');

// Open the sessions database
var Datastore = require('nedb');
var sessionDB = new Datastore({filename: './db/sessions.db', autoload: true});

// Automatically compact the DB every 5 minutes
sessionDB.persistence.setAutocompactionInterval(300000);

var config = require('./config').getConfig();
var filteredConfig = require('./config').getFilteredConfig();

exports.authCheck = function (req, res, next) {
    if (!config.login.enabled) {
        return next();
    }

    var allowed = (req.user !== undefined) ? req.user.allowed : false;
    var provider = (req.user !== undefined) ? req.user.provider : 'none';
    var providerAllowed = (provider !== 'none') ? config.login[provider].enabled : false;

    if (req.query.key || req.cookies.socketToken) {
        tokens.find({token: req.query.key || req.cookies.socketToken}, function (err, token) {
            if (err) throw err;
            if (token) next();
            else {
                req.session.returnTo = req.url;
                res.redirect('/login');
            }
        });
    } else if (req.isAuthenticated() && allowed && providerAllowed) {
        // Create token
        tokens.findOrCreate({provider: provider, id: req.user.id}, function(err, token) {
            if (err) throw err;

            // To set a cookie on localhost, domain must be "null"
            var domain = config.host === 'localhost'
                ? null
                : '.' + config.host;
            res.cookie('socketToken', token, {domain: domain});
            next();
        });
    } else {
        req.session.returnTo = req.url;
        res.redirect('/login');
    }
};

exports.findSession = function(params, cb) {
    params = params || {};
    sessionDB.findOne(params, function (err, doc) {
        if (err) cb(err);
        else cb(null, doc);
    });
};

exports.injectScripts = function (pathOrHtml, resourceType, opts, cb) {
    // Graphics only pass the path to the html file.
    // Panels and dialogs pass a cached HTML string.
    if (resourceType === 'graphic') {
        fs.readFile(pathOrHtml, inject);
    } else {
        inject(null, pathOrHtml);
    }

    function inject(err, html) {
        var $ = cheerio.load(html);

        // Everything needs the shims and config
        var scripts = [
            '<script src="/components/observe-shim/lib/observe-shim.js"></script>',
            '<script src="/shims/WeakMap.js"></script>',
            '<script>window.ncgConfig = ' + JSON.stringify(filteredConfig) + ';</script>'
        ];

        var styles = [];

        if (resourceType === 'panel' || resourceType === 'dialog') {
            // Panels and dialogs can grab the API from the dashboard
            scripts.push('<script>window.NodeCG = window.top.NodeCG</script>');

            // Both panels and dialogs need the main default style framework
            scripts.push('<link rel="import" href="/dashboard/style/nodecg-styles.html">');

            // They both also need to reference the dashboard window's socket, rather than make their own
            scripts.push('<script>window.socket = parent.socket;</script>');

            // Likewise, they both need the contentWindow portion of the iframeResizer
            scripts.push('<script src="/components/iframe-resizer/js/iframeResizer.contentWindow.min.js"></script>');

            // Panels need the default panel styles and the dialog_opener
            if (resourceType === 'panel') {
                styles.push('<link rel="stylesheet" href="/dashboard/style/panel.css">');
                scripts.push('<script src="/dashboard/dialog_opener.js"></script>');
            }

            // Dialogs need the default dialog styles and the dialog_helper
            else if (resourceType === 'dialog') {
                styles.push('<link rel="stylesheet" href="/dashboard/style/dialog.css">');
                scripts.push('<script src="/dashboard/dialog_helper.js"></script>');
            }
        }

        else if (resourceType === 'graphic') {
            // Graphics need to create their own socket
            scripts.push('<script src="/socket.io/socket.io.js"></script>');

            // If login security is enabled, graphics must provide a valid token when they connect to the socket
            // They also need cookies-js and a helper to manage URL query strings
            var socketScript;
            if (config.login.enabled) {
                scripts.push('<script src="/components/cookies-js/dist/cookies.min.js"></script>');
                scripts.push('<script src="/login/QueryString.js"></script>');
                socketScript =
                    '<script>\n' +
                    'window.token = qs["key"] || Cookies.get("socketToken");\n' +
                    'window.socket = io.connect("//%s/",{query: "token=" + window.token});\n' +
                    '</script>';
            } else {
                socketScript = '<script>window.socket = io.connect("//%s/");</script>';
            }
            scripts.push(util.format(socketScript, filteredConfig.baseURL));

            // Graphics must include the API script themselves before attempting to make an instance of it
            scripts.push('<script src="/nodecg-api.js"></script>');
        }

        else {
            throw new Error('Invalid resourceType "' + resourceType + '"');
        }

        // Inject a small script to create a NodeCG API instance, if requested.
        if (opts.createApiInstance) {
            var partialBundle = {
                name: opts.createApiInstance.name,
                config: opts.createApiInstance.config
            };

            scripts.push(
                util.format('<script>window.nodecg = new NodeCG(%s, window.socket);</script>',
                    JSON.stringify(partialBundle))
            );
        }

        // Inject the scripts required for singleInstance behavior, if requested.
        if (opts.singleInstance) {
            scripts.push('<script src="/instance/client_heart.js"></script>');
        }

        scripts = scripts.join('\n');

        // Put our scripts before their first script or HTML import.
        // If they have no scripts or imports, put our scripts at the end of <body>.
        var theirScriptsAndImports = $('script, link[rel="import"]');
        if (theirScriptsAndImports.length > 0) {
            // DO NOT CHANGE THIS WITHOUT THROUGHLY TESTING SINGLE INSTANCE GRAPHICS FIRST
            $('head').prepend(scripts);
        } else {
            $('body').append(scripts);
        }

        // Inject the needed stylesheets, if any.
        // If there are <script> tags in the head, inject before them.
        // Otherwise, add at the end of the <head>.
        if (styles.length > 0) {
            styles = styles.join('\n');

            var headScripts = $('head').find('script');
            if (headScripts.length > 0) {
                headScripts.first().before(styles);
            } else {
                $('head').append(styles);
            }
        }

        cb($.html());
    }
};

exports.versionCompare = function (v1, v2, options) {
    var lexicographical = options && options.lexicographical;
    var zeroExtend = options && options.zeroExtend;
    var v1parts = v1.split('.');
    var v2parts = v2.split('.');

    function isValidPart(x) { return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x); }
    if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) { return NaN; }
    if (zeroExtend) {
        while (v1parts.length < v2parts.length) v1parts.push('0');
        while (v2parts.length < v1parts.length) v2parts.push('0');
    }
    if (!lexicographical) {
        v1parts = v1parts.map(Number);
        v2parts = v2parts.map(Number);
    }
    for (var i = 0; i < v1parts.length; ++i) {
        if (v2parts.length === i) { return 1; }
        if (v1parts[i] === v2parts[i]) { continue; }
        else if (v1parts[i] > v2parts[i]) { return 1; }
        else { return -1; }
    }
    if (v1parts.length !== v2parts.length) { return -1; }
    return 0;
};

module.exports = exports;
<|endoftext|>


<commit_before>(function(scope) {
    'use strict';

    var Scope = scope.window ? window : global;

    if (typeof module === 'object' && module.exports)
        module.exports = new UtilProto();
    else if (!Scope.Util)
        Scope.Util = new UtilProto();

    function UtilProto() {
        var Util = this;

        /*
         * apply arguemnts to constructor
         *
         * @param constructor
         * @param args
         */
        this.applyConstructor   = function(constructor, args) {
            var F = function () {
                return constructor.apply(this, args);
            };

            F.prototype = constructor.prototype;
            return new F();
        };

        /**
         * Функция ищет в имени файла расширение
         * и если находит возвращает true
         * @param name - получает имя файла
         * @param ext - расширение
         */
        this.checkExt           = function(name, ext) {
            var isMatch, str,
                type        = Util.type(ext),
                regStr      = '\\.({{ exts }})$',
                regExp;

            switch(type) {
            case 'string':
                regStr      = Util.render(regStr, {
                    exts: ext
                });

                regExp      = new RegExp(regStr, 'i');
                isMatch     = regExp.test(name);

                break;

            case 'array':
                str         = ext.join('|');
                isMatch     = Util.checkExt(name, str);

                break;
            }

            return isMatch;
        };

        this.check              = new checkProto();

        function checkProto() {
            /**
             * Check is all arguments with names present
             *
             * @param name
             * @param arg
             * @param type
             */
            var check = function check(args, names) {
                var msg         = '',
                    name        = '',
                    template    = '{{ name }} coud not be empty!',

                    indexOf     = Array.prototype.indexOf,

                    lenNames    = names.length,
                    lenArgs     = args.length,
                    lessArgs    = lenArgs < lenNames,
                    emptyIndex  = indexOf.call(args),
                    isEmpty     = ~emptyIndex;

                if (lessArgs || isEmpty) {
                    if (lessArgs)
                        name        = names[lenNames - 1];
                    else
                        name        = names[emptyIndex];

                    msg         = Util.render(template, {
                        name: name
                    });

                    throw(Error(msg));
                }

                return check;
            };

            check.check = check;

            /**
             * Check is type of arg with name is equal to type
             *
             * @param name
             * @param arg
             * @param type
             */
            check.type  = function(name, arg, type) {
                var is = Util.type(arg) === type;

                if (!is)
                    throw(Error(name + ' should be ' + type));

                return check;
            };

            return check;
        }

        /**
         * Copy properties from from to to
         *
         * @param from
         * @param to
         */
        this.copyObj                = function(to, from) {
            if (!from) {
                from    = to;
                to      = {};
            }

            if (to)
                Object.keys(from).forEach(function(name) {
                    to[name]    = from[name];
                });

            return to;
        };

        /**
         * copy objFrom properties to target
         *
         * @target
         * @objFrom
         */
        this.extend                 = function(target, objFrom) {
            var obj,
                keys,
                proto,
                isFunc  = Util.type.function(objFrom),
                isArray = Util.type.array(objFrom),
                isObj   = Util.type.object(target),
                ret     = isObj ? target : {};

            if (isArray)
                objFrom.forEach(function(item) {
                   ret = Util.extend(target, item);
                });

            else if (objFrom) {
                obj     = isFunc ? new objFrom() : objFrom;
                keys    = Object.keys(obj);

                if (!keys.length) {
                    proto = Object.getPrototypeOf(objFrom);
                    keys  = Object.keys(proto);
                }

                keys.forEach(function(name) {
                    ret[name] = obj[name];
                });
            }

            return ret;
        };

        /**
         * extend proto
         *
         * @obj
         */
        this.extendProto           = function(obj) {
            var ret, F      = function() {};
            F.prototype     = Util.extend({}, obj);
            ret             = new F();

            return ret;
        };

        this.json               = new JsonProto();

        function JsonProto() {
            /**
             * @param str
             */
            this.parse      = function(str) {
                var obj;

                Util.exec.try(function() {
                    obj = JSON.parse(str);
                });

                return obj;
            },

            /**
             * @param obj
             */
            this.stringify  = function(obj) {
                var str;

                Util.exec.try(function() {
                    str = JSON.stringify(obj, null, 4);
                });

                return str;
            };
        }

        this.escapeRegExp = function(str) {
            var isStr   = Util.type.string(str);

            if (isStr)
                str = str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');

            return str;
        };

        /**
         * get regexp from wild card
         */
        this.getRegExp              = function(wildcard) {
            var regExp;

            if (!wildcard)
                wildcard = '*';

            wildcard    = '^' + wildcard /* search from start of line */
                .replace('.', '\\.')
                .replace('*', '.*')
                .replace('?', '.?\\');

            wildcard    += '$'; /* search to end of line */

            regExp      = new RegExp(wildcard);

            return regExp;
        };

        /**
         * function render template with view and own symbols
         *
         * @param templ
         * @param view
         */
        this.render = function(templ, view) {
            var str, regExp,
                result  = templ;

            Object
                .keys(view)
                .forEach(function(param) {
                    str     = view[param];
                    regExp  = RegExp('{{\\s' + param + '\\s}}', 'g');
                    result  = result.replace(regExp, str);
                });

            if (~result.indexOf('{{'))
                result = result.replace(/{{.*}}/g, '');

            return result;
        };

        this.type                   = new TypeProto();

        function TypeProto() {
            /**
             * get type of variable
             *
             * @param variable
             */
            function type(variable) {
                var regExp      = /\s([a-zA-Z]+)/,
                    str         = {}.toString.call(variable),
                    typeBig     = str.match(regExp)[1],
                    result      = typeBig.toLowerCase();

                return result;
            }

            /**
             * functions check is variable is type of name
             *
             * @param variable
             */
            function typeOf(name, variable) {
                return type(variable) === name;
            }

            function typeOfSimple(name, variable) {
                return typeof variable === name;
            }

            ['null', 'arrayBuffer', 'file', 'array', 'object']
                .forEach(function(name) {
                    type[name] = typeOf.bind(null, name);
                });

            ['string', 'undefined', 'boolean', 'number', 'function']
                .forEach(function(name) {
                    type[name] = typeOfSimple.bind(null, name);
                });

            return type;
        }

        this.exec                       = new ExecProto();

        function ExecProto() {
            /**
             * function do save exec of function
             * @param callback
             * @param arg1
             * ...
             * @param argN
             */
            var exec        = function(callback) {
                var ret,
                    isFunc  = Util.type.function(callback),
                    args    = [].slice.call(arguments, 1);

                if (isFunc)
                    ret     = callback.apply(null, args);

                return ret;
            };

            /*
             * return function that calls callback with arguments
             */

            exec.with           =  function(callback) {
                var result,
                    bind        = Function.bind;

                arguments[0]    = null;
                result          = bind.apply(callback, arguments);

                return result;
            };

             /**
             * return save exec function
             * @param callback
             */
            exec.ret        = function() {
                var result,
                    args        = [].slice.call(arguments);

                args.unshift(exec);
                result          = exec.with.apply(null, args);

                return result;
            };

            /**
             * function do conditional save exec of function
             * @param condition
             * @param callback
             * @param func
             */
            exec.if         = function(condition, callback, func) {
                var ret;

                if (condition)
                    exec(callback);
                else
                    exec(func, callback);

                return ret;
            };

            /**
             * exec function if it exist in object
             *
             * @param obj
             * @param name
             * @param arg
             */
            exec.ifExist                = function(obj, name, arg) {
                var ret,
                    func    = obj && obj[name];

                if (func)
                    func    = func.apply(obj, arg);

                return ret;
            };

            exec.parallel   = function(funcs, callback) {
                var keys        = [],
                    callbackWas = false,
                    arr         = [],
                    obj         = {},
                    count       = 0,
                    countFuncs  = 0,
                    type        = Util.type(funcs);

                Util.check(arguments, ['funcs', 'callback']);

                switch(type) {
                case 'array':
                    countFuncs  = funcs.length;

                    funcs.forEach(function(func, num) {
                        exec(func, function() {
                            checkFunc(num, arguments, arr);
                        });
                    });
                    break;

                case 'object':
                    keys        = Object.keys(funcs);
                    countFuncs  = keys.length;

                    keys.forEach(function(name) {
                        var func    = funcs[name];

                        exec(func, function() {
                            checkFunc(name, arguments, obj);
                        });
                    });
                    break;
                }

                function checkFunc(num, data, all) {
                    var args    = [].slice.call(data, 1),
                        isLast  = false,
                        error   = data[0],
                        length  = args.length;

                    ++count;

                    isLast = count === countFuncs;

                    if (!error)
                        if (length >= 2)
                            all[num] = args;
                        else
                            all[num] = args[0];

                    if (!callbackWas && (error || isLast)) {
                        callbackWas = true;

                        if (type === 'array')
                            callback.apply(null, [error].concat(all));
                        else
                            callback(error, all);
                    }
                }
            };

            /**
             * load functions thrue callbacks one-by-one
             * @param funcs {Array} - array of functions
             */
            exec.series             = function(funcs) {
                var func, callback,
                    isArray     = Util.type.array(funcs);

                if (isArray) {
                    func        = funcs.shift();

                    callback    = function() {
                        return exec.series(funcs);
                    };

                    exec(func, callback);
                }
            };

           /**
             * function execute param function in
             * try...catch block
             *
             * @param callback
             */
            exec.try                = function(callback) {
                var ret;
                try {
                    ret = callback();
                } catch(error) {
                    ret = error;
                }

                return ret;
            };

            return exec;
        }

        /**
         * function gets file extension
         * @param pFileName
         * @return Ext
         */
        this.getExt                     = function(name) {
            var ret     = '',
                dot,
                isStr   = Util.type.string(name);

            if (isStr) {
                dot = name.lastIndexOf('.');

                if (~dot)
                    ret = name.substr(dot);
            }

            return ret;
        };

       /**
         * get values from Object Array name properties
         * or
         * @pObj
         */
        this.getNamesFromObjArray       = function(arr) {
            var ret     = [],
                isArray = Util.type.array(arr);

            if (arr && !isArray)
                arr = arr.data;

            if (arr)
                arr.forEach(function(item) {
                    ret.push(item.name || item);
                });

            return ret;
        };

        /**
         * find object by name in arrray
         *
         * @param array
         * @param name
         */
        this.findObjByNameInArr         = function(array, name) {
            var ret,
                isArray = Util.type.array(array);

            if (isArray) {
                array.some(function(item) {
                    var is = item.name === name,
                        isArray = Util.type.array(item);

                    if (is)
                        ret = item;
                    else if (isArray)
                        item.some(function(item) {
                            is = item.name === name;

                            if (is)
                                ret = item.data;

                            return is;
                        });

                    return is;
                });
            }

            return ret;
        };

        /**
         * Gets current time in format hh:mm:ss
         */
        this.getTime                    = function() {
            var ret,
                date        = new Date(),
                hours       = date.getHours(),
                minutes     = date.getMinutes(),
                seconds     = date.getSeconds();

            minutes         = minutes < 10 ? '0' + minutes : minutes;
            seconds         = seconds < 10 ? '0' + seconds : seconds;

            ret            = hours + ':' + minutes + ':' + seconds;

            return ret;
        };

        /**
         * start timer
         * @param name
         */
        this.time                       = function(name) {
            var console     = Scope.console;

            Util.exec.ifExist(console, 'time', [name]);

            return this;
        };

        /**
         * stop timer
         * @param name
         */
        this.timeEnd                   = function(name) {
            var console    = Scope.console;

            Util.exec.ifExist(console, 'timeEnd', [name]);

            return this;
        };
    }

})(this);
<commit_msg>fix(util) getRegExp<commit_after>(function(scope) {
    'use strict';

    var Scope = scope.window ? window : global;

    if (typeof module === 'object' && module.exports)
        module.exports = new UtilProto();
    else if (!Scope.Util)
        Scope.Util = new UtilProto();

    function UtilProto() {
        var Util = this;

        /*
         * apply arguemnts to constructor
         *
         * @param constructor
         * @param args
         */
        this.applyConstructor   = function(constructor, args) {
            var F = function () {
                return constructor.apply(this, args);
            };

            F.prototype = constructor.prototype;
            return new F();
        };

        /**
         * Функция ищет в имени файла расширение
         * и если находит возвращает true
         * @param name - получает имя файла
         * @param ext - расширение
         */
        this.checkExt           = function(name, ext) {
            var isMatch, str,
                type        = Util.type(ext),
                regStr      = '\\.({{ exts }})$',
                regExp;

            switch(type) {
            case 'string':
                regStr      = Util.render(regStr, {
                    exts: ext
                });

                regExp      = new RegExp(regStr, 'i');
                isMatch     = regExp.test(name);

                break;

            case 'array':
                str         = ext.join('|');
                isMatch     = Util.checkExt(name, str);

                break;
            }

            return isMatch;
        };

        this.check              = new checkProto();

        function checkProto() {
            /**
             * Check is all arguments with names present
             *
             * @param name
             * @param arg
             * @param type
             */
            var check = function check(args, names) {
                var msg         = '',
                    name        = '',
                    template    = '{{ name }} coud not be empty!',

                    indexOf     = Array.prototype.indexOf,

                    lenNames    = names.length,
                    lenArgs     = args.length,
                    lessArgs    = lenArgs < lenNames,
                    emptyIndex  = indexOf.call(args),
                    isEmpty     = ~emptyIndex;

                if (lessArgs || isEmpty) {
                    if (lessArgs)
                        name        = names[lenNames - 1];
                    else
                        name        = names[emptyIndex];

                    msg         = Util.render(template, {
                        name: name
                    });

                    throw(Error(msg));
                }

                return check;
            };

            check.check = check;

            /**
             * Check is type of arg with name is equal to type
             *
             * @param name
             * @param arg
             * @param type
             */
            check.type  = function(name, arg, type) {
                var is = Util.type(arg) === type;

                if (!is)
                    throw(Error(name + ' should be ' + type));

                return check;
            };

            return check;
        }

        /**
         * Copy properties from from to to
         *
         * @param from
         * @param to
         */
        this.copyObj                = function(to, from) {
            if (!from) {
                from    = to;
                to      = {};
            }

            if (to)
                Object.keys(from).forEach(function(name) {
                    to[name]    = from[name];
                });

            return to;
        };

        /**
         * copy objFrom properties to target
         *
         * @target
         * @objFrom
         */
        this.extend                 = function(target, objFrom) {
            var obj,
                keys,
                proto,
                isFunc  = Util.type.function(objFrom),
                isArray = Util.type.array(objFrom),
                isObj   = Util.type.object(target),
                ret     = isObj ? target : {};

            if (isArray)
                objFrom.forEach(function(item) {
                   ret = Util.extend(target, item);
                });

            else if (objFrom) {
                obj     = isFunc ? new objFrom() : objFrom;
                keys    = Object.keys(obj);

                if (!keys.length) {
                    proto = Object.getPrototypeOf(objFrom);
                    keys  = Object.keys(proto);
                }

                keys.forEach(function(name) {
                    ret[name] = obj[name];
                });
            }

            return ret;
        };

        /**
         * extend proto
         *
         * @obj
         */
        this.extendProto           = function(obj) {
            var ret, F      = function() {};
            F.prototype     = Util.extend({}, obj);
            ret             = new F();

            return ret;
        };

        this.json               = new JsonProto();

        function JsonProto() {
            /**
             * @param str
             */
            this.parse      = function(str) {
                var obj;

                Util.exec.try(function() {
                    obj = JSON.parse(str);
                });

                return obj;
            },

            /**
             * @param obj
             */
            this.stringify  = function(obj) {
                var str;

                Util.exec.try(function() {
                    str = JSON.stringify(obj, null, 4);
                });

                return str;
            };
        }

        this.escapeRegExp = function(str) {
            var isStr   = Util.type.string(str);

            if (isStr)
                str = str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');

            return str;
        };

        /**
         * get regexp from wild card
         */
        this.getRegExp              = function(wildcard) {
            var regExp;

            if (!wildcard)
                wildcard = '*';

            wildcard    = '^' + wildcard /* search from start of line */
                .replace('.', '\\.')
                .replace('*', '.*')
                .replace('?', '.?');

            wildcard    += '$'; /* search to end of line */

            regExp      = new RegExp(wildcard);

            return regExp;
        };

        /**
         * function render template with view and own symbols
         *
         * @param templ
         * @param view
         */
        this.render = function(templ, view) {
            var str, regExp,
                result  = templ;

            Object
                .keys(view)
                .forEach(function(param) {
                    str     = view[param];
                    regExp  = RegExp('{{\\s' + param + '\\s}}', 'g');
                    result  = result.replace(regExp, str);
                });

            if (~result.indexOf('{{'))
                result = result.replace(/{{.*}}/g, '');

            return result;
        };

        this.type                   = new TypeProto();

        function TypeProto() {
            /**
             * get type of variable
             *
             * @param variable
             */
            function type(variable) {
                var regExp      = /\s([a-zA-Z]+)/,
                    str         = {}.toString.call(variable),
                    typeBig     = str.match(regExp)[1],
                    result      = typeBig.toLowerCase();

                return result;
            }

            /**
             * functions check is variable is type of name
             *
             * @param variable
             */
            function typeOf(name, variable) {
                return type(variable) === name;
            }

            function typeOfSimple(name, variable) {
                return typeof variable === name;
            }

            ['null', 'arrayBuffer', 'file', 'array', 'object']
                .forEach(function(name) {
                    type[name] = typeOf.bind(null, name);
                });

            ['string', 'undefined', 'boolean', 'number', 'function']
                .forEach(function(name) {
                    type[name] = typeOfSimple.bind(null, name);
                });

            return type;
        }

        this.exec                       = new ExecProto();

        function ExecProto() {
            /**
             * function do save exec of function
             * @param callback
             * @param arg1
             * ...
             * @param argN
             */
            var exec        = function(callback) {
                var ret,
                    isFunc  = Util.type.function(callback),
                    args    = [].slice.call(arguments, 1);

                if (isFunc)
                    ret     = callback.apply(null, args);

                return ret;
            };

            /*
             * return function that calls callback with arguments
             */

            exec.with           =  function(callback) {
                var result,
                    bind        = Function.bind;

                arguments[0]    = null;
                result          = bind.apply(callback, arguments);

                return result;
            };

             /**
             * return save exec function
             * @param callback
             */
            exec.ret        = function() {
                var result,
                    args        = [].slice.call(arguments);

                args.unshift(exec);
                result          = exec.with.apply(null, args);

                return result;
            };

            /**
             * function do conditional save exec of function
             * @param condition
             * @param callback
             * @param func
             */
            exec.if         = function(condition, callback, func) {
                var ret;

                if (condition)
                    exec(callback);
                else
                    exec(func, callback);

                return ret;
            };

            /**
             * exec function if it exist in object
             *
             * @param obj
             * @param name
             * @param arg
             */
            exec.ifExist                = function(obj, name, arg) {
                var ret,
                    func    = obj && obj[name];

                if (func)
                    func    = func.apply(obj, arg);

                return ret;
            };

            exec.parallel   = function(funcs, callback) {
                var keys        = [],
                    callbackWas = false,
                    arr         = [],
                    obj         = {},
                    count       = 0,
                    countFuncs  = 0,
                    type        = Util.type(funcs);

                Util.check(arguments, ['funcs', 'callback']);

                switch(type) {
                case 'array':
                    countFuncs  = funcs.length;

                    funcs.forEach(function(func, num) {
                        exec(func, function() {
                            checkFunc(num, arguments, arr);
                        });
                    });
                    break;

                case 'object':
                    keys        = Object.keys(funcs);
                    countFuncs  = keys.length;

                    keys.forEach(function(name) {
                        var func    = funcs[name];

                        exec(func, function() {
                            checkFunc(name, arguments, obj);
                        });
                    });
                    break;
                }

                function checkFunc(num, data, all) {
                    var args    = [].slice.call(data, 1),
                        isLast  = false,
                        error   = data[0],
                        length  = args.length;

                    ++count;

                    isLast = count === countFuncs;

                    if (!error)
                        if (length >= 2)
                            all[num] = args;
                        else
                            all[num] = args[0];

                    if (!callbackWas && (error || isLast)) {
                        callbackWas = true;

                        if (type === 'array')
                            callback.apply(null, [error].concat(all));
                        else
                            callback(error, all);
                    }
                }
            };

            /**
             * load functions thrue callbacks one-by-one
             * @param funcs {Array} - array of functions
             */
            exec.series             = function(funcs) {
                var func, callback,
                    isArray     = Util.type.array(funcs);

                if (isArray) {
                    func        = funcs.shift();

                    callback    = function() {
                        return exec.series(funcs);
                    };

                    exec(func, callback);
                }
            };

           /**
             * function execute param function in
             * try...catch block
             *
             * @param callback
             */
            exec.try                = function(callback) {
                var ret;
                try {
                    ret = callback();
                } catch(error) {
                    ret = error;
                }

                return ret;
            };

            return exec;
        }

        /**
         * function gets file extension
         * @param pFileName
         * @return Ext
         */
        this.getExt                     = function(name) {
            var ret     = '',
                dot,
                isStr   = Util.type.string(name);

            if (isStr) {
                dot = name.lastIndexOf('.');

                if (~dot)
                    ret = name.substr(dot);
            }

            return ret;
        };

       /**
         * get values from Object Array name properties
         * or
         * @pObj
         */
        this.getNamesFromObjArray       = function(arr) {
            var ret     = [],
                isArray = Util.type.array(arr);

            if (arr && !isArray)
                arr = arr.data;

            if (arr)
                arr.forEach(function(item) {
                    ret.push(item.name || item);
                });

            return ret;
        };

        /**
         * find object by name in arrray
         *
         * @param array
         * @param name
         */
        this.findObjByNameInArr         = function(array, name) {
            var ret,
                isArray = Util.type.array(array);

            if (isArray) {
                array.some(function(item) {
                    var is = item.name === name,
                        isArray = Util.type.array(item);

                    if (is)
                        ret = item;
                    else if (isArray)
                        item.some(function(item) {
                            is = item.name === name;

                            if (is)
                                ret = item.data;

                            return is;
                        });

                    return is;
                });
            }

            return ret;
        };

        /**
         * Gets current time in format hh:mm:ss
         */
        this.getTime                    = function() {
            var ret,
                date        = new Date(),
                hours       = date.getHours(),
                minutes     = date.getMinutes(),
                seconds     = date.getSeconds();

            minutes         = minutes < 10 ? '0' + minutes : minutes;
            seconds         = seconds < 10 ? '0' + seconds : seconds;

            ret            = hours + ':' + minutes + ':' + seconds;

            return ret;
        };

        /**
         * start timer
         * @param name
         */
        this.time                       = function(name) {
            var console     = Scope.console;

            Util.exec.ifExist(console, 'time', [name]);

            return this;
        };

        /**
         * stop timer
         * @param name
         */
        this.timeEnd                   = function(name) {
            var console    = Scope.console;

            Util.exec.ifExist(console, 'timeEnd', [name]);

            return this;
        };
    }

})(this);
<|endoftext|>


<commit_before>'use strict';
var fs = require('fs');
var path = require('path');
var os = require('os');
var mkdir = require('mkdirp');
var chalk = require('chalk');
var exec = require('child_process').exec;
var which = require('which');
var tar = require('tar');
var zlib = require('zlib');
var request = require('request').defaults({
	proxy: process.env.http_proxy || process.env.HTTP_PROXY ||
			process.env.https_proxy || process.env.HTTPS_PROXY || ''
});
var progress = require('request-progress');
var tmpdir = os.tmpdir ? os.tmpdir() : os.tmpDir();
var util = module.exports;

util.fetch = function (url, dest, cb) {
	cb = cb || function () {};

	if (!fs.existsSync(path.dirname(dest))) {
		mkdir.sync(path.dirname(dest));
	}

	return progress(request.get(url))
		.on('response', function (resp) {
			var status = resp.statusCode;

			if (status < 200 || status > 300) {
				return cb(new Error('Status code ' + status));
			}
		})
		.on('progress', function (state) {
			console.log(chalk.cyan('Downloading %s: %s%'), path.basename(url), state.percent);
		})
		.on('error', cb)
		.pipe(fs.createWriteStream(dest))
		.on('close', cb);
};

util.extract = function (src, dest, cb) {
	cb = cb || function () {};
	var file = path.basename(src);

	if (path.extname(file) !== '.gz') {
		return cb(new Error('File ' + file + ' is not a known archive'));
	}

	return fs.createReadStream(src)
		.on('error', cb)
		.pipe(zlib.Unzip())
		.on('error', cb)
		.pipe(tar.Extract({ path: dest, strip: 1 }))
		.on('error', cb)
		.on('close', function () {
			fs.unlink(src);
			cb();
		});
};

util.build = function (url, dest, cb) {
	if (!(process.platform === 'darwin' || process.platform === 'linux')) {
		return cb(new Error('Building is not supported on ' + process.platform));
	}

	cb = cb || function () {};
	var self = this;
	var file = path.join(tmpdir, path.basename(url));
	var tmp = path.join(tmpdir, path.basename(file, '.tar.gz'));
	var buildScript = 'make install BINPREFIX='+ dest;

	if (process.platform === 'darwin') {
		buildScript += ' USE_COCOA=1';
	}

	try {
		which.sync('make');
	} catch (err) {
		return cb(new Error('`make` not found'));
	}

	return this.fetch(url, file, function (err) {
		if (err) {
			return cb(new Error(err.message));
		}

		self.extract(file, tmp, function (err) {
			if (err) {
				return cb(new Error(err.message));
			}

			exec(buildScript, { cwd: tmp }, function (err) {
				if (err) {
					return cb(new Error(err.message));
				}

				cb();
			});
		});
	});
};
<commit_msg>Disable USE_COCOA for now<commit_after>'use strict';
var fs = require('fs');
var path = require('path');
var os = require('os');
var mkdir = require('mkdirp');
var chalk = require('chalk');
var exec = require('child_process').exec;
var which = require('which');
var tar = require('tar');
var zlib = require('zlib');
var request = require('request').defaults({
	proxy: process.env.http_proxy || process.env.HTTP_PROXY ||
			process.env.https_proxy || process.env.HTTPS_PROXY || ''
});
var progress = require('request-progress');
var tmpdir = os.tmpdir ? os.tmpdir() : os.tmpDir();
var util = module.exports;

util.fetch = function (url, dest, cb) {
	cb = cb || function () {};

	if (!fs.existsSync(path.dirname(dest))) {
		mkdir.sync(path.dirname(dest));
	}

	return progress(request.get(url))
		.on('response', function (resp) {
			var status = resp.statusCode;

			if (status < 200 || status > 300) {
				return cb(new Error('Status code ' + status));
			}
		})
		.on('progress', function (state) {
			console.log(chalk.cyan('Downloading %s: %s%'), path.basename(url), state.percent);
		})
		.on('error', cb)
		.pipe(fs.createWriteStream(dest))
		.on('close', cb);
};

util.extract = function (src, dest, cb) {
	cb = cb || function () {};
	var file = path.basename(src);

	if (path.extname(file) !== '.gz') {
		return cb(new Error('File ' + file + ' is not a known archive'));
	}

	return fs.createReadStream(src)
		.on('error', cb)
		.pipe(zlib.Unzip())
		.on('error', cb)
		.pipe(tar.Extract({ path: dest, strip: 1 }))
		.on('error', cb)
		.on('close', function () {
			fs.unlink(src);
			cb();
		});
};

util.build = function (url, dest, cb) {
	if (!(process.platform === 'darwin' || process.platform === 'linux')) {
		return cb(new Error('Building is not supported on ' + process.platform));
	}

	cb = cb || function () {};
	var self = this;
	var file = path.join(tmpdir, path.basename(url));
	var tmp = path.join(tmpdir, path.basename(file, '.tar.gz'));
	var buildScript = 'make install BINPREFIX='+ dest;

	// disable it for now:
	// https://github.com/pornel/pngquant/issues/48
	// if (process.platform === 'darwin') {
	// 	buildScript += ' USE_COCOA=1';
	// }

	try {
		which.sync('make');
	} catch (err) {
		return cb(new Error('`make` not found'));
	}

	return this.fetch(url, file, function (err) {
		if (err) {
			return cb(new Error(err.message));
		}

		self.extract(file, tmp, function (err) {
			if (err) {
				return cb(new Error(err.message));
			}

			exec(buildScript, { cwd: tmp }, function (err) {
				if (err) {
					return cb(new Error(err.message));
				}

				cb();
			});
		});
	});
};
<|endoftext|>


<commit_before>/**
 * Created by nuintun on 2015/4/27.
 */

'use strict';

var is = require('is');
var path = require('path');
var join = path.join;
var extname = path.extname;
var dirname = path.dirname;
var basename = path.basename;
var isAbsolute = path.isAbsolute;
var util = require('util');
var gutil = require('gulp-util');
var debug = require('debug')('transport:util');
var colors = require('colors/safe');

var cwd = process.cwd();

// set colors theme
colors.setTheme({
  input: 'grey',
  verbose: 'cyan',
  prompt: 'grey',
  info: 'green',
  data: 'grey',
  help: 'cyan',
  warn: 'yellow',
  debug: 'blue',
  error: 'red',
  inputBold: ['grey', 'bold'],
  verboseBold: ['cyan', 'bold'],
  promptBold: ['grey', 'bold'],
  infoBold: ['green', 'bold'],
  dataBold: ['grey', 'bold'],
  helpBold: ['cyan', 'bold'],
  warnBold: ['yellow', 'bold'],
  debugBold: ['blue', 'bold'],
  errorBold: ['red', 'bold']
});

/**
 * parse package form file
 * @param file
 * @returns {object}
 */
function parsePackage(file){
  var filedir = slashPath(dirname(file.relative));
  var filename = basename(file.relative);
  var SPLITRE = /\/((?:\d+\.){2}\d+)(?:\/|$)/;
  var match = filedir.split(SPLITRE);

  return {
    name: match[0] || '',
    version: match[1] || '',
    file: match[2] ? match[2] + '/' + filename : filename
  }
}

/**
 * simple template
 * ```
 * var tpl = '{{name}}/{{version}}';
 * util.template(tpl, {name:'base', version: '1.0.0'});
 * ```
 */

function template(format, data){
  if (!format) return '';

  return format.replace(/{{([a-z]*)}}/g, function (all, match){
    return data[match] || '';
  });
}

/**
 * set options
 * @param options
 * @returns {object}
 */

function extendOption(options){
  var defaults = {
    alias: {}, // The alias info
    paths: {}, // The paths info
    vars: {}, // The vars info
    ignore: [], // Omit the given dependencies when transport
    wwwroot: null,
    idleading: '{{name}}/{{version}}/{{file}}', // The id prefix template that can use pkg as it's data
    rename: null,
    include: 'relative'
  };

  if (!options) return defaults;

  for (var key in options) {
    if (options.hasOwnProperty(key)) {
      var value = options[key];

      if (value !== undefined && value !== null) {
        defaults[key] = value;
      }
    }
  }

  if (!is.string(defaults.wwwroot)) {
    throwError('options.wwwroot\'s value should be string.');
  }

  defaults.wwwroot = join(cwd, defaults.wwwroot);

  return defaults;
}

/**
 * get normalize id form id
 * for example a/b/c# should be a/b/c.
 * a/b/c?v=.0.0.1 should be a/b/c.
 * @param id
 * @returns {*}
 */
function normalize(id){
  var index;
  var last = id.length - 1;
  var charCode = id.charCodeAt(last);

  // if it ends with # or /, we should return the uri without #
  if (charCode === 35 /* "#" */ || charCode === 47 /* "/" */) return id.substring(0, last);

  // if it has with ?, we should return the uri without search params
  if ((index = id.indexOf('?')) !== -1) return id.substring(0, index);

  // ext logical
  return id;
}

var PATHS_RE = /^([^/:]+)(\/.+)$/;
var VARS_RE = /{([^{]+)}/g;

/**
 * parse alias
 * @param id
 * @param alias
 * @returns {*}
 */

function parseAlias(id, alias){
  alias = alias || {};

  return alias && is.string(alias[id]) ? alias[id] : id;
}

/**
 * parse paths
 * @param id
 * @param paths
 * @returns {*}
 */

function parsePaths(id, paths){
  var m;

  paths = paths || {};

  if (paths && (m = id.match(PATHS_RE)) && is.string(paths[m[1]])) {
    id = paths[m[1]] + m[2];
  }

  return id;
}

/**
 * parse vars
 * @param id
 * @param vars
 * @returns {*}
 */

function parseVars(id, vars){
  vars = vars || {};

  if (vars && id.indexOf('{') > -1) {
    id = id.replace(VARS_RE, function (m, key){
      return is.string(vars[key]) ? vars[key] : m;
    });
  }

  return id;
}

/**
 * hide .js if exists
 * @param filepath
 * @returns {*}
 */

function hideExt(filepath){
  return extname(filepath) === '.js' ? filepath.replace(/\.js$/, '') : filepath;
}

/**
 * add .js if not exists
 * @param filepath
 * @returns {*}
 */

function addExt(filepath){
  return extname(filepath) === '.js' ? filepath : (filepath + '.js');
}

/**
 * test filepath is relative path or not
 * @param filepath
 * @returns {boolean}
 */

function isRelative(filepath){
  return /^\.{1,2}[\\/]/.test(filepath);
}

/**
 * test filepath is local path or not
 * @param filepath
 * @returns {boolean}
 */

function isLocal(filepath){
  return !/^https?:\/\/|^\/\//.test(filepath) && !/^data:/.test(filepath);
}

/**
 * resolve a `relative` path base on `base` path
 * @param relative
 * @param base
 * @returns {*}
 */

function resolve(relative, base){
  if (!isRelative(relative) || !base) return relative;

  debug('transport resolve path ( %s ) of basepath ( %s )', colors.dataBold(relative), colors.dataBold(base));

  relative = slashPath(join(dirname(base), relative));

  debug('transport resolve result ( %s )', colors.dataBold(relative));

  if (isRelative(relative)) {
    throwError('%s is out of bound of %s.', relative, base);
  }

  return relative;
}

/**
 * Normalize path \ to /
 * @param path
 * @returns {string}
 */

function slashPath(path){
  path = path.replace(/\\+/g, '/');
  path = path.replace(/([^:/])\/+\//g, '$1/');
  path = path.replace(/^\/{2,}|(:)\/{2,}/, '//');

  return path;
}

/**
 * Plugin error
 */

function throwError(){
  var message = util.format.apply(null, [].slice.call(arguments));

  throw new gutil.PluginError('gulp-cmd', message);
}

/**
 * Get rename options
 * @param opts
 * @returns {*}
 */

function getRenameOpts(opts){
  if (typeof opts === 'function') {
    return opts;
  }

  var ret = {};

  opts = opts || {};

  if (opts.min) {
    ret.suffix = '-min';
  }

  if (opts.debug) {
    ret.suffix = '-debug';
  }

  return ret;
}

/**
 * node.extend
 * Copyright 2011, John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * @fileoverview
 * Port of jQuery.extend that actually works on node.js
 */

function extend(){
  var target = arguments[0] || {};
  var i = 1;
  var length = arguments.length;
  var deep = false;
  var options, name, src, copy, copy_is_array, clone;

  // handle a deep copy situation
  if (typeof target === 'boolean') {
    deep = target;
    target = arguments[1] || {};
    // skip the boolean and the target
    i = 2;
  }

  // handle case when target is a string or something (possible in deep copy)
  if (typeof target !== 'object' && !is.fn(target)) {
    target = {};
  }

  for (; i < length; i++) {
    // only deal with non-null/undefined values
    options = arguments[i];

    if (options !== null) {
      if (typeof options === 'string') {
        options = options.split('');
      }

      // extend the base object
      for (name in options) {
        if (options.hasOwnProperty(name)) {
          src = target[name];
          copy = options[name];

          // prevent never-ending loop
          if (target === copy) {
            continue;
          }

          // recurse if we're merging plain objects or arrays
          if (deep && copy && (is.hash(copy) || (copy_is_array = is.array(copy)))) {
            if (copy_is_array) {
              copy_is_array = false;
              clone = src && is.array(src) ? src : [];
            } else {
              clone = src && is.hash(src) ? src : {};
            }

            // never move original objects, clone them
            target[name] = extend(deep, clone, copy);

            // don't bring in undefined values
          } else if (typeof copy !== 'undefined') {
            target[name] = copy;
          }
        }
      }
    }
  }

  // return the modified object
  return target;
}

/**
 * transform array to string
 * @param arr
 * @returns {string}
 */

function arr2str(arr){
  return arr.map(function (item){
    return '"' + item + '"';
  }).join(',');
}

/**
 * Exports module.
 */

exports.template = template;
exports.parsePackage = parsePackage;
exports.extendOption = extendOption;
exports.normalize = normalize;
exports.parseAlias = parseAlias;
exports.parsePaths = parsePaths;
exports.parseVars = parseVars;
exports.hideExt = hideExt;
exports.addExt = addExt;
exports.isRelative = isRelative;
exports.isAbsolute = isAbsolute;
exports.isLocal = isLocal;
exports.resolve = resolve;
exports.slashPath = slashPath;
exports.throwError = throwError;
exports.getRenameOpts = getRenameOpts;
exports.extend = extend;
exports.colors = colors;
exports.arr2str = arr2str;<commit_msg>add source files<commit_after>/**
 * Created by nuintun on 2015/4/27.
 */

'use strict';

var is = require('is');
var path = require('path');
var join = path.join;
var extname = path.extname;
var dirname = path.dirname;
var basename = path.basename;
var isAbsolute = path.isAbsolute;
var util = require('util');
var gutil = require('gulp-util');
var debug = require('debug')('transport:util');
var colors = require('colors/safe');

var cwd = process.cwd();

// set colors theme
colors.setTheme({
  input: 'grey',
  verbose: 'cyan',
  prompt: 'grey',
  info: 'green',
  data: 'grey',
  help: 'cyan',
  warn: 'yellow',
  debug: 'blue',
  error: 'red',
  inputBold: ['grey', 'bold'],
  verboseBold: ['cyan', 'bold'],
  promptBold: ['grey', 'bold'],
  infoBold: ['green', 'bold'],
  dataBold: ['grey', 'bold'],
  helpBold: ['cyan', 'bold'],
  warnBold: ['yellow', 'bold'],
  debugBold: ['blue', 'bold'],
  errorBold: ['red', 'bold']
});

/**
 * parse package form file
 * @param file
 * @returns {object}
 */
function parsePackage(file){
  var filedir = slashPath(dirname(file.relative));
  var filename = basename(file.relative);
  var SPLITRE = /\/((?:\d+\.){2}\d+)(?:\/|$)/;
  var match = filedir.split(SPLITRE);

  return {
    name: match[0] || '',
    version: match[1] || '',
    file: match[2] ? match[2] + '/' + filename : filename
  }
}

/**
 * simple template
 * ```
 * var tpl = '{{name}}/{{version}}';
 * util.template(tpl, {name:'base', version: '1.0.0'});
 * ```
 */

function template(format, data){
  if (!format) return '';

  return format.replace(/{{([a-z]*)}}/g, function (all, match){
    return data[match] || '';
  });
}

/**
 * set options
 * @param options
 * @returns {object}
 */

function extendOption(options){
  var defaults = {
    alias: {}, // The alias info
    paths: {}, // The paths info
    vars: {}, // The vars info
    ignore: [], // Omit the given dependencies when transport
    wwwroot: null,
    idleading: '{{name}}/{{version}}/{{file}}', // The id prefix template that can use pkg as it's data
    rename: null,
    include: 'relative'
  };

  if (!options) return defaults;

  for (var key in options) {
    if (options.hasOwnProperty(key)) {
      var value = options[key];

      if (value !== undefined && value !== null) {
        defaults[key] = value;
      }
    }
  }

  if (!is.string(defaults.wwwroot)) {
    throwError('options.wwwroot\'s value should be string.');
  }

  defaults.wwwroot = join(cwd, defaults.wwwroot);

  return defaults;
}

/**
 * get normalize id form id
 * for example a/b/c# should be a/b/c.
 * a/b/c?v=.0.0.1 should be a/b/c.
 * @param id
 * @returns {*}
 */
function normalize(id){
  var index;
  var last = id.length - 1;
  var charCode = id.charCodeAt(last);

  // if it ends with # or /, we should return the uri without #
  if (charCode === 35 /* "#" */ || charCode === 47 /* "/" */) return id.substring(0, last);

  // if it has with ?, we should return the uri without search params
  if ((index = id.indexOf('?')) !== -1) return id.substring(0, index);

  // ext logical
  return id;
}

var PATHS_RE = /^([^/:]+)(\/.+)$/;
var VARS_RE = /{([^{]+)}/g;

/**
 * parse alias
 * @param id
 * @param alias
 * @returns {*}
 */

function parseAlias(id, alias){
  alias = alias || {};

  return alias && is.string(alias[id]) ? alias[id] : id;
}

/**
 * parse paths
 * @param id
 * @param paths
 * @returns {*}
 */

function parsePaths(id, paths){
  var m;

  paths = paths || {};

  if (paths && (m = id.match(PATHS_RE)) && is.string(paths[m[1]])) {
    id = paths[m[1]] + m[2];
  }

  return id;
}

/**
 * parse vars
 * @param id
 * @param vars
 * @returns {*}
 */

function parseVars(id, vars){
  vars = vars || {};

  if (vars && id.indexOf('{') > -1) {
    id = id.replace(VARS_RE, function (m, key){
      return is.string(vars[key]) ? vars[key] : m;
    });
  }

  return id;
}

/**
 * hide .js if exists
 * @param filepath
 * @returns {*}
 */

function hideExt(filepath){
  return extname(filepath) === '.js' ? filepath.replace(/\.js$/, '') : filepath;
}

/**
 * add .js if not exists
 * @param filepath
 * @returns {*}
 */

function addExt(filepath){
  return extname(filepath) === '.js' ? filepath : (filepath + '.js');
}

/**
 * test filepath is relative path or not
 * @param filepath
 * @returns {boolean}
 */

function isRelative(filepath){
  return /^\.{1,2}[\\/]/.test(filepath);
}

/**
 * test filepath is local path or not
 * @param filepath
 * @returns {boolean}
 */

function isLocal(filepath){
  return !/^https?:\/\/|^\/\//.test(filepath) && !/^data:/.test(filepath);
}

/**
 * resolve a `relative` path base on `base` path
 * @param relative
 * @param base
 * @returns {*}
 */

function resolve(relative, base){
  if (!isRelative(relative) || !base) return relative;

  debug('transport resolve path ( %s ) of basepath ( %s )', colors.dataBold(relative), colors.dataBold(base));

  relative = slashPath(join(dirname(base), relative));

  debug('transport resolve result ( %s )', colors.dataBold(relative));

  if (isRelative(relative)) {
    throwError('%s is out of bound of %s.', relative, base);
  }

  return relative;
}

/**
 * Normalize path \ to /
 * @param path
 * @returns {string}
 */

function slashPath(path){
  path = path.replace(/\\+/g, '/');
  path = path.replace(/([^:/])\/+\//g, '$1/');
  path = path.replace(/^\/{2,}|(:)\/{2,}/, '//');

  return path;
}

/**
 * Plugin error
 */

function throwError(){
  var message = util.format.apply(null, [].slice.call(arguments));

  throw new gutil.PluginError('gulp-cmd', message);
}

/**
 * Get rename options
 * @param opts
 * @returns {*}
 */

function getRenameOpts(opts){
  if (typeof opts === 'function') {
    return opts;
  }

  var ret = {};

  opts = opts || {};

  if (opts.min) {
    ret.suffix = '-min';
  }

  if (opts.debug) {
    ret.suffix = '-debug';
  }

  return ret;
}

/**
 * node.extend
 * Copyright 2011, John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * @fileoverview
 * Port of jQuery.extend that actually works on node.js
 */

function extend(){
  var target = arguments[0] || {};
  var i = 1;
  var length = arguments.length;
  var deep = false;
  var options, name, src, copy, copy_is_array, clone;

  // handle a deep copy situation
  if (typeof target === 'boolean') {
    deep = target;
    target = arguments[1] || {};
    // skip the boolean and the target
    i = 2;
  }

  // handle case when target is a string or something (possible in deep copy)
  if (typeof target !== 'object' && !is.fn(target)) {
    target = {};
  }

  for (; i < length; i++) {
    // only deal with non-null/undefined values
    options = arguments[i];

    if (options !== null) {
      if (typeof options === 'string') {
        options = options.split('');
      }

      // extend the base object
      for (name in options) {
        if (options.hasOwnProperty(name)) {
          src = target[name];
          copy = options[name];

          // prevent never-ending loop
          if (target === copy) {
            continue;
          }

          // recurse if we're merging plain objects or arrays
          if (deep && copy && (is.hash(copy) || (copy_is_array = Array.isArray(copy)))) {
            if (copy_is_array) {
              copy_is_array = false;
              clone = src && Array.isArray(src) ? src : [];
            } else {
              clone = src && is.hash(src) ? src : {};
            }

            // never move original objects, clone them
            target[name] = extend(deep, clone, copy);

            // don't bring in undefined values
          } else if (typeof copy !== 'undefined') {
            target[name] = copy;
          }
        }
      }
    }
  }

  // return the modified object
  return target;
}

/**
 * transform array to string
 * @param arr
 * @returns {string}
 */

function arr2str(arr){
  return arr.map(function (item){
    return '"' + item + '"';
  }).join(',');
}

/**
 * Exports module.
 */

exports.template = template;
exports.parsePackage = parsePackage;
exports.extendOption = extendOption;
exports.normalize = normalize;
exports.parseAlias = parseAlias;
exports.parsePaths = parsePaths;
exports.parseVars = parseVars;
exports.hideExt = hideExt;
exports.addExt = addExt;
exports.isRelative = isRelative;
exports.isAbsolute = isAbsolute;
exports.isLocal = isLocal;
exports.resolve = resolve;
exports.slashPath = slashPath;
exports.throwError = throwError;
exports.getRenameOpts = getRenameOpts;
exports.extend = extend;
exports.colors = colors;
exports.arr2str = arr2str;<|endoftext|>


<commit_before>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 * View means something special in yamvish. there is no view instance as you could find in other MV* lib.
 * View here is just a __Template__ that will always produce a container that will be mounted in parent node.
 * (in dom output case of course, but it's transparent for string or twopass output)
 *
 * Additionnaly, it will produce and hold its own context in produced container.
 *
 * Exactly as what a classic view's instance would encapsulate (some nodes and a local context).
 *
 * But here finally, we just have simple nodes that could be mounted/unmounted and that refer to a local context. And nothing more.
 *
 * In place of View's class instanciation, you have View's template execution.
 *
 * As a Template descendant, you could use it exactly as a normal template and everywhere a template do the job.
 *
 * As such descendant :
 * You could add some methods in View api that will not be accessible to Template's instances.
 * But every methods added to Template prototype will be accessible in View's instance.
 *
 * It's interesting when you want to benefit from the container produced when View's template is executed.
 * As yamvish-route do by implementing .route method in View api.
 *
 * All that sounds much more complex than when you use it... less is more... ;)
 */

var Template = require('./template');

function setContainer(context, container) {
	context.viewData.container = container;
}

function View(data, parent, path) {
	this.__yView__ = true;
	Template.call(this);
	this.newContext(data, parent, path)
		.context(function(context) {
			context.viewData = {};
		})
		.dom(setContainer)
		.secondPass(setContainer);
};

View.prototype = new Template();

// kill all attributes related methods
['attr', 'css', 'setClass', 'cl', 'visible', 'disabled', 'val']
.forEach(function(method) {
	View.prototype[method] = null;
});

module.exports = View;
<commit_msg>remove View class<commit_after><|endoftext|>


<commit_before>import { useQuery, useMutation } from '@apollo/react-hooks'
import { makeStyles } from '@material-ui/core'
import gql from 'graphql-tag'
import * as R from 'ramda'
import React, { useState } from 'react'

import { Button, SupportLinkButton } from 'src/components/buttons'
import { RadioGroup } from 'src/components/inputs'
import { H4, Info3 } from 'src/components/typography'
import FormRenderer from 'src/pages/Services/FormRenderer'
import schema from 'src/pages/Services/schemas'
import { ReactComponent as WarningIcon } from 'src/styling/icons/warning-icon/comet.svg'

import styles from './Shared.styles'
import { getItems } from './getItems'

const useStyles = makeStyles(styles)

const GET_CONFIG = gql`
  {
    accounts
    accountsConfig {
      code
      display
      class
      cryptos
    }
    cryptoCurrencies {
      code
      display
    }
  }
`

const SAVE_ACCOUNTS = gql`
  mutation Save($accounts: JSONObject) {
    saveAccounts(accounts: $accounts)
  }
`

const isConfigurable = it => !R.isNil(it) && !R.contains(it)(['mock-exchange'])

const ChooseExchange = ({ data: currentData, addData }) => {
  const classes = useStyles()
  const { data } = useQuery(GET_CONFIG)
  const [saveAccounts] = useMutation(SAVE_ACCOUNTS, {
    onCompleted: () => submit()
  })

  const [selected, setSelected] = useState(null)
  const [error, setError] = useState(false)

  const accounts = data?.accounts ?? []
  const accountsConfig = data?.accountsConfig ?? []

  const coin = currentData.coin
  const exchanges = getItems(accountsConfig, accounts, 'exchange', coin)

  const submit = () => {
    if (!selected) return setError(true)
    addData({ exchange: selected })
  }

  const saveExchange = name => exchange => {
    const accounts = { [name]: exchange }
    return saveAccounts({ variables: { accounts } })
  }

  const onSelect = e => {
    setSelected(e.target.value)
    setError(false)
  }

  const supportArticles = {
    kraken:
      'https://support.lamassu.is/hc/en-us/articles/115001206891-Kraken-trading',
    itbit:
      'https://support.lamassu.is/hc/en-us/articles/360026195032-itBit-trading',
    bitstamp:
      'https://support.lamassu.is/hc/en-us/articles/115001206911-Bitstamp-trading'
  }

  return (

Choose your exchange

      <RadioGroup
        labelClassName={classes.radioLabel}
        className={classes.radioGroup}
        options={R.union(exchanges.filled, exchanges.unfilled)}
        value={selected}
        onChange={onSelect}
      />
      {!isConfigurable(selected) && (
        <Button size="lg" onClick={submit} className={classes.button}>
          Continue
        </Button>
      )}
      {isConfigurable(selected) && (
        <>

            <WarningIcon />
            <Info3>
              Make sure you set up {schema[selected].name} to enter the
              necessary information below. Please follow the instructions on our
              support page if you haven’t.
            </Info3>

          <SupportLinkButton
            link={supportArticles[selected]}
            label={`${schema[selected].name} trading`}
          />

Enter exchange information

          <FormRenderer
            value={accounts[selected]}
            save={saveExchange(selected)}
            elements={schema[selected].elements}
            validationSchema={schema[selected].validationSchema}
            buttonLabel={'Continue'}
            buttonClass={classes.formButton}
          />
        </>
      )}

  )
}

export default ChooseExchange
<commit_msg>fix: crash on setup wizard when choosing "No exchange"<commit_after>import { useQuery, useMutation } from '@apollo/react-hooks'
import { makeStyles } from '@material-ui/core'
import gql from 'graphql-tag'
import * as R from 'ramda'
import React, { useState } from 'react'

import { Button, SupportLinkButton } from 'src/components/buttons'
import { RadioGroup } from 'src/components/inputs'
import { H4, Info3 } from 'src/components/typography'
import FormRenderer from 'src/pages/Services/FormRenderer'
import schema from 'src/pages/Services/schemas'
import { ReactComponent as WarningIcon } from 'src/styling/icons/warning-icon/comet.svg'

import styles from './Shared.styles'
import { getItems } from './getItems'

const useStyles = makeStyles(styles)

const GET_CONFIG = gql`
  {
    accounts
    accountsConfig {
      code
      display
      class
      cryptos
    }
    cryptoCurrencies {
      code
      display
    }
  }
`

const SAVE_ACCOUNTS = gql`
  mutation Save($accounts: JSONObject) {
    saveAccounts(accounts: $accounts)
  }
`

const isConfigurable = it =>
  !R.isNil(it) && !R.contains(it)(['mock-exchange', 'no-exchange'])

const ChooseExchange = ({ data: currentData, addData }) => {
  const classes = useStyles()
  const { data } = useQuery(GET_CONFIG)
  const [saveAccounts] = useMutation(SAVE_ACCOUNTS, {
    onCompleted: () => submit()
  })

  const [selected, setSelected] = useState(null)
  const [error, setError] = useState(false)

  const accounts = data?.accounts ?? []
  const accountsConfig = data?.accountsConfig ?? []

  const coin = currentData.coin
  const exchanges = getItems(accountsConfig, accounts, 'exchange', coin)

  const submit = () => {
    if (!selected) return setError(true)
    addData({ exchange: selected })
  }

  const saveExchange = name => exchange => {
    const accounts = { [name]: exchange }
    return saveAccounts({ variables: { accounts } })
  }

  const onSelect = e => {
    setSelected(e.target.value)
    setError(false)
  }

  const supportArticles = {
    kraken:
      'https://support.lamassu.is/hc/en-us/articles/115001206891-Kraken-trading',
    itbit:
      'https://support.lamassu.is/hc/en-us/articles/360026195032-itBit-trading',
    bitstamp:
      'https://support.lamassu.is/hc/en-us/articles/115001206911-Bitstamp-trading'
  }

  return (

Choose your exchange

      <RadioGroup
        labelClassName={classes.radioLabel}
        className={classes.radioGroup}
        options={R.union(exchanges.filled, exchanges.unfilled)}
        value={selected}
        onChange={onSelect}
      />
      {!isConfigurable(selected) && (
        <Button size="lg" onClick={submit} className={classes.button}>
          Continue
        </Button>
      )}
      {isConfigurable(selected) && (
        <>

            <WarningIcon />
            <Info3>
              Make sure you set up {schema[selected].name} to enter the
              necessary information below. Please follow the instructions on our
              support page if you haven’t.
            </Info3>

          <SupportLinkButton
            link={supportArticles[selected]}
            label={`${schema[selected].name} trading`}
          />

Enter exchange information

          <FormRenderer
            value={accounts[selected]}
            save={saveExchange(selected)}
            elements={schema[selected].elements}
            validationSchema={schema[selected].validationSchema}
            buttonLabel={'Continue'}
            buttonClass={classes.formButton}
          />
        </>
      )}

  )
}

export default ChooseExchange
<|endoftext|>