<commit_before>(function(env) {
var quixey_image_domain = "d1z22zla46lb9g.cloudfront.net";

// spice callback function
env.ddg_spice_quixey = function(api_result) {

    if (api_result.result_count == 0) return;

    var q = api_result.q.replace(/\s/g, '+');
    var relevants = getRelevant(api_result.results);

    if (!relevants) return;

    Spice.add({
        id: 'quixey',
        name: 'Apps',

        data: relevants,

        meta: {
            count: relevants.length,
            total: api_result.results.length,
            itemType: 'Apps',
            sourceName: 'Quixey',
            sourceUrl: 'https://www.quixey.com/search?q=' + q,
            sourceIconUrl: DDG.get_asset_path('quixey','quixey_logo.png')
        },

        normalize : function(item) {

            // skip ones that have less than three reviews
            if (!item.rating_count || item.rating_count < 3)
                return null;

            return {
                img: make_icon_url(item),
                title: item.name,
                heading: item.name,
                ratingData: {
                    stars: item.rating,
                    reviews: item.rating_count
                },
                url_review: item.dir_url,
                price: pricerange(item),
                abstract: item.short_desc || "",
                brand: (item.developer && item.developer.name) || "",
                products_buy: Spice.quixey_buy,

                // this should be the array of screenshots with captions
                // and check for the existence of them
                img_m: quixey_image(item.editions[0].screenshots[0].image_url)
            };
        },

        templates: {
            item: DDG.templates.products,
            detail: DDG.templates.products_detail
        }
    });

    // Check for relevant app results
    function getRelevant (results) {
        var res,
            apps = [],
            backupApps = [],
            categories = [
                "developer tools",
                "action",
                "adventure",
                "arcade",
                "board",
                "business",
                "casino",
                "design",
                "dice",
                "education",
                "educational",
                "entertainment",
                "family",
                "finance",
                "graphics",
                "graphics and design",
                "health and fitness",
                "kids",
                "lifestyle",
                "medical",
                "music",
                "networking",
                "news",
                "photography",
                "productivity",
                "puzzle",
                "racing",
                "role playing",
                "simulation",
                "social networking",
                "social",
                "sports",
                "strategy",
                "travel",
                "trivia",
                "utilities",
                "video",
                "weather"],
            skip_words = [
                "google play store",
                "windows phone 8",
                "apple app store",
                "windows mobile",
                "windows phone",
                "applications",
                "release data",
                "application",
                "google play",
                "blackberry",
                "ipod touch",
                "downloaded",
                "apple app",
                "playbook",
                "download",
                "android",
                "release",
                "iphone",
                "search",
                "droid",
                "apps",
                "free",
                "ipod",
                "ipad",
                "ios",
                "app"
            ],
            app;

        categories = new RegExp(categories.join("|"), "i");
        for (var i = 0; i < results.length; i++) {
            app = results[i];

            // make sure it has at least 3 reviews:
            if(!app.rating_count || app.rating_count < 3){
                continue;
            }

            // check if this app result is relevant
            if (DDG.isRelevant(app.name.toLowerCase(), skip_words) && app.icon_url) {
                apps.push(app);
            } else if (app.hasOwnProperty("short_desc") &&
                       DDG.isRelevant(app.short_desc.toLowerCase(), skip_words) && app.icon_url) {
                            backupApps.push(app);
            } else if (app.custom && app.custom.hasOwnProperty("category") &&
                       DDG.isRelevant(app.custom.category.toLowerCase(), skip_words) && app.icon_url) {
                            backupApps.push(app);
            }
        }

        // Return highly relevant results
        if (apps.length > 0) {
            res = apps;
        }

        // Return mostly relevant results
        else if (backupApps.length > 0) {
            res = backupApps;
        }

        else {

            // No relevant results,
            // check if it was a categorical search
            // Eg."social apps for android"
            var q = DDG.get_query();
            res = q.match(categories) ? results : null;
        }

        // normalize it:
        // res = res.map(function(app){
        //     var normal = {
        //         img: make_icon_url(app),
        //         title: app.name,
        //         ratingData: {
        //             stars: app.rating,
        //             reviews: app.rating_count
        //         },
        //         price: pricerange(app),
        //         abstract: app.short_desc || "",
        //         brand: (app.developer && app.developer.name) || "",
        //         products_buy: Handlebars.templates.quixey_buy // should/will be Spice.quixey.products_buy
        //     };

        //     // this should be the array of screenshots with captions
        //     // and check for the existence of them
        //     normal.img_m = quixey_image(app.editions[0].screenshots[0].image_url);

        //     return normal;
        // });

        return res;
    }
}

// format a price
// p is expected to be a number
function qprice(p) {
    if (p == 0) {    // == type coercion is ok here
        return "FREE";
    }

    return "$" + (p/100).toFixed(2).toString();
}

// template helper for price formatting
// {{price x}}
Handlebars.registerHelper("qprice", function(obj) {
    return qprice(obj);
});

var quixey_image = function(image_url) {
    return "http://" + quixey_image_domain + image_url.match(/\/image\/.+/)[0];
}

var make_icon_url = function(item) {
    var domain = "d1z22zla46lb9g.cloudfront.net";

    // Get the image server that the icon_url in platforms is pointing to.
    // It's not ideal, but the link to the app's image still has to redirect
    // and it redirects to HTTPS. What we want is an HTTP link (for speed).
    if (item.platforms && item.platforms.length > 0 && item.platforms[0].icon_url) {
        domain = item.platforms[0].icon_url.match(/https?:\/\/([^\/]+)/)[1];
    }

    // Replace the domain in our icon_url to the one that we got from
    // the platforms array.
    // return "/iu/?u=http://" + domain + item.icon_url.match(/\/image\/.+/)[0] + "&f=1";
    return "http://" + domain + item.icon_url.match(/\/image\/.+/)[0];
};

Handlebars.registerHelper("toHTTP", function(icon_url, platforms) {
    var domain = "d1z22zla46lb9g.cloudfront.net";

    // Get the image server that the icon_url in platforms is pointing to.
    // It's not ideal, but the link to the app's image still has to redirect
    // and it redirects to HTTPS. What we want is an HTTP link (for speed).
    if(platforms && platforms.length > 0 && platforms[0].icon_url) {
    domain = platforms[0].icon_url.match(/https?:\/\/([^\/]+)/)[1];
    }

    // Replace the domain in our icon_url to the one that we got from
    // the platforms array.
    icon_url = icon_url.match(/\/image\/.+/)[0];
    return "http://" + domain + icon_url;
});

// template helper to format a price range
var pricerange = function(item) {

    if (!item || !item.editions)
        return "";

    var low  = item.editions[0].cents;
    var high = item.editions[0].cents;
    var tmp, range, lowp, highp;

    for (var i in item.editions) {
        tmp = item.editions[i].cents;
        if (tmp < low) low = tmp;
        if (tmp > high) high = tmp;
    }

    lowp = qprice(low);

    if (high > low) {
       highp = qprice(high);
       range = lowp + " - " + highp;
       item.hasPricerange = true;
    } else {
        range = lowp;
    }

    return range;
};

Handlebars.registerHelper("pricerange", function() {
    return pricerange(this);
});

// template helper to replace iphone and ipod icons with
// smaller 'Apple' icons
Handlebars.registerHelper("platform_icon", function(icon_url) {
    if (this.id === 2004 || this.id === 2015) {
        return "https://icons.duckduckgo.com/i/itunes.apple.com.ico";
    }

    // return "/iu/?u=" + icon_url + "&f=1";
    return icon_url;
});

// template helper that returns and unifies platform names
Handlebars.registerHelper("platform_name", function() {
    var name;
    var platforms = this.platforms;

    name = platforms[0].name;

    if (platforms.length > 1) {
        switch (platforms[0].name) {
            case "iPhone" :
            case "iPad" :
                name = "iOS";
                break;

            case "Blackberry":
            case "Blackberry 10":
                name = "Blackberry";
                break;
        }
    }

    return name;
});

// template helper to give url for star icon
Handlebars.registerHelper("quixey_star", function() {
    return DDG.get_asset_path("quixey", "star.png").replace("//", "/");
});

})(this);
<commit_msg>quixey - new relevancy groups and specification<commit_after>(function(env) {
var quixey_image_domain = "d1z22zla46lb9g.cloudfront.net";

// spice callback function
env.ddg_spice_quixey = function(api_result) {

    // if (api_result.result_count == 0) return;

    var q = api_result.q.replace(/\s/g, '+');
    // var relevants = getRelevant(api_result.results);

    // if (!relevants) return;

    var category_regexp = new RegExp([
            "action",
            "adventure",
            "arcade",
            "board",
            "business",
            "casino",
            "design",
            "developer tools",
            "dice",
            "education",
            "educational",
            "entertainment",
            "family",
            "finance",
            "graphics and design",
            "graphics",
            "health and fitness",
            "kids",
            "lifestyle",
            "medical",
            "music",
            "networking",
            "news",
            "photography",
            "productivity",
            "puzzle",
            "racing",
            "role playing",
            "simulation",
            "social networking",
            "social",
            "sports",
            "strategy",
            "travel",
            "trivia",
            "utilities",
            "video",
            "weather"
        ].join("|"), "i");

    console.log("quixey: category match: %o", DDG.get_query().match(category_regexp));

    Spice.add({
        id: 'quixey',
        name: 'Apps',

        data: api_result.results,   //relevants,

        meta: {
            // count is now computed by Spice
            // count: relevants.length,
            total: api_result.results.length,
            itemType: 'Apps',
            sourceName: 'Quixey',
            sourceUrl: 'https://www.quixey.com/search?q=' + q,
            sourceIconUrl: DDG.get_asset_path('quixey','quixey_logo.png')
        },

        normalize : function(item) {

            // relevancy pre-filter: skip ones that have less than three reviews
            if (!item.rating_count || item.rating_count < 3)
                return null;

            return {
                'img':           make_icon_url(item),
                'title':         item.name,
                'heading':       item.name,
                'ratingData':    {
                                   stars: item.rating,
                                   reviews: item.rating_count
                               },
                'url_review':    item.dir_url,
                'price':         pricerange(item),
                'abstract':      item.short_desc || "",
                'brand':         (item.developer && item.developer.name) || "",
                'products_buy':  Spice.quixey_buy,

                // this should be the array of screenshots with captions
                // and check for the existence of them
                'img_m': quixey_image(item.editions[0].screenshots[0].image_url)
            };
        },

        /* keys refer to non-normalized item */
        // relevancy: [
        //     { key: 'name', skip_words: skip_words },
        //     { key: 'short_desc', skip_words: skip_words },
        //     { key: 'custom.category', skip_words: skip_words }
        // ],

        relevancy: {
            type: DDG.get_query().match(category_regexp) ? "category" : "primary",
            skip_words: [
                "android",
                "app",
                "apple app store",
                "apple app",
                "application",
                "applications",
                "apps",
                "blackberry",
                "download",
                "downloaded",
                "droid",
                "free",
                "google play store",
                "google play",
                "ios",
                "ipad",
                "iphone",
                "ipod touch",
                "ipod",
                "playbook",
                "release data",
                "release",
                "search",
                "windows mobile",
                "windows phone 8",
                "windows phone"
            ],

            // maybe these are search types
            category: [
                { key: 'short_desc' },
                { key: 'name' },
                { key: 'custom.features.category', match: category_regexp },
                { required: 'icon_url' }
            ],

            // vine twitter app
            // one or both words in header
            // one in header, one elsewhere

            primary: [
                { key: 'name' },    // this should somehow indicate that a name match == more relevant
                { required: 'icon_url' }
            ],

            secondary:  [
                { key: 'short_desc' },
                { key: 'name' },
                { key: 'custom.features.category' },
                { required: 'icon_url' }
            ],

            // last_resort: { query: quixey_categories },

            dup: 'id',  // identifier for de duplication,
                        // or function(item) { return item.id; }

        },

        //TODO context specific sort

        // sort: {
        //     'rating': //Spice.rating_comparator('rating', 'rating_count')
        //         function(a,b) {
        //             var rank = function(r,count) {
        //                 return r*r*r*count/5;
        //             };
        //         return rank(a.rating,a.rating_count) > rank(b.rating, b.rating_count) ? -1: 1;
        //     },
        // },

        default_sort: 'rating',

        templates: {
            item: DDG.templates.products,
            detail: DDG.templates.products_detail
        }
    });

    // Check for relevant app results
    function getRelevant (results) {
        var res,
            apps = [],
            backupApps = [],
            categories = [
                "developer tools",
                "action",
                "adventure",
                "arcade",
                "board",
                "business",
                "casino",
                "design",
                "dice",
                "education",
                "educational",
                "entertainment",
                "family",
                "finance",
                "graphics",
                "graphics and design",
                "health and fitness",
                "kids",
                "lifestyle",
                "medical",
                "music",
                "networking",
                "news",
                "photography",
                "productivity",
                "puzzle",
                "racing",
                "role playing",
                "simulation",
                "social networking",
                "social",
                "sports",
                "strategy",
                "travel",
                "trivia",
                "utilities",
                "video",
                "weather"],
            skip_words = [
                "google play store",
                "windows phone 8",
                "apple app store",
                "windows mobile",
                "windows phone",
                "applications",
                "release data",
                "application",
                "google play",
                "blackberry",
                "ipod touch",
                "downloaded",
                "apple app",
                "playbook",
                "download",
                "android",
                "release",
                "iphone",
                "search",
                "droid",
                "apps",
                "free",
                "ipod",
                "ipad",
                "ios",
                "app"
            ],
            app;

        categories = new RegExp(categories.join("|"), "i");
        for (var i = 0; i < results.length; i++) {
            app = results[i];

            // make sure it has at least 3 reviews:
            if(!app.rating_count || app.rating_count < 3){
                continue;
            }

            // check if this app result is relevant
            if (DDG.isRelevant(app.name.toLowerCase(), skip_words) && app.icon_url) {
                apps.push(app);
            } else if (app.hasOwnProperty("short_desc") &&
                       DDG.isRelevant(app.short_desc.toLowerCase(), skip_words) && app.icon_url) {
                            backupApps.push(app);
            } else if (app.custom && app.custom.hasOwnProperty("category") &&
                       DDG.isRelevant(app.custom.category.toLowerCase(), skip_words) && app.icon_url) {
                            backupApps.push(app);
            }
        }

        // Return highly relevant results
        if (apps.length > 0) {
            res = apps;
        }

        // Return mostly relevant results
        else if (backupApps.length > 0) {
            res = backupApps;
        }

        else {

            console.warn("quixey: category search");

            // No relevant results,
            // check if it was a categorical search
            // Eg."social apps for android"
            var q = DDG.get_query();
            res = q.match(categories) ? results : null;
        }

        return res;
    }
}

// format a price
// p is expected to be a number
function qprice(p) {
    if (p == 0) {    // == type coercion is ok here
        return "FREE";
    }

    return "$" + (p/100).toFixed(2).toString();
}

// template helper for price formatting
// {{price x}}
Handlebars.registerHelper("qprice", function(obj) {
    return qprice(obj);
});

var quixey_image = function(image_url) {
    return "http://" + quixey_image_domain + image_url.match(/\/image\/.+/)[0];
}

var make_icon_url = function(item) {
    var domain = "d1z22zla46lb9g.cloudfront.net",
        icon_url = item.icon_url;

    if (!icon_url) {
        console.warn("quixey: icon_url is null for %o", item);
        if (item.editions && item.editions[0].icon_url)
            icon_url = item.editions[0].icon_url;
        else
            return "";
    }

    // Get the image server that the icon_url in platforms is pointing to.
    // It's not ideal, but the link to the app's image still has to redirect
    // and it redirects to HTTPS. What we want is an HTTP link (for speed).
    if (item.platforms && item.platforms.length > 0 && item.platforms[0].icon_url) {
        domain = item.platforms[0].icon_url.match(/https?:\/\/([^\/]+)/)[1];
    }

    // Replace the domain in our icon_url to the one that we got from
    // the platforms array.
    // return "/iu/?u=http://" + domain + item.icon_url.match(/\/image\/.+/)[0] + "&f=1";
    return "http://" + domain + icon_url.match(/\/image\/.+/)[0];
};

Handlebars.registerHelper("toHTTP", function(icon_url, platforms) {
    var domain = "d1z22zla46lb9g.cloudfront.net";

    // Get the image server that the icon_url in platforms is pointing to.
    // It's not ideal, but the link to the app's image still has to redirect
    // and it redirects to HTTPS. What we want is an HTTP link (for speed).
    if(platforms && platforms.length > 0 && platforms[0].icon_url) {
    domain = platforms[0].icon_url.match(/https?:\/\/([^\/]+)/)[1];
    }

    // Replace the domain in our icon_url to the one that we got from
    // the platforms array.
    icon_url = icon_url.match(/\/image\/.+/)[0];
    return "http://" + domain + icon_url;
});

// template helper to format a price range
var pricerange = function(item) {

    if (!item || !item.editions)
        return "";

    var low  = item.editions[0].cents;
    var high = item.editions[0].cents;
    var tmp, range, lowp, highp;

    for (var i in item.editions) {
        tmp = item.editions[i].cents;
        if (tmp < low) low = tmp;
        if (tmp > high) high = tmp;
    }

    lowp = qprice(low);

    if (high > low) {
       highp = qprice(high);
       range = lowp + " - " + highp;
       item.hasPricerange = true;
    } else {
        range = lowp;
    }

    return range;
};

Handlebars.registerHelper("pricerange", function() {
    return pricerange(this);
});

// template helper to replace iphone and ipod icons with
// smaller 'Apple' icons
Handlebars.registerHelper("platform_icon", function(icon_url) {
    if (this.id === 2004 || this.id === 2015) {
        return "https://icons.duckduckgo.com/i/itunes.apple.com.ico";
    }

    // return "/iu/?u=" + icon_url + "&f=1";
    return icon_url;
});

// template helper that returns and unifies platform names
Handlebars.registerHelper("platform_name", function() {
    var name;
    var platforms = this.platforms;

    name = platforms[0].name;

    if (platforms.length > 1) {
        switch (platforms[0].name) {
            case "iPhone" :
            case "iPad" :
                name = "iOS";
                break;

            case "Blackberry":
            case "Blackberry 10":
                name = "Blackberry";
                break;
        }
    }

    return name;
});

// template helper to give url for star icon
Handlebars.registerHelper("quixey_star", function() {
    return DDG.get_asset_path("quixey", "star.png").replace("//", "/");
});

})(this);
<|endoftext|>


<commit_before>const worder = require('../get-word')
const _ = require('lodash')

// load the words array
const words = worder.getWords()

for (let len = 3; len <= 5; len += 1) {
  const freqs = {}

  words.forEach(word => {
    // start
    const part = word.substr(0, len)

    // end
    // const part = word.substr(-len)

    if (part in freqs) {
      freqs[part] += 1
    } else {
      freqs[part] = 1
    }
  })

  const best = _.sortBy(Object.keys(freqs), w => freqs[w]).slice(-10)

  best.forEach(b => console.log(b, freqs[b]))
}

/*

non 1536
sub 1575
out 1715
int 1719
mis 1725
pro 2183
pre 2429
con 2711
dis 2795

mono 546
cont 562
comp 605
para 659
anti 892
over 2234

trans 543
under 744
super 839
inter 1108

 */
<commit_msg>long word beginnings<commit_after>const worder = require('../get-word')
const _ = require('lodash')

// load the words array
const words = worder.getWords().filter(w => w.length === 7 || w.length === 8)

for (let len = 3; len <= 5; len += 1) {
  const freqs = {}

  words.forEach(word => {
    // start
    const part = word.substr(0, len)

    // end
    // const part = word.substr(-len)

    if (part in freqs) {
      freqs[part] += 1
    } else {
      freqs[part] = 1
    }
  })

  const best = _.sortBy(Object.keys(freqs), w => freqs[w]).slice(-10)

  best.forEach(b => console.log(b, freqs[b]))
}

/*

non 1536
sub 1575
out 1715
int 1719
mis 1725
pro 2183
pre 2429
con 2711
dis 2795

mono 546
cont 562
comp 605
para 659
anti 892
over 2234

trans 543
under 744
super 839
inter 1108

 */
<|endoftext|>


<commit_before>const path = require('path');
const chalk = require('chalk');
const util = require('util');
const Generator = require('yeoman-generator');
const yosay = require('yosay');
const mkdirp = require('mkdirp');
const foldername = path.basename(process.cwd());

module.exports = class extends Generator {
    initializing() {
        this.props = {};
    }
    prompting() {
        this.log(yosay(
            '~' + chalk.red('generator-phaser-h5') + '~'
        ));
        return this.prompt([{
                type: 'input',
                name: 'projectName',
                message: 'What\'s the name of your application(in English Please)',
                default: foldername
            },
            {
                type: 'input',
                name: 'projectDesc',
                message: 'What\'s the description of your application:'
            },
            {
                type: 'list',
                name: 'projectLicense',
                message: 'Please choose license:',
                choices: ['MIT', 'ISC', 'Apache-2.0', 'AGPL-3.0']
            },
            {
                type: 'confirm',
                name: 'projectSass',
                message: 'Do You Use Sass?',
                default: false
            }
        ]).then(answers => {
            this.projectName = answers.projectName ? answers.projectName : ' ';
            this.projectDesc = answers.projectDesc ? answers.projectDesc : ' ';
            this.projectLicense = answers.projectLicense || 'MIT';
            this.projectSass = answers.projectSass || false;
        });
    }
    configuring() {
        this.config.set('projectName', this.projectName);
        this.config.set('projectDesc', this.projectDesc);
        this.config.set('projectLicense', this.projectLicense);
    }
    writing() {
        this.fs.copyTpl(
            this.templatePath('src'),
            this.destinationPath('src'),
            this
        );
        mkdirp('src/assets/media');
        if (this.projectSass) {
            this.fs.copyTpl(
                this.templatePath('_package_sass.json'),
                this.destinationPath('package.json'),
                this
            );
            this.fs.copy(
                this.templatePath('_gulpfile_sass.js'),
                this.destinationPath('gulpfile.js'),
                this
            );
        } else {
            this.fs.copyTpl(
                this.templatePath('_package.json'),
                this.destinationPath('package.json'),
                this
            );
            this.fs.copy(
                this.templatePath('_gulpfile.js'),
                this.destinationPath('gulpfile.js'),
                this
            );
        }

        this.fs.copy(
            this.templatePath('jshintrc'),
            this.destinationPath('.jshintrc'),
            this
        );

    }
    install() { //安装依赖
        this.installDependencies({ bower: false });
    }
};<commit_msg>:bug: Try to Fix bug<commit_after>const path = require('path');
const chalk = require('chalk');
const util = require('util');
const Generator = require('yeoman-generator');
const yosay = require('yosay');
const mkdirp = require('mkdirp');
const foldername = path.basename(process.cwd());

module.exports = class extends Generator {
    initializing() {
        this.props = {};
    }
    prompting() {
        this.log(yosay(
            '~' + chalk.red('generator-phaser-h5') + '~'
        ));
        return this.prompt([{
                type: 'input',
                name: 'projectName',
                message: 'What\'s the name of your application(in English Please)',
                default: foldername
            },
            {
                type: 'input',
                name: 'projectDesc',
                message: 'What\'s the description of your application:'
            },
            {
                type: 'list',
                name: 'projectLicense',
                message: 'Please choose license:',
                choices: ['MIT', 'ISC', 'Apache-2.0', 'AGPL-3.0']
            },
            {
                type: 'confirm',
                name: 'projectSass',
                message: 'Do You Use Sass?',
                default: false
            }
        ]).then(answers => {
            this.projectName = answers.projectName ? answers.projectName : ' ';
            this.projectDesc = answers.projectDesc ? answers.projectDesc : ' ';
            this.projectLicense = answers.projectLicense || 'MIT';
            this.projectSass = answers.projectSass || false;
        });
    }
    configuring() {
        this.config.set('projectName', this.projectName);
        this.config.set('projectDesc', this.projectDesc);
        this.config.set('projectLicense', this.projectLicense);
    }
    writing() {
        this.fs.copyTpl(
            this.templatePath('src/index.html'),
            this.destinationPath('src/index.html'),
            this
        );
        this.fs.copy(
            this.templatePath('src/assets/**'),
            this.destinationPath('src/assets/'),
            this
        );
        mkdirp('src/assets/media');
        if (this.projectSass) {
            this.fs.copyTpl(
                this.templatePath('_package_sass.json'),
                this.destinationPath('package.json'),
                this
            );
            this.fs.copy(
                this.templatePath('_gulpfile_sass.js'),
                this.destinationPath('gulpfile.js'),
                this
            );
        } else {
            this.fs.copyTpl(
                this.templatePath('_package.json'),
                this.destinationPath('package.json'),
                this
            );
            this.fs.copy(
                this.templatePath('_gulpfile.js'),
                this.destinationPath('gulpfile.js'),
                this
            );
        }

        this.fs.copy(
            this.templatePath('jshintrc'),
            this.destinationPath('.jshintrc'),
            this
        );

    }
    install() { //安装依赖
        this.installDependencies({ bower: false });
    }
};<|endoftext|>


<commit_before>var endpoint;

// Register a Service Worker.
navigator.serviceWorker.register('service-worker.js')
.then(function(registration) {
  // Use the PushManager to get the user's subscription to the push service.
  return registration.pushManager.getSubscription()
  .then(function(subscription) {
    // If a subscription was found, return it.
    if (subscription) {
      return subscription;
    }

    // Otherwise, subscribe the user (userVisibleOnly allows to specify that we don't plan to
    // send notifications that don't have a visible effect for the user).
    return registration.pushManager.subscribe({ userVisibleOnly: true })
    .then(function(newSubscription) {
      return newSubscription;
    });
  });
}).then(function(subscription) {
  endpoint = subscription.endpoint;

  // Show curl command to send the notification on the page.
  document.getElementById('curl').textContent = 'curl -X POST ' + subscription.endpoint;

  // Send the subscription details to the server using the Fetch API.
  fetch('./register', {
    method: 'post',
    headers: {
      'Content-type': 'application/json'
    },
    body: JSON.stringify({
      endpoint: subscription.endpoint,
    }),
  });
});

document.getElementById('doIt').onclick = function() {
  var delay = document.getElementById('notification-delay').value;
  var ttl = document.getElementById('notification-ttl').value;

  // Ask the server to send the client a notification.
  // This is for testing purposes, in a real application the notifications will be
  // directly generated by the server without the user asking for it (otherwise, what
  // would be the point?).
  fetch('./sendNotification?endpoint=' + endpoint + '&delay=' + delay +
        '&ttl=' + ttl,
    {
      method: 'post',
    }
  );
};
<commit_msg>Fix lint warning<commit_after>var endpoint;

// Register a Service Worker.
navigator.serviceWorker.register('service-worker.js')
.then(function(registration) {
  // Use the PushManager to get the user's subscription to the push service.
  return registration.pushManager.getSubscription()
  .then(function(subscription) {
    // If a subscription was found, return it.
    if (subscription) {
      return subscription;
    }

    // Otherwise, subscribe the user (userVisibleOnly allows to specify that we don't plan to
    // send notifications that don't have a visible effect for the user).
    return registration.pushManager.subscribe({ userVisibleOnly: true })
    .then(function(newSubscription) {
      return newSubscription;
    });
  });
}).then(function(subscription) {
  endpoint = subscription.endpoint;

  // Show curl command to send the notification on the page.
  document.getElementById('curl').textContent = 'curl -X POST ' + endpoint;

  // Send the subscription details to the server using the Fetch API.
  fetch('./register', {
    method: 'post',
    headers: {
      'Content-type': 'application/json'
    },
    body: JSON.stringify({
      endpoint: subscription.endpoint,
    }),
  });
});

document.getElementById('doIt').onclick = function() {
  var delay = document.getElementById('notification-delay').value;
  var ttl = document.getElementById('notification-ttl').value;

  // Ask the server to send the client a notification.
  // This is for testing purposes, in a real application the notifications will be
  // directly generated by the server without the user asking for it (otherwise, what
  // would be the point?).
  fetch('./sendNotification?endpoint=' + endpoint + '&delay=' + delay +
        '&ttl=' + ttl,
    {
      method: 'post',
    }
  );
};
<|endoftext|>


<commit_before><commit_msg>BIG Refactoring. Might be unstable. - More<commit_after><|endoftext|>


<commit_before>import { map, prop, groupBy, sum, mapObjIndexed } from 'ramda'
import * as taskRecipes from '../../tasks/data/recipes'
const feathersKnex = require('feathers-knex')
const { iff } = require('feathers-hooks-common')

module.exports = function () {
  const app = this
  const db = app.get('db')

  const name = 'taskWorks'
  const options = { Model: db, name }

  app.use(name, feathersKnex(options))
  app.service(name).hooks(hooks)
}

const hooks = {
  before: {},
  after: {
    create: [
      iff(taskRecipeIsCompleteOrderSetup, createCastOrderIntentTaskPlan),
      iff(taskRecipeIsCompleteOrderSetup, createCloseOrderTaskPlan),
      iff(taskRecipeIsCloseOrder, createCastOrderIntentTaskWorks),
      iff(taskRecipeIsCloseOrder, createOrderPlans),
      iff(taskRecipeIsCloseOrder, createViewOrderSummaryTaskPlan)
    ]
  },
  error: {}
}

function taskRecipeIsCompleteOrderSetup (hook) {
  return hook.data.taskRecipeId === 'completeOrderSetupWithPrereqs'
    || hook.data.taskRecipeId === 'completeOrderSetup'
}

function taskRecipeIsCloseOrder (hook) {
  return hook.data.taskRecipeId === 'closeOrder'
}

function createOrderPlans (hook) {
  const orders = hook.app.service('orders')
  const taskPlans = hook.app.service('taskPlans')
  const orderIntents = hook.app.service('orderIntents')
  const orderPlans = hook.app.service('orderPlans')
  const priceSpecs = hook.app.service('priceSpecs')
  return taskPlans.get(hook.data.taskPlanId)
    .then((taskPlan) => {
      return orders.get(taskPlan.params.orderId)
    })
    .then((order) => {
      return orderIntents.find({
        query: {
          orderId: order.id
        }
      })
    })
    .then((queriedOrderIntents) => {
      // TODO: IK: similar logic will also be needed on the client for showing the current state of the order per product - i.e. which priceSpec is currently going to be enforced

      // for each productId of the orderIntents, sum the 'quantity' field of all orderIntents with the same productId
      const orderIntentsByProductId = groupBy(prop('productId'), queriedOrderIntents)
      const quantitiesOrderedByProductId = map((intent) => sum(map(prop('desiredQuantity'), intent)), orderIntentsByProductId)
      // find the priceSpec for each productId where the summed quantity is equal to or greater than the 'minimum' (but only the priceSpec with the largest minimum)
      // need to test how combos of query params work in conjunction
      console.log('all orderd by productId is: ', quantitiesOrderedByProductId)
      return Promise.all([
        // Why does this need to be surrounded in an array?
        mapObjIndexed((quantity, productId) => {
          return priceSpecs.find({
            query: {
              productId,
              $limit: 1,
              $sort: {
                minimum: -1
              },
              minimum: {
                $lte: quantity
              }
            }
          })
        }, quantitiesOrderedByProductId)
      ])
      .then((queriedPriceSpecs) => {
        console.log('price specs: ', queriedOrderIntents)
        // might need to flatten() queriedPriceSpecs
        // might want to groupBy on queriedPriceSpecs to group them by productId (might be better to use keyBy if it exists?)
        // for each unique combination of an orderIntent's agentId and productId, create a single orderPlan with the found priceSpecId
        // if no found priceSpecId, this means the combined orderIntents didn't meet a minimum quantity, therefore no orderPlan for that product
        // const matchedOrderIntents = filter()
      })

      // return Promise.all(
      //   map((orderIntent) => {
      //     return orderPlans.create({
      //       orderId: orderIntent.orderId,
      //       agentId: orderIntent.agentId,
      //       quantity: orderIntent.desiredQuantity,
      //       productId: orderIntent.productId,
      //       priceSpecId: orderIntent.priceSpecId
      //     })
      //   }, orderIntents)
      // )
    })
    .then(() => hook)
}

function createCastOrderIntentTaskPlan (hook) {
  const taskPlans = hook.app.service('taskPlans')
  const orders = hook.app.service('orders')
  const relationships = hook.app.service('relationships')
  const taskRecipeId = taskRecipes.castIntent.id
  const completeOrderTaskPlanId = hook.data.taskPlanId

  return taskPlans.get(completeOrderTaskPlanId)
  .then((completeOrderTaskPlan) => {
    const orderId = completeOrderTaskPlan.params.orderId
    return orders.get(orderId)
  })
  .then((order) => {
    const { id, consumerAgentId, supplierAgentId, adminAgentId } = order
    const params = { orderId: id, consumerAgentId, supplierAgentId, adminAgentId }
    return Promise.all([
      Promise.resolve(params),
      relationships.find({
        query: {
          sourceId: consumerAgentId,
          relationshipType: 'member'
        }
      })
    ])
  })
  .then(([params, relationships]) => {
    return Promise.all(
      map((relationship) => {
        const assigneeId = prop('targetId', relationship)
        return taskPlans.create({ taskRecipeId, params, assigneeId })
      }, relationships)
    )
  })
  .then(() => hook)
}

function createCloseOrderTaskPlan (hook) {
  const taskPlans = hook.app.service('taskPlans')
  const orders = hook.app.service('orders')
  const taskRecipeId = taskRecipes.closeOrder.id
  const completedTaskPlanId = hook.result.taskPlanId

  return taskPlans.get(completedTaskPlanId)
    .then((completedTaskPlan) => {
      const { orderId } = completedTaskPlan.params
      return orders.get(orderId)
    })
    .then((order) => {
      const { id, adminAgentId } = order
      const params = {
        orderId: id,
      }
      return taskPlans.create({ taskRecipeId, params, assigneeId: adminAgentId })
    })
    .then(() => {
      return hook
    })
}

function createCastOrderIntentTaskWorks (hook) {
  // order has closed, get all relevant taskPlans, create a taskWork for em
  const taskPlans = hook.app.service('taskPlans')
  const taskWorks = hook.app.service('taskWorks')
  const closeOrderTaskPlanId = hook.data.taskPlanId

  return taskPlans.get(closeOrderTaskPlanId)
    .then((closeOrderTaskPlan) => {
      const orderId = closeOrderTaskPlan.params.orderId
      // const params = { orderId, consumerAgentId: groupId, supplierAgentId }

      // TODO: IK: feels like a pretty sub-optimal way of querying, probably makes sense to have orderId as it's own column
      return taskPlans.find({
        query: {
          taskRecipeId: 'castIntent',
          params: {
            $like: `%"orderId":${orderId}%`
          }
        }
      })
        .then((taskPlans) => {
          return Promise.all(taskPlans.map((taskPlan) => {
            const { id, taskRecipeId, assigneeId, params } = taskPlan
            return taskWorks.create({
              taskPlanId: id,
              taskRecipeId,
              workerAgentId: assigneeId,
              params
            })
          }))
        })
    })
    .then(() => hook)
}

function createViewOrderSummaryTaskPlan (hook) {
  const taskPlans = hook.app.service('taskPlans')
  const orders = hook.app.service('orders')
  const taskRecipeId = taskRecipes.viewOrderSummary.id
  const closeOrderTaskPlanId = hook.data.taskPlanId

  return taskPlans.get(closeOrderTaskPlanId)
    .then((closeOrderTaskPlan) => {
      const orderId = closeOrderTaskPlan.params.orderId
      return orders.get(orderId)
    })
    .then((order) => {
      const { id, adminAgentId } = order
      const params = { orderId: id }
      return taskPlans.create({ taskRecipeId, params, assigneeId: adminAgentId })
    })
    .then(() => {
      return hook
    })
}
<commit_msg>TEMP: towards ramda-ifying orderPlan creation, but think down a rabbit hole that doesn't lead to promised land<commit_after>import { map, prop, groupBy, sum, mapObjIndexed, values, tap, pipe, uniq, pick, sortBy, reverse } from 'ramda'
import * as taskRecipes from '../../tasks/data/recipes'
const feathersKnex = require('feathers-knex')
const { iff } = require('feathers-hooks-common')

module.exports = function () {
  const app = this
  const db = app.get('db')

  const name = 'taskWorks'
  const options = { Model: db, name }

  app.use(name, feathersKnex(options))
  app.service(name).hooks(hooks)
}

const hooks = {
  before: {},
  after: {
    create: [
      iff(taskRecipeIsCompleteOrderSetup, createCastOrderIntentTaskPlan),
      iff(taskRecipeIsCompleteOrderSetup, createCloseOrderTaskPlan),
      iff(taskRecipeIsCloseOrder, createCastOrderIntentTaskWorks),
      iff(taskRecipeIsCloseOrder, createOrderPlans),
      iff(taskRecipeIsCloseOrder, createViewOrderSummaryTaskPlan)
    ]
  },
  error: {}
}

function taskRecipeIsCompleteOrderSetup (hook) {
  return hook.data.taskRecipeId === 'completeOrderSetupWithPrereqs'
    || hook.data.taskRecipeId === 'completeOrderSetup'
}

function taskRecipeIsCloseOrder (hook) {
  return hook.data.taskRecipeId === 'closeOrder'
}

function createOrderPlans (hook) {
  const orders = hook.app.service('orders')
  const taskPlans = hook.app.service('taskPlans')
  const orderIntents = hook.app.service('orderIntents')
  const orderPlans = hook.app.service('orderPlans')
  const priceSpecs = hook.app.service('priceSpecs')
  return taskPlans.get(hook.data.taskPlanId)
    .then((taskPlan) => {
      return orders.get(taskPlan.params.orderId)
    })
    .then((order) => {
      return orderIntents.find({
        query: {
          orderId: order.id
        }
      })
    })
    .then((queriedOrderIntents) => {
      // TODO: IK: similar logic will also be needed on the client for showing the current state of the order per product - i.e. which priceSpec is currently going to be enforced
      // this is logic which can be expressed as: given a set of orderIntents (and related priceSpecs), what is the desiredQuantity and applicable priceSpecId per product of the orderIntents?
      // actually, thinking about this again, probably easier to just get / query for all the possible priceSpecs... will query for more records but saves a whole logic step, plus means back and front logic is more similar, perhaps even the same

      const getUniqPriceSpecIds = pipe(map(prop('priceSpecId')), uniq)
      return priceSpecs.find({
        query: {
          id: {
            $in: getUniqPriceSpecIds(queriedOrderIntents)
          }
        }
      })
      .then((queriedPriceSpecs) => {
        // for each productId of the orderIntents, sum the 'quantity' field of all orderIntents with the same productId
        const groupByProductId = groupBy(prop('productId'))
        // we need to sum the quantities at each priceSpec
        const groupByPriceSpecId = groupBy(prop('priceSpecId'))
        const mapToQuantities = map(prop('desiredQuantity'))
        // const priceSpecQuantitiesByProductId = map(, orderIntentsByProductId)
        // const quantitiesOrderedByProductId = map((intent) => sum(map(prop('desiredQuantity'), intent)), orderIntentsByProductId)
        // find the priceSpec for each productId where the summed quantity is equal to or greater than the 'minimum' (but only the priceSpec with the largest minimum)
        // need to test how combos of query params work in conjunction

        const priceSpecsByProductId = pipe(
          groupByProductId,
          map(pipe(
            sortBy(prop('minimum')),
            reverse
          ))
        )(queriedPriceSpecs)

        const getCollectiveQuantityAndPriceSpec = pipe(
          groupByProductId,
          map(pipe(
            groupByPriceSpecId,
            map(pipe(
              mapToQuantities,
              sum
            )),
          )),
          // map()
          tap(console.log)
        )
        return getCollectiveQuantityAndPriceSpec(queriedOrderIntents)
      })

      // console.log('all orderd by productId is: ', quantitiesOrderedByProductId)
      // return Promise.all(values(
      //   mapObjIndexed((quantity, productId) => {
      //     return priceSpecs.find({
      //       query: {
      //         productId,
      //         $limit: 1,
      //         $sort: {
      //           minimum: -1
      //         },
      //         minimum: {
      //           $lte: quantity
      //         }
      //       }
      //     })
      //   }, quantitiesOrderedByProductId)
      // ))
      // .then((queriedPriceSpecs) => {
      //   console.log('price specs: ', queriedPriceSpecs)
      //   // might need to flatten() queriedPriceSpecs
      //   // might want to groupBy on queriedPriceSpecs to group them by productId (might be better to use keyBy if it exists?)
      //   // for each unique combination of an orderIntent's agentId and productId, create a single orderPlan with the found priceSpecId
      //   // if no found priceSpecId, this means the combined orderIntents didn't meet a minimum quantity, therefore no orderPlan for that product
      //   // const matchedOrderIntents = filter()
      // })

      // return Promise.all(
      //   map((orderIntent) => {
      //     return orderPlans.create({
      //       orderId: orderIntent.orderId,
      //       agentId: orderIntent.agentId,
      //       quantity: orderIntent.desiredQuantity,
      //       productId: orderIntent.productId,
      //       priceSpecId: orderIntent.priceSpecId
      //     })
      //   }, orderIntents)
      // )
    })
    .then(() => hook)
}

function createCastOrderIntentTaskPlan (hook) {
  const taskPlans = hook.app.service('taskPlans')
  const orders = hook.app.service('orders')
  const relationships = hook.app.service('relationships')
  const taskRecipeId = taskRecipes.castIntent.id
  const completeOrderTaskPlanId = hook.data.taskPlanId

  return taskPlans.get(completeOrderTaskPlanId)
  .then((completeOrderTaskPlan) => {
    const orderId = completeOrderTaskPlan.params.orderId
    return orders.get(orderId)
  })
  .then((order) => {
    const { id, consumerAgentId, supplierAgentId, adminAgentId } = order
    const params = { orderId: id, consumerAgentId, supplierAgentId, adminAgentId }
    return Promise.all([
      Promise.resolve(params),
      relationships.find({
        query: {
          sourceId: consumerAgentId,
          relationshipType: 'member'
        }
      })
    ])
  })
  .then(([params, relationships]) => {
    return Promise.all(
      map((relationship) => {
        const assigneeId = prop('targetId', relationship)
        return taskPlans.create({ taskRecipeId, params, assigneeId })
      }, relationships)
    )
  })
  .then(() => hook)
}

function createCloseOrderTaskPlan (hook) {
  const taskPlans = hook.app.service('taskPlans')
  const orders = hook.app.service('orders')
  const taskRecipeId = taskRecipes.closeOrder.id
  const completedTaskPlanId = hook.result.taskPlanId

  return taskPlans.get(completedTaskPlanId)
    .then((completedTaskPlan) => {
      const { orderId } = completedTaskPlan.params
      return orders.get(orderId)
    })
    .then((order) => {
      const { id, adminAgentId } = order
      const params = {
        orderId: id,
      }
      return taskPlans.create({ taskRecipeId, params, assigneeId: adminAgentId })
    })
    .then(() => {
      return hook
    })
}

function createCastOrderIntentTaskWorks (hook) {
  // order has closed, get all relevant taskPlans, create a taskWork for em
  const taskPlans = hook.app.service('taskPlans')
  const taskWorks = hook.app.service('taskWorks')
  const closeOrderTaskPlanId = hook.data.taskPlanId

  return taskPlans.get(closeOrderTaskPlanId)
    .then((closeOrderTaskPlan) => {
      const orderId = closeOrderTaskPlan.params.orderId
      // const params = { orderId, consumerAgentId: groupId, supplierAgentId }

      // TODO: IK: feels like a pretty sub-optimal way of querying, probably makes sense to have orderId as it's own column
      return taskPlans.find({
        query: {
          taskRecipeId: 'castIntent',
          params: {
            $like: `%"orderId":${orderId}%`
          }
        }
      })
        .then((taskPlans) => {
          return Promise.all(taskPlans.map((taskPlan) => {
            const { id, taskRecipeId, assigneeId, params } = taskPlan
            return taskWorks.create({
              taskPlanId: id,
              taskRecipeId,
              workerAgentId: assigneeId,
              params
            })
          }))
        })
    })
    .then(() => hook)
}

function createViewOrderSummaryTaskPlan (hook) {
  const taskPlans = hook.app.service('taskPlans')
  const orders = hook.app.service('orders')
  const taskRecipeId = taskRecipes.viewOrderSummary.id
  const closeOrderTaskPlanId = hook.data.taskPlanId

  return taskPlans.get(closeOrderTaskPlanId)
    .then((closeOrderTaskPlan) => {
      const orderId = closeOrderTaskPlan.params.orderId
      return orders.get(orderId)
    })
    .then((order) => {
      const { id, adminAgentId } = order
      const params = { orderId: id }
      return taskPlans.create({ taskRecipeId, params, assigneeId: adminAgentId })
    })
    .then(() => {
      return hook
    })
}
<|endoftext|>


<commit_before>/**
 * ngStomp
 *
 * @version 0.4.0
 * @author Maik Hummel <m@ikhummel.com>
 * @license MIT
 */

/*global
    angular, SockJS, Stomp */
(function () {
  angular
    .module('ngStomp', [])
    .service('$stomp', [
      '$rootScope', '$q',
      function ($rootScope, $q) {
        this.sock = null
        this.stomp = null
        this.debug = null

        this.setDebug = function (callback) {
          this.debug = callback
        }

        this.connect = function (endpoint, headers, errorCallback, sockjsOpts) {
          headers = headers || {}
          sockjsOpts = sockjsOpts || {}

          var dfd = $q.defer()

          this.sock = new SockJS(endpoint, null, sockjsOpts)
          this.sock.onclose = function () {
            if (angular.isFunction(errorCallback)) {
              errorCallback(new Error('Connection broken'))
            }
          }

          this.stomp = Stomp.over(this.sock)
          this.stomp.debug = this.debug
          this.stomp.connect(headers, function (frame) {
            dfd.resolve(frame)
          }, function (err) {
            dfd.reject(err)
            if (angular.isFunction(errorCallback)) {
              errorCallback(err)
            }
          })

          return dfd.promise
        }

        this.disconnect = function () {
          var dfd = $q.defer()
          this.stomp.disconnect(dfd.resolve)
          return dfd.promise
        }

        this.subscribe = this.on = function (destination, callback, headers) {
          headers = headers || {}
          return this.stomp.subscribe(destination, function (res) {
            var payload = null
            try {
              payload = JSON.parse(res.body)
            } finally {
              if (callback) {
                callback(payload, res.headers, res)
              }
            }
          }, headers)
        }

        this.unsubscribe = this.off = function (subscription) {
          subscription.unsubscribe()
        }

        this.send = function (destination, body, headers) {
          var dfd = $q.defer()
          try {
            var payloadJson = JSON.stringify(body)
            headers = headers || {}
            this.stomp.send(destination, headers, payloadJson)
            dfd.resolve()
          } catch (e) {
            dfd.reject(e)
          }
          return dfd.promise
        }
      }]
  )
})()
<commit_msg>Update ng-stomp.js<commit_after>/**
 * ngStomp
 *
 * @version 0.4.0
 * @author Maik Hummel <m@ikhummel.com>
 * @license MIT
 */

/*global
    angular, SockJS, Stomp */
(function () {
  angular
    .module('ngStomp', [])
    .service('$stomp', [
      '$rootScope', '$q',
      function ($rootScope, $q) {
        this.sock = null
        this.stomp = null
        this.debug = null

        this.setDebug = function (callback) {
          this.debug = callback
        }

        this.connect = function (endpoint, headers, errorCallback, sockjsOpts) {
          headers = headers || {}
          sockjsOpts = sockjsOpts || {}

          var dfd = $q.defer()

          this.sock = new SockJS(endpoint, null, sockjsOpts)
          this.sock.onclose = function () {
            if (angular.isFunction(errorCallback)) {
              errorCallback(new Error('Connection broken'))
            }
          }

          this.stomp = Stomp.over(this.sock)
          this.stomp.debug = this.debug
          this.stomp.connect(headers, function (frame) {
            dfd.resolve(frame)
          }, function (err) {
            dfd.reject(err)
            if (angular.isFunction(errorCallback)) {
              errorCallback(err)
            }
          })

          return dfd.promise
        }

        this.disconnect = function () {
          var dfd = $q.defer()
          this.stomp.disconnect(dfd.resolve)
          return dfd.promise
        }

        this.subscribe = this.on = function (destination, callback, headers) {
          headers = headers || {}
          return this.stomp.subscribe(destination, function (res) {
            var payload = null
            try {
              payload = JSON.parse(res.body)
            } finally {
              if (callback) {
                callback(payload, res.headers, res)
              }
            }
          }, headers)
        }

        this.unsubscribe = this.off = function (subscription) {
          subscription.unsubscribe()
        }

        this.send = function (destination, body, headers) {
          var dfd = $q.defer()
          try {
            var payloadJson = JSON.stringify(body)
            headers = headers || {}
            this.stomp.send(destination, headers, payloadJson)
            dfd.resolve()
          } catch (e) {
            dfd.reject(e)
          }
          return dfd.promise
        }
      }]
  )
})();
<|endoftext|>


<commit_before>var
		regexpWhitespace = /\s/g,
		regexpLinearCondition = /([!]?[\w\.-]+)([!<>=]{1,2})?([^\|&]+)?([\|&]{2})?/g,
		regexpEscapedChar = {
			"'": /\\'/g,
			'"': /\\"/g,
			'{': /\\\{/g,
			'>': /\\>/g,
			';': /\\>/g
		},
		regexpTabsAndNL = /[\t\n\r]{1,}/g,
		regexpMultipleSpaces = / {2,}/g,

		hasOwnProp = {}.hasOwnProperty;<commit_msg>[fix] regexp: \w in range<commit_after>var
		regexpWhitespace = /\s/g,
		regexpLinearCondition = /([!]?[A-Za-z0-9_\-\.]+)([!<>=]{1,2})?([^\|&]+)?([\|&]{2})?/g,
		regexpEscapedChar = {
			"'": /\\'/g,
			'"': /\\"/g,
			'{': /\\\{/g,
			'>': /\\>/g,
			';': /\\>/g
		},
		regexpTabsAndNL = /[\t\n\r]{1,}/g,
		regexpMultipleSpaces = / {2,}/g,

		hasOwnProp = {}.hasOwnProperty;<|endoftext|>


<commit_before>/*
 * teleprolly
 * https://github.com/marcoscaceres/teleprolly
 *
 * Copyright (c) 2013 Marcos Caceres
 * Licensed under the MIT license.
 */

require.config({
	paths: {
		"deps": "../deps",
		"DOM": "../deps/DOM",
		"WebIDL": "../webidl/lib/WebIDL",
		"deps/webidlParser": "../webidl/deps/webidlParser",

		//create alias to plugins (not needed if plugins are on the baseUrl)
        async: '../deps/require-plugins/async',
        goog: '../deps/require-plugins/goog',
        json: '../deps/require-plugins/json',
        noext: '../deps/require-plugins/noext',
        propertyParser : '../deps/sync/propertyParser'
	}
});

// convert Futures into an AMD module
define('Futures', ['DOM/Futures'],
function(){
    // return the gmaps namespace for brevity
    return window.Future;
});

// convert Google Maps into an AMD module
define('Geocoder', ['async!http://maps.google.com/maps/api/js?v=3&sensor=false'],
function(){
    // return the gmaps namespace for brevity
    return new window.google.maps.Geocoder();
});

require(["interfaces/Navigator"]);<commit_msg>fixing paths<commit_after>/*
 * teleprolly
 * https://github.com/marcoscaceres/teleprolly
 *
 * Copyright (c) 2013 Marcos Caceres
 * Licensed under the MIT license.
 */

require.config({
	paths: {
		"deps": "../deps",
		"DOM": "../deps/DOM",
		"WebIDL": "../webidl/lib/WebIDL",
		"deps/webidlParser": "../webidl/deps/webidlParser",
		"DOM/Futures" : "../deps/DOM/Futures",
		"DOM/EventHandler": "../deps/DOM/EventHandler",
		"DOM/EventTarget" : "../deps/DOM/EventTarget",

		//create alias to plugins (not needed if plugins are on the baseUrl)
        async: '../deps/require-plugins/async',
        goog: '../deps/require-plugins/goog',
        json: '../deps/require-plugins/json',
        noext: '../deps/require-plugins/noext',
        propertyParser : '../deps/sync/propertyParser'
	}
});

// convert Futures into an AMD module
define('Futures', ['DOM/Futures'],
function(){
    // return the gmaps namespace for brevity
    return window.Future;
});

// convert Google Maps into an AMD module
define('Geocoder', ['async!http://maps.google.com/maps/api/js?v=3&sensor=false'],
function(){
    // return the gmaps namespace for brevity
    return new window.google.maps.Geocoder();
});

require(["interfaces/Navigator"]);<|endoftext|>


<commit_before>import getStream from 'get-stream'
import humanFormat from 'human-format'
import React from 'react'
import ReadableStream from 'readable-stream'
import { connect } from 'react-redux'
import { FormattedDate } from 'react-intl'
import {
  clone,
  escapeRegExp,
  every,
  forEach,
  isArray,
  isEmpty,
  isFunction,
  isPlainObject,
  isString,
  join,
  keys,
  map,
  mapValues,
  replace,
  sample,
  startsWith,
} from 'lodash'

import _ from './intl'
import * as actions from './store/actions'
import BaseComponent from './base-component'
import invoke from './invoke'
import store from './store'
import { getObject } from './selectors'

export const EMPTY_ARRAY = Object.freeze([])
export const EMPTY_OBJECT = Object.freeze({})

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

export addSubscriptions from './add-subscriptions'

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

export const ensureArray = value => {
  if (value === undefined) {
    return []
  }

  return Array.isArray(value) ? value : [value]
}

export const propsEqual = (o1, o2, props) => {
  props = ensureArray(props)

  for (const prop of props) {
    if (o1[prop] !== o2[prop]) {
      return false
    }
  }

  return true
}

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

export const checkPropsState = (propsNames, stateNames) => Component => {
  const nProps = propsNames && propsNames.length
  const nState = stateNames && stateNames.length

  Component.prototype.shouldComponentUpdate = (newProps, newState) => {
    const { props, state } = this

    for (let i = 0; i < nProps; ++i) {
      const name = propsNames[i]
      if (newProps[name] !== props[name]) {
        return true
      }
    }

    for (let i = 0; i < nState; ++i) {
      const name = stateNames[i]
      if (newState[name] !== state[name]) {
        return true
      }
    }
  }

  return Component
}

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

const _normalizeMapStateToProps = mapper => {
  if (isFunction(mapper)) {
    const factoryOrMapper = (state, props) => {
      const result = mapper(state, props)

      // Properly handles factory pattern.
      if (isFunction(result)) {
        mapper = result
        return factoryOrMapper
      }

      if (isPlainObject(result)) {
        if (isEmpty(result)) {
          // Nothing can be determined, wait for it.
          return result
        }

        if (every(result, isFunction)) {
          indirection = (state, props) =>
            mapValues(result, selector => selector(state, props))
          return indirection(state, props)
        }
      }

      indirection = mapper
      return result
    }

    let indirection = factoryOrMapper
    return (state, props) => indirection(state, props)
  }

  mapper = mapValues(mapper, _normalizeMapStateToProps)
  return (state, props) => mapValues(mapper, fn => fn(state, props))
}

export const connectStore = (mapStateToProps, opts = {}) => {
  const connector = connect(
    _normalizeMapStateToProps(mapStateToProps),
    actions,
    undefined,
    opts
  )

  return Component => {
    const ConnectedComponent = connector(Component)

    if (opts.withRef && 'value' in Component.prototype) {
      Object.defineProperty(ConnectedComponent.prototype, 'value', {
        configurable: true,
        get () {
          return this.getWrappedInstance().value
        },
        set (value) {
          this.getWrappedInstance().value = value
        },
      })
    }

    return ConnectedComponent
  }
}

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

export { default as Debug } from './debug'

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

// Returns the current XOA Plan or the Plan name if number given
export const getXoaPlan = plan => {
  switch (plan || +process.env.XOA_PLAN) {
    case 1:
      return 'Free'
    case 2:
      return 'Starter'
    case 3:
      return 'Enterprise'
    case 4:
      return 'Premium'
    case 5:
      return 'Community'
  }
  return 'Unknown'
}

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

export const mapPlus = (collection, cb) => {
  const result = []
  const push = ::result.push
  forEach(collection, (value, index) => cb(value, push, index))
  return result
}

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

export const noop = () => {}

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

export const osFamily = invoke(
  {
    centos: ['centos'],
    debian: ['debian'],
    docker: ['coreos'],
    fedora: ['fedora'],
    freebsd: ['freebsd'],
    gentoo: ['gentoo'],
    'linux-mint': ['linux-mint'],
    netbsd: ['netbsd'],
    oracle: ['oracle'],
    osx: ['osx'],
    redhat: ['redhat', 'rhel'],
    solaris: ['solaris'],
    suse: ['sles', 'suse'],
    ubuntu: ['ubuntu'],
    windows: ['windows'],
  },
  osByFamily => {
    const osToFamily = Object.create(null)
    forEach(osByFamily, (list, family) => {
      forEach(list, os => {
        osToFamily[os] = family
      })
    })

    return osName => osName && osToFamily[osName.toLowerCase()]
  }
)

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

export const formatSize = bytes =>
  humanFormat(bytes, { scale: 'binary', unit: 'B' })

export const formatSizeShort = bytes =>
  humanFormat(bytes, { scale: 'binary', unit: 'B', decimals: 0 })

export const formatSizeRaw = bytes =>
  humanFormat.raw(bytes, { scale: 'binary', unit: 'B' })

export const formatSpeed = (bytes, milliseconds) =>
  humanFormat(bytes * 1e3 / milliseconds, { scale: 'binary', unit: 'B/s' })

export const parseSize = size => {
  let bytes = humanFormat.parse.raw(size, { scale: 'binary' })
  if (bytes.unit && bytes.unit !== 'B') {
    bytes = humanFormat.parse.raw(size)

    if (bytes.unit && bytes.unit !== 'B') {
      throw new Error('invalid size: ' + size)
    }
  }
  return Math.floor(bytes.value * bytes.factor)
}

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

export const normalizeXenToolsStatus = status => {
  if (status === false) {
    return 'not-installed'
  }
  if (status === undefined) {
    return 'unknown'
  }
  if (status === 'up to date') {
    return 'up-to-date'
  }
  return 'out-of-date'
}

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

const _NotFound = () =>
{_('errorPageNotFound')}

// Decorator to declare routes on a component.
//
// TODO: add support for function childRoutes (getChildRoutes).
export const routes = (indexRoute, childRoutes) => target => {
  if (isArray(indexRoute)) {
    childRoutes = indexRoute
    indexRoute = undefined
  } else if (isFunction(indexRoute)) {
    indexRoute = {
      component: indexRoute,
    }
  } else if (isString(indexRoute)) {
    indexRoute = {
      onEnter: invoke(indexRoute, pathname => (state, replace) => {
        const current = state.location.pathname
        replace((current === '/' ? '' : current) + '/' + pathname)
      }),
    }
  }

  if (isPlainObject(childRoutes)) {
    childRoutes = map(childRoutes, (component, path) => {
      // The logic can be bypassed by passing a plain object.
      if (isPlainObject(component)) {
        return { ...component, path }
      }

      return { ...component.route, component, path }
    })
  }

  if (childRoutes) {
    childRoutes.push({ component: _NotFound, path: '*' })
  }

  target.route = {
    indexRoute,
    childRoutes,
  }

  return target
}

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

// Creates a new function which throws an error.
//
// ```js
// promise.catch(throwFn('an error has occured'))
//
// function foo (param = throwFn('param is required')) {}
// ```
export const throwFn = error => () => {
  throw isString(error) ? new Error(error) : error
}

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

export const resolveResourceSet = resourceSet => {
  if (!resourceSet) {
    return
  }

  const { objects, ipPools, ...attrs } = resourceSet
  const resolvedObjects = {}
  const resolvedSet = {
    ...attrs,
    missingObjects: [],
    objectsByType: resolvedObjects,
    ipPools,
  }
  const state = store.getState()

  forEach(objects, id => {
    const object = getObject(state, id, true) // true: useResourceSet to bypass permissions

    // Error, missing resource.
    if (!object) {
      resolvedSet.missingObjects.push(id)
      return
    }

    const { type } = object

    if (!resolvedObjects[type]) {
      resolvedObjects[type] = [object]
    } else {
      resolvedObjects[type].push(object)
    }
  })

  return resolvedSet
}

export const resolveResourceSets = resourceSets =>
  map(resourceSets, resolveResourceSet)

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

// Creates a string replacer based on a pattern and a list of rules
//
// ```js
// const myReplacer = buildTemplate('{name}_COPY_{name}_{id}_%', {
//   '{name}': vm => vm.name_label,
//   '{id}': vm => vm.id,
//   '%': (_, i) => i
// })
//
// const newString = myReplacer({
//   name_label: 'foo',
//   id: 42,
// }, 32)
//
// newString === 'foo_COPY_foo_42_32'
// ```
export function buildTemplate (pattern, rules) {
  const regExp = new RegExp(join(map(keys(rules), escapeRegExp), '|'), 'g')
  return (...params) =>
    replace(pattern, regExp, match => {
      const rule = rules[match]
      return isFunction(rule) ? rule(...params) : rule
    })
}

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

export const streamToString = getStream

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

/* global FileReader */

// Creates a readable stream from a HTML file.
export const htmlFileToStream = file => {
  const reader = new FileReader()
  const stream = new ReadableStream()
  let offset = 0

  reader.onloadend = evt => {
    stream.push(evt.target.result)
  }
  reader.onerror = error => {
    stream.emit('error', error)
  }

  stream._read = function (size) {
    if (offset >= file.size) {
      stream.push(null)
    } else {
      reader.readAsBinaryString(file.slice(offset, offset + size))
      offset += size
    }
  }

  return stream
}

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

export const resolveId = value =>
  value != null && typeof value === 'object' && 'id' in value ? value.id : value

export const resolveIds = params => {
  for (const key in params) {
    const param = params[key]
    if (param != null && typeof param === 'object' && 'id' in param) {
      params[key] = param.id
    }
  }
  return params
}

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

const OPs = {
  '<': a => a < 0,
  '<=': a => a <= 0,
  '===': a => a === 0,
  '>': a => a > 0,
  '>=': a => a >= 0,
}

const makeNiceCompare = compare =>
  function () {
    const { length } = arguments
    if (length === 2) {
      return compare(arguments[0], arguments[1])
    }

    let i = 1
    let v1 = arguments[0]
    let op, v2
    while (i < length) {
      op = arguments[i++]
      v2 = arguments[i++]
      if (!OPs[op](compare(v1, v2))) {
        return false
      }
      v1 = v2
    }
    return true
  }

export const compareVersions = makeNiceCompare((v1, v2) => {
  v1 = v1.split('.')
  v2 = v2.split('.')

  for (let i = 0; i < Math.max(v1.length, v2.length); i++) {
    const n1 = +v1[i] || 0
    const n2 = +v2[i] || 0

    if (n1 < n2) return -1
    if (n1 > n2) return 1
  }

  return 0
})

export const isXosanPack = ({ name }) => startsWith(name, 'XOSAN')

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

export const getCoresPerSocketPossibilities = (maxCoresPerSocket, vCPUs) => {
  // According to : https://www.citrix.com/blogs/2014/03/11/citrix-xenserver-setting-more-than-one-vcpu-per-vm-to-improve-application-performance-and-server-consolidation-e-g-for-cad3-d-graphical-applications/
  const maxVCPUs = 16

  const options = []
  if (maxCoresPerSocket !== undefined && vCPUs !== '') {
    const ratio = vCPUs / maxVCPUs

    for (
      let coresPerSocket = maxCoresPerSocket;
      coresPerSocket >= ratio;
      coresPerSocket--
    ) {
      if (vCPUs % coresPerSocket === 0) options.push(coresPerSocket)
    }
  }

  return options
}

// Generates a random human-readable string of length `length`
// Useful to generate random default names intended for the UI user
export const generateReadableRandomString = (() => {
  const CONSONANTS = 'bdfgklmnprtvz'.split('')
  const VOWELS = 'aeiou'.split('')
  return (length = 8) => {
    const result = new Array(length)
    for (let i = 0; i < length; ++i) {
      result[i] = sample((i & 1) === 0 ? VOWELS : CONSONANTS)
    }
    return result.join('')
  }
})()

export const cowSet = (object, path, value, depth = 0) => {
  if (depth >= path.length) {
    return value
  }

  object = object != null ? clone(object) : {}
  const prop = path[depth]
  object[prop] = cowSet(object[prop], path, value, depth + 1)
  return object
}

// Generates a function that returns a value between 0 and 1
// This function returns an estimated progress value between 0 and 1
// based on the elapsed time since the createFakeProgress call and
// the given estimated duration d
//
// const getProgress = createFakeProgress(120)
// setInterval(() => console.log(`Progress: ${getProgress() * 100} %`), 1000)
export const createFakeProgress = (() => {
  const S = 0.95 // Progress value after d seconds
  return d => {
    const startTime = Date.now() / 1e3
    return () => {
      const x = Date.now() / 1e3 - startTime
      return -Math.exp(x * Math.log(1 - S) / d) + 1
    }
  }
})()

export const ShortDate = ({ timestamp }) => (
  <FormattedDate value={timestamp} month='short' day='numeric' year='numeric' />
)
<commit_msg>chore(utils): remove unused checkPropsState<commit_after>import getStream from 'get-stream'
import humanFormat from 'human-format'
import React from 'react'
import ReadableStream from 'readable-stream'
import { connect } from 'react-redux'
import { FormattedDate } from 'react-intl'
import {
  clone,
  escapeRegExp,
  every,
  forEach,
  isArray,
  isEmpty,
  isFunction,
  isPlainObject,
  isString,
  join,
  keys,
  map,
  mapValues,
  replace,
  sample,
  startsWith,
} from 'lodash'

import _ from './intl'
import * as actions from './store/actions'
import invoke from './invoke'
import store from './store'
import { getObject } from './selectors'

export const EMPTY_ARRAY = Object.freeze([])
export const EMPTY_OBJECT = Object.freeze({})

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

export addSubscriptions from './add-subscriptions'

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

export const ensureArray = value => {
  if (value === undefined) {
    return []
  }

  return Array.isArray(value) ? value : [value]
}

export const propsEqual = (o1, o2, props) => {
  props = ensureArray(props)

  for (const prop of props) {
    if (o1[prop] !== o2[prop]) {
      return false
    }
  }

  return true
}

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

const _normalizeMapStateToProps = mapper => {
  if (isFunction(mapper)) {
    const factoryOrMapper = (state, props) => {
      const result = mapper(state, props)

      // Properly handles factory pattern.
      if (isFunction(result)) {
        mapper = result
        return factoryOrMapper
      }

      if (isPlainObject(result)) {
        if (isEmpty(result)) {
          // Nothing can be determined, wait for it.
          return result
        }

        if (every(result, isFunction)) {
          indirection = (state, props) =>
            mapValues(result, selector => selector(state, props))
          return indirection(state, props)
        }
      }

      indirection = mapper
      return result
    }

    let indirection = factoryOrMapper
    return (state, props) => indirection(state, props)
  }

  mapper = mapValues(mapper, _normalizeMapStateToProps)
  return (state, props) => mapValues(mapper, fn => fn(state, props))
}

export const connectStore = (mapStateToProps, opts = {}) => {
  const connector = connect(
    _normalizeMapStateToProps(mapStateToProps),
    actions,
    undefined,
    opts
  )

  return Component => {
    const ConnectedComponent = connector(Component)

    if (opts.withRef && 'value' in Component.prototype) {
      Object.defineProperty(ConnectedComponent.prototype, 'value', {
        configurable: true,
        get () {
          return this.getWrappedInstance().value
        },
        set (value) {
          this.getWrappedInstance().value = value
        },
      })
    }

    return ConnectedComponent
  }
}

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

export { default as Debug } from './debug'

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

// Returns the current XOA Plan or the Plan name if number given
export const getXoaPlan = plan => {
  switch (plan || +process.env.XOA_PLAN) {
    case 1:
      return 'Free'
    case 2:
      return 'Starter'
    case 3:
      return 'Enterprise'
    case 4:
      return 'Premium'
    case 5:
      return 'Community'
  }
  return 'Unknown'
}

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

export const mapPlus = (collection, cb) => {
  const result = []
  const push = ::result.push
  forEach(collection, (value, index) => cb(value, push, index))
  return result
}

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

export const noop = () => {}

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

export const osFamily = invoke(
  {
    centos: ['centos'],
    debian: ['debian'],
    docker: ['coreos'],
    fedora: ['fedora'],
    freebsd: ['freebsd'],
    gentoo: ['gentoo'],
    'linux-mint': ['linux-mint'],
    netbsd: ['netbsd'],
    oracle: ['oracle'],
    osx: ['osx'],
    redhat: ['redhat', 'rhel'],
    solaris: ['solaris'],
    suse: ['sles', 'suse'],
    ubuntu: ['ubuntu'],
    windows: ['windows'],
  },
  osByFamily => {
    const osToFamily = Object.create(null)
    forEach(osByFamily, (list, family) => {
      forEach(list, os => {
        osToFamily[os] = family
      })
    })

    return osName => osName && osToFamily[osName.toLowerCase()]
  }
)

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

export const formatSize = bytes =>
  humanFormat(bytes, { scale: 'binary', unit: 'B' })

export const formatSizeShort = bytes =>
  humanFormat(bytes, { scale: 'binary', unit: 'B', decimals: 0 })

export const formatSizeRaw = bytes =>
  humanFormat.raw(bytes, { scale: 'binary', unit: 'B' })

export const formatSpeed = (bytes, milliseconds) =>
  humanFormat(bytes * 1e3 / milliseconds, { scale: 'binary', unit: 'B/s' })

export const parseSize = size => {
  let bytes = humanFormat.parse.raw(size, { scale: 'binary' })
  if (bytes.unit && bytes.unit !== 'B') {
    bytes = humanFormat.parse.raw(size)

    if (bytes.unit && bytes.unit !== 'B') {
      throw new Error('invalid size: ' + size)
    }
  }
  return Math.floor(bytes.value * bytes.factor)
}

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

export const normalizeXenToolsStatus = status => {
  if (status === false) {
    return 'not-installed'
  }
  if (status === undefined) {
    return 'unknown'
  }
  if (status === 'up to date') {
    return 'up-to-date'
  }
  return 'out-of-date'
}

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

const _NotFound = () =>
{_('errorPageNotFound')}

// Decorator to declare routes on a component.
//
// TODO: add support for function childRoutes (getChildRoutes).
export const routes = (indexRoute, childRoutes) => target => {
  if (isArray(indexRoute)) {
    childRoutes = indexRoute
    indexRoute = undefined
  } else if (isFunction(indexRoute)) {
    indexRoute = {
      component: indexRoute,
    }
  } else if (isString(indexRoute)) {
    indexRoute = {
      onEnter: invoke(indexRoute, pathname => (state, replace) => {
        const current = state.location.pathname
        replace((current === '/' ? '' : current) + '/' + pathname)
      }),
    }
  }

  if (isPlainObject(childRoutes)) {
    childRoutes = map(childRoutes, (component, path) => {
      // The logic can be bypassed by passing a plain object.
      if (isPlainObject(component)) {
        return { ...component, path }
      }

      return { ...component.route, component, path }
    })
  }

  if (childRoutes) {
    childRoutes.push({ component: _NotFound, path: '*' })
  }

  target.route = {
    indexRoute,
    childRoutes,
  }

  return target
}

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

// Creates a new function which throws an error.
//
// ```js
// promise.catch(throwFn('an error has occured'))
//
// function foo (param = throwFn('param is required')) {}
// ```
export const throwFn = error => () => {
  throw isString(error) ? new Error(error) : error
}

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

export const resolveResourceSet = resourceSet => {
  if (!resourceSet) {
    return
  }

  const { objects, ipPools, ...attrs } = resourceSet
  const resolvedObjects = {}
  const resolvedSet = {
    ...attrs,
    missingObjects: [],
    objectsByType: resolvedObjects,
    ipPools,
  }
  const state = store.getState()

  forEach(objects, id => {
    const object = getObject(state, id, true) // true: useResourceSet to bypass permissions

    // Error, missing resource.
    if (!object) {
      resolvedSet.missingObjects.push(id)
      return
    }

    const { type } = object

    if (!resolvedObjects[type]) {
      resolvedObjects[type] = [object]
    } else {
      resolvedObjects[type].push(object)
    }
  })

  return resolvedSet
}

export const resolveResourceSets = resourceSets =>
  map(resourceSets, resolveResourceSet)

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

// Creates a string replacer based on a pattern and a list of rules
//
// ```js
// const myReplacer = buildTemplate('{name}_COPY_{name}_{id}_%', {
//   '{name}': vm => vm.name_label,
//   '{id}': vm => vm.id,
//   '%': (_, i) => i
// })
//
// const newString = myReplacer({
//   name_label: 'foo',
//   id: 42,
// }, 32)
//
// newString === 'foo_COPY_foo_42_32'
// ```
export function buildTemplate (pattern, rules) {
  const regExp = new RegExp(join(map(keys(rules), escapeRegExp), '|'), 'g')
  return (...params) =>
    replace(pattern, regExp, match => {
      const rule = rules[match]
      return isFunction(rule) ? rule(...params) : rule
    })
}

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

export const streamToString = getStream

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

/* global FileReader */

// Creates a readable stream from a HTML file.
export const htmlFileToStream = file => {
  const reader = new FileReader()
  const stream = new ReadableStream()
  let offset = 0

  reader.onloadend = evt => {
    stream.push(evt.target.result)
  }
  reader.onerror = error => {
    stream.emit('error', error)
  }

  stream._read = function (size) {
    if (offset >= file.size) {
      stream.push(null)
    } else {
      reader.readAsBinaryString(file.slice(offset, offset + size))
      offset += size
    }
  }

  return stream
}

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

export const resolveId = value =>
  value != null && typeof value === 'object' && 'id' in value ? value.id : value

export const resolveIds = params => {
  for (const key in params) {
    const param = params[key]
    if (param != null && typeof param === 'object' && 'id' in param) {
      params[key] = param.id
    }
  }
  return params
}

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

const OPs = {
  '<': a => a < 0,
  '<=': a => a <= 0,
  '===': a => a === 0,
  '>': a => a > 0,
  '>=': a => a >= 0,
}

const makeNiceCompare = compare =>
  function () {
    const { length } = arguments
    if (length === 2) {
      return compare(arguments[0], arguments[1])
    }

    let i = 1
    let v1 = arguments[0]
    let op, v2
    while (i < length) {
      op = arguments[i++]
      v2 = arguments[i++]
      if (!OPs[op](compare(v1, v2))) {
        return false
      }
      v1 = v2
    }
    return true
  }

export const compareVersions = makeNiceCompare((v1, v2) => {
  v1 = v1.split('.')
  v2 = v2.split('.')

  for (let i = 0; i < Math.max(v1.length, v2.length); i++) {
    const n1 = +v1[i] || 0
    const n2 = +v2[i] || 0

    if (n1 < n2) return -1
    if (n1 > n2) return 1
  }

  return 0
})

export const isXosanPack = ({ name }) => startsWith(name, 'XOSAN')

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

export const getCoresPerSocketPossibilities = (maxCoresPerSocket, vCPUs) => {
  // According to : https://www.citrix.com/blogs/2014/03/11/citrix-xenserver-setting-more-than-one-vcpu-per-vm-to-improve-application-performance-and-server-consolidation-e-g-for-cad3-d-graphical-applications/
  const maxVCPUs = 16

  const options = []
  if (maxCoresPerSocket !== undefined && vCPUs !== '') {
    const ratio = vCPUs / maxVCPUs

    for (
      let coresPerSocket = maxCoresPerSocket;
      coresPerSocket >= ratio;
      coresPerSocket--
    ) {
      if (vCPUs % coresPerSocket === 0) options.push(coresPerSocket)
    }
  }

  return options
}

// Generates a random human-readable string of length `length`
// Useful to generate random default names intended for the UI user
export const generateReadableRandomString = (() => {
  const CONSONANTS = 'bdfgklmnprtvz'.split('')
  const VOWELS = 'aeiou'.split('')
  return (length = 8) => {
    const result = new Array(length)
    for (let i = 0; i < length; ++i) {
      result[i] = sample((i & 1) === 0 ? VOWELS : CONSONANTS)
    }
    return result.join('')
  }
})()

export const cowSet = (object, path, value, depth = 0) => {
  if (depth >= path.length) {
    return value
  }

  object = object != null ? clone(object) : {}
  const prop = path[depth]
  object[prop] = cowSet(object[prop], path, value, depth + 1)
  return object
}

// Generates a function that returns a value between 0 and 1
// This function returns an estimated progress value between 0 and 1
// based on the elapsed time since the createFakeProgress call and
// the given estimated duration d
//
// const getProgress = createFakeProgress(120)
// setInterval(() => console.log(`Progress: ${getProgress() * 100} %`), 1000)
export const createFakeProgress = (() => {
  const S = 0.95 // Progress value after d seconds
  return d => {
    const startTime = Date.now() / 1e3
    return () => {
      const x = Date.now() / 1e3 - startTime
      return -Math.exp(x * Math.log(1 - S) / d) + 1
    }
  }
})()

export const ShortDate = ({ timestamp }) => (
  <FormattedDate value={timestamp} month='short' day='numeric' year='numeric' />
)
<|endoftext|>