<commit_before>/*
 * Copyright 2013 Andrey Sitnik <andrey@sitnik.ru>,
 * sponsored by Evil Martians.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
(function () {
'use strict';

var rework = require('rework');

// Return array, that doesn’t contain duplicates.
var uniq = function (array) {
    var filtered = [];
    array.forEach(function (i) {
        if ( filtered.indexOf(i) === -1 ) {
            filtered.push(i);
        }
    });
    return filtered;
};

// Split prefix and property name.
var splitPrefix = function (prop) {
    if ( prop[0] === '-' ) {
        var sep = prop.indexOf('-', 1) + 1;
        return { prefix: prop.slice(0, sep), name: prop.slice(sep) };
    } else {
        return { prefix: null, name: prop };
    }
};

// Generate RegExp to test, does CSS value contain some `word`.
var containRegexp = function (word) {
    return new RegExp('(^|\\s|,|\\()' +
               word.replace(/([.?*+\^\$\[\]\\(){}|\-])/g, "\\$1") +
               '($|\\s|\\()', 'ig');
};

// Throw error with `messages with mark, that is from Autoprefixer.
var error = function (message) {
    var err = new Error(message);
    err.autoprefixer = true;
    throw err;
};

// Parse CSS and add prefixed properties and values by Can I Use database
// for actual browsers.
//
//   var prefixed = autoprefixer.compile(css);
//
// By default, it add prefixes for last 2 releases of each browsers.
// You can use global statistics to select browsers:
//
//   autoprefixer.compile(css, '> 1%');
//
// versions fo each browsers:
//
//   autoprefixer.compile(css, 'last 1 version');
//
// or set them manually:
//
//   autoprefixer.compile(css, ['chrome 26', 'ff 20', 'ie 10']);
//
// If you want to combine Autoprefixer with another Rework filters,
// you can use it as separated filter:
//
//   rework(css).
//     use(autoprefixer.rework(last 1 version')).
//     toString();
var autoprefixer = {
    // Load data
    data: {
        browsers: require('../data/browsers'),
        values:   require('../data/values'),
        props:    require('../data/props')
    },

    // Parse `css` by Rework and add prefixed properties for browsers
    // in `requirements`.
    compile: function (css, requirements) {
        return rework(css).use(autoprefixer.rework(requirements)).toString();
    },

    // Return Rework filter, which will add necessary prefixes for browsers
    // in `requirements`.
    rework: function (requirements) {
        if ( !requirements ) {
            requirements = [];
        } else if ( !Array.isArray(requirements) ) {
            requirements = [requirements];
        }

        var browsers   = this.parse(requirements);
        var values     = this.filter(this.data.values, browsers);
        var props      = this.filter(this.data.props,  browsers);
        var prefixes   = this.prefixes(props, values);
        var unprefixes = this.unprefixes(props, values);

        return function (style) {
            autoprefixer.unprefixer(unprefixes, style);
            autoprefixer.prefixer(prefixes, style);
        };
    },

    // Change `style` declarations in parsed CSS, to add prefixes for `props`.
    prefixer: function (props, style) {
        var all      = props['*'];
        var prefixes = ['-webkit-', '-moz-', '-ms-', '-o-'];

        var transitions = { };
        for ( var i in props ) {
            if ( props[i].transition && props[i].prefixes ) {
                transitions[i] = props[i];
            }
        }
        var isTransition = /(-(webkit|moz|ms|o)-)?transition(-property)?/;

        // Keyframes
        if ( props['@keyframes'] ) {
            style.rules.forEach(function(rule) {
                if ( !rule.keyframes ) {
                    return;
                }

                props['@keyframes'].prefixes.forEach(function (prefix) {
                    var contain = style.rules.some(function (other) {
                        return other.keyframes && rule.name === other.name &&
                               other.vendor === prefix;
                    });
                    if ( contain ) {
                        return;
                    }

                    var clone = { name: rule.name };
                    clone.vendor = rule.vendor;
                    clone.keyframes = [];
                    rule.keyframes.forEach(function (keyframe) {
                        var keyframeClone          = { };
                        keyframeClone.values       = keyframe.values.slice();
                        keyframeClone.declarations = keyframe.declarations.map(
                            function (i) {
                                return { property: i.property, value: i.value };
                            });

                        clone.keyframes.push(keyframeClone);
                    });

                    clone.vendor = prefix;
                    style.rules.push(clone);
                });
             });
        }

        rework.visit.declarations(style, function (rules, node) {
            var vendor = node.vendor;

            var contain = function (rules, prop, value) {
                return rules.some(function (rule) {
                    return rule.property === prop && rule.value === value;
                });
            };
            var add = function (rules, num, prop, value) {
                if ( contain(rules, prop, value) ) {
                    return num;
                }

                rules.splice(num, 0, { property: prop, value: value });
                return num + 1;
            };
            var num, rule, prop;

            // Properties
            for ( num = 0; num < rules.length; num += 1 ) {
                rule = rules[num];
                prop = props[rule.property];

                if ( !prop || !prop.prefixes ) {
                    continue;
                }
                if ( prop.check && !prop.check.call(rule.value, rule) ) {
                    continue;
                }

                prop.prefixes.forEach(function (prefix) {
                    if ( vendor && vendor !== prefix ) {
                        return;
                    }
                    var wrong = prefixes.some(function (other) {
                        if ( other === prefix ) {
                            return false;
                        }
                        return rule.value.indexOf(other) !== -1;
                    });
                    if ( wrong ) {
                        return;
                    }

                    num = add(rules, num, prefix + rule.property, rule.value);
                });
            }

            // Values
            for ( num = 0; num < rules.length; num += 1 ) {
                rule = rules[num];

                var split      = splitPrefix(rule.property);
                var propVendor = split.prefix || vendor;
                prop = props[split.name];

                var valuePrefixer = function (values) {
                    var prefixed = { };

                    for ( var name in values ) {
                        var value = values[name];
                        if ( !rule.value.match(value.regexp) ) {
                            continue;
                        }

                        value.prefixes.forEach(function (prefix) {
                            if ( propVendor && propVendor !== prefix ) {
                                return;
                            }
                            if ( !prefixed[prefix]) {
                                prefixed[prefix] = rule.value;
                            }
                            if ( value.replace ) {
                                if ( prefixed[prefix].match(value.regexp) ) {
                                    var replaced = value.replace(
                                        prefixed[prefix], prefix);
                                    if ( replaced ) {
                                        prefixed[prefix] = replaced;
                                        return;
                                    }
                                }
                            }
                            prefixed[prefix] = prefixed[prefix].replace(
                                value.regexp, '$1' + prefix + name + '$2');
                        });
                    }

                    for ( var prefix in prefixed ) {
                        if ( prefixed[prefix] !== rule.value ) {
                            if ( propVendor ) {
                                var exists = contain(rules, rule.property,
                                                     prefixed[prefix]);
                                if ( exists ) {
                                    rules.splice(num, 1);
                                } else {
                                    rule.value = prefixed[prefix];
                                }
                            } else {
                                num = add(rules, num, rule.property,
                                          prefixed[prefix]);
                            }
                        }
                    }
                };

                if ( all ) {
                    valuePrefixer(all.values);
                }
                if ( prop ) {
                    valuePrefixer(prop.values);
                }
                if ( rule.property.match(isTransition) ) {
                    valuePrefixer(transitions);
                }
            }
        });
    },

    // Change `style` declarations in parsed CSS, to remove `remove`.
    unprefixer: function (remove, style) {
        var all = remove.values['*'];

        // Keyframes
        style.rules = style.rules.filter(function (rule) {
            return !(rule.keyframes && remove.keyframes[rule.vendor]);
        });

        rework.visit.declarations(style, function (rules) {
            for ( var num = 0; num < rules.length; num += 1 ) {
                var rule = rules[num];

                // Properties
                if ( remove.props[rule.property] ) {
                    rules.splice(num, 1);
                    continue;
                }

                // Values
                var prop   = splitPrefix(rule.property).name;
                var values = all;
                if ( remove.values[prop] ) {
                    values = values.concat(remove.values[prop]);
                }
                if ( prop === 'transition' || prop === 'transition-property' ) {
                    values = values.concat(remove.transition);
                }
                values.forEach(function (value) {
                    if ( rule.value.match(value) ) {
                        rules.splice(num, 1);
                        return false;
                    }
                });
            }
        });
    },

    // Return array of browsers for requirements in free form.
    parse: function (requirements) {
        if ( requirements.length === 0 ) {
            requirements = ['last 2 versions'];
        }

        var match;
        var browsers = [];
        requirements.map(function (req) {

          if ( match = req.match(/^last (\d+) versions?$/i) ) {
              return autoprefixer.browsers(function(browser) {
                  return browser.versions.slice(0, match[1]);
              });

          } else if ( match = req.match(/^> (\d+(\.\d+)?)%$/i) ) {
              return autoprefixer.browsers(function(browser) {
                  return browser.versions.filter(function (version, i) {
                      return browser.popularity[i] > match[1];
                  });
              });

          } else {
              return [autoprefixer.check(req)];
          }

        }).forEach(function (reqBrowsers) {
            browsers = browsers.concat(reqBrowsers);
        });
        return uniq(browsers);
    },

    // Select browsers by some `criteria`.
    browsers: function (criteria) {
        var selected = [];
        for ( var name in this.data.browsers ) {
            var browser  = this.data.browsers[name];
            var versions = criteria(browser).map(function (version) {
                return name + ' ' + version;
            });
            selected = selected.concat(versions);
        }
        return selected;
    },

    // Check browser name and reduce version if them from future.
    check: function (req) {
        req = req.split(/\s+/);
        if ( req.length > 2 ) {
            error('Unknown browsers requirement `' + req.join(' ')  + '`');
        }

        var name    = req[0];
        var version = parseFloat(req[1]);

        var data = this.data.browsers[name];
        if ( !data ) {
            error('Unknown browser `' + name + '`');
        }
        if ( !version ) {
            error("Can't recognize version in `" + req + '`');
        }

        var last = data.versions[0];
        if ( data.future && data.future[0] ) {
            last = data.future[0];
        }

        if ( version > last ) {
            version = last;
        }
        if ( version < data.versions[data.versions.length - 1] ) {
            version = data.versions[data.versions.length - 1];
        }

        return name + ' ' + version;
    },

    // Return new `data` only with items, which need prefixes
    // for selected `browsers`.
    filter: function (data, browsers) {
        var selected = { };
        for ( var name in data ) {
            var need     = data[name].browsers;
            var prefixes = browsers.filter(function (browser) {
                return need.indexOf(browser) !== -1;
            }).map(function (browser) {
                var key = browser.split(' ')[0];
                return autoprefixer.data.browsers[key].prefix;
            }).sort(function (a, b) { return b.length - a.length; });

            if ( prefixes.length ) {
                prefixes = uniq(prefixes);

                var obj = {
                    prefixes: prefixes,
                    browsers: browsers
                };
                for ( var key in data[name] ) {
                    if ( key === 'browsers' ) {
                        continue;
                    }
                    obj[key] = data[name][key];
                }

                if ( obj.props || obj.transition ) {
                    obj.regexp = containRegexp(name);
                }

                selected[name] = obj;
            }
        }
        return selected;
    },

    // Return properties, which them prefixed values inside.
    prefixes: function (props, values) {
        for ( var name in values ) {
            values[name].props.forEach(function (prop) {
                if ( !props[prop] ) {
                    props[prop] = { values: { } };
                } else if ( !props[prop].values ) {
                    props[prop].values = { };
                }

                props[prop].values[name] = values[name];
            });
        }

        return props;
    },

    // Return old properties and values to remove.
    unprefixes: function (props, values) {
        var remove = { props: {}, values: {}, transition: [], keyframes: {} };
        var name, prefixes, prop, value, names;

        for ( name in this.data.props ) {
            prop     = this.data.props[name];
            prefixes = prop.browsers.map(function (b) {
                var key = b.split(' ')[0];
                return autoprefixer.data.browsers[key].prefix;
            });
            uniq(prefixes).filter(function (prefix) {
                if ( !props[name] ) {
                    return true;
                }
                return props[name].prefixes.indexOf(prefix) === -1;
            }).forEach(function (prefix) {
                if ( prop.transition ) {
                    remove.transition.push(containRegexp(prefix + name));
                }
                if ( name === '@keyframes' ) {
                    remove.keyframes[prefix] = true;
                } else {
                    if ( prop.prefixed && prop.prefixed[prefix] ) {
                        remove.props[prop.prefixed[prefix]] = true;
                    } else {
                        remove.props[prefix + name] = true;
                    }
                }
            });
        }

        for ( name in this.data.values ) {
            value = this.data.values[name];
            prefixes = value.browsers.map(function (b) {
                var key = b.split(' ')[0];
                return autoprefixer.data.browsers[key].prefix;
            });
            names = uniq(prefixes).filter(function (prefix) {
                if ( !values[name] ) {
                    return true;
                }
                return values[name].prefixes.indexOf(prefix) === -1;
            }).map(function (prefix) {
                return containRegexp(prefix + name);
            });

            value.props.forEach(function (prop) {
                if ( !remove.values[prop] ) {
                    remove.values[prop] = [];
                }
                remove.values[prop] = remove.values[prop].concat(names);
            });
        }

        return remove;
    }
};

module.exports = autoprefixer;
})();
<commit_msg>Clean up code by Rules object<commit_after>/*
 * Copyright 2013 Andrey Sitnik <andrey@sitnik.ru>,
 * sponsored by Evil Martians.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
(function () {
'use strict';

var rework = require('rework');

// Return array, that doesn’t contain duplicates.
var uniq = function (array) {
    var filtered = [];
    array.forEach(function (i) {
        if ( filtered.indexOf(i) === -1 ) {
            filtered.push(i);
        }
    });
    return filtered;
};

// Split prefix and property name.
var splitPrefix = function (prop) {
    if ( prop[0] === '-' ) {
        var sep = prop.indexOf('-', 1) + 1;
        return { prefix: prop.slice(0, sep), name: prop.slice(sep) };
    } else {
        return { prefix: null, name: prop };
    }
};

// Generate RegExp to test, does CSS value contain some `word`.
var containRegexp = function (word) {
    return new RegExp('(^|\\s|,|\\()' +
               word.replace(/([.?*+\^\$\[\]\\(){}|\-])/g, "\\$1") +
               '($|\\s|\\()', 'ig');
};

// Throw error with `messages with mark, that is from Autoprefixer.
var error = function (message) {
    var err = new Error(message);
    err.autoprefixer = true;
    throw err;
};

// Class to edit rules array inside forEach.
var Rules = function(rules) {
    this.rules = rules;
};
Rules.prototype = {
    // Execute `callback` on every rule.
    forEach: function (callback) {
        for ( this.num = 0; this.num < this.rules.length; this.num += 1 ) {
            callback(this.rules[this.num]);
        }
    },

    // Check that rules contain rule with `prop` and `values`.
    contain: function (prop, value) {
        return this.rules.some(function (rule) {
            return rule.property === prop && rule.value === value;
        });
    },

    // Add new rule with `prop` and `value`.
    add: function (prop, value) {
        if ( this.contain(prop, value) ) {
            return;
        }

        this.rules.splice(this.num, 0, { property: prop, value: value });
        this.num += 1;
    },

    // Remove current rule.
    removeCurrent: function () {
        this.rules.splice(this.num, 1);
    }
};

// Parse CSS and add prefixed properties and values by Can I Use database
// for actual browsers.
//
//   var prefixed = autoprefixer.compile(css);
//
// By default, it add prefixes for last 2 releases of each browsers.
// You can use global statistics to select browsers:
//
//   autoprefixer.compile(css, '> 1%');
//
// versions fo each browsers:
//
//   autoprefixer.compile(css, 'last 1 version');
//
// or set them manually:
//
//   autoprefixer.compile(css, ['chrome 26', 'ff 20', 'ie 10']);
//
// If you want to combine Autoprefixer with another Rework filters,
// you can use it as separated filter:
//
//   rework(css).
//     use(autoprefixer.rework(last 1 version')).
//     toString();
var autoprefixer = {
    // Load data
    data: {
        browsers: require('../data/browsers'),
        values:   require('../data/values'),
        props:    require('../data/props')
    },

    // Parse `css` by Rework and add prefixed properties for browsers
    // in `requirements`.
    compile: function (css, requirements) {
        return rework(css).use(autoprefixer.rework(requirements)).toString();
    },

    // Return Rework filter, which will add necessary prefixes for browsers
    // in `requirements`.
    rework: function (requirements) {
        if ( !requirements ) {
            requirements = [];
        } else if ( !Array.isArray(requirements) ) {
            requirements = [requirements];
        }

        var browsers   = this.parse(requirements);
        var values     = this.filter(this.data.values, browsers);
        var props      = this.filter(this.data.props,  browsers);
        var prefixes   = this.prefixes(props, values);
        var unprefixes = this.unprefixes(props, values);

        return function (style) {
            autoprefixer.unprefixer(unprefixes, style);
            autoprefixer.prefixer(prefixes, style);
        };
    },

    // Change `style` declarations in parsed CSS, to add prefixes for `props`.
    prefixer: function (props, style) {
        var all      = props['*'];
        var prefixes = ['-webkit-', '-moz-', '-ms-', '-o-'];

        var transitions = { };
        for ( var i in props ) {
            if ( props[i].transition && props[i].prefixes ) {
                transitions[i] = props[i];
            }
        }
        var isTransition = /(-(webkit|moz|ms|o)-)?transition(-property)?/;

        // Keyframes
        if ( props['@keyframes'] ) {
            style.rules.forEach(function(rule) {
                if ( !rule.keyframes ) {
                    return;
                }

                props['@keyframes'].prefixes.forEach(function (prefix) {
                    var contain = style.rules.some(function (other) {
                        return other.keyframes && rule.name === other.name &&
                               other.vendor === prefix;
                    });
                    if ( contain ) {
                        return;
                    }

                    var clone = { name: rule.name };
                    clone.vendor = rule.vendor;
                    clone.keyframes = [];
                    rule.keyframes.forEach(function (keyframe) {
                        var keyframeClone          = { };
                        keyframeClone.values       = keyframe.values.slice();
                        keyframeClone.declarations = keyframe.declarations.map(
                            function (i) {
                                return { property: i.property, value: i.value };
                            });

                        clone.keyframes.push(keyframeClone);
                    });

                    clone.vendor = prefix;
                    style.rules.push(clone);
                });
             });
        }

        rework.visit.declarations(style, function (list, node) {
            var rules = new Rules(list);

            // Properties
            rules.forEach(function (rule) {
                var prop = props[rule.property];

                if ( !prop || !prop.prefixes ) {
                    return;
                }
                if ( prop.check && !prop.check.call(rule.value, rule) ) {
                    return;
                }

                prop.prefixes.forEach(function (prefix) {
                    if ( node.vendor && node.vendor !== prefix ) {
                        return;
                    }
                    var wrong = prefixes.some(function (other) {
                        if ( other === prefix ) {
                            return false;
                        }
                        return rule.value.indexOf(other) !== -1;
                    });
                    if ( wrong ) {
                        return;
                    }

                    rules.add(prefix + rule.property, rule.value);
                });
            });

            // Values
            rules.forEach(function (rule) {
                var split  = splitPrefix(rule.property);
                var vendor = split.prefix || node.vendor;
                var prop   = props[split.name];

                var valuePrefixer = function (values) {
                    var prefixed = { };

                    for ( var name in values ) {
                        var value = values[name];
                        if ( !rule.value.match(value.regexp) ) {
                            continue;
                        }

                        value.prefixes.forEach(function (prefix) {
                            if ( vendor && vendor !== prefix ) {
                                return;
                            }
                            if ( !prefixed[prefix]) {
                                prefixed[prefix] = rule.value;
                            }
                            if ( value.replace ) {
                                if ( prefixed[prefix].match(value.regexp) ) {
                                    var replaced = value.replace(
                                        prefixed[prefix], prefix);
                                    if ( replaced ) {
                                        prefixed[prefix] = replaced;
                                        return;
                                    }
                                }
                            }
                            prefixed[prefix] = prefixed[prefix].replace(
                                value.regexp, '$1' + prefix + name + '$2');
                        });
                    }

                    for ( var prefix in prefixed ) {
                        if ( prefixed[prefix] !== rule.value ) {
                            if ( vendor ) {
                                var exists = rules.contain(
                                    rule.property, prefixed[prefix]);
                                if ( exists ) {
                                    rules.removeCurrent();
                                } else {
                                    rule.value = prefixed[prefix];
                                }
                            } else {
                                rules.add(rule.property, prefixed[prefix]);
                            }
                        }
                    }
                };

                if ( all ) {
                    valuePrefixer(all.values);
                }
                if ( prop ) {
                    valuePrefixer(prop.values);
                }
                if ( rule.property.match(isTransition) ) {
                    valuePrefixer(transitions);
                }
            });
        });
    },

    // Change `style` declarations in parsed CSS, to remove `remove`.
    unprefixer: function (remove, style) {
        var all = remove.values['*'];

        // Keyframes
        style.rules = style.rules.filter(function (rule) {
            return !(rule.keyframes && remove.keyframes[rule.vendor]);
        });

        rework.visit.declarations(style, function (rules) {
            for ( var num = 0; num < rules.length; num += 1 ) {
                var rule = rules[num];

                // Properties
                if ( remove.props[rule.property] ) {
                    rules.splice(num, 1);
                    continue;
                }

                // Values
                var prop   = splitPrefix(rule.property).name;
                var values = all;
                if ( remove.values[prop] ) {
                    values = values.concat(remove.values[prop]);
                }
                if ( prop === 'transition' || prop === 'transition-property' ) {
                    values = values.concat(remove.transition);
                }
                values.forEach(function (value) {
                    if ( rule.value.match(value) ) {
                        rules.splice(num, 1);
                        return false;
                    }
                });
            }
        });
    },

    // Return array of browsers for requirements in free form.
    parse: function (requirements) {
        if ( requirements.length === 0 ) {
            requirements = ['last 2 versions'];
        }

        var match;
        var browsers = [];
        requirements.map(function (req) {

          if ( match = req.match(/^last (\d+) versions?$/i) ) {
              return autoprefixer.browsers(function(browser) {
                  return browser.versions.slice(0, match[1]);
              });

          } else if ( match = req.match(/^> (\d+(\.\d+)?)%$/i) ) {
              return autoprefixer.browsers(function(browser) {
                  return browser.versions.filter(function (version, i) {
                      return browser.popularity[i] > match[1];
                  });
              });

          } else {
              return [autoprefixer.check(req)];
          }

        }).forEach(function (reqBrowsers) {
            browsers = browsers.concat(reqBrowsers);
        });
        return uniq(browsers);
    },

    // Select browsers by some `criteria`.
    browsers: function (criteria) {
        var selected = [];
        for ( var name in this.data.browsers ) {
            var browser  = this.data.browsers[name];
            var versions = criteria(browser).map(function (version) {
                return name + ' ' + version;
            });
            selected = selected.concat(versions);
        }
        return selected;
    },

    // Check browser name and reduce version if them from future.
    check: function (req) {
        req = req.split(/\s+/);
        if ( req.length > 2 ) {
            error('Unknown browsers requirement `' + req.join(' ')  + '`');
        }

        var name    = req[0];
        var version = parseFloat(req[1]);

        var data = this.data.browsers[name];
        if ( !data ) {
            error('Unknown browser `' + name + '`');
        }
        if ( !version ) {
            error("Can't recognize version in `" + req + '`');
        }

        var last = data.versions[0];
        if ( data.future && data.future[0] ) {
            last = data.future[0];
        }

        if ( version > last ) {
            version = last;
        }
        if ( version < data.versions[data.versions.length - 1] ) {
            version = data.versions[data.versions.length - 1];
        }

        return name + ' ' + version;
    },

    // Return new `data` only with items, which need prefixes
    // for selected `browsers`.
    filter: function (data, browsers) {
        var selected = { };
        for ( var name in data ) {
            var need     = data[name].browsers;
            var prefixes = browsers.filter(function (browser) {
                return need.indexOf(browser) !== -1;
            }).map(function (browser) {
                var key = browser.split(' ')[0];
                return autoprefixer.data.browsers[key].prefix;
            }).sort(function (a, b) { return b.length - a.length; });

            if ( prefixes.length ) {
                prefixes = uniq(prefixes);

                var obj = {
                    prefixes: prefixes,
                    browsers: browsers
                };
                for ( var key in data[name] ) {
                    if ( key === 'browsers' ) {
                        continue;
                    }
                    obj[key] = data[name][key];
                }

                if ( obj.props || obj.transition ) {
                    obj.regexp = containRegexp(name);
                }

                selected[name] = obj;
            }
        }
        return selected;
    },

    // Return properties, which them prefixed values inside.
    prefixes: function (props, values) {
        for ( var name in values ) {
            values[name].props.forEach(function (prop) {
                if ( !props[prop] ) {
                    props[prop] = { values: { } };
                } else if ( !props[prop].values ) {
                    props[prop].values = { };
                }

                props[prop].values[name] = values[name];
            });
        }

        return props;
    },

    // Return old properties and values to remove.
    unprefixes: function (props, values) {
        var remove = { props: {}, values: {}, transition: [], keyframes: {} };
        var name, prefixes, prop, value, names;

        for ( name in this.data.props ) {
            prop     = this.data.props[name];
            prefixes = prop.browsers.map(function (b) {
                var key = b.split(' ')[0];
                return autoprefixer.data.browsers[key].prefix;
            });
            uniq(prefixes).filter(function (prefix) {
                if ( !props[name] ) {
                    return true;
                }
                return props[name].prefixes.indexOf(prefix) === -1;
            }).forEach(function (prefix) {
                if ( prop.transition ) {
                    remove.transition.push(containRegexp(prefix + name));
                }
                if ( name === '@keyframes' ) {
                    remove.keyframes[prefix] = true;
                } else {
                    if ( prop.prefixed && prop.prefixed[prefix] ) {
                        remove.props[prop.prefixed[prefix]] = true;
                    } else {
                        remove.props[prefix + name] = true;
                    }
                }
            });
        }

        for ( name in this.data.values ) {
            value = this.data.values[name];
            prefixes = value.browsers.map(function (b) {
                var key = b.split(' ')[0];
                return autoprefixer.data.browsers[key].prefix;
            });
            names = uniq(prefixes).filter(function (prefix) {
                if ( !values[name] ) {
                    return true;
                }
                return values[name].prefixes.indexOf(prefix) === -1;
            }).map(function (prefix) {
                return containRegexp(prefix + name);
            });

            value.props.forEach(function (prop) {
                if ( !remove.values[prop] ) {
                    remove.values[prop] = [];
                }
                remove.values[prop] = remove.values[prop].concat(names);
            });
        }

        return remove;
    }
};

module.exports = autoprefixer;
})();
<|endoftext|>


<commit_before>var nOrg = (function nOrg() {
  // Properties prefixed with '$' are considered internal to the
  // UI/porcelain and will not be written back to the server.

  function Node() {
    this.init();
  }
  Node.prototype.init = function init() {
    // child nodes must override parent to avoid scope inheritance
    // leaking the cursor down
    this.$length = 0;
    this.$childHead = undefined;
    this.$childTail = undefined;
    this.$nextSibling = undefined;
    this.$prevSibling = undefined;
    this.$collapsed = true;
    this.$cursor = false;

    this.headers = new Headers(this);

    // Cursor initialization
    if (this.$root && (! this.$cursorObject)) {
      // Cursor defaults to first node
      this.cursorTo(this);
    }
  };
  Node.prototype.newChild = function newChild(object) {
    function Node() {
      this.init();
    }
    var child;
    Node.prototype = this;
    child = new Node();
    child.headers = this.headers.newChild(child);
    this.pushChild(child);

    if (object) {
      child.extend(object);
    }

    return child;
  };
  Node.prototype.pushChild = function pushChild(child) {
    // Take a child node and append it to this node as the last child
    child.$parent = this;
    if (this.$childHead) {
      child.$prevSibling = this.$childTail;
      this.$childTail.$nextSibling = child;
    } else {
      this.$childHead = child;
    }
    this.$childTail = child;
    this.$length++;
  }; Node.prototype.popFromParent = function popFromParent() {
    // Remove this node from it's parent
    this.$parent.$length--;

    if (this.$prevSibling) {
      this.$prevSibling.$nextSibling = this.$nextSibling;
    } else {
      this.$parent.$childHead = this.$nextSibling;
    }
    if (this.$nextSibling) {
      this.$nextSibling.$prevSibling = this.$prevSibling;
    } else {
      this.$parent.$childTail = this.$prevSibling;
    }

    this.$parent = undefined;
    this.$prevSibling = undefined;
    this.$nextSibling = undefined;
  };
  Node.prototype.children = function children() {
    // Avoid using this if there's a way to iterate
    var results = [];
    var child = this.$childHead;
    while (child) {
      results.push(child);
      child = child.$nextSibling;
    }
    return results;
  };
  Node.prototype.extend = function extend(object) {
    for (var key in object) {
      if (key === 'headers') {
        this.headers.extend(object.headers);
      } else if (key === 'children') {
        object.children.forEach(this.newChild, this);
      } else {
        this[key] = object[key];
      }
    }
  };
  Node.prototype.toId = function toId() {
    // Generate a valid HTML ID and CSS selector from the message
    // ID using base64 encoding
    return window.btoa(this.headers["Message-ID"]).slice(0, -1);
  };

  // Moving nodes

  Node.prototype.demote = function demote() {
    // Demote a node if appropriate
    var parent = this.$prevSibling;
    if (! parent) {
      throw new Error("Cannot demote first sibling!");
    }

    this.popFromParent();
    parent.$collapsed = false;
    parent.pushChild(this);
  };

  Node.prototype.promote = function promote() {
    // Promote a node if appropriate
    var $prevSibling = this.$parent;
    if (! $prevSibling.$parent) {
      throw new Error("Cannot promote nodes without parents!");
    }

    this.popFromParent();
    if (! $prevSibling.$childHead) {
      $prevSibling.collapsed = true;
    }

    this.$parent = $prevSibling.$parent;
    this.$prevSibling = $prevSibling;
    if ($prevSibling.$nextSibling) {
      this.$nextSibling = $prevSibling.$nextSibling;
      this.$nextSibling.$prevSibling = this;
    } else {
      this.$parent.$childTail = this;
    }
    $prevSibling.$nextSibling = this;
    this.$parent.$length++;
  };

  Node.prototype.moveUp = function moveUp() {
    // Move a node up relative to it's siblings if appropriate
    var $nextSibling = this.$prevSibling;
    if (! $nextSibling) {
      throw new Error("Cannot move first nodes up!");
    }

    $nextSibling.$nextSibling = this.$nextSibling;
    if (this.$nextSibling) {
      // not last child
      this.$nextSibling.$prevSibling = $nextSibling;
    } else {
      // now last child
      this.$parent.$childTail = $nextSibling;
    }
    this.$nextSibling = $nextSibling;

    this.$prevSibling = $nextSibling.$prevSibling;
    if ($nextSibling.$prevSibling) {
      // not first child
      this.$prevSibling = $nextSibling.$prevSibling;
      this.$prevSibling.$nextSibling = this;
    } else {
      // now first child
      this.$parent.$childHead = this;
    }
    $nextSibling.$prevSibling = this;
  };

  Node.prototype.moveDown = function moveDown() {
    // Move a node down relative to it's siblings if appropriate
    var $prevSibling = this.$nextSibling;
    if (! $prevSibling) {
      throw new Error("Cannot move last nodes down!");
    }

    $prevSibling.$prevSibling = this.$prevSibling;
    if (this.$prevSibling) {
      // not first child
      this.$prevSibling.$nextSibling = $prevSibling;
    } else {
      // now first child
      this.$parent.$childHead = $prevSibling;
    }
    this.$prevSibling = $prevSibling;

    this.$nextSibling = $prevSibling.$nextSibling;
    if (! this.$nextSibling) {
      // now last child
      this.$parent.$childTail = this;
    } else {
          this.$nextSibling.$prevSibling = this;
    }
    $prevSibling.$nextSibling = this;
  };

  // Root cursor state
  Node.prototype.cursorTo = function cursorTo(object, index) {
    if (typeof object == "undefined") {
      object = this;
    }
    if (this.$cursorObject) {
      this.$cursorObject.$cursor = false;
    }
    object.$cursor = true;
    this.$root.$cursorObject = object;
    this.$root.$cursorIndex = index;

    return object;
  };

  Node.prototype.cursorDown = function cursorDown(event) {
    var object = this.$cursorObject;
    if (event) {
      event.preventDefault();
    }

    if ((! object.headers) && object['NOrg-User-Headers'][this.$cursorIndex + 1]) {
      // next header
      return this.cursorTo(object, this.$cursorIndex + 1);
    } else if (object.headers && object.headers['NOrg-User-Headers'].length &&
               (! object.headers.$collapsed)) {
      // first expanded header
      return this.cursorTo(object.headers, 0);
    }

    // no more header cases
    object = object.$node || object;
    if (object.$length && (! object.$collapsed)) {
      // first expanded child
      return this.cursorTo(object.$childHead);
    }
    while ((! object.$nextSibling) && object.$parent.$parent) {
      object = object.$parent;
    }
    if (object.$nextSibling) {
      // next ancestor node with a next sibling
      return this.cursorTo(object.$nextSibling);
    }
    return false;
  };

  Node.prototype.cursorUp = function cursorUp(event) {
    var object = this.$cursorObject;
    var cursor;
    if (event) {
      event.preventDefault();
    }

    if (! object.headers) {
      if (object['NOrg-User-Headers'][this.$cursorIndex - 1]) {
        // previous header
        return this.cursorTo(object, this.$cursorIndex - 1);
      } else {
        // header node
        return this.cursorTo(object.$node);
      }
    }
    // no more header cases
    object = object.$node || object;

    if (object.$prevSibling &&
        object.$prevSibling.$length &&
        (! object.$prevSibling.$collapsed)) {
      // previous expanded $parent sibling last child
      cursor = object.$prevSibling.$childTail;
    }
    if (! object.$prevSibling) {
      if (object.$parent.$parent) {
        // parent
        cursor = object.$parent;
      }
    } else if (!cursor) {
      // previous sibling
      cursor = object.$prevSibling;
    }
    if (cursor) {
      if ((! cursor.headers.$collapsed) &&
          cursor.headers['NOrg-User-Headers'].length) {
        return this.cursorTo(cursor.headers,
                             cursor.headers['NOrg-User-Headers'].length - 1);
      } else {
        return this.cursorTo(cursor);
      }
    }
    return false;
  };

  Node.prototype.cursorRight = function cursorRight(event) {
    if (event) {
      event.preventDefault();
    }

    if (this.$cursorObject.headers &&
        (! this.$cursorObject.headers.$collapsed) &&
        this.$cursorObject.headers['NOrg-User-Headers'].length) {
      // first expanded header
      return this.cursorTo(this.$cursorObject.headers, 0);
    } else if (this.$cursorObject.$length) {
      // expand and move to first child
      this.$cursorObject.$collapsed = false;
      return this.cursorTo(this.$cursorObject.$childHead);
    }
    return false;
  };

  Node.prototype.cursorLeft = function cursorLeft(event) {
    if (event) {
      event.preventDefault();
    }

    if (! this.$cursorObject.headers) {
      return this.cursorTo(this.$cursorObject.$node);
    } else if (this.$cursorObject.$parent.$parent) {
      return this.cursorTo(this.$cursorObject.$parent);
    }
    return false;
  };

  // expand/collapse node
  Node.prototype.toggle = function toggle(event) {
    if (event) {
      event.preventDefault();
    }

    if (this.$cursorObject.$length) {
      this.$cursorObject.$collapsed = ! this.$cursorObject.$collapsed;
    }};

  // expand/collapse headers
  Node.prototype.toggleHeaders = function toggleHeaders(event) {
    var headers;
    if (event) {
      event.preventDefault();
    }

    headers = this.$cursorObject.headers || this.$cursorObject;
    if (headers['NOrg-User-Headers'].length) {
      if (headers.$node) {
        this.cursorTo(headers.$node);
      }
      headers.$collapsed = (! headers.$collapsed);
    }
  };

  function Headers(node) {
    this.init(node);
  }
  Headers.prototype.init = function init(node) {
    this.$node = node;
    this.$collapsed = true;
    this.$cursor = false;
    this['NOrg-User-Headers'] = [];
  };
  Headers.prototype.newChild = function newChild(node) {
    // prototypical inheritance from parent headerss
    function Headers() {}
    var child;
    Headers.prototype = this;
    child = new Headers();
    child.init(node);
    return child;
  };
  Headers.prototype.extend = function extend(object) {
    for (var key in object) {
      this[key] = object[key];
    }
    this['NOrg-User-Headers'] = object['NOrg-User-Headers'] || [];
  };
  Headers.prototype.push = function push(key, value) {
    this[key] = value;
    this['NOrg-User-Headers'].push(key);
  };

  function newRoot(object) {
    var root = new Node();
    root.$root = root;  // for looking up the root node
    root.headers.hiddenKeys = {"Subject": true, "Message-ID": true,
                               "collapsed": true};
    root.extend(object);
    return root;
  }

  return {
    Node: Node,
    Headers: Headers,
    newRoot: newRoot,
    root: newRoot()
  };
}());
<commit_msg>Oops, formatting<commit_after>var nOrg = (function nOrg() {
  // Properties prefixed with '$' are considered internal to the
  // UI/porcelain and will not be written back to the server.

  function Node() {
    this.init();
  }
  Node.prototype.init = function init() {
    // child nodes must override parent to avoid scope inheritance
    // leaking the cursor down
    this.$length = 0;
    this.$childHead = undefined;
    this.$childTail = undefined;
    this.$nextSibling = undefined;
    this.$prevSibling = undefined;
    this.$collapsed = true;
    this.$cursor = false;

    this.headers = new Headers(this);

    // Cursor initialization
    if (this.$root && (! this.$cursorObject)) {
      // Cursor defaults to first node
      this.cursorTo(this);
    }
  };
  Node.prototype.newChild = function newChild(object) {
    function Node() {
      this.init();
    }
    var child;
    Node.prototype = this;
    child = new Node();
    child.headers = this.headers.newChild(child);
    this.pushChild(child);

    if (object) {
      child.extend(object);
    }

    return child;
  };
  Node.prototype.pushChild = function pushChild(child) {
    // Take a child node and append it to this node as the last child
    child.$parent = this;
    if (this.$childHead) {
      child.$prevSibling = this.$childTail;
      this.$childTail.$nextSibling = child;
    } else {
      this.$childHead = child;
    }
    this.$childTail = child;
    this.$length++;
  };
  Node.prototype.popFromParent = function popFromParent() {
    // Remove this node from it's parent
    this.$parent.$length--;

    if (this.$prevSibling) {
      this.$prevSibling.$nextSibling = this.$nextSibling;
    } else {
      this.$parent.$childHead = this.$nextSibling;
    }
    if (this.$nextSibling) {
      this.$nextSibling.$prevSibling = this.$prevSibling;
    } else {
      this.$parent.$childTail = this.$prevSibling;
    }

    this.$parent = undefined;
    this.$prevSibling = undefined;
    this.$nextSibling = undefined;
  };
  Node.prototype.children = function children() {
    // Avoid using this if there's a way to iterate
    var results = [];
    var child = this.$childHead;
    while (child) {
      results.push(child);
      child = child.$nextSibling;
    }
    return results;
  };
  Node.prototype.extend = function extend(object) {
    for (var key in object) {
      if (key === 'headers') {
        this.headers.extend(object.headers);
      } else if (key === 'children') {
        object.children.forEach(this.newChild, this);
      } else {
        this[key] = object[key];
      }
    }
  };
  Node.prototype.toId = function toId() {
    // Generate a valid HTML ID and CSS selector from the message
    // ID using base64 encoding
    return window.btoa(this.headers["Message-ID"]).slice(0, -1);
  };

  // Moving nodes

  Node.prototype.demote = function demote() {
    // Demote a node if appropriate
    var parent = this.$prevSibling;
    if (! parent) {
      throw new Error("Cannot demote first sibling!");
    }

    this.popFromParent();
    parent.$collapsed = false;
    parent.pushChild(this);
  };

  Node.prototype.promote = function promote() {
    // Promote a node if appropriate
    var $prevSibling = this.$parent;
    if (! $prevSibling.$parent) {
      throw new Error("Cannot promote nodes without parents!");
    }

    this.popFromParent();
    if (! $prevSibling.$childHead) {
      $prevSibling.collapsed = true;
    }

    this.$parent = $prevSibling.$parent;
    this.$prevSibling = $prevSibling;
    if ($prevSibling.$nextSibling) {
      this.$nextSibling = $prevSibling.$nextSibling;
      this.$nextSibling.$prevSibling = this;
    } else {
      this.$parent.$childTail = this;
    }
    $prevSibling.$nextSibling = this;
    this.$parent.$length++;
  };

  Node.prototype.moveUp = function moveUp() {
    // Move a node up relative to it's siblings if appropriate
    var $nextSibling = this.$prevSibling;
    if (! $nextSibling) {
      throw new Error("Cannot move first nodes up!");
    }

    $nextSibling.$nextSibling = this.$nextSibling;
    if (this.$nextSibling) {
      // not last child
      this.$nextSibling.$prevSibling = $nextSibling;
    } else {
      // now last child
      this.$parent.$childTail = $nextSibling;
    }
    this.$nextSibling = $nextSibling;

    this.$prevSibling = $nextSibling.$prevSibling;
    if ($nextSibling.$prevSibling) {
      // not first child
      this.$prevSibling = $nextSibling.$prevSibling;
      this.$prevSibling.$nextSibling = this;
    } else {
      // now first child
      this.$parent.$childHead = this;
    }
    $nextSibling.$prevSibling = this;
  };

  Node.prototype.moveDown = function moveDown() {
    // Move a node down relative to it's siblings if appropriate
    var $prevSibling = this.$nextSibling;
    if (! $prevSibling) {
      throw new Error("Cannot move last nodes down!");
    }

    $prevSibling.$prevSibling = this.$prevSibling;
    if (this.$prevSibling) {
      // not first child
      this.$prevSibling.$nextSibling = $prevSibling;
    } else {
      // now first child
      this.$parent.$childHead = $prevSibling;
    }
    this.$prevSibling = $prevSibling;

    this.$nextSibling = $prevSibling.$nextSibling;
    if (! this.$nextSibling) {
      // now last child
      this.$parent.$childTail = this;
    } else {
          this.$nextSibling.$prevSibling = this;
    }
    $prevSibling.$nextSibling = this;
  };

  // Root cursor state
  Node.prototype.cursorTo = function cursorTo(object, index) {
    if (typeof object == "undefined") {
      object = this;
    }
    if (this.$cursorObject) {
      this.$cursorObject.$cursor = false;
    }
    object.$cursor = true;
    this.$root.$cursorObject = object;
    this.$root.$cursorIndex = index;

    return object;
  };

  Node.prototype.cursorDown = function cursorDown(event) {
    var object = this.$cursorObject;
    if (event) {
      event.preventDefault();
    }

    if ((! object.headers) && object['NOrg-User-Headers'][this.$cursorIndex + 1]) {
      // next header
      return this.cursorTo(object, this.$cursorIndex + 1);
    } else if (object.headers && object.headers['NOrg-User-Headers'].length &&
               (! object.headers.$collapsed)) {
      // first expanded header
      return this.cursorTo(object.headers, 0);
    }

    // no more header cases
    object = object.$node || object;
    if (object.$length && (! object.$collapsed)) {
      // first expanded child
      return this.cursorTo(object.$childHead);
    }
    while ((! object.$nextSibling) && object.$parent.$parent) {
      object = object.$parent;
    }
    if (object.$nextSibling) {
      // next ancestor node with a next sibling
      return this.cursorTo(object.$nextSibling);
    }
    return false;
  };

  Node.prototype.cursorUp = function cursorUp(event) {
    var object = this.$cursorObject;
    var cursor;
    if (event) {
      event.preventDefault();
    }

    if (! object.headers) {
      if (object['NOrg-User-Headers'][this.$cursorIndex - 1]) {
        // previous header
        return this.cursorTo(object, this.$cursorIndex - 1);
      } else {
        // header node
        return this.cursorTo(object.$node);
      }
    }
    // no more header cases
    object = object.$node || object;

    if (object.$prevSibling &&
        object.$prevSibling.$length &&
        (! object.$prevSibling.$collapsed)) {
      // previous expanded $parent sibling last child
      cursor = object.$prevSibling.$childTail;
    }
    if (! object.$prevSibling) {
      if (object.$parent.$parent) {
        // parent
        cursor = object.$parent;
      }
    } else if (!cursor) {
      // previous sibling
      cursor = object.$prevSibling;
    }
    if (cursor) {
      if ((! cursor.headers.$collapsed) &&
          cursor.headers['NOrg-User-Headers'].length) {
        return this.cursorTo(cursor.headers,
                             cursor.headers['NOrg-User-Headers'].length - 1);
      } else {
        return this.cursorTo(cursor);
      }
    }
    return false;
  };

  Node.prototype.cursorRight = function cursorRight(event) {
    if (event) {
      event.preventDefault();
    }

    if (this.$cursorObject.headers &&
        (! this.$cursorObject.headers.$collapsed) &&
        this.$cursorObject.headers['NOrg-User-Headers'].length) {
      // first expanded header
      return this.cursorTo(this.$cursorObject.headers, 0);
    } else if (this.$cursorObject.$length) {
      // expand and move to first child
      this.$cursorObject.$collapsed = false;
      return this.cursorTo(this.$cursorObject.$childHead);
    }
    return false;
  };

  Node.prototype.cursorLeft = function cursorLeft(event) {
    if (event) {
      event.preventDefault();
    }

    if (! this.$cursorObject.headers) {
      return this.cursorTo(this.$cursorObject.$node);
    } else if (this.$cursorObject.$parent.$parent) {
      return this.cursorTo(this.$cursorObject.$parent);
    }
    return false;
  };

  // expand/collapse node
  Node.prototype.toggle = function toggle(event) {
    if (event) {
      event.preventDefault();
    }

    if (this.$cursorObject.$length) {
      this.$cursorObject.$collapsed = ! this.$cursorObject.$collapsed;
    }};

  // expand/collapse headers
  Node.prototype.toggleHeaders = function toggleHeaders(event) {
    var headers;
    if (event) {
      event.preventDefault();
    }

    headers = this.$cursorObject.headers || this.$cursorObject;
    if (headers['NOrg-User-Headers'].length) {
      if (headers.$node) {
        this.cursorTo(headers.$node);
      }
      headers.$collapsed = (! headers.$collapsed);
    }
  };

  function Headers(node) {
    this.init(node);
  }
  Headers.prototype.init = function init(node) {
    this.$node = node;
    this.$collapsed = true;
    this.$cursor = false;
    this['NOrg-User-Headers'] = [];
  };
  Headers.prototype.newChild = function newChild(node) {
    // prototypical inheritance from parent headerss
    function Headers() {}
    var child;
    Headers.prototype = this;
    child = new Headers();
    child.init(node);
    return child;
  };
  Headers.prototype.extend = function extend(object) {
    for (var key in object) {
      this[key] = object[key];
    }
    this['NOrg-User-Headers'] = object['NOrg-User-Headers'] || [];
  };
  Headers.prototype.push = function push(key, value) {
    this[key] = value;
    this['NOrg-User-Headers'].push(key);
  };

  function newRoot(object) {
    var root = new Node();
    root.$root = root;  // for looking up the root node
    root.headers.hiddenKeys = {"Subject": true, "Message-ID": true,
                               "collapsed": true};
    root.extend(object);
    return root;
  }

  return {
    Node: Node,
    Headers: Headers,
    newRoot: newRoot,
    root: newRoot()
  };
}());
<|endoftext|>


<commit_before>/**
 *
 * Basic WiFi Manager for Linux based systems, like Raspberry Pi.
 * For network generation the generation is:
 *
 * 1. Generate the configuration file based on passed in SSID & network password.
 * 2. Start the HOSTAPD service based on the configuration file.
 * 3. Start the DHCP service.
 *
 *
 * If this code works it was created by Ken W. Alger on 8/28/2015.
 * If not, I don't know who wrote it.
 *
 */

var fs = require('fs');
var color = require('colors');

var COMMANDS = {
    dhcp: 'sudo service udhcpd start',
    dhcp_disable: 'sudo service udhcpd stop',
    host: 'sudo service hostapd start',
    host_disable: 'sudo service hostapd stop',
    host_status: 'sudo service hostapd status'
};

/**
 * Configuration of the Hostapd service
 * https://w1.fi/hostapd/
 *
 * hostapd is a user space daemon for access point and authentication servers.
 *
 */

var startHostapdService = require('child_process').exec,
    sudo_hostapd = startHostapdService(COMMANDS.host);

var stopHostapdService = require('child_process').exec,
    sudo_stopHostpd = stopHostapdService(COMMANDS.host_disable);

/**
 * Configures the start of the DHCP service, we are utilizing udhcpd
 * http://manpages.ubuntu.com/manpages/hardy/man8/udhcpd.8.html
 *
 * A very small DHCP server which negotiates leases with DHCP clients
 *
 */

var startDHCPService = require('child_process').exec,
    sudo_udhcpd = startDHCPService(COMMANDS.dhcp);

var stopDHCPService = require('child_process').exec,
    sudo_stopDHCP = stopDHCPService(COMMANDS.dhcp_disable);

/**
 * defaultValues for the hostapd.conf file
 *
 * @type {{interface: string, driver: string, ssid: string, hw_mode: string, channel: string, macaddr_acl: string, auth_algs: string, ignore_broadcast_ssid: string, wpa: string, wpa_passphrase: string, wpa_key_mgmt: string, wpa_pairwise: string, rsn_pairwise: string}}
 */

var defaultValues = {
    interface: "wlan0",
    driver: "rtl871xdrv",
    //ssid: "thingsSDK",
    hw_mode: "g",
    channel: "6",
    macaddr_acl: "0",
    auth_algs: "1",
    ignore_broadcast_ssid: "0",
    wpa: "2",
    //wpa_passphrase: "Chalkers",
    wpa_key_mgmt: "WPA-PSK",
    wpa_pairwise: "TKIP",
    rsn_pairwise: "CCMP"
};

/**
 * Generates the configuration key:value pairs for the configuration file.
 */

var fileoutput = Object.keys(defaultValues).map(function(key){
    return key + "=" + defaultValues[key];
}).join("\n");

function BasicManager () {

}

/**
 * createAdHocNetwork() configures the hostapd.conf file based on the ssid and password variables supplied and then
 * starts the required services.
 *
 * @param ssid The broadcasted network name
 * @param wpa_passphrase The password for network access, minimum 8 characters
 */

BasicManager.prototype.createAdHocNetwork = function (ssid, wpa_passphrase) {

    if (wpa_passphrase.length < 8) {
        console.log("\n" +"Password length too short. Must be at least 8 characters.".inverse.red);
        exit(0);
    }

    ssid = typeof ssid !== undefined ? ssid : 'thingsSDK';
    wpa_passphrase = typeof wpa_passphrase !== undefined ? wpa_passphrase : 'Chalkers';

    // Generate the hostapd.conf file required for the WiFi Network

    fs.writeFile("/etc/hostapd/hostapd.conf",
        fileoutput + "\n" +
        "ssid=" + ssid + "\n" +
        "wpa_passphrase=" + wpa_passphrase + "\n");

    console.log("\n[WIFIMANAGER] hostapd.conf was successfully saved.".yellow);
    console.info("[WIFIMANAGER] Network name: " + (ssid).green);
    console.info("[WIFIMANAGER] Network password: " + (wpa_passphrase).green);

    // Start the hostapd (wifi management service)
    // Using user: thingssdk, sudo access to start services restricted in the /etc/sudoer file

    console.log(("[WIFIMANAGER] Attempting to start HOSTAPD service for network " + ssid + ".").cyan);
    sudo_hostapd.stdout.on('data', function(data) {
        console.log('Starting HOSTAPD service - stdout: ' + data);
    });

    // Start the DHCP Server

    console.log("[WIFIMANAGER] Attempting to start UDHCPD service.".cyan);
    sudo_udhcpd.stdout.on('data', function(data) {
        console.log('Starting UDHCPD service - stdout: ' + data);
    });
};

BasicManager.prototype.connect = function() {
    //TODO: Connect the device to a network
};

BasicManager.prototype.isConnected = function() {
    //TODO: Check to see if the device is connected to any network
};

BasicManager.prototype.isAdHocNetwork = function() {
    //TODO: Check to see if the network to which the device is connected is an AdHoc network

    // if isConnected() is false, then we don't need to continue
    // if isConnected() is true, then check if network SSID is the same as the created network
}

/**
 * stopAdHocNetwork() stops the required services.
 */
BasicManager.prototype.stopAdHocNetwork = function() {

    // Stop the DHCP Service
    sudo_stopDHCP.stdout.on('data', function (data) {
        console.log(('Stopping the DHCP Service: \n' + data).red);
    });

    // Stop the Wifi Management Service
    sudo_stopHostpd.stdout.on('data', function(data) {
        console.log(('Stopping Hostapd Service = stdout: \n' + data).red);
    });
};

//BasicManager.createAdHocNetwork("someNetwork", "password");
module.exports = BasicManager;<commit_msg>password length check<commit_after>/**
 *
 * Basic WiFi Manager for Linux based systems, like Raspberry Pi.
 * For network generation the generation is:
 *
 * 1. Generate the configuration file based on passed in SSID & network password.
 * 2. Start the HOSTAPD service based on the configuration file.
 * 3. Start the DHCP service.
 *
 *
 * If this code works it was created by Ken W. Alger on 8/28/2015.
 * If not, I don't know who wrote it.
 *
 */

var fs = require('fs');
var color = require('colors');

var COMMANDS = {
    dhcp: 'sudo service udhcpd start',
    dhcp_disable: 'sudo service udhcpd stop',
    host: 'sudo service hostapd start',
    host_disable: 'sudo service hostapd stop',
    host_status: 'sudo service hostapd status'
};

/**
 * Configuration of the Hostapd service
 * https://w1.fi/hostapd/
 *
 * hostapd is a user space daemon for access point and authentication servers.
 *
 */

var startHostapdService = require('child_process').exec,
    sudo_hostapd = startHostapdService(COMMANDS.host);

var stopHostapdService = require('child_process').exec,
    sudo_stopHostpd = stopHostapdService(COMMANDS.host_disable);

/**
 * Configures the start of the DHCP service, we are utilizing udhcpd
 * http://manpages.ubuntu.com/manpages/hardy/man8/udhcpd.8.html
 *
 * A very small DHCP server which negotiates leases with DHCP clients
 *
 */

var startDHCPService = require('child_process').exec,
    sudo_udhcpd = startDHCPService(COMMANDS.dhcp);

var stopDHCPService = require('child_process').exec,
    sudo_stopDHCP = stopDHCPService(COMMANDS.dhcp_disable);

/**
 * defaultValues for the hostapd.conf file
 *
 * @type {{interface: string, driver: string, ssid: string, hw_mode: string, channel: string, macaddr_acl: string, auth_algs: string, ignore_broadcast_ssid: string, wpa: string, wpa_passphrase: string, wpa_key_mgmt: string, wpa_pairwise: string, rsn_pairwise: string}}
 */

var defaultValues = {
    interface: "wlan0",
    driver: "rtl871xdrv",
    //ssid: "thingsSDK",
    hw_mode: "g",
    channel: "6",
    macaddr_acl: "0",
    auth_algs: "1",
    ignore_broadcast_ssid: "0",
    wpa: "2",
    //wpa_passphrase: "Chalkers",
    wpa_key_mgmt: "WPA-PSK",
    wpa_pairwise: "TKIP",
    rsn_pairwise: "CCMP"
};

/**
 * Generates the configuration key:value pairs for the configuration file.
 */

var fileoutput = Object.keys(defaultValues).map(function(key){
    return key + "=" + defaultValues[key];
}).join("\n");

function BasicManager () {

}

/**
 * createAdHocNetwork() configures the hostapd.conf file based on the ssid and password variables supplied and then
 * starts the required services.
 *
 * @param ssid The broadcasted network name
 * @param wpa_passphrase The password for network access, minimum 8 characters
 */

BasicManager.prototype.createAdHocNetwork = function (ssid, wpa_passphrase) {

    if (wpa_passphrase.length < 8) {
        console.log("\n" +"Password length too short. Must be at least 8 characters.".inverse.red);
        return false;
    }

    ssid = typeof ssid !== undefined ? ssid : 'thingsSDK';
    wpa_passphrase = typeof wpa_passphrase !== undefined ? wpa_passphrase : 'Chalkers';

    // Generate the hostapd.conf file required for the WiFi Network

    fs.writeFile("/etc/hostapd/hostapd.conf",
        fileoutput + "\n" +
        "ssid=" + ssid + "\n" +
        "wpa_passphrase=" + wpa_passphrase + "\n");

    console.log("\n[WIFIMANAGER] hostapd.conf was successfully saved.".yellow);
    console.info("[WIFIMANAGER] Network name: " + (ssid).green);
    console.info("[WIFIMANAGER] Network password: " + (wpa_passphrase).green);

    // Start the hostapd (wifi management service)
    // Using user: thingssdk, sudo access to start services restricted in the /etc/sudoer file

    console.log(("[WIFIMANAGER] Attempting to start HOSTAPD service for network " + ssid + ".").cyan);
    sudo_hostapd.stdout.on('data', function(data) {
        console.log('Starting HOSTAPD service - stdout: ' + data);
    });

    // Start the DHCP Server

    console.log("[WIFIMANAGER] Attempting to start UDHCPD service.".cyan);
    sudo_udhcpd.stdout.on('data', function(data) {
        console.log('Starting UDHCPD service - stdout: ' + data);
    });
};

BasicManager.prototype.connect = function() {
    //TODO: Connect the device to a network
};

BasicManager.prototype.isConnected = function() {
    //TODO: Check to see if the device is connected to any network
};

BasicManager.prototype.isAdHocNetwork = function() {
    //TODO: Check to see if the network to which the device is connected is an AdHoc network

    // if isConnected() is false, then we don't need to continue
    // if isConnected() is true, then check if network SSID is the same as the created network
}

/**
 * stopAdHocNetwork() stops the required services.
 */
BasicManager.prototype.stopAdHocNetwork = function() {

    // Stop the DHCP Service
    sudo_stopDHCP.stdout.on('data', function (data) {
        console.log(('Stopping the DHCP Service: \n' + data).red);
    });

    // Stop the Wifi Management Service
    sudo_stopHostpd.stdout.on('data', function(data) {
        console.log(('Stopping Hostapd Service = stdout: \n' + data).red);
    });
};

//BasicManager.createAdHocNetwork("someNetwork", "password");
module.exports = BasicManager;<|endoftext|>


<commit_before>import browser from 'detect-browser';
import { parseInteger } from './utils';

export function isIELowerEquals(version) {
  return browser.name === 'ie' && parseInteger(browser.version.substr(0, browser.version.indexOf('.'))) <= version;
}
<commit_msg>未知のブラウザで開いたときになにも表示されない不具合を修正<commit_after>import browser from 'detect-browser';
import { parseInteger } from './utils';

export function isIELowerEquals(version) {
  // browserが定義されていないときは未知のブラウザ
  if (!browser) return false;
  return browser.name === 'ie' && parseInteger(browser.version.substr(0, browser.version.indexOf('.'))) <= version;
}
<|endoftext|>


<commit_before>"use strict";
const path = require('path');
const os = require('os');
const Convert = require('./convert-source-map');
const fs = require('../file-system');
const SourceInclusion = require('./source-inclusion').SourceInclusion;
const DependencyInclusion = require('./dependency-inclusion').DependencyInclusion;

exports.Bundle = class {
  constructor(bundler, config) {
    this.Minimatch = require('minimatch').Minimatch; //nested dep of vinyl-fs
    this.bundler = bundler;
    this.config = config;
    this.dependencies = [];
    this.prepend = (config.prepend || []).filter(x => bundler.itemIncludedInBuild(x));
    this.moduleId = config.name.replace(path.extname(config.name), '');
    this.hash = '';
    this.includes = (config.source || []);
    this.excludes = [];
    if(this.includes instanceof Array){
      this.includes = this.includes.map(x => new SourceInclusion(this, x));
    } else {
      this.excludes = (this.includes.exclude || []).map(x => this.createMatcher(x));
      this.includes = this.includes.include.map(x => new SourceInclusion(this, x));
    }
    this.buildOptions = bundler.interpretBuildOptions(config.options, bundler.buildOptions);
    this.requiresBuild = true;
    this.fileCache = {};
  }

  static create(bundler, config) {
    let bundle = new exports.Bundle(bundler, config);
    let dependencies = config.dependencies || [];

    return Promise.all(
      dependencies
        .filter(x => bundler.itemIncludedInBuild(x))
        .map(dependency => bundler.configureDependency(dependency)
        .then(description => bundle.addDependency(description)))
    ).then(() => bundle);
  }

  createMatcher(pattern) {
    return new this.Minimatch(pattern);
  }

  addDependency(description) {
    this.dependencies.push(description);
    this.includes.push(new DependencyInclusion(this, description));
  }

  trySubsume(item) {
    let includes = this.includes;

    for (let i = 0, ii = includes.length; i < ii; ++i) {
      if (includes[i].trySubsume(item)) {
        this.requiresBuild = true;
        return true;
      }
    }

    return false;
  }

  transform() {
    if (this.requiresBuild) {
      let index = -1;
      let items = this.includes;

      function doTransform() {
        index++;

        if (index < items.length) {
          return items[index].transform().then(doTransform);
        }

        return Promise.resolve();
      }

      return doTransform();
    }

    return Promise.resolve();
  }

  getBundledModuleIds() {
    return unique(this.includes.reduce((a, b) => a.concat(b.getAllModuleIds()), []));
  }

  getBundledFiles() {
    return this.includes.reduce((a, b) => a.concat(b.getAllFiles()), []);
  }

  write(platform) {
    if (!this.requiresBuild) {
      return Promise.resolve();
    }

    let work = Promise.resolve();
    let loaderOptions = this.bundler.loaderOptions;
    let buildOptions = this.buildOptions;
    let files = [];

    if (this.prepend.length) {
      work = work.then(() => addFilesInOrder(this, this.prepend, files));
    }

    if (loaderOptions.configTarget === this.config.name) {
      work = work.then(() => {
        files.push({ contents: "_aureliaConfigureModuleLoader();"});
      });
    }

    return work.then(() => {
      files = files.concat(this.getBundledFiles());

      const Concat = require('./concat-with-sourcemaps');
      let concat = new Concat(true, this.config.name, os.EOL);
      const generateHashedPath = require('./utils').generateHashedPath;
      const generateHash = require('./utils').generateHash;
      let needsSourceMap = false;

      for (let i = 0; i < files.length; ++i) {
        let currentFile = files[i];
        let sourceMap = buildOptions.sourcemaps ? currentFile.sourceMap : undefined;

        if (sourceMap) {
          needsSourceMap = true;
        }

        concat.add(currentFile.path, currentFile.contents, sourceMap ? JSON.stringify(sourceMap) : undefined);
      }

      let mapContents;
      let contents = concat.content;
      let bundleFileName = this.config.name;

      if (buildOptions.rev) {
        //Generate a unique hash based off of the bundle contents
        this.hash = generateHash(concat.content);
        bundleFileName = generateHashedPath(this.config.name, this.hash);
      }

      if (loaderOptions.configTarget === this.config.name) {
        //Add to the config bundle the loader config and change the "index.html" to reference the appropriate config bundle
        concat.add(undefined, this.writeLoaderConfig(platform, loaderOptions));
        contents = concat.content;
        let outputDir = platform.baseUrl || platform.output; //If we have a baseUrl, then the files are served from there, else it's the output
        if (platform.index) {
          this.setIndexFileConfigTarget(platform, path.join(outputDir, bundleFileName));
        }
      }

      let mapFileName = bundleFileName + '.map';
      let mapSourceRoot = path.relative(
        path.join(process.cwd(), platform.output),
        path.join(process.cwd(), this.bundler.project.paths.root)
      );

      console.log(`Writing ${bundleFileName}...`);

      if (buildOptions.minify) {
        let minificationOptions = { fromString: true };

        if (needsSourceMap) {
          minificationOptions.inSourceMap = Convert.fromJSON(concat.sourceMap).toObject();
          minificationOptions.outSourceMap = mapFileName;
          minificationOptions.sourceRoot = mapSourceRoot;
        }

        const UglifyJS = require('uglify-js'); //added to user project devDependencies
        let minificationResult = UglifyJS.minify(String(contents), minificationOptions);

        contents = minificationResult.code;
        mapContents = needsSourceMap ? Convert.fromJSON(minificationResult.map).toJSON() : undefined;
      } else if (needsSourceMap) {
        mapContents = Convert.fromJSON(concat.sourceMap)
          .setProperty('sourceRoot', mapSourceRoot)
          .toJSON();

        contents += os.EOL + '//# sourceMappingURL=' + mapFileName;
      }

      return fs.writeFile(path.join(platform.output, bundleFileName), contents).then(() => {
        this.requiresBuild = false;

        if (mapContents) {
          return fs.writeFile(path.join(platform.output, mapFileName), mapContents);
        }
      });
    });
  }

  getFileFromCacheOrLoad(x) {
    let found = this.fileCache[x];
    if (found) {
      return Promise.resolve(found);
    }

    return fs.readFile(x).then(data => {
      found = { contents: data.toString() };
      this.fileCache[x] = found;
      return found;
    });
  }

  writeLoaderConfig(platform, loaderOptions) {
    let loaderConfig = '';
    switch(loaderOptions.type) {
      case 'require':
        loaderConfig = this.createRequireJSConfig(platform);
        break;
      default:
        throw new Error(`Loader configuration style ${loaderOptions.type} is not supported.`);
    }
    return 'function _aureliaConfigureModuleLoader(){' + loaderConfig + '}'
  }

  createRequireJSConfig(platform) {
    let bundler = this.bundler;
    let loaderOptions = bundler.loaderOptions;
    let buildOptions = this.buildOptions;
    let loaderConfig = bundler.loaderConfig;
    let bundles = bundler.bundles;
    let name = this.config.name;
    let bundleMetadata = {};
    let includeBundles = shouldIncludeBundleMetadata(bundles, loaderOptions);
    let config = Object.assign({}, loaderConfig);
    let location = platform.baseUrl || platform.output;

    if (platform.useAbsolutePath) {
      location = '/' + location;
    } else {
      location = '../' + location;
    }

    for (let i = 0; i < bundles.length; ++i) {
      let currentBundle = bundles[i];
      let currentName = currentBundle.config.name;

      if (currentName === name) {
        continue;
      }

      if (includeBundles) {
        bundleMetadata[currentBundle.moduleId] = currentBundle.getBundledModuleIds();
      }
      //If build revisions are enabled, append the revision hash to the appropriate module id
      config.paths[currentBundle.moduleId] = location + '/' + currentBundle.moduleId + (buildOptions.rev && currentBundle.hash ? '-' + currentBundle.hash : '');
    }

    if (includeBundles) {
      config.bundles = bundleMetadata;
    }

    return 'requirejs.config(' + JSON.stringify(config) + ')'
  }

  setIndexFileConfigTarget(platform, location){
    //Replace the reference to the vendor bundle in the "index.html" file to use the correct build revision file (or remove the build revision hash);
    const escapeForRegex = require('./utils').escapeForRegex;
    const createSrcFileRegex = require('./utils').createSrcFileRegex;
    let indexLocation = platform.index;
    try {
      let indexFile = fs.readFileSync(indexLocation);
      let outputDir = platform.baseUrl || platform.output; //If we have a baseUrl, then the files are served from there, else it's the output
      let configMatcher = createSrcFileRegex(outputDir, this.moduleId);
      if(configMatcher.test(indexFile)){
        indexFile = indexFile.replace(configMatcher, 'src="$2' + location + '"');//Replace the old reference to the file with whatever the new one is (preserving any unknown path parts before)
        fs.writeFile(indexLocation, indexFile);
      } else {
        console.log('Error: Unable to update ' + this.moduleId + ' path to ' + location + ', could not find existing reference to replace');
      }
    } catch (err){
      if (err.code === 'ENOENT') {
        console.log('Error: No index file found at "' + indexLocation + '"');
      } else {
        console.log(err);
      }
    }
  }
}

function addFilesInOrder(bundle, paths, files) {
  let index = -1;

  function addFile() {
    index++;

    if (index < paths.length) {
      return bundle.getFileFromCacheOrLoad(paths[index])
        .then(file => files.push(file))
        .then(addFile);
    } else {
      return Promise.resolve();
    }
  }

  return addFile();
}

function shouldIncludeBundleMetadata(bundles, loaderOptions) {
  let setting = loaderOptions.includeBundleMetadataInConfig;

  if (typeof setting === 'string') {
    switch (setting.toLowerCase()) {
      case 'auto':
        return bundles.length > 1;
      case 'true':
        return true;
      default:
        return false;
    }
  }

  return setting === true;
}

function unique(collection){
  var u = {}, a = [];

  for(var i = 0, l = collection.length; i < l; ++i){
    if(u.hasOwnProperty(collection[i])) {
      continue;
    }

    a.push(collection[i]);
    u[collection[i]] = 1;
  }

  return a;
}
<commit_msg>chore(bundle): add placeholder for system.js support<commit_after>"use strict";
const path = require('path');
const os = require('os');
const Convert = require('./convert-source-map');
const fs = require('../file-system');
const SourceInclusion = require('./source-inclusion').SourceInclusion;
const DependencyInclusion = require('./dependency-inclusion').DependencyInclusion;

exports.Bundle = class {
  constructor(bundler, config) {
    this.Minimatch = require('minimatch').Minimatch; //nested dep of vinyl-fs
    this.bundler = bundler;
    this.config = config;
    this.dependencies = [];
    this.prepend = (config.prepend || []).filter(x => bundler.itemIncludedInBuild(x));
    this.moduleId = config.name.replace(path.extname(config.name), '');
    this.hash = '';
    this.includes = (config.source || []);
    this.excludes = [];
    if(this.includes instanceof Array){
      this.includes = this.includes.map(x => new SourceInclusion(this, x));
    } else {
      this.excludes = (this.includes.exclude || []).map(x => this.createMatcher(x));
      this.includes = this.includes.include.map(x => new SourceInclusion(this, x));
    }
    this.buildOptions = bundler.interpretBuildOptions(config.options, bundler.buildOptions);
    this.requiresBuild = true;
    this.fileCache = {};
  }

  static create(bundler, config) {
    let bundle = new exports.Bundle(bundler, config);
    let dependencies = config.dependencies || [];

    return Promise.all(
      dependencies
        .filter(x => bundler.itemIncludedInBuild(x))
        .map(dependency => bundler.configureDependency(dependency)
        .then(description => bundle.addDependency(description)))
    ).then(() => bundle);
  }

  createMatcher(pattern) {
    return new this.Minimatch(pattern);
  }

  addDependency(description) {
    this.dependencies.push(description);
    this.includes.push(new DependencyInclusion(this, description));
  }

  trySubsume(item) {
    let includes = this.includes;

    for (let i = 0, ii = includes.length; i < ii; ++i) {
      if (includes[i].trySubsume(item)) {
        this.requiresBuild = true;
        return true;
      }
    }

    return false;
  }

  transform() {
    if (this.requiresBuild) {
      let index = -1;
      let items = this.includes;

      function doTransform() {
        index++;

        if (index < items.length) {
          return items[index].transform().then(doTransform);
        }

        return Promise.resolve();
      }

      return doTransform();
    }

    return Promise.resolve();
  }

  getBundledModuleIds() {
    return unique(this.includes.reduce((a, b) => a.concat(b.getAllModuleIds()), []));
  }

  getBundledFiles() {
    return this.includes.reduce((a, b) => a.concat(b.getAllFiles()), []);
  }

  write(platform) {
    if (!this.requiresBuild) {
      return Promise.resolve();
    }

    let work = Promise.resolve();
    let loaderOptions = this.bundler.loaderOptions;
    let buildOptions = this.buildOptions;
    let files = [];

    if (this.prepend.length) {
      work = work.then(() => addFilesInOrder(this, this.prepend, files));
    }

    if (loaderOptions.configTarget === this.config.name) {
      work = work.then(() => {
        files.push({ contents: "_aureliaConfigureModuleLoader();"});
      });
    }

    return work.then(() => {
      files = files.concat(this.getBundledFiles());

      const Concat = require('./concat-with-sourcemaps');
      let concat = new Concat(true, this.config.name, os.EOL);
      const generateHashedPath = require('./utils').generateHashedPath;
      const generateHash = require('./utils').generateHash;
      let needsSourceMap = false;

      for (let i = 0; i < files.length; ++i) {
        let currentFile = files[i];
        let sourceMap = buildOptions.sourcemaps ? currentFile.sourceMap : undefined;

        if (sourceMap) {
          needsSourceMap = true;
        }

        concat.add(currentFile.path, currentFile.contents, sourceMap ? JSON.stringify(sourceMap) : undefined);
      }

      let mapContents;
      let contents = concat.content;
      let bundleFileName = this.config.name;

      if (buildOptions.rev) {
        //Generate a unique hash based off of the bundle contents
        this.hash = generateHash(concat.content);
        bundleFileName = generateHashedPath(this.config.name, this.hash);
      }

      if (loaderOptions.configTarget === this.config.name) {
        //Add to the config bundle the loader config and change the "index.html" to reference the appropriate config bundle
        concat.add(undefined, this.writeLoaderConfig(platform, loaderOptions));
        contents = concat.content;
        let outputDir = platform.baseUrl || platform.output; //If we have a baseUrl, then the files are served from there, else it's the output
        if (platform.index) {
          this.setIndexFileConfigTarget(platform, path.join(outputDir, bundleFileName));
        }
      }

      let mapFileName = bundleFileName + '.map';
      let mapSourceRoot = path.relative(
        path.join(process.cwd(), platform.output),
        path.join(process.cwd(), this.bundler.project.paths.root)
      );

      console.log(`Writing ${bundleFileName}...`);

      if (buildOptions.minify) {
        let minificationOptions = { fromString: true };

        if (needsSourceMap) {
          minificationOptions.inSourceMap = Convert.fromJSON(concat.sourceMap).toObject();
          minificationOptions.outSourceMap = mapFileName;
          minificationOptions.sourceRoot = mapSourceRoot;
        }

        const UglifyJS = require('uglify-js'); //added to user project devDependencies
        let minificationResult = UglifyJS.minify(String(contents), minificationOptions);

        contents = minificationResult.code;
        mapContents = needsSourceMap ? Convert.fromJSON(minificationResult.map).toJSON() : undefined;
      } else if (needsSourceMap) {
        mapContents = Convert.fromJSON(concat.sourceMap)
          .setProperty('sourceRoot', mapSourceRoot)
          .toJSON();

        contents += os.EOL + '//# sourceMappingURL=' + mapFileName;
      }

      return fs.writeFile(path.join(platform.output, bundleFileName), contents).then(() => {
        this.requiresBuild = false;

        if (mapContents) {
          return fs.writeFile(path.join(platform.output, mapFileName), mapContents);
        }
      });
    });
  }

  getFileFromCacheOrLoad(x) {
    let found = this.fileCache[x];
    if (found) {
      return Promise.resolve(found);
    }

    return fs.readFile(x).then(data => {
      found = { contents: data.toString() };
      this.fileCache[x] = found;
      return found;
    });
  }

  writeLoaderConfig(platform, loaderOptions) {
    let loaderConfig = '';

    switch(loaderOptions.type) {
      case 'require':
        loaderConfig = this.createRequireJSConfig(platform);
        break;
      case 'system':
        loaderConfig = this.createSystemJSConfig(platform);
        break;
      default:
        throw new Error(`Loader configuration style ${loaderOptions.type} is not supported.`);
    }

    return 'function _aureliaConfigureModuleLoader(){' + loaderConfig + '}'
  }

  createRequireJSConfig(platform) {
    let bundler = this.bundler;
    let loaderOptions = bundler.loaderOptions;
    let buildOptions = this.buildOptions;
    let loaderConfig = bundler.loaderConfig;
    let bundles = bundler.bundles;
    let name = this.config.name;
    let bundleMetadata = {};
    let includeBundles = shouldIncludeBundleMetadata(bundles, loaderOptions);
    let config = Object.assign({}, loaderConfig);
    let location = platform.baseUrl || platform.output;

    if (platform.useAbsolutePath) {
      location = '/' + location;
    } else {
      location = '../' + location;
    }

    for (let i = 0; i < bundles.length; ++i) {
      let currentBundle = bundles[i];
      let currentName = currentBundle.config.name;

      if (currentName === name) {
        continue;
      }

      if (includeBundles) {
        bundleMetadata[currentBundle.moduleId] = currentBundle.getBundledModuleIds();
      }
      //If build revisions are enabled, append the revision hash to the appropriate module id
      config.paths[currentBundle.moduleId] = location + '/' + currentBundle.moduleId + (buildOptions.rev && currentBundle.hash ? '-' + currentBundle.hash : '');
    }

    if (includeBundles) {
      config.bundles = bundleMetadata;
    }

    return 'requirejs.config(' + JSON.stringify(config) + ')';
  }

  createSystemJSConfig(platform) {
    throw new Error('SystemJS is not yet supported');
  }

  setIndexFileConfigTarget(platform, location){
    //Replace the reference to the vendor bundle in the "index.html" file to use the correct build revision file (or remove the build revision hash);
    const escapeForRegex = require('./utils').escapeForRegex;
    const createSrcFileRegex = require('./utils').createSrcFileRegex;
    let indexLocation = platform.index;
    try {
      let indexFile = fs.readFileSync(indexLocation);
      let outputDir = platform.baseUrl || platform.output; //If we have a baseUrl, then the files are served from there, else it's the output
      let configMatcher = createSrcFileRegex(outputDir, this.moduleId);
      if(configMatcher.test(indexFile)){
        indexFile = indexFile.replace(configMatcher, 'src="$2' + location + '"');//Replace the old reference to the file with whatever the new one is (preserving any unknown path parts before)
        fs.writeFile(indexLocation, indexFile);
      } else {
        console.log('Error: Unable to update ' + this.moduleId + ' path to ' + location + ', could not find existing reference to replace');
      }
    } catch (err){
      if (err.code === 'ENOENT') {
        console.log('Error: No index file found at "' + indexLocation + '"');
      } else {
        console.log(err);
      }
    }
  }
}

function addFilesInOrder(bundle, paths, files) {
  let index = -1;

  function addFile() {
    index++;

    if (index < paths.length) {
      return bundle.getFileFromCacheOrLoad(paths[index])
        .then(file => files.push(file))
        .then(addFile);
    } else {
      return Promise.resolve();
    }
  }

  return addFile();
}

function shouldIncludeBundleMetadata(bundles, loaderOptions) {
  let setting = loaderOptions.includeBundleMetadataInConfig;

  if (typeof setting === 'string') {
    switch (setting.toLowerCase()) {
      case 'auto':
        return bundles.length > 1;
      case 'true':
        return true;
      default:
        return false;
    }
  }

  return setting === true;
}

function unique(collection){
  var u = {}, a = [];

  for(var i = 0, l = collection.length; i < l; ++i){
    if(u.hasOwnProperty(collection[i])) {
      continue;
    }

    a.push(collection[i]);
    u[collection[i]] = 1;
  }

  return a;
}
<|endoftext|>


<commit_before>'use strict';

const browserify = require('browserify');
const envify = require('envify/custom');
const uglify = require('uglify-js');
const zlib = require('zlib');

module.exports = (packages, env) => {
  const files = Array.isArray(packages) ? packages : [packages];
  let data = '';

  return new Promise((resolve, reject) => {
    const bundler = browserify();

    files.forEach((file) => {
      bundler.require(file);
    });

    if (env) {
      process.env.NODE_ENV = env;
      bundler.transform(envify({
        NODE_ENV: env
      }));
    }

    bundler.bundle()
      .on('data', function (buf) {
        data += buf.toString();
      })
      .on('end', function () {
        const minify = uglify.minify(data, {
          fromString: true,
          mangle: false,
          compress: {
            dead_code: true
          }
        });
        const results = {
          packages: files,
          bundle: data.length,
          min: minify.code.length
        };
        if (env) {
          results.env = env;
        }
        zlib.gzip(minify.code, (err, buffer) => {
          if (err) {
            console.error(err);
          }
          results.gzip = buffer.toString('base64').length;
          resolve(results);
        });
      });
  });
};
<commit_msg>refactor: to arrow function<commit_after>'use strict';

const browserify = require('browserify');
const envify = require('envify/custom');
const uglify = require('uglify-js');
const zlib = require('zlib');

module.exports = (packages, env) => {
  const files = Array.isArray(packages) ? packages : [packages];
  let data = '';

  return new Promise((resolve, reject) => {
    const bundler = browserify();

    files.forEach((file) => {
      bundler.require(file);
    });

    if (env) {
      process.env.NODE_ENV = env;
      bundler.transform(envify({
        NODE_ENV: env
      }));
    }

    bundler.bundle()
      .on('data', (buf) => {
        data += buf.toString();
      })
      .on('end', () => {
        const minify = uglify.minify(data, {
          fromString: true,
          mangle: false,
          compress: {
            dead_code: true
          }
        });
        const results = {
          packages: files,
          bundle: data.length,
          min: minify.code.length
        };
        if (env) {
          results.env = env;
        }
        zlib.gzip(minify.code, (err, buffer) => {
          if (err) {
            console.error(err);
          }
          results.gzip = buffer.toString('base64').length;
          resolve(results);
        });
      });
  });
};
<|endoftext|>


<commit_before>((typeof define === "function" && define.amd && function (m) {
    define(["sinon", "buster-test", "stack-filter", "formatio"], m);
}) || (typeof module === "object" &&
       typeof require === "function" && function (m) {
        module.exports = m(
            require("sinon"),
            require("buster-test"),
            require("stack-filter"),
            require("formatio")
        );
    }) || function (m) {
        m(this.sinon, this.buster, this.stackFilter, this.formatio);
    }
)(function (sinon, bt, stackFilter, formatio) {
    stackFilter.filters.push("lib/sinon");

    bt.testRunner.onCreate(function (runner) {
        runner.on("test:setUp", function (test) {
            var config = sinon.getConfig(sinon.config);
            config.useFakeServer = false;
            var sandbox = sinon.sandbox.create();
            sandbox.inject(test.testCase);

            test.testCase.useFakeTimers = function () {
                return sandbox.useFakeTimers.apply(sandbox, arguments);
            };

            test.testCase.useFakeServer = function () {
                return sandbox.useFakeServer.apply(sandbox, arguments);
            };

            test.testCase.sandbox = sandbox;
            var testFunc = test.func;
        });

        runner.on("test:tearDown", function (test) {
            try {
                test.testCase.sandbox.verifyAndRestore();
            } catch (e) {
                runner.assertionFailure(e);
            }
        });
    });
});
<commit_msg>Sinon mock expectations count as assertions<commit_after>((typeof define === "function" && define.amd && function (m) {
    define(["sinon", "buster-test", "stack-filter", "formatio"], m);
}) || (typeof module === "object" &&
       typeof require === "function" && function (m) {
        module.exports = m(
            require("sinon"),
            require("buster-test"),
            require("stack-filter"),
            require("formatio")
        );
    }) || function (m) {
        m(this.sinon, this.buster, this.stackFilter, this.formatio);
    }
)(function (sinon, bt, stackFilter, formatio) {
    stackFilter.filters.push("lib/sinon");

    bt.testRunner.onCreate(function (runner) {
        runner.on("test:setUp", function (test) {
            var config = sinon.getConfig(sinon.config);
            config.useFakeServer = false;
            var sandbox = sinon.sandbox.create();
            sandbox.inject(test.testCase);

            test.testCase.useFakeTimers = function () {
                return sandbox.useFakeTimers.apply(sandbox, arguments);
            };

            test.testCase.useFakeServer = function () {
                return sandbox.useFakeServer.apply(sandbox, arguments);
            };

            test.testCase.sandbox = sandbox;
            var testFunc = test.func;
        });

        runner.on("test:tearDown", function (test) {
            try {
                test.testCase.sandbox.verifyAndRestore();
            } catch (e) {
                runner.assertionFailure(e);
            }
        });

        sinon.expectation.pass = function () {
            runner.assertionPass();
        };
    });
});
<|endoftext|>