<commit_before>(function (){

	// global on the server, window in the browser
	var root = this,
		previous_re = root.Re;

	Re.noConflict = function(){
		root.Re = previous_re;
		return Re;
	};

	// start actual code
	Re.STRATEGIES = {CONSTANT: 0, EXPONENTIAL: 1, LINEAR: 2};

	var RETRIES_DEFAULT = 10,
		EXP_STRAT_DEFAULT = {"type": Re.STRATEGIES.EXPONENTIAL, "initial":100, "base":2},
		CONST_STRAT_DEFAULT = {"type": Re.STRATEGIES.CONSTANT, "initial":400},
		LINEAR_STRAT_DEFAULT = {"type": Re.STRATEGIES.LINEAR, "initial": 100};

	Re.prototype.retryInterval;

	function Re(options){
		if(!(this instanceof Re)) return new Re(options);

		var strategy;

		if(typeof options === "undefined") options = {};
		if(typeof options.retries === "undefined") options.retries = RETRIES_DEFAULT;
		if(typeof options.strategy === "undefined") options.strategy = EXP_STRAT_DEFAULT;
		if(typeof options.strategy.type === "undefined") throw new TypeError("Invalid retry strategy");

		strategy = options.strategy;

		this.retry = 0;
		this.timeout = options.timeout;
		this.maxRetries = options.retries;

		switch(options.strategy.type){
			case Re.STRATEGIES.CONSTANT:
				if(typeof strategy.initial === "undefined") strategy.initial = CONST_STRAT_DEFAULT.initial;
				this.retryInterval = createConstantRetry(strategy);
				break;
			case Re.STRATEGIES.EXPONENTIAL:
				if(typeof strategy.initial === "undefined") strategy.initial = EXP_STRAT_DEFAULT.initial;
				if(typeof strategy.base === "undefined") strategy.base = EXP_STRAT_DEFAULT.base;
				this.retryInterval = createExponentialRetry(strategy);
				break;
			case Re.STRATEGIES.LINEAR:
				if(typeof strategy.initial === "undefined") strategy.initial = LINEAR_STRAT_DEFAULT.initial;
				this.retryInterval = createLinearRetry(strategy);
				break;
			default:
				throw new TypeError("Invalid retry strategy");
				break;
		}
	};

	Re.prototype.try = function(operation, callback){
		var done = this.createDoneCallback(operation, callback, this.try);

		try{
			operation(this.retry, done);
		} catch(err) {
			done(err);
		}
	};

	Re.prototype.do = function(operation, callback){
		var fail = this.createDoneCallback(operation, callback, this.do);

		operation(this.retry, done);
	};

	Re.prototype.createDoneCallback = function(operation, callback, method){
		var self = this;
		return function(err){
			var doneArguments = arguments;

			callback = callback || function () {};

			if(!err) return setTimeout(function(){callback.apply(null, doneArguments);}, 0);

			if(self.retry < self.maxRetries){
				setTimeout(function(){
						method.call(self, operation, callback);
					},
					self.retryInterval(self.retry));
			} else {
				return setTimeout(function(){callback.apply(null, doneArguments);}, 0);
			}

			self.retry++;
		};
	};

	createExponentialRetry = function(spec){
		return function(retries){
			var spread = spec.rand ? Math.random() + 1 : 1,
				initial = spec.initial,
				base = spec.base,
				max = spec.max,
				full = spread * initial * Math.pow(base, retries);

			return max ? Math.min(full, max) : full;
		};
	};

	createLinearRetry = function(spec){
		return function(retries){
			var spread = spec.rand ? Math.random() + 1 : 1,
				initial = spec.initial,
				max = spec.max,
				full = spread*initial*(retries+1);

			return max ? Math.min(full, max) : full;
		};
	};

	createConstantRetry = function(spec){
		return function(){
			var spread = spec.rand ? Math.random() + 1 : 1,
				initial = spec.initial;
			return spread*initial;
		};
	};

	// Node.js
	if(typeof module !== 'undefined' && module.exports){
		module.exports = Re;
	}
	// included directly via <script> tag
	else {
		root.Re = Re;
	}

}());<commit_msg>Fix calling undefined function<commit_after>(function (){

	// global on the server, window in the browser
	var root = this,
		previous_re = root.Re;

	Re.noConflict = function(){
		root.Re = previous_re;
		return Re;
	};

	// start actual code
	Re.STRATEGIES = {CONSTANT: 0, EXPONENTIAL: 1, LINEAR: 2};

	var RETRIES_DEFAULT = 10,
		EXP_STRAT_DEFAULT = {"type": Re.STRATEGIES.EXPONENTIAL, "initial":100, "base":2},
		CONST_STRAT_DEFAULT = {"type": Re.STRATEGIES.CONSTANT, "initial":400},
		LINEAR_STRAT_DEFAULT = {"type": Re.STRATEGIES.LINEAR, "initial": 100};

	Re.prototype.retryInterval;

	function Re(options){
		if(!(this instanceof Re)) return new Re(options);

		var strategy;

		if(typeof options === "undefined") options = {};
		if(typeof options.retries === "undefined") options.retries = RETRIES_DEFAULT;
		if(typeof options.strategy === "undefined") options.strategy = EXP_STRAT_DEFAULT;
		if(typeof options.strategy.type === "undefined") throw new TypeError("Invalid retry strategy");

		strategy = options.strategy;

		this.retry = 0;
		this.timeout = options.timeout;
		this.maxRetries = options.retries;

		switch(options.strategy.type){
			case Re.STRATEGIES.CONSTANT:
				if(typeof strategy.initial === "undefined") strategy.initial = CONST_STRAT_DEFAULT.initial;
				this.retryInterval = createConstantRetry(strategy);
				break;
			case Re.STRATEGIES.EXPONENTIAL:
				if(typeof strategy.initial === "undefined") strategy.initial = EXP_STRAT_DEFAULT.initial;
				if(typeof strategy.base === "undefined") strategy.base = EXP_STRAT_DEFAULT.base;
				this.retryInterval = createExponentialRetry(strategy);
				break;
			case Re.STRATEGIES.LINEAR:
				if(typeof strategy.initial === "undefined") strategy.initial = LINEAR_STRAT_DEFAULT.initial;
				this.retryInterval = createLinearRetry(strategy);
				break;
			default:
				throw new TypeError("Invalid retry strategy");
				break;
		}
	};

	Re.prototype.try = function(operation, callback){
		var done = this.createDoneCallback(operation, callback, this.try);

		try{
			operation(this.retry, done);
		} catch(err) {
			done(err);
		}
	};

	Re.prototype.do = function(operation, callback){
		var done = this.createDoneCallback(operation, callback, this.do);

		operation(this.retry, done);
	};

	Re.prototype.createDoneCallback = function(operation, callback, method){
		var self = this;
		return function(err){
			var doneArguments = arguments;

			callback = callback || function () {};

			if(!err) return setTimeout(function(){callback.apply(null, doneArguments);}, 0);

			if(self.retry < self.maxRetries){
				setTimeout(function(){
						method.call(self, operation, callback);
					},
					self.retryInterval(self.retry));
			} else {
				return setTimeout(function(){callback.apply(null, doneArguments);}, 0);
			}

			self.retry++;
		};
	};

	createExponentialRetry = function(spec){
		return function(retries){
			var spread = spec.rand ? Math.random() + 1 : 1,
				initial = spec.initial,
				base = spec.base,
				max = spec.max,
				full = spread * initial * Math.pow(base, retries);

			return max ? Math.min(full, max) : full;
		};
	};

	createLinearRetry = function(spec){
		return function(retries){
			var spread = spec.rand ? Math.random() + 1 : 1,
				initial = spec.initial,
				max = spec.max,
				full = spread*initial*(retries+1);

			return max ? Math.min(full, max) : full;
		};
	};

	createConstantRetry = function(spec){
		return function(){
			var spread = spec.rand ? Math.random() + 1 : 1,
				initial = spec.initial;
			return spread*initial;
		};
	};

	// Node.js
	if(typeof module !== 'undefined' && module.exports){
		module.exports = Re;
	}
	// included directly via <script> tag
	else {
		root.Re = Re;
	}

}());<|endoftext|>


<commit_before>var _ = require('underscore');
var fs = require('fs');
var url = require('url');
var path = require('path');
var yaml = require('js-yaml');
var mapnik = require('mapnik');
var mkdirp = require('mkdirp');
var chrono = require('chrono');
var crypto = require('crypto');
var tilelive = require('tilelive');
var existsSync = require('fs').existsSync || require('path').existsSync;

tilelive.protocols['mbtiles:'] = require('mbtiles');

var tm = {};

// Set or get config.
tm.db;
tm._config = {};
tm.config = function(opts, callback) {
    if (!opts) return tm._config;

    tm._config = _(opts).defaults(tm._config);
    // @TODO create other paths (cache, etc.)
    try {
        mkdirp.sync(path.dirname(tm.config().db));
        mkdirp.sync(tm.config().cache);
        mkdirp.sync(tm.config().fonts);
    } catch(err) { throw err; }

    // Register default fonts.
    mapnik.register_fonts(path.dirname(require.resolve('tm2-default-fonts')), { recurse: true });
    mapnik.register_fonts(tm.config().fonts, { recurse: true });

    // Load + compact the app database.
    var old = require('dirty')(tm.config().db);
    old.on('load', function() {
        var db_name = tm.config().db;
        if (existsSync(db_name)) {
            fs.unlinkSync(db_name);
        }
        tm.db = require('dirty')(db_name);

        // Check app db version and run any migrations if necessary.
        switch (old.get('version')) {
        case 2:
            old.forEach(function(k,v) { tm.db.set(k,v); });
            break;
        case 1:
        case undefined:
            old.set('version', 2);
            old.set('history', _(old.get('history')||{}).reduce(function(memo, list, type) {
                if (type !== 'style' && type !== 'source') return memo;
                memo[type] = list.map(function(id) {
                    var uri = url.parse(id);
                    if (uri.protocol === 'mapbox:') {
                        return !uri.pathname ? id.replace('://', ':///') : id;
                    } else if (!uri.protocol) {
                        return 'tm' + type + '://' + uri.pathname;
                    } else {
                        return id;
                    }
                });
                return memo;
            }, { style:[], source:[] }));
            old.forEach(function(k,v) { tm.db.set(k,v); });
            break;
        };

        if (callback) return callback();
    });
    return tm._config;
};
tm.config({
    db: path.join(process.env.HOME, '.tilemill', 'v2', 'app.db'),
    cache: path.join(process.env.HOME, '.tilemill', 'v2', 'cache'),
    fonts: path.join(process.env.HOME, '.tilemill', 'v2', 'fonts'),
    mapboxauth: 'https://tiles.mapbox.com',
    mapboxtile: 'http://a.tiles.mapbox.com/v3'
});

// Set or remove a project id from recent history.
var defaultSources = [
    'mapbox:///mapbox.mapbox-streets-v4'
];
tm.history = function(type, id, invalidate) {
    var history = tm.db.get('history') || {};
    history = _(history).isArray() ? { style: history } : history;
    history.style = history.style || [];
    history.source = history.source || [];

    if (id && type) {
        if (!history[type]) throw new Error('History set requires valid type');
        var update = invalidate
            ? _(history[type]).reject(function(k) { return k === id; })
            : _(history[type].concat([id])).uniq();
        if (!_(update).isEqual(history[type])) {
            history[type] = update;
            tm.db.set('history', history);
        }
    }
    history.source = _(history.source.concat(defaultSources)).uniq();
    history.style.sort();
    history.source.sort();
    return history;
};

// Remotes cache.
tm.remote = function(id, data) {
    var remote = tm.db.get('remote') || {};
    if (!data) {
        return remote[id] || false;
    } else {
        remote[id] = data;
        tm.db.set('remote', remote);
        return remote[id];
    }
};

// Load templates.
tm.templates = _(fs.readdirSync(__dirname + '/../templates')).reduce(function(memo, file) {
    if (file.charAt(0) === '.') return memo;
    memo[file.split('.')[0]] = _(fs.readFileSync(__dirname + '/../templates/' + file, 'utf8')).template();
    console.log(memo);
    return memo;
}, {});

// Writes an array of files defined by { basename:[basename], data:[data] }
tm.writefiles = function(basepath, files, callback) {
    var write = function() {
        if (!files.length) return callback();
        var file = files.shift();
        fs.writeFile(path.join(basepath, file.basename), file.data, function(err) {
            if (err) return callback(err);
            write();
        });
    };
    mkdirp(basepath, function(err) {
        if (err) return callback(err);
        write();
    });
};

// Reads a directory of files.
tm.dirfiles = function(basepath, callback) {
    fs.readdir(path.resolve(basepath), function(err, files) {
        if (err) return callback(err);
        files = files.filter(function(f) { return f[0] !== '.' });

        var stats = [];
        var stat = function() {
            if (!files.length) {
                stats.sort(function(a,b) {
                    if (a.type < b.type) return -1;
                    if (a.type > b.type) return 1;
                    if (a.basename.toLowerCase() < b.basename.toLowerCase()) return -1;
                    if (a.basename.toLowerCase() > b.basename.toLowerCase()) return 1;
                    return 0;
                });
                return callback(null, stats);
            }
            var p = path.join(basepath, files.shift());
            fs.stat(p, function(err, s) {
                if (err) return callback(err);
                if (s.isFile()) s.type = 'file';
                if (s.isDirectory()) s.type = 'dir';
                if (s.type) {
                    s.path = p;
                    s.extname = path.extname(p);
                    s.basename = path.basename(p);
                    stats.push(s);
                }
                stat();
            });
        };
        stat();
    });
};

// Filter keys out of an object that are not present in defaults.
tm.filterkeys = function(data, defaults) {
    return _(data).reduce(function(memo,v,k) {
        if (!(k in defaults)) return memo;
        memo[k] = v;
        return memo;
    }, {})
};

// Return an object with sorted keys, ignoring case.
tm.sortkeys = function(obj) {
    try {
        return obj.map(tm.sortkeys);
    } catch(e) {};
    try {
        return Object.keys(obj).sort(function(a, b) {
            a = a.toLowerCase();
            b = b.toLowerCase();
            if (a === 'id') return -1;
            if (b === 'id') return 1;
            if (a > b) return 1;
            if (a < b) return -1;
            return 0;
        }).reduce(function(memo, key) {
            memo[key] = tm.sortkeys(obj[key]);
            return memo;
        }, {});
    } catch(e) { return obj };
};

// Generate or verify that an id is a temporary one.
tm.tmpid = function(protocol, id, md5) {
    if (id && !md5) return (new RegExp(protocol + '\/\/\/tmp-[0-9a-f]{8}')).test(id);

    if (id && md5) {
        return protocol + '///tmp-' + crypto.createHash('md5').update(id).digest('hex').substr(0,8);
    } else {
        id = protocol + '///tmp-';
        var base16 = '0123456789abcdef';
        for (var i = 0; i < 8; i++) id += base16[Math.random() * 16 | 0];
        return id;
    }
};

// Named projections.
tm.srs = {
    'WGS84': '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs',
    '900913': '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over'
};
tm.extent = {
    'WGS84': '-180,-85.0511,180,85.0511',
    '900913': '-20037508.34,-20037508.34,20037508.34,20037508.34'
};
// Reverse the above hash to allow for srs name lookups.
tm.srsname = {};
for (name in tm.srs) tm.srsname[tm.srs[name]] = name;

// Render a preview image for a font.
tm.font = function(name, callback) {
    tm.fonts = tm.fonts || mapnik.fonts();
    if (tm.fonts.indexOf(name) === -1) return callback(new Error('Invalid font ' + name));

    // Attempt to retrieve from cache.
    var xml = tm.templates.xrayfont(name);
    var ckey = 'font-' + crypto.createHash('md5').update(xml).digest('hex').substr(0,8) + '.png';
    var file = tm.config().cache + '/' + ckey;
    fs.readFile(file, function(err, buffer) {
        if (err && err.code !== 'ENOENT') return callback(err);
        if (buffer) return callback(null, buffer);

        var map = new mapnik.Map(400,40);
        map.extent = [-180,-10,180,10];
        map.fromString(xml, function(err) {
            if (err) return callback(err);
            map.render(new mapnik.Image(400,40), {}, function(err, image) {
                if (err) return callback(err);
                image.encode('png8:m=h:c=64', function(err, buffer) {
                    if (err) return callback(err);

                    // Don't wait for disk write to return image buffer.
                    // If caching fails, error is logged to console.
                    callback(null, buffer);
                    fs.writeFile(file, buffer, function(err) {
                        if (err) console.error(err);
                    });
                });
            });
        });
    });
};

// For a given from => to copy task,
// 1. Returns a completed progress object if export exists.
// 2. Returns the current in-progress object if export is active.
// 3. Creates a new copy task for the export otherwise.
tm._copy = null;
tm.copytask = function(from, to, callback) {
    function state() {
        if (!tm._copy) return callback();
        // Snapshot current task stats.
        tm._copy.stats = tm._copy.task ? tm._copy.task.stats.snapshot() : null;
        // Return job object to caller.
        callback(null, tm._copy);
        // Clear out current job reference if complete.
        tm._copy = tm._copy.task ? tm._copy : null;
        return;
    };

    if (!from && !to) return state();

    if (tm._copy) return tm._copy.id !== from
        ? callback(new Error('Active task already in progress'))
        : state();

    var furi = url.parse(from);
    var turi = url.parse(to);

    if (furi.protocol !== 'tmsource:')
        return callback(new Error('Unsupported source protocol'));

    if (turi.protocol !== 'mbtiles:')
        return callback(new Error('Unsupported sink protocol'));

    fs.stat(turi.pathname, function(err, stat) {
        if (err && err.code !== 'ENOENT') return callback(err);

        if (stat) return callback(null, {
            id: from,
            file: turi.pathname,
            stat: stat,
            task: null,
            stats: null
        });

        var source = require('./source');
        source(from, function(err, s) {
            if (err) return callback(err);
            s.getInfo(function(err, info) {
                if (err) return callback(err);

                // Bounds may be set in source data. If not, derive.
                info.bounds = s.data.bounds || source.extent(s.data);

                var tmp = 'mbtiles:///tmp/' + path.basename(turi.pathname);
                var opts = {
                    minzoom: info.minzoom,
                    maxzoom: info.maxzoom,
                    bbox: info.bounds
                };
                var scheme = tilelive.Scheme.create('scanline', opts);
                var task = new tilelive.CopyTask(from, tmp, scheme);
                tm._copy = {
                    id: from,
                    file: null,
                    stat: null,
                    task: task,
                    stats: task.stats.snapshot()
                };

                // This method responds early to be as responsive as possible.
                // Errors in the export will be apparent one way or another.
                callback(null, tm._copy);

                // Move tmp export into place when complete.
                tm._copy.task.on('finished', function(err) {
                    // Enable caching on source again.
                    delete s._nocache;

                    fs.unlink(tm._copy.task.job, function(err) {
                        if (err) console.error(err);
                    });
                    fs.rename(url.parse(tmp).pathname, turi.pathname, function(err) {
                        if (err) return (tm._copy = err) && console.error(err);
                        fs.stat(turi.pathname, function(err, stat) {
                            if (err) return (tm._copy = err) && console.error(err);
                            tm._copy = {
                                id: from,
                                file: turi.pathname,
                                stat: stat,
                                task: null,
                                stats: null
                            };
                            console.log('[%s] %s complete',
                                (new Date).toUTCString(),
                                path.basename(from));
                        });
                    });
                });
                // Start the task.
                console.log('[%s] %s (z%d-%d @ %s)',
                    (new Date).toUTCString(),
                    path.basename(from),
                    opts.minzoom,
                    opts.maxzoom,
                    opts.bbox.join(','));

                // Disable source caching for export.
                s._nocache = true;

                tm._copy.task.start(function(err) {

                    // Emit an event for tests.
                    tm._copy.task.emit('started');

                    if (err) return (tm._copy = err) && console.error(err);
                    tm._copy.task.sink.putInfo(info, function(err) {
                        if (err) return (tm._copy = err) && console.error(err);
                    });
                });
            });
        });
    });
};

// Cancel/clear the current active task.
// No-op if no task is active.
tm.cleartask = function(callback) {
    if (!tm._copy) return callback();
    if (tm._copy.task) return tm._copy.task.pause(function(err) {
        if (err) return callback(err);
        // Remove sink file.
        fs.unlink(tm._copy.task.sink.filename, function(err) {
            if (err && err.code !== 'ENOENT') return callback(Err);
            // Remove job file.
            fs.unlink(tm._copy.task.job, function(err) {
                if (err && err.code !== 'ENOENT') return callback(Err);
                console.log('[%s] %s canceled',
                    (new Date).toUTCString(),
                    path.basename(tm._copy.id));
                tm._copy = null;
                return callback();
            });
        });
    });
    tm._copy = null;
    return callback();
};

module.exports = tm;
<commit_msg>remove console.log:<commit_after>var _ = require('underscore');
var fs = require('fs');
var url = require('url');
var path = require('path');
var yaml = require('js-yaml');
var mapnik = require('mapnik');
var mkdirp = require('mkdirp');
var chrono = require('chrono');
var crypto = require('crypto');
var tilelive = require('tilelive');
var existsSync = require('fs').existsSync || require('path').existsSync;

tilelive.protocols['mbtiles:'] = require('mbtiles');

var tm = {};

// Set or get config.
tm.db;
tm._config = {};
tm.config = function(opts, callback) {
    if (!opts) return tm._config;

    tm._config = _(opts).defaults(tm._config);
    // @TODO create other paths (cache, etc.)
    try {
        mkdirp.sync(path.dirname(tm.config().db));
        mkdirp.sync(tm.config().cache);
        mkdirp.sync(tm.config().fonts);
    } catch(err) { throw err; }

    // Register default fonts.
    mapnik.register_fonts(path.dirname(require.resolve('tm2-default-fonts')), { recurse: true });
    mapnik.register_fonts(tm.config().fonts, { recurse: true });

    // Load + compact the app database.
    var old = require('dirty')(tm.config().db);
    old.on('load', function() {
        var db_name = tm.config().db;
        if (existsSync(db_name)) {
            fs.unlinkSync(db_name);
        }
        tm.db = require('dirty')(db_name);

        // Check app db version and run any migrations if necessary.
        switch (old.get('version')) {
        case 2:
            old.forEach(function(k,v) { tm.db.set(k,v); });
            break;
        case 1:
        case undefined:
            old.set('version', 2);
            old.set('history', _(old.get('history')||{}).reduce(function(memo, list, type) {
                if (type !== 'style' && type !== 'source') return memo;
                memo[type] = list.map(function(id) {
                    var uri = url.parse(id);
                    if (uri.protocol === 'mapbox:') {
                        return !uri.pathname ? id.replace('://', ':///') : id;
                    } else if (!uri.protocol) {
                        return 'tm' + type + '://' + uri.pathname;
                    } else {
                        return id;
                    }
                });
                return memo;
            }, { style:[], source:[] }));
            old.forEach(function(k,v) { tm.db.set(k,v); });
            break;
        };

        if (callback) return callback();
    });
    return tm._config;
};
tm.config({
    db: path.join(process.env.HOME, '.tilemill', 'v2', 'app.db'),
    cache: path.join(process.env.HOME, '.tilemill', 'v2', 'cache'),
    fonts: path.join(process.env.HOME, '.tilemill', 'v2', 'fonts'),
    mapboxauth: 'https://tiles.mapbox.com',
    mapboxtile: 'http://a.tiles.mapbox.com/v3'
});

// Set or remove a project id from recent history.
var defaultSources = [
    'mapbox:///mapbox.mapbox-streets-v4'
];
tm.history = function(type, id, invalidate) {
    var history = tm.db.get('history') || {};
    history = _(history).isArray() ? { style: history } : history;
    history.style = history.style || [];
    history.source = history.source || [];

    if (id && type) {
        if (!history[type]) throw new Error('History set requires valid type');
        var update = invalidate
            ? _(history[type]).reject(function(k) { return k === id; })
            : _(history[type].concat([id])).uniq();
        if (!_(update).isEqual(history[type])) {
            history[type] = update;
            tm.db.set('history', history);
        }
    }
    history.source = _(history.source.concat(defaultSources)).uniq();
    history.style.sort();
    history.source.sort();
    return history;
};

// Remotes cache.
tm.remote = function(id, data) {
    var remote = tm.db.get('remote') || {};
    if (!data) {
        return remote[id] || false;
    } else {
        remote[id] = data;
        tm.db.set('remote', remote);
        return remote[id];
    }
};

// Load templates.
tm.templates = _(fs.readdirSync(__dirname + '/../templates')).reduce(function(memo, file) {
    if (file.charAt(0) === '.') return memo;
    memo[file.split('.')[0]] = _(fs.readFileSync(__dirname + '/../templates/' + file, 'utf8')).template();
    return memo;
}, {});

// Writes an array of files defined by { basename:[basename], data:[data] }
tm.writefiles = function(basepath, files, callback) {
    var write = function() {
        if (!files.length) return callback();
        var file = files.shift();
        fs.writeFile(path.join(basepath, file.basename), file.data, function(err) {
            if (err) return callback(err);
            write();
        });
    };
    mkdirp(basepath, function(err) {
        if (err) return callback(err);
        write();
    });
};

// Reads a directory of files.
tm.dirfiles = function(basepath, callback) {
    fs.readdir(path.resolve(basepath), function(err, files) {
        if (err) return callback(err);
        files = files.filter(function(f) { return f[0] !== '.' });

        var stats = [];
        var stat = function() {
            if (!files.length) {
                stats.sort(function(a,b) {
                    if (a.type < b.type) return -1;
                    if (a.type > b.type) return 1;
                    if (a.basename.toLowerCase() < b.basename.toLowerCase()) return -1;
                    if (a.basename.toLowerCase() > b.basename.toLowerCase()) return 1;
                    return 0;
                });
                return callback(null, stats);
            }
            var p = path.join(basepath, files.shift());
            fs.stat(p, function(err, s) {
                if (err) return callback(err);
                if (s.isFile()) s.type = 'file';
                if (s.isDirectory()) s.type = 'dir';
                if (s.type) {
                    s.path = p;
                    s.extname = path.extname(p);
                    s.basename = path.basename(p);
                    stats.push(s);
                }
                stat();
            });
        };
        stat();
    });
};

// Filter keys out of an object that are not present in defaults.
tm.filterkeys = function(data, defaults) {
    return _(data).reduce(function(memo,v,k) {
        if (!(k in defaults)) return memo;
        memo[k] = v;
        return memo;
    }, {})
};

// Return an object with sorted keys, ignoring case.
tm.sortkeys = function(obj) {
    try {
        return obj.map(tm.sortkeys);
    } catch(e) {};
    try {
        return Object.keys(obj).sort(function(a, b) {
            a = a.toLowerCase();
            b = b.toLowerCase();
            if (a === 'id') return -1;
            if (b === 'id') return 1;
            if (a > b) return 1;
            if (a < b) return -1;
            return 0;
        }).reduce(function(memo, key) {
            memo[key] = tm.sortkeys(obj[key]);
            return memo;
        }, {});
    } catch(e) { return obj };
};

// Generate or verify that an id is a temporary one.
tm.tmpid = function(protocol, id, md5) {
    if (id && !md5) return (new RegExp(protocol + '\/\/\/tmp-[0-9a-f]{8}')).test(id);

    if (id && md5) {
        return protocol + '///tmp-' + crypto.createHash('md5').update(id).digest('hex').substr(0,8);
    } else {
        id = protocol + '///tmp-';
        var base16 = '0123456789abcdef';
        for (var i = 0; i < 8; i++) id += base16[Math.random() * 16 | 0];
        return id;
    }
};

// Named projections.
tm.srs = {
    'WGS84': '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs',
    '900913': '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over'
};
tm.extent = {
    'WGS84': '-180,-85.0511,180,85.0511',
    '900913': '-20037508.34,-20037508.34,20037508.34,20037508.34'
};
// Reverse the above hash to allow for srs name lookups.
tm.srsname = {};
for (name in tm.srs) tm.srsname[tm.srs[name]] = name;

// Render a preview image for a font.
tm.font = function(name, callback) {
    tm.fonts = tm.fonts || mapnik.fonts();
    if (tm.fonts.indexOf(name) === -1) return callback(new Error('Invalid font ' + name));

    // Attempt to retrieve from cache.
    var xml = tm.templates.xrayfont(name);
    var ckey = 'font-' + crypto.createHash('md5').update(xml).digest('hex').substr(0,8) + '.png';
    var file = tm.config().cache + '/' + ckey;
    fs.readFile(file, function(err, buffer) {
        if (err && err.code !== 'ENOENT') return callback(err);
        if (buffer) return callback(null, buffer);

        var map = new mapnik.Map(400,40);
        map.extent = [-180,-10,180,10];
        map.fromString(xml, function(err) {
            if (err) return callback(err);
            map.render(new mapnik.Image(400,40), {}, function(err, image) {
                if (err) return callback(err);
                image.encode('png8:m=h:c=64', function(err, buffer) {
                    if (err) return callback(err);

                    // Don't wait for disk write to return image buffer.
                    // If caching fails, error is logged to console.
                    callback(null, buffer);
                    fs.writeFile(file, buffer, function(err) {
                        if (err) console.error(err);
                    });
                });
            });
        });
    });
};

// For a given from => to copy task,
// 1. Returns a completed progress object if export exists.
// 2. Returns the current in-progress object if export is active.
// 3. Creates a new copy task for the export otherwise.
tm._copy = null;
tm.copytask = function(from, to, callback) {
    function state() {
        if (!tm._copy) return callback();
        // Snapshot current task stats.
        tm._copy.stats = tm._copy.task ? tm._copy.task.stats.snapshot() : null;
        // Return job object to caller.
        callback(null, tm._copy);
        // Clear out current job reference if complete.
        tm._copy = tm._copy.task ? tm._copy : null;
        return;
    };

    if (!from && !to) return state();

    if (tm._copy) return tm._copy.id !== from
        ? callback(new Error('Active task already in progress'))
        : state();

    var furi = url.parse(from);
    var turi = url.parse(to);

    if (furi.protocol !== 'tmsource:')
        return callback(new Error('Unsupported source protocol'));

    if (turi.protocol !== 'mbtiles:')
        return callback(new Error('Unsupported sink protocol'));

    fs.stat(turi.pathname, function(err, stat) {
        if (err && err.code !== 'ENOENT') return callback(err);

        if (stat) return callback(null, {
            id: from,
            file: turi.pathname,
            stat: stat,
            task: null,
            stats: null
        });

        var source = require('./source');
        source(from, function(err, s) {
            if (err) return callback(err);
            s.getInfo(function(err, info) {
                if (err) return callback(err);

                // Bounds may be set in source data. If not, derive.
                info.bounds = s.data.bounds || source.extent(s.data);

                var tmp = 'mbtiles:///tmp/' + path.basename(turi.pathname);
                var opts = {
                    minzoom: info.minzoom,
                    maxzoom: info.maxzoom,
                    bbox: info.bounds
                };
                var scheme = tilelive.Scheme.create('scanline', opts);
                var task = new tilelive.CopyTask(from, tmp, scheme);
                tm._copy = {
                    id: from,
                    file: null,
                    stat: null,
                    task: task,
                    stats: task.stats.snapshot()
                };

                // This method responds early to be as responsive as possible.
                // Errors in the export will be apparent one way or another.
                callback(null, tm._copy);

                // Move tmp export into place when complete.
                tm._copy.task.on('finished', function(err) {
                    // Enable caching on source again.
                    delete s._nocache;

                    fs.unlink(tm._copy.task.job, function(err) {
                        if (err) console.error(err);
                    });
                    fs.rename(url.parse(tmp).pathname, turi.pathname, function(err) {
                        if (err) return (tm._copy = err) && console.error(err);
                        fs.stat(turi.pathname, function(err, stat) {
                            if (err) return (tm._copy = err) && console.error(err);
                            tm._copy = {
                                id: from,
                                file: turi.pathname,
                                stat: stat,
                                task: null,
                                stats: null
                            };
                            console.log('[%s] %s complete',
                                (new Date).toUTCString(),
                                path.basename(from));
                        });
                    });
                });
                // Start the task.
                console.log('[%s] %s (z%d-%d @ %s)',
                    (new Date).toUTCString(),
                    path.basename(from),
                    opts.minzoom,
                    opts.maxzoom,
                    opts.bbox.join(','));

                // Disable source caching for export.
                s._nocache = true;

                tm._copy.task.start(function(err) {

                    // Emit an event for tests.
                    tm._copy.task.emit('started');

                    if (err) return (tm._copy = err) && console.error(err);
                    tm._copy.task.sink.putInfo(info, function(err) {
                        if (err) return (tm._copy = err) && console.error(err);
                    });
                });
            });
        });
    });
};

// Cancel/clear the current active task.
// No-op if no task is active.
tm.cleartask = function(callback) {
    if (!tm._copy) return callback();
    if (tm._copy.task) return tm._copy.task.pause(function(err) {
        if (err) return callback(err);
        // Remove sink file.
        fs.unlink(tm._copy.task.sink.filename, function(err) {
            if (err && err.code !== 'ENOENT') return callback(Err);
            // Remove job file.
            fs.unlink(tm._copy.task.job, function(err) {
                if (err && err.code !== 'ENOENT') return callback(Err);
                console.log('[%s] %s canceled',
                    (new Date).toUTCString(),
                    path.basename(tm._copy.id));
                tm._copy = null;
                return callback();
            });
        });
    });
    tm._copy = null;
    return callback();
};

module.exports = tm;
<|endoftext|>


<commit_before>'use strict'

const read  = require('fs').readFileSync
const path  = require('path')
const h     = require('pithy')
const filesize = require('filesize')

const css = {
	  base:   read(path.join(__dirname, '../css/base.css'))
	, dir:    read(path.join(__dirname, '../css/dir.css'))
	, menu:   read(path.join(__dirname, '../css/menu.css'))
	, upload: read(path.join(__dirname, '../css/upload.css'))
}
const js = {
	  fetch:  read(require.resolve('whatwg-fetch/fetch'))
	, delete: read(path.join(__dirname, '../js/delete.js'))
	, upload: read(path.join(__dirname, '../js/upload.js'))
}

const size = (bytes) => filesize(bytes, {
	spacer: '', round: 1,
	symbols: {B: 'b', KB: 'k', MB: 'm', GB: 'g', TB: 't'}
})

const head = (_) => `
<!DOCTYPE html>

	<title>${_.name}/${_.path}</title>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width,initial-scale=1">

`

const partOfPath = (part, i, all) =>
	h.li(i === (all.length - 1) ? '.active' : null, [
		h.a({href: encodeURI(part.path)}, part.name)
	])

const menu = (_) => `

`
+ _.breadcrumb.map(partOfPath).join('\n')
+ `</ul></div>`

const upload = (_) => `

<form id="upload" class="container" action="${_.path}" method="POST" enctype="multipart/form-data">

		select files
		<input name="files" type="file" required multiple>

	<input id="upload-submit" type="submit" value="upload">
</form>
`

const file = (file) => `

		${file.name}${file.isDir ? '/' : ''}

	${file.isDir ? '' : size(file.size)}

	<form class="file-actions-delete" method="DELETE"
		action="${encodeURI(file.path)}">
		<input class="file-actions-delete-button" type="submit" value="delete">
	</form>

`

const ui = (_) =>
  head(_)
+ `<body>`
+ menu(_)
+ upload(_)
+ `

`
+ _.files.map(file).join('\n')
+ `

`

module.exports = ui
<commit_msg>refactor ui code<commit_after>'use strict'

const read  = require('fs').readFileSync
const path  = require('path')
const h     = require('pithy')
const filesize = require('filesize')

const css = {
	  base:   read(path.join(__dirname, '../css/base.css'))
	, dir:    read(path.join(__dirname, '../css/dir.css'))
	, menu:   read(path.join(__dirname, '../css/menu.css'))
	, upload: read(path.join(__dirname, '../css/upload.css'))
}
const js = {
	  fetch:  read(require.resolve('whatwg-fetch/fetch'))
	, delete: read(path.join(__dirname, '../js/delete.js'))
	, upload: read(path.join(__dirname, '../js/upload.js'))
}

const size = (bytes) => filesize(bytes, {
	spacer: '', round: 1,
	symbols: {B: 'b', KB: 'k', MB: 'm', GB: 'g', TB: 't'}
})

const head = (_) => `
<!DOCTYPE html>

	<title>${_.name}/${_.path}</title>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width,initial-scale=1">

`

const partOfPath = (part, i, all) =>
	h.li(i === (all.length - 1) ? '.active' : null, [
		h.a({href: encodeURI(part.path)}, part.name)
	])

const menu = (_) =>
	`<style>${css.menu}</style>`
	+ h.div({id: 'menu'}, [
		h.ul({id: 'breadcrumb', class: 'container'},
			_.breadcrumb.map(partOfPath))
	])

const upload = (_) =>
	`<style>${css.upload}</style>`
	+ h.form({
		id: 'upload', class: 'container',
		method: 'POST', action: _.path, enctype: 'multipart/form-data'
	}, [
		h.label({id: 'upload-files'}, [
			h.span({class: 'button'}, 'select files'),
			h.input({name: 'files', type: 'file', required: true, multiple: true})
		]),
		h.input({id: 'upload-submit', type: 'submit', value: 'upload'})
	])
	+ `<script type="application/javascript">${js.upload}</script>`

const nameColumn = (file) =>
	h.td({class: 'file-name'}, [
		h.a({href: encodeURI(file.path)}, [
			file.name,
			file.isDir ? h.span({class: 'file-suffix'}, '/') : ''
		])
	])

const sizeColumn = (file) =>
	h.td({class: 'file-size'}, file.isDir ? '' : size(file.size))

const actionsColumn = (file) =>
	h.td({class: 'file-actions'}, [
		h.form({class: 'file-actions-delete',
			method: 'DELETE', action: encodeURI(file.path)}, [
			h.input({class: 'file-actions-delete-button', type: 'submit', value: 'delete'})
		])
	])

const file = (file) => h.tr({class: 'file'}, [
	nameColumn(file),
	sizeColumn(file),
	actionsColumn(file)
])

const ui = (_) =>
  head(_)
+ `<body>`
+ menu(_)
+ upload(_)
+ `

`
+ _.files.map(file).join('\n')
+ `

`

module.exports = ui
<|endoftext|>


<commit_before>/*****************************************************************************
    User Interface Components

    Major Sections
        fill_vertical   Function to max out an element's potential height
        progress        Class to help draw and update CSS+JS progress bars
*****************************************************************************/

/**
 *  UI Namespace Container
 *
 */
var ui = {};

/**
 *  Modifies an element's height to completely fill the remaining vertical
 *  space of a reference element.  If the reference element happens to be the
 *  document element, the target element will fill the remainder of the
 *  viewport.
 *
 *  @param elem         The target element to resize
 *  @param relem        The reference element to attempt to fill
 *  @param bounce       Optional amount of margin below the target element
 *  @return             The height value that was used to resize the element
 */
function fill_vertical( elem, relem ) {

    //check/default the bounce argument
    var bounce = arguments[ 2 ] ? arguments[ 2 ] : 0;

    //retrieve the bounding rectangles of both elements
    var elem_rect  = elem.getBoundingClientRect();
    var relem_rect = relem.getBoundingClientRect();

    //determine the height that will be filled
    var fill_height = relem_rect.height;
    if( relem.clientHeight ) {
        fill_height = relem.clientHeight;
    }

    //get the target element's current style information
    var style = window.getComputedStyle( elem, null );

    //compensate for other styling factors that add padding/borders
    var inner_height = parseInt( style.getPropertyValue( 'height' ) );
    var vertical_padding = elem_rect.height - inner_height;

    //compensate for differences in the tops of both elements
    var vertical_offset = elem_rect.top - relem_rect.top;

    //compute the new height of target element
    var height = fill_height - vertical_offset - vertical_padding - bounce;

    //resize to and report the new height
    elem.style.height = height + 'px';
    return height;
}

/**
 *  Class to augment an indeterminate progress bar so it can be updated to
 *  show computed progress for a task.
 *
 *  @param element      The DOM element for an indeterminate progress bar
 */
ui.progress = function( element ) {

    this.bar = element;

    //this locks the bar's height as it's about to lose all its content
    this.bar.style.height = this.bar.clientHeight + 'px';

    //create a wrapper element that will draw the unfilled area of the bar
    this.wrapper = document.createElement( 'div' );
    this.wrapper.className = 'progress_wrapper';

    //swap the bar node with the wrapper node in the document
    var pnode = this.bar.parentNode;
    pnode.replaceChild( this.wrapper, this.bar );
    this.wrapper.appendChild( this.bar );

    //create a content element to control the bar's contents without being
    //  affected by changes to its width (which indicate progress ratio)
    this.content = document.createElement( 'div' );
    this.content.className = 'progress_content';

    //re-attach the bar's children to the content element
    while( this.bar.childNodes.length > 0 ) {
        this.content.appendChild(
            this.bar.removeChild( this.bar.firstChild )
        );
    }

    //attach the content element to the wrapper
    this.wrapper.appendChild( this.content );
};

/**
 *  Retrieves the outer-most DOM element for this widget.
 *
 *  @return             Reference to outer-most DOM element
 */
ui.progress.prototype.get_container = function() {
    return this.wrapper;
};

/**
 *  Sends updates to the progress bar.
 *
 *  @param ratio        The fill ratio from 0.0 to 1.0.
 */
ui.progress.prototype.update = function( ratio ) {
    this.bar.style.width = ( ratio * 100.0 ) + '%'
};

<commit_msg>Porting some old code to UI library.<commit_after>/*****************************************************************************
    User Interface Components

    Components
        body_append     Function to append to body
        body_remove_id  Function to remove an element from the body
        fill_vertical   Function to max out an element's potential height
        progress        Class to help draw and update CSS+JS progress bars
*****************************************************************************/

/**
 *  UI Namespace Container
 *
 */
var ui = {};

/**
 *  Shorthand to append an element to the document body.
 *
 *  @param element      The element to append
 */
ui.body_append = function( element ) {
    document.getElementsByTagName( 'body' ).item( 0 ).appendChild( element );
};

/**
 *  Shorthand to remove an element from the document body by ID.
 *
 *  @param id           The ID of the element to remove
 *  @return             True if removed, false on failure
 */
ui.body_remove_id = function( id ) {
    var body = document.getElementsByTagName( 'body' ).item( 0 );
    var element = document.getElementById( id );
    if( element != null ) {
        body.removeChild( element );
        return true;
    }
    return false;
};

/**
 *
 *
 */
ui.close_id = function( id, result ) {
    var element = document.getElementById( id );
    if( element != null ) {
        ////ZIH - close detection and events happen here
        ui.body_remove_id( id );
    }
};

/**
 *
 *
 */
ui.create_overlay = function() {

    //specifying a closer element ID can pass a close result back to the
    //  dialog that probably requested the overlay in the first place
    //if the overlay doesn't have an interactive dialog on top of it, you can
    //  also just pass 'hzui_overlay' to allow it to close itself
    var closer = arguments[ 0 ] ? arguments[ 0 ] : false;
    var element = document.createElement( 'div' );
    element.id = 'hzui_overlay';
    element.className = 'overlay';
    if( closer != false ) {
        element.onclick = function( e ) {
            ui.close_id( closer, true );
        };
    }
    ui.body_append( element );
};

/**
 *  Modifies an element's height to completely fill the remaining vertical
 *  space of a reference element.  If the reference element happens to be the
 *  document element, the target element will fill the remainder of the
 *  viewport.
 *
 *  @param elem         The target element to resize
 *  @param relem        The reference element to attempt to fill
 *  @param bounce       Optional amount of margin below the target element
 *  @return             The height value that was used to resize the element
 */
ui.fill_vertical = function( elem, relem ) {

    //check/default the bounce argument
    var bounce = arguments[ 2 ] ? arguments[ 2 ] : 0;

    //retrieve the bounding rectangles of both elements
    var elem_rect  = elem.getBoundingClientRect();
    var relem_rect = relem.getBoundingClientRect();

    //determine the height that will be filled
    var fill_height = relem_rect.height;
    if( relem.clientHeight ) {
        fill_height = relem.clientHeight;
    }

    //get the target element's current style information
    var style = window.getComputedStyle( elem, null );

    //compensate for other styling factors that add padding/borders
    var inner_height = parseInt( style.getPropertyValue( 'height' ) );
    var vertical_padding = elem_rect.height - inner_height;

    //compensate for differences in the tops of both elements
    var vertical_offset = elem_rect.top - relem_rect.top;

    //compute the new height of target element
    var height = fill_height - vertical_offset - vertical_padding - bounce;

    //resize to and report the new height
    elem.style.height = height + 'px';
    return height;
};

/**
 *  Shorthand to map data from one object to another.
 *
 *  @param target       The recipient of the data
 *  @param source       The originator of the data
 */
ui.omap = function( target, source ) {
    for( var key in source ) {
        target[ key ] = source[ key ];
    }
};

/**
 *  Class to augment an indeterminate progress bar so it can be updated to
 *  show computed progress for a task.
 *
 *  @param element      The DOM element for an indeterminate progress bar
 */
ui.progress = function( element ) {

    this.bar = element;

    //this locks the bar's height as it's about to lose all its content
    this.bar.style.height = this.bar.clientHeight + 'px';

    //create a wrapper element that will draw the unfilled area of the bar
    this.wrapper = document.createElement( 'div' );
    this.wrapper.className = 'progress_wrapper';

    //swap the bar node with the wrapper node in the document
    var pnode = this.bar.parentNode;
    pnode.replaceChild( this.wrapper, this.bar );
    this.wrapper.appendChild( this.bar );

    //create a content element to control the bar's contents without being
    //  affected by changes to its width (which indicate progress ratio)
    this.content = document.createElement( 'div' );
    this.content.className = 'progress_content';

    //re-attach the bar's children to the content element
    while( this.bar.childNodes.length > 0 ) {
        this.content.appendChild(
            this.bar.removeChild( this.bar.firstChild )
        );
    }

    //attach the content element to the wrapper
    this.wrapper.appendChild( this.content );
};

/**
 *  Retrieves the outer-most DOM element for this widget.
 *
 *  @return             Reference to outer-most DOM element
 */
ui.progress.prototype.get_container = function() {
    return this.wrapper;
};

/**
 *  Sends updates to the progress bar.
 *
 *  @param ratio        The fill ratio from 0.0 to 1.0.
 */
ui.progress.prototype.update = function( ratio ) {
    this.bar.style.width = ( ratio * 100.0 ) + '%'
};

<|endoftext|>


<commit_before>/* eslint-env node */
module.exports = {
  test_page: 'tests/index.html?hidepassed',
  disable_watching: true,
  parallel: -1,
  launch_in_ci: [
    'Chrome',
    'Firefox'
  ],
  launch_in_dev: [
    'Chrome',
    'Firefox'
  ],
  browser_args: {
    Chrome: [
      '--headless',
      '--remote-debugging-port=9222',
      '--window-size=1440,900'
    ],
    Firefox: [
      '-headless',
      '--window-size=1440,900'
    ]
  }
};
<commit_msg>test(chrome): add `--disable-gpu` option back to chrome launcher<commit_after>/* eslint-env node */
module.exports = {
  test_page: 'tests/index.html?hidepassed',
  disable_watching: true,
  parallel: -1,
  launch_in_ci: [
    'Chrome',
    'Firefox'
  ],
  launch_in_dev: [
    'Chrome',
    'Firefox'
  ],
  browser_args: {
    Chrome: [
      '--headless',
      '--disable-gpu',
      '--remote-debugging-port=9222',
      '--window-size=1440,900'
    ],
    Firefox: [
      '-headless',
      '--window-size=1440,900'
    ]
  }
};
<|endoftext|>


<commit_before>/* eslint-env node */
module.exports = {
  test_page: 'tests/index.html?hidepassed',
  disable_watching: true,
  launch_in_ci: [
    'Chrome'
  ],
  launch_in_dev: [
    'Chrome'
  ],
  browser_args: {
    Chrome: {
      mode: 'ci',
      args: [
        '--disable-gpu',
        '--headless',
        '--remote-debugging-port=0',
        '--window-size=1440,900'
      ]
    }
  }
};
<commit_msg>Fix issue with Chrome + Travis & setuid...<commit_after>/* eslint-env node */
module.exports = {
  test_page: 'tests/index.html?hidepassed',
  disable_watching: true,
  launch_in_ci: [
    'Chrome'
  ],
  launch_in_dev: [
    'Chrome'
  ],
  browser_args: {
    Chrome: {
      mode: 'ci',
      args: [
        // --no-sandbox is needed when running Chrome inside a container
        process.env.TRAVIS ? '--no-sandbox' : null,

        '--disable-gpu',
        '--headless',
        '--remote-debugging-port=0',
        '--window-size=1440,900'
      ].filter(Boolean)
    }
  }
};
<|endoftext|>


<commit_before>#!/usr/bin/env node
const path = require('path')
const spawn = require('child_process').spawn
const pkgDir = require('pkg-dir')
const suite = {
  'android': {
    'testName': 'test_android.js',
    'appiumVersions': ['1.4.16', '1.5.3'],
    'devices': ['Android Emulator'],
    'platforms': ['5.1', '5.0', '4.4'],
    'avd': {
      'name': 'Nexus_6_API_23',
      'deviceName': 'Android Emulator',
      'platformVersion': '5.0'
    }
  }
}
function createGrid (suite, args) {
  let testArgs = []
  let grid = []
  for (let a in suite.appiumVersions) {
    for (let d in suite.devices) {
      for (let p in suite.platforms) {
        testArgs.push('--appiumVersion')
        testArgs.push(suite.appiumVersions[a])
        testArgs.push('--deviceName')
        testArgs.push(suite.devices[d])
        testArgs.push('--platformVersion')
        testArgs.push(suite.platforms[p])
        grid.push(args.concat(testArgs))
        testArgs = []
      }
    }
  }
  return grid
}
function runTest (cmd, grid) {
  if (grid.length === 0) {
    console.log('All tests done')
    process.exit(0)
  }
  let test = grid.shift()
  let child = spawn(cmd, test, {stdio: 'inherit'})
  child.on('close', function (code) {
    if (code !== 0) {
      process.exit(1)
    }
    runTest(cmd, grid)
  })
}
function testAllDaThings () {
  let cmd = './node_modules/mocha/bin/mocha'
  for (let key in suite) {
    let args = []
    args.push(path.join(pkgDir.sync(__dirname), 'tests', suite[key].testName))
    args.push('--compilers')
    args.push('js:babel-core/register')
    args.push('-t')
    args.push('0')
    let grid = []
    if (process.env.IS_LOCAL === '1') {
      args.push('-R')
      args.push('nyan')
      // local testing
      if (key === 'android') {
        args.push('--avdName')
        args.push(suite[key].avd.name)
        args.push('--deviceName')
        args.push(`'${suite[key].avd.deviceName}'`)
        args.push('--platformVersion')
        args.push(suite[key].avd.platformVersion)
      }
      grid.push(args)
    } else {
      // sauce testing
      grid = createGrid(suite[key], args)
    }
    runTest(cmd, grid)
  }
}

testAllDaThings()
<commit_msg>use one version of appium<commit_after>#!/usr/bin/env node
const path = require('path')
const spawn = require('child_process').spawn
const pkgDir = require('pkg-dir')
const suite = {
  'android': {
    'testName': 'test_android.js',
    'appiumVersions': ['1.5.3'],
    'devices': ['Android Emulator'],
    'platforms': ['5.1', '5.0', '4.4'],
    'avd': {
      'name': 'Nexus_6_API_23',
      'deviceName': 'Android Emulator',
      'platformVersion': '5.0'
    }
  }
}
function createGrid (suite, args) {
  let testArgs = []
  let grid = []
  for (let a in suite.appiumVersions) {
    for (let d in suite.devices) {
      for (let p in suite.platforms) {
        testArgs.push('--appiumVersion')
        testArgs.push(suite.appiumVersions[a])
        testArgs.push('--deviceName')
        testArgs.push(suite.devices[d])
        testArgs.push('--platformVersion')
        testArgs.push(suite.platforms[p])
        grid.push(args.concat(testArgs))
        testArgs = []
      }
    }
  }
  return grid
}
function runTest (cmd, grid) {
  if (grid.length === 0) {
    console.log('All tests done')
    process.exit(0)
  }
  let test = grid.shift()
  let child = spawn(cmd, test, {stdio: 'inherit'})
  child.on('close', function (code) {
    if (code !== 0) {
      process.exit(1)
    }
    runTest(cmd, grid)
  })
}
function testAllDaThings () {
  let cmd = './node_modules/mocha/bin/mocha'
  for (let key in suite) {
    let args = []
    args.push(path.join(pkgDir.sync(__dirname), 'tests', suite[key].testName))
    args.push('--compilers')
    args.push('js:babel-core/register')
    args.push('-t')
    args.push('0')
    let grid = []
    if (process.env.IS_LOCAL === '1') {
      args.push('-R')
      args.push('nyan')
      // local testing
      if (key === 'android') {
        args.push('--avdName')
        args.push(suite[key].avd.name)
        args.push('--deviceName')
        args.push(`'${suite[key].avd.deviceName}'`)
        args.push('--platformVersion')
        args.push(suite[key].avd.platformVersion)
      }
      grid.push(args)
    } else {
      // sauce testing
      grid = createGrid(suite[key], args)
    }
    runTest(cmd, grid)
  }
}

testAllDaThings()
<|endoftext|>


<commit_before>
let rpn = (number1, number2, operator) => {

    if (operator === '+') {
        return number1 + number2
    } else if (operator === '-') {
        return number1 - number2
    } else if (operator === '/') {
        return number1 / number2
    } else if (operator === '*') {
        return number1 * number2
    }

    console.log(result);
    return result;
}

const calculations = {

};

const myMethods = {
      '+'(a) {
          return b => a + b;
      },
    '-'(a, b) {
        return a - b;
    },
    '/'(a, b) {
        return a / b;
    },
   '*'(a, b) {
        return a * b;
    },
};

const myMethods = new Map([
   ['*', mult],
]);

myMethods.get('*');

const withA = myMethods[operator](a);
a(b) === a + b;

// const withA = myMethods[operator](a);
// a(b) === a + b;

// let calculation = (input) => {
//     let result = 0;
//
//     let arLoop = () => {
//         let inputArgs = input, values = [], i;
//         i = inputArgs.shift();
//
//         if (isFinite(inputArgs[i])) {
//             values.push(inputArgs[i])
//         } else {
//             let number1 = values.pop(), number2 = values.pop();
//
//             //Check what operator was used and apply the correct formula
//             if (inputArgs[i] === "+") {
//                 result = number1 + number2;
//             } else if (inputArgs[i] === "-") {
//                 result = number1 - number2;
//             } else if (inputArgs[i] === "*") {
//                 result = number1 * number2;
//             } else if (inputArgs[i] === "/") {
//                 result = number1 / number2;
//             }
//         } if (values.length > 1) {
//             return arLoop();
//         } else if (isNaN(result) || result === "undefined") {
//             console.log("Ohh you fucked up!")
//         } else {
//             return result;
//         }
//     }
// };
<commit_msg>Delete Random.js<commit_after><|endoftext|>


<commit_before>/*

  Note:
    link to original code:
    https://github.com/Max-Makhrov/GoogleSheets/edit/master/Sheets.js

    this code use:
    https://github.com/Max-Makhrov/GoogleSheets/blob/master/2dArray.js

*/

/*
   _____ _               _         _____        __
  / ____| |             | |       |_   _|      / _|
 | (___ | |__   ___  ___| |_ ___    | |  _ __ | |_ ___
  \___ \| '_ \ / _ \/ _ \ __/ __|   | | | '_ \|  _/ _ \
  ____) | | | |  __/  __/ |_\__ \  _| |_| | | | || (_) |
 |_____/|_| |_|\___|\___|\__|___/ |_____|_| |_|_| \___/

*/

/*
    use getSheetsInfo(ids)

    write the report into sheet:

    input:
      * file                       SpreadSheet
      * strSheet                   'Sheet1'
      * data                       [['Name', 'Age'], ['Max', 28], ['Lu', 26]]

  If strSheet doesn't exist → creates new sheet

*/
function writeDataIntoSheet(file, sheet, data, rowStart, colStart) {
  file = file || SpreadsheetApp.getActiveSpreadsheet();

  // get sheet as object
  switch(typeof sheet) {
    case 'object':
        break;
    case 'string':
        sheet = createSheetIfNotExists(file, sheet);
        break;
    default:
        return 'sheet is invalid';
  }

  // get dimansions and get range
  rowStart = rowStart || 1;
  colStart = colStart || 1;
  var numRows = data.length;
  var numCols = data[0].length;
  var range = sheet.getRange(rowStart, colStart, numRows, numCols);

  // clear old data if rowStart or colStart are not defined
  if(!rowStart && !colStart) { sheet.clearContents(); }

  // set values
  range.setValues(data);

  // report success
  return 'Wtite data to sheet -- ok!';

}

function TESTwriteDataIntoSheet() {
  var data = [['Name', 'Age'], ['Max', 28], ['Lu', 26]];
  var strSheet = "Sheet1";
  Logger.log(writeDataIntoSheet(false, strSheet, data));

}

/*

  input
    * ids                          '16rzrnZrAQK9czPHOfAN...'

                            or 2Darray:

                              column
                                   [['sdfswee...'], ['s123df...'], ['...'], ...]

                              or line
                                  ['sdfswee...', 's123df...', '...', ...]]
  output
    array
      ____________________________________________________________________________
      [['Id*', 'fileId', 'fileName', 'sheetId', 'sheetName', 'lastRow', 'lastCol']
       ['...', '16rr...', 'My Fi...', 'sdFg...', 'my she...',     5000 ,       28]
       [ ...                                                                     ]]
      -----------------------------------------------------------------------------
      * Id = fileName/sheetName/fileId/sheetId
*/
function getSheetsInfo(ids) {

  var result = [];
  var headers = ['Id', 'fileId', 'fileName', 'sheetId', 'sheetName', 'lastRow', 'lastCol'];
  // Id = fileName/sheetName/fileId/sheetId

  result.push(headers);

  if (Array.isArray(ids)) {

    ids = get1DArray(ids);

    var rows = [];
    for (var i = 0; i < ids.length; i++) {
      rows = [];
      rows = getSheetsInfo_(ids[i]);
      result = result.concat(rows);
    }

  }
  else {
    result = getSheetsInfo_(ids);
  }

  return result;

}
function TESTgetSheetsInfo() {
  var ids = ['16rzrnZrAQK9cz...', '1ld-Ww6WiOO8r39vcOPcF...'];
  var data = getSheetsInfo(ids);
  Logger.log(data);

}

/*
  input
    * fileId                '16rzrnZrAQK9czPHOfANJNsDN1_Ni3ecU40GStF3aWSM'

  output
    array
      [['fileId', 'fileName', 'sheetId', 'sheetName', 'lastRow', 'lastCol']
      ______________________________________________________________________
   →  [['16r...', 'My Fi...', 'sdFg...', 'my she...',     5000 ,       28 ]
       [...                                                               ]]
      ----------------------------------------------------------------------

*/
function getSheetsInfo_(fileId) {
  var result = [];

  var row = [];

  var file = SpreadsheetApp.openById(fileId);
  var fileName = file.getName();
  var sheets = file.getSheets();
  var sheetName, sheetId
  for (var i = 0; i < sheets.length; i++) {

    var sheet = sheets[i];

    row = [];

    sheetName = sheet.getName();
    sheetId = sheet.getSheetId();
    // Id = fileName/sheetName/fileId/sheetId
    row.push(fileName + '/' + sheetName + '/' + fileId + '/' + sheetId);
    row.push(fileId);
    row.push(fileName);
    row.push(sheetId);
    row.push(sheetName);
    row.push(sheet.getLastRow());
    row.push(sheet.getLastColumn());

    result.push(row);

  }

  return result;

}

/*

  __  __             _             _       _          _____ _               _
 |  \/  |           (_)           | |     | |        / ____| |             | |
 | \  / | __ _ _ __  _ _ __  _   _| | __ _| |_ ___  | (___ | |__   ___  ___| |_ ___
 | |\/| |/ _` | '_ \| | '_ \| | | | |/ _` | __/ _ \  \___ \| '_ \ / _ \/ _ \ __/ __|
 | |  | | (_| | | | | | |_) | |_| | | (_| | ||  __/  ____) | | | |  __/  __/ |_\__ \
 |_|  |_|\__,_|_| |_|_| .__/ \__,_|_|\__,_|\__\___| |_____/|_| |_|\___|\___|\__|___/
                      | |
                      |_|
*/

/* copySheet
  * make copy of sheet and mave it after current sheet

  * SS           SpreadSheet
  * strToCopy    Name of sheet to copy
  * strName      Name of new sheet
*/
function copySheet(SS, strToCopy, strName) {

  var SS = SS || SpreadsheetApp.getActiveSpreadsheet();
  var sheet = SS.getSheetByName(strToCopy);
  var newSheet = sheet.copyTo(SS);
  newSheet.setName(strName);
  var index = sheet.getIndex() + 1;
  SS.setActiveSheet(newSheet);
  SS.moveActiveSheet(index);

}

/*
  Creates sheet if it does not exist
  Returns sheet object

  * ss           SpreadSheet                 default: current sheet
  * name         Name of sheet
*/
function createSheetIfNotExists(ss, name) {
  var ss = ss || SpreadsheetApp.getActiveSpreadsheet();

  try {ss.setActiveSheet(ss.getSheetByName(name));}
    catch (e) {ss.insertSheet(name);}

  var sheet = ss.getSheetByName(name);
  return sheet;
}

<commit_msg>Update Sheets.js<commit_after>/*

  Note:
    link to original code:
    https://github.com/Max-Makhrov/GoogleSheets/edit/master/Sheets.js

    this code use:
    https://github.com/Max-Makhrov/GoogleSheets/blob/master/2dArray.js

*/

/*
   _____ _               _         _____        __
  / ____| |             | |       |_   _|      / _|
 | (___ | |__   ___  ___| |_ ___    | |  _ __ | |_ ___
  \___ \| '_ \ / _ \/ _ \ __/ __|   | | | '_ \|  _/ _ \
  ____) | | | |  __/  __/ |_\__ \  _| |_| | | | || (_) |
 |_____/|_| |_|\___|\___|\__|___/ |_____|_| |_|_| \___/

*/

/*
    use getSheetsInfo(ids)

    write the report into sheet:

    input:
      * file                       SpreadSheet
      * strSheet                   'Sheet1'
      * data                       [['Name', 'Age'], ['Max', 28], ['Lu', 26]]

  If strSheet doesn't exist → creates new sheet

*/
function writeDataIntoSheet(file, sheet, data, rowStart, colStart) {
  file = file || SpreadsheetApp.getActiveSpreadsheet();

  // get sheet as object
  switch(typeof sheet) {
    case 'object':
        break;
    case 'string':
        sheet = createSheetIfNotExists(file, sheet);
        break;
    default:
        return 'sheet is invalid';
  }

  // get dimansions and get range
  rowStart = rowStart || 1;
  colStart = colStart || 1;
  var numRows = data.length;
  var numCols = data[0].length;
  var range = sheet.getRange(rowStart, colStart, numRows, numCols);

  // clear old data if rowStart or colStart are not defined
  if(!rowStart && !colStart) { sheet.clearContents(); }

  // set values
  range.setValues(data);

  // report success
  return 'Wtite data to sheet -- ok!';

}

function TESTwriteDataIntoSheet() {
  var data = [['Name', 'Age'], ['Max', 28], ['Lu', 26]];
  var strSheet = "Sheet1";
  Logger.log(writeDataIntoSheet(false, strSheet, data));

}

/*

  input
    * ids                          '16rzrnZrAQK9czPHOfAN...'

                            or 2Darray:

                              column
                                   [['sdfswee...'], ['s123df...'], ['...'], ...]

                              or line
                                  ['sdfswee...', 's123df...', '...', ...]]
  output
    array
      ____________________________________________________________________________
      [['Id*', 'fileId', 'fileName', 'sheetId', 'sheetName', 'lastRow', 'lastCol']
       ['...', '16rr...', 'My Fi...', 'sdFg...', 'my she...',     5000 ,       28]
       [ ...                                                                     ]]
      -----------------------------------------------------------------------------
      * Id = fileName/sheetName/fileId/sheetId
*/
function getSheetsInfo(ids) {

  var result = [];
  var headers = ['Id', 'fileId', 'fileName', 'sheetId', 'sheetName', 'lastRow', 'lastCol'];
  // Id = fileName/sheetName/fileId/sheetId

  result.push(headers);

  if (Array.isArray(ids)) {

    ids = get1DArray(ids);

    var rows = [];
    for (var i = 0; i < ids.length; i++) {
      rows = [];
      rows = getSheetsInfo_(ids[i]);
      result = result.concat(rows);
    }

  }
  else {
    result = getSheetsInfo_(ids);
  }

  return result;

}
function TESTgetSheetsInfo() {
  var ids = ['16rzrnZrAQK9cz...', '1ld-Ww6WiOO8r39vcOPcF...'];
  var data = getSheetsInfo(ids);
  Logger.log(data);

}

/*
  input
    * fileId                '16rzrnZrAQK9czPHOfANJNsDN1_Ni3ecU40GStF3aWSM'

  output
    array
      [['fileId', 'fileName', 'sheetId', 'sheetName', 'lastRow', 'lastCol']
      ______________________________________________________________________
   →  [['16r...', 'My Fi...', 'sdFg...', 'my she...',     5000 ,       28 ]
       [...                                                               ]]
      ----------------------------------------------------------------------

*/
function getSheetsInfo_(fileId) {
  var result = [];

  var row = [];

  var file = SpreadsheetApp.openById(fileId);
  var fileName = file.getName();
  var sheets = file.getSheets();
  var sheetName, sheetId
  for (var i = 0; i < sheets.length; i++) {

    var sheet = sheets[i];

    row = [];

    sheetName = sheet.getName();
    sheetId = sheet.getSheetId();
    // Id = fileName/sheetName/fileId/sheetId
    row.push(fileName + '/' + sheetName + '/' + fileId + '/' + sheetId);
    row.push(fileId);
    row.push(fileName);
    row.push(sheetId);
    row.push(sheetName);
    row.push(sheet.getLastRow());
    row.push(sheet.getLastColumn());

    result.push(row);

  }

  return result;

}

/*
  returns sheet {} by given fileId, sheetId
*/
function test_getSheetById()
{
 var fileId = '1wTEo0fat1y5dh_JwGHqaVCPNSjaodD6OrVdbglM8WD8';
 var sheetId = 0;
  Logger.log(getSheetById(fileId, sheetId).getName());

}
function getSheetById(fileId, sheetId)
{
  var file = SpreadsheetApp.openById(fileId);
  var sheets = file.getSheets();

  for(var i = 0, l = sheets.length; i < l; i++)
  {
   if (sheets[i].getSheetId() == sheetId) return sheets[i];
  }

  return false;

}

/*

  __  __             _             _       _          _____ _               _
 |  \/  |           (_)           | |     | |        / ____| |             | |
 | \  / | __ _ _ __  _ _ __  _   _| | __ _| |_ ___  | (___ | |__   ___  ___| |_ ___
 | |\/| |/ _` | '_ \| | '_ \| | | | |/ _` | __/ _ \  \___ \| '_ \ / _ \/ _ \ __/ __|
 | |  | | (_| | | | | | |_) | |_| | | (_| | ||  __/  ____) | | | |  __/  __/ |_\__ \
 |_|  |_|\__,_|_| |_|_| .__/ \__,_|_|\__,_|\__\___| |_____/|_| |_|\___|\___|\__|___/
                      | |
                      |_|
*/

/* copySheet
  * make copy of sheet and mave it after current sheet

  * SS           SpreadSheet
  * strToCopy    Name of sheet to copy
  * strName      Name of new sheet
*/
function copySheet(SS, strToCopy, strName) {

  var SS = SS || SpreadsheetApp.getActiveSpreadsheet();
  var sheet = SS.getSheetByName(strToCopy);
  var newSheet = sheet.copyTo(SS);
  newSheet.setName(strName);
  var index = sheet.getIndex() + 1;
  SS.setActiveSheet(newSheet);
  SS.moveActiveSheet(index);

}

/*
  Creates sheet if it does not exist
  Returns sheet object

  * ss           SpreadSheet                 default: current sheet
  * name         Name of sheet
*/
function createSheetIfNotExists(ss, name) {
  var ss = ss || SpreadsheetApp.getActiveSpreadsheet();

  try {ss.setActiveSheet(ss.getSheetByName(name));}
    catch (e) {ss.insertSheet(name);}

  var sheet = ss.getSheetByName(name);
  return sheet;
}

<|endoftext|>


<commit_before>walk(document.body);

function walk(node)
{
	// I stole this function from here:
	// http://is.gd/mwZp7E

	var child, next;

	switch ( node.nodeType )
	{
		case 1:  // Element
		case 9:  // Document
		case 11: // Document fragment
			child = node.firstChild;
			while ( child )
			{
				next = child.nextSibling;
				walk(child);
				child = next;
			}
			break;

		case 3: // Text node
			handleText(node);
			break;
	}
}

function handleText(textNode)
{
	var v = textNode.nodeValue;

	// Fix some misspellings
	v = v.replace(/\b(M|m)illienial(s)?\b/g, "$1illennial$2");
	v = v.replace(/\b(M|m)illenial(s)?\b/g, "$1illennial$2");
	v = v.replace(/\b(M|m)ilennial(s)?\b/g, "$1illennial$2");
	v = v.replace(/\b(M|m)ilenial(s)?\b/g, "$1illennial$2");

	// Millennial Generation
	v = v.replace(
		/\b(?:Millennial Generation)|(?:Generation Millennial)\b/g,
		"Plissken Faction"
	);
	v = v.replace(
		/\b(?:millennial generation)|(?:generation millennial)\b/g,
		"Plissken faction"
	);

	// Millennial
	v = v.replace(/\bMillennial\b/g, "Snake Person");
	v = v.replace(/\bmillennial\b/g, "snake person");
	v = v.replace(/\bMillennials\b/g, "Snake People");
	v = v.replace(/\bmillennials\b/g, "snake people");
	v = v.replace(/\bMillennials'\b/g, "Snake People's");
	v = v.replace(/\bmillennials'\b/g, "snake people's");

	// The Great Recession
	v = v.replace(/\bGreat Recession\b/g, "Time of Shedding and Cold Rocks");
	v = v.replace(/\bgreat recession\b/g, "time of shedding and cold rocks");

	// The Great Depression
	v = v.replace(/\bGreat Depression\b/g, "Clutch Plague");
	v = v.replace(/\bgreat depression\b/g, "clutch plague");

	// Occupy Wall Street
	v = v.replace(
		/\b(?:(?:Occupy|OWS) (?:M|m)ovement)|(?:Occupy Wall Street)\b/g,
		"Great Ape-Snake War"
	);
	v = v.replace(
		/\b(?:(?:occupy|OWS|ows) movement)|(?:occupy wall street)\b/g,
		"great ape-snake war"
	);
	v = v.replace(/\bOWS\b/g, "GA-SW");
	v = v.replace(/\bows\b/g, "ga-sw");

	// Helicopter Parents
	v = v.replace(/\bHelicopter Parents\b/g, "Thulsa Doom");
	v = v.replace(/\bhelicopter parents\b/g, "Thoth-Amon");
	v = v.replace(/\bHelicopter Parents'\b/g, "Thulsa Doom's");
	v = v.replace(/\bhelicopter parents'\b/g, "Thoth-Amon's");

	// Trophy Kids
	v = v.replace(/\bTrophy Kids\b/g, "Quetzalcoatl's Chosen");
	v = v.replace(/\btrophy kids\b/g, "Quetzalcoatl's chosen");
	v = v.replace(/\bTrophy Kids'\b/g, "Quetzalcoatl's Chosen's");
	v = v.replace(/\btrophy kids'\b/g, "Quetzalcoatl's chosen's");

	// Digital Natives
	v = v.replace(/\bDigital Native(s)?\b/g, "Parseltongue$1");
	v = v.replace(/\bdigital native(s)?\b/g, "parseltongue$1");

	// Generation Y
	v = v.replace(/\b(?:G(?:eneration )?Y)|(?:Generation Why)\b/g,
		"Serpent Society");
	v = v.replace(/\bgen(?:eration)? ?(?:wh)?y\b/g, "serpent society");
	v = v.replace(/\bGen Y\b/g, "Society of the Serpent");

	// Generation We
	v = v.replace(/\bGeneration We\b/g, "Caduceus Cult");
	v = v.replace(/\bgeneration we\b/g, "caduceus cult");
	v = v.replace(/\bWe Generation\b/g, "Cult of the Caduceus");
	v = v.replace(/\bwe generation\b/g, "cult of the caduceus");

	// Generation Me
	v = v.replace(/\bGeneration Me\b/g, "The Cult of the Serpent");
	v = v.replace(/\bgeneration me\b/g, "the cult of the serpent");

	// Global Generation
	v = v.replace(/\bGlobal Generation\b/g, "Tannin's Horde");
	v = v.replace(/\bglobal generation\b/g, "Tannin's horde");
	v = v.replace(/\bGeneration Global\b/g, "Horde of Tannin");
	v = v.replace(/\bgeneration global\b/g, "horde of Tannin");

	// Generation Next
	v = v.replace(/\bGeneration Next\b/g, "Time of Nidhogg");
	v = v.replace(/\bgeneration next\b/g, "time of Nidhogg");

	// Net Generation
	v = v.replace(/\bNet Generation\b/g, "Damballa's Coils");
	v = v.replace(/\bnet generation\b/g, "Damballa's coils");
	v = v.replace(/\bGeneration Net\b/g, "Coils of Damballa");
	v = v.replace(/\bgeneration net\b/g, "Coils of Damballa");

	// Echo Boomers
	v = v.replace(/\bEcho Boomers\b/g, "Crotalids");
	v = v.replace(/\becho Boomers\b/g, "crotalids");

	// New Boomers
	v = v.replace(/\bNew Boomers\b/g, "Jörmungandr's Circle");
	v = v.replace(/\bnew Boomers\b/g, "Jörmungandr's circle");
	v = v.replace(/\bNew Boomers'\b/g, "Jörmungandr's Circle's");
	v = v.replace(/\bnew Boomers'\b/g, "Jörmungandr's circle's");

	// Generation Flux
	v = v.replace(/\b(?:Generation Flux)|(?:Flux Generation)\b/g, "Hiss Club");
	v = v.replace(/\b(?:generation flux)|(?:flux generation)\b/g, "hiss club");

	// Generation Sell
	v = v.replace(/\bGeneration Sell\b/g, "Kaa Tribe");
	v = v.replace(/\bgeneration sell\b/g, "Kaa tribe");
	v = v.replace(/\bSell Generation\b/g, "Tribe of Kaa");
	v = v.replace(/\bsell generation\b/g, "tribe of Kaa");

	// Boomerang Generation
	v = v.replace(
		/\b(?:Boomerang Generation)|(?:Generation Boomerang)\b/g,
		"Ouroboros Society"
	);
	v = v.replace(
		/\b(?:boomerang generation)|(?:generation boomerang)\b/g,
		"ouroboros society"
	);

	// Peter Pan Generation
	v = v.replace(/\bPeter Pan Generation\b/g, "Neheb-Kau Cult");
	v = v.replace(/\b(?:P|p)eter (?:P|p)an generation\b/g, "Neheb-Kau cult");
	v = v.replace(/\bGeneration Peter Pan\b/g, "Cult of Neheb-Kau");
	v = v.replace(/\bgeneration (?:P|p)eter (?:P|p)an\b/g, "cult of Neheb-Kau");

	// Generation 911
	v = v.replace(/\bGen(?:eration)? 9\/?11\b/g, "Kaa Tribe");
	v = v.replace(/\bgen(?:eration)? 9\/?11\b/g, "Kaa tribe");
	v = v.replace(/\b9\/?11 Generation\b/g, "Tribe of the Kaa");
	v = v.replace(/\b9\/?11 generation\b/g, "tribe of the Kaa");

	// The Generation of €700
	v = v.replace(
		/\b(?:The Generation of €700)|(?:€700 Generation)\b/g,
		"Ophion"
	);
	v = v.replace(
		/\b(?:the generation of €700)|(?:€700 generation)\b/g,
		"ophion"
	);

	// Mileurista
	v = v.replace(/\b(?:M|m)ill?eurista\b/g, "Nagual");

	// Precarious Generation
	v = v.replace(
		/\b(?:Precarious Generation)|(?:Generation Precarious)\b/g,
		"Gargouille"
	);
	v = v.replace(
		/\b(?:precarious generation)|(?:generation precarious)\b/g,
		"gargouille"
	);

	textNode.nodeValue = v;
}

<commit_msg>Fix an issue with the first Generation Y regex<commit_after>walk(document.body);

function walk(node)
{
	// I stole this function from here:
	// http://is.gd/mwZp7E

	var child, next;

	switch ( node.nodeType )
	{
		case 1:  // Element
		case 9:  // Document
		case 11: // Document fragment
			child = node.firstChild;
			while ( child )
			{
				next = child.nextSibling;
				walk(child);
				child = next;
			}
			break;

		case 3: // Text node
			handleText(node);
			break;
	}
}

function handleText(textNode)
{
	var v = textNode.nodeValue;

	// Fix some misspellings
	v = v.replace(/\b(M|m)illienial(s)?\b/g, "$1illennial$2");
	v = v.replace(/\b(M|m)illenial(s)?\b/g, "$1illennial$2");
	v = v.replace(/\b(M|m)ilennial(s)?\b/g, "$1illennial$2");
	v = v.replace(/\b(M|m)ilenial(s)?\b/g, "$1illennial$2");

	// Millennial Generation
	v = v.replace(
		/\b(?:Millennial Generation)|(?:Generation Millennial)\b/g,
		"Plissken Faction"
	);
	v = v.replace(
		/\b(?:millennial generation)|(?:generation millennial)\b/g,
		"Plissken faction"
	);

	// Millennial
	v = v.replace(/\bMillennial\b/g, "Snake Person");
	v = v.replace(/\bmillennial\b/g, "snake person");
	v = v.replace(/\bMillennials\b/g, "Snake People");
	v = v.replace(/\bmillennials\b/g, "snake people");
	v = v.replace(/\bMillennials'\b/g, "Snake People's");
	v = v.replace(/\bmillennials'\b/g, "snake people's");

	// The Great Recession
	v = v.replace(/\bGreat Recession\b/g, "Time of Shedding and Cold Rocks");
	v = v.replace(/\bgreat recession\b/g, "time of shedding and cold rocks");

	// The Great Depression
	v = v.replace(/\bGreat Depression\b/g, "Clutch Plague");
	v = v.replace(/\bgreat depression\b/g, "clutch plague");

	// Occupy Wall Street
	v = v.replace(
		/\b(?:(?:Occupy|OWS) (?:M|m)ovement)|(?:Occupy Wall Street)\b/g,
		"Great Ape-Snake War"
	);
	v = v.replace(
		/\b(?:(?:occupy|OWS|ows) movement)|(?:occupy wall street)\b/g,
		"great ape-snake war"
	);
	v = v.replace(/\bOWS\b/g, "GA-SW");
	v = v.replace(/\bows\b/g, "ga-sw");

	// Helicopter Parents
	v = v.replace(/\bHelicopter Parents\b/g, "Thulsa Doom");
	v = v.replace(/\bhelicopter parents\b/g, "Thoth-Amon");
	v = v.replace(/\bHelicopter Parents'\b/g, "Thulsa Doom's");
	v = v.replace(/\bhelicopter parents'\b/g, "Thoth-Amon's");

	// Trophy Kids
	v = v.replace(/\bTrophy Kids\b/g, "Quetzalcoatl's Chosen");
	v = v.replace(/\btrophy kids\b/g, "Quetzalcoatl's chosen");
	v = v.replace(/\bTrophy Kids'\b/g, "Quetzalcoatl's Chosen's");
	v = v.replace(/\btrophy kids'\b/g, "Quetzalcoatl's chosen's");

	// Digital Natives
	v = v.replace(/\bDigital Native(s)?\b/g, "Parseltongue$1");
	v = v.replace(/\bdigital native(s)?\b/g, "parseltongue$1");

	// Generation Y
	v = v.replace(/\b(?:Generation Y)|(?:Generation Why)\b/g,
		"Serpent Society");
	v = v.replace(/\bgen(?:eration)? ?(?:wh)?y\b/g, "serpent society");
	v = v.replace(/\bGen Y\b/g, "Society of the Serpent");

	// Generation We
	v = v.replace(/\bGeneration We\b/g, "Caduceus Cult");
	v = v.replace(/\bgeneration we\b/g, "caduceus cult");
	v = v.replace(/\bWe Generation\b/g, "Cult of the Caduceus");
	v = v.replace(/\bwe generation\b/g, "cult of the caduceus");

	// Generation Me
	v = v.replace(/\bGeneration Me\b/g, "The Cult of the Serpent");
	v = v.replace(/\bgeneration me\b/g, "the cult of the serpent");

	// Global Generation
	v = v.replace(/\bGlobal Generation\b/g, "Tannin's Horde");
	v = v.replace(/\bglobal generation\b/g, "Tannin's horde");
	v = v.replace(/\bGeneration Global\b/g, "Horde of Tannin");
	v = v.replace(/\bgeneration global\b/g, "horde of Tannin");

	// Generation Next
	v = v.replace(/\bGeneration Next\b/g, "Time of Nidhogg");
	v = v.replace(/\bgeneration next\b/g, "time of Nidhogg");

	// Net Generation
	v = v.replace(/\bNet Generation\b/g, "Damballa's Coils");
	v = v.replace(/\bnet generation\b/g, "Damballa's coils");
	v = v.replace(/\bGeneration Net\b/g, "Coils of Damballa");
	v = v.replace(/\bgeneration net\b/g, "Coils of Damballa");

	// Echo Boomers
	v = v.replace(/\bEcho Boomers\b/g, "Crotalids");
	v = v.replace(/\becho Boomers\b/g, "crotalids");

	// New Boomers
	v = v.replace(/\bNew Boomers\b/g, "Jörmungandr's Circle");
	v = v.replace(/\bnew Boomers\b/g, "Jörmungandr's circle");
	v = v.replace(/\bNew Boomers'\b/g, "Jörmungandr's Circle's");
	v = v.replace(/\bnew Boomers'\b/g, "Jörmungandr's circle's");

	// Generation Flux
	v = v.replace(/\b(?:Generation Flux)|(?:Flux Generation)\b/g, "Hiss Club");
	v = v.replace(/\b(?:generation flux)|(?:flux generation)\b/g, "hiss club");

	// Generation Sell
	v = v.replace(/\bGeneration Sell\b/g, "Kaa Tribe");
	v = v.replace(/\bgeneration sell\b/g, "Kaa tribe");
	v = v.replace(/\bSell Generation\b/g, "Tribe of Kaa");
	v = v.replace(/\bsell generation\b/g, "tribe of Kaa");

	// Boomerang Generation
	v = v.replace(
		/\b(?:Boomerang Generation)|(?:Generation Boomerang)\b/g,
		"Ouroboros Society"
	);
	v = v.replace(
		/\b(?:boomerang generation)|(?:generation boomerang)\b/g,
		"ouroboros society"
	);

	// Peter Pan Generation
	v = v.replace(/\bPeter Pan Generation\b/g, "Neheb-Kau Cult");
	v = v.replace(/\b(?:P|p)eter (?:P|p)an generation\b/g, "Neheb-Kau cult");
	v = v.replace(/\bGeneration Peter Pan\b/g, "Cult of Neheb-Kau");
	v = v.replace(/\bgeneration (?:P|p)eter (?:P|p)an\b/g, "cult of Neheb-Kau");

	// Generation 911
	v = v.replace(/\bGen(?:eration)? 9\/?11\b/g, "Kaa Tribe");
	v = v.replace(/\bgen(?:eration)? 9\/?11\b/g, "Kaa tribe");
	v = v.replace(/\b9\/?11 Generation\b/g, "Tribe of the Kaa");
	v = v.replace(/\b9\/?11 generation\b/g, "tribe of the Kaa");

	// The Generation of €700
	v = v.replace(
		/\b(?:The Generation of €700)|(?:€700 Generation)\b/g,
		"Ophion"
	);
	v = v.replace(
		/\b(?:the generation of €700)|(?:€700 generation)\b/g,
		"ophion"
	);

	// Mileurista
	v = v.replace(/\b(?:M|m)ill?eurista\b/g, "Nagual");

	// Precarious Generation
	v = v.replace(
		/\b(?:Precarious Generation)|(?:Generation Precarious)\b/g,
		"Gargouille"
	);
	v = v.replace(
		/\b(?:precarious generation)|(?:generation precarious)\b/g,
		"gargouille"
	);

	textNode.nodeValue = v;
}

<|endoftext|>


<commit_before>/**
 * 文本输入组件输入法hack mixin
 * @author Brian Li
 * @email lbxxlht@163.com
 * @version 0.0.2.1
 * @note
 * ###说明文档
 * #####1 mixin解决的问题
 * React设计理念是单向数据流，FCUI2也遵守这一原则。即input类型组件如果配置了value（或checked）属性，未配置onChange属性，
 * 那这个组件是只读的。这种单向数据流的设计模式让应用架构变得更简单，同时让程序鲁棒性更高。但对于文本输入类组件，如
 * TextBox或TextArea，这种模式会带来一个很严重的问题，在某些情况下，无法使用IME输入法输入。
 * #####2 问题产生原因
 * React中，input组件的value要存放在外部，父级的state中、某个祖先的state中或整个应用的外部。通过props.value导入给组件，
 * 组件被操作后派发onChange回调，通知外部修改value的源头，然后回来重新渲染，这也是MVVM的要求。
 * React为了避免频繁setState带来性能问题，内部使用了异步渲染机制。但正是由于异步渲染，用户输入时派发onChange，
 * 外部经过一段时间，把value写回，这打断了IME输入法的连续性，输入法中存储的临时内容被清空，无法正常输入。
 * 上面说的“某些情况”，具体说就是最终存储value源头的地方离input组件比较远，中间React比对虚拟dom树用了相当一段时间，
 * 超出了输入法容忍的范围。下面是个抽象模型：
 *
 *      <body>
 *          <input type="text" id="inputbox"/>
 *      </body>
 *      <script type="text/javascript">
 *          var box = document.getElementById('inputbox');
 *          box.addEventListener('keyup', function (e) {
 *              var target = e.target;
 *              var value = e.target.value;
 *              console.log(value);
 *              setTimeout(function () {
 *                  e.target.value = value + '';
 *               }, 100);
 *          });
 *      </script>
 * #####3 问题解决方法
 * input有三个比较特殊的事件：compositionstart、compositionend、compositionupdate，
 * 分别表示输入法开始输入、完成输入上屏、输入更新，触发顺序是：start、update、update...update、end。
 * 解决方法是手动阻断onChange派发，在compositionstart和compositionend中修改一个开关，在onChange中判断这个开关，
 * 只在输入完毕后派发事件。
 * #####4 this实例注入
 * * this.___lastFiredValue___ {String|Number|Boolean} 组件上一次派发出去的值，避免重复派发
 * * this.___lastCursorPos___ {Number} 组件上次keyup后光标位置
 * * this.___imeStart___ {Boolean} 输入法是否处于输入状态
 * * this.___isPressing___ {Boolean} 键盘是否正在敲击
 * #####5 需要手动绑定到原生DOM的事件，mixin通过这些事件重新描述了onChange派发规则
 * * this.___onCompositionStart___，对应onCompositionStart事件
 * * this.___onCompositionEnd___，对应onCompositionEnd事件
 * * this.___onKeyDown___，对应onKeyDown事件
 * * this.___onKeyUp___，对应onKeyUp事件
 */
define(function (require) {

    var util = require('../core/util');

    return {
        // @override
        componentDidMount: function () {
            var value = this.___getValue___();
            this.refs.inputbox.value = value;
            this.___lastFiredValue___ = value;
            this.___lastCursorPos___ = -1;
            this.___imeStart___ = false;
            this.___isPressing___ = false;
            this.___workerTimer___ = null;
        },
        // @override
        componentWillReceiveProps: function (nextProps) {
            this.___syncValue___(nextProps);
        },
        ___syncValue___: function (props) {
            // 键盘keyup过了一段时间，但是外部还没有刷新组件，手动同步一下value
            props = props || this.props;
            var value = props.value;
            // 外部没有导入value或导入的value和输入框的相同
            if (typeof value == null || value === undefined || value + '' === this.refs.inputbox.value + '') return;
            value = value + '';
            this.___lastFiredValue___ = value;
            this.setState({___value___: value});
            this.refs.inputbox.value = value;
            if (this.___lastCursorPos___ > -1 && this.___lastCursorPos___ < value.length) {
                util.setCursorPosition(this.refs.inputbox, this.___lastCursorPos___);
            }
        },

        ___onCompositionStart___: function (e) {
            this.___imeStart___ = true;
        },
        ___onCompositionEnd___: function (e) {
            this.___imeStart___ = false;
        },
        ___onKeyDown___: function (e) {
            this.___isPressing___ = true;
        },
        ___onKeyUp___: function (e) {
            this.___isPressing___ = false;
            this.___lastCursorPos___ = util.getCursorPosition(e.target);
            e.keyCode === 13 && typeof this.onEnterPress === 'function' && this.onEnterPress();
            clearInterval(this.___workerTimer___);
            if (this.___imeStart___ || this.___lastFiredValue___ === this.refs.inputbox.value) return;
            this.______callDispatch______(e);
        },
        ___onInput___: function (e) {
            // 在window的chrome中：
            // 输入法开启，输入英文，回车，上屏英文，不会触发keyup，也不会触发compositionend，你敢信？
            // 但是会触发input事件，所以这个事件就是为了修复这种非常特殊的情况
            // 这个问题在IE11、mac的chrome、firefox中，完全没有！！！
            if (this.___imeStart___ || this.___lastFiredValue___ === e.target.value) return;
            this.______callDispatch______(e);
        },
        ___onFocus___: function (e) {
            this.setState({hasFocus: true});
            typeof this.props.onFocus === 'function' && this.props.onFocus(e);
        },
        ___onBlur___: function (e) {
            this.setState({hasFocus: false});
            typeof this.props.onBlur === 'function' && this.props.onBlur(e);
        },
        ______callDispatch______: function (e) {
            var me = this;
            var lastValue = this.___lastFiredValue___;
            e.target = this.refs.container;
            e.target.value = this.___lastFiredValue___ = this.refs.inputbox.value;
            this.___dispatchChange___(e, this.___lastFiredValue___, lastValue);
            this.___workerTimer___ = setInterval(function () {
                clearInterval(me.___workerTimer___);
                me.___syncValue___();
            }, 10);
        }
    };
});
<commit_msg>fixed ime bug<commit_after>/**
 * 文本输入组件输入法hack mixin
 * @author Brian Li
 * @email lbxxlht@163.com
 * @version 0.0.2.1
 * @note
 * ###说明文档
 * #####1 mixin解决的问题
 * React设计理念是单向数据流，FCUI2也遵守这一原则。即input类型组件如果配置了value（或checked）属性，未配置onChange属性，
 * 那这个组件是只读的。这种单向数据流的设计模式让应用架构变得更简单，同时让程序鲁棒性更高。但对于文本输入类组件，如
 * TextBox或TextArea，这种模式会带来一个很严重的问题，在某些情况下，无法使用IME输入法输入。
 * #####2 问题产生原因
 * React中，input组件的value要存放在外部，父级的state中、某个祖先的state中或整个应用的外部。通过props.value导入给组件，
 * 组件被操作后派发onChange回调，通知外部修改value的源头，然后回来重新渲染，这也是MVVM的要求。
 * React为了避免频繁setState带来性能问题，内部使用了异步渲染机制。但正是由于异步渲染，用户输入时派发onChange，
 * 外部经过一段时间，把value写回，这打断了IME输入法的连续性，输入法中存储的临时内容被清空，无法正常输入。
 * 上面说的“某些情况”，具体说就是最终存储value源头的地方离input组件比较远，中间React比对虚拟dom树用了相当一段时间，
 * 超出了输入法容忍的范围。下面是个抽象模型：
 *
 *      <body>
 *          <input type="text" id="inputbox"/>
 *      </body>
 *      <script type="text/javascript">
 *          var box = document.getElementById('inputbox');
 *          box.addEventListener('keyup', function (e) {
 *              var target = e.target;
 *              var value = e.target.value;
 *              console.log(value);
 *              setTimeout(function () {
 *                  e.target.value = value + '';
 *               }, 100);
 *          });
 *      </script>
 * #####3 问题解决方法
 * input有三个比较特殊的事件：compositionstart、compositionend、compositionupdate，
 * 分别表示输入法开始输入、完成输入上屏、输入更新，触发顺序是：start、update、update...update、end。
 * 解决方法是手动阻断onChange派发，在compositionstart和compositionend中修改一个开关，在onChange中判断这个开关，
 * 只在输入完毕后派发事件。
 * #####4 this实例注入
 * * this.___lastFiredValue___ {String|Number|Boolean} 组件上一次派发出去的值，避免重复派发
 * * this.___lastCursorPos___ {Number} 组件上次keyup后光标位置
 * * this.___imeStart___ {Boolean} 输入法是否处于输入状态
 * * this.___isPressing___ {Boolean} 键盘是否正在敲击
 * #####5 需要手动绑定到原生DOM的事件，mixin通过这些事件重新描述了onChange派发规则
 * * this.___onCompositionStart___，对应onCompositionStart事件
 * * this.___onCompositionEnd___，对应onCompositionEnd事件
 * * this.___onKeyDown___，对应onKeyDown事件
 * * this.___onKeyUp___，对应onKeyUp事件
 */
define(function (require) {

    var util = require('../core/util');

    return {
        // @override
        componentDidMount: function () {
            var value = this.___getValue___();
            this.refs.inputbox.value = value;
            this.___lastFiredValue___ = value;
            this.___lastCursorPos___ = -1;
            this.___imeStart___ = false;
            this.___isPressing___ = false;
            this.___workerTimer___ = null;
        },
        // @override
        componentWillReceiveProps: function (nextProps) {
            this.___syncValue___(nextProps);
        },
        ___syncValue___: function (props) {
            // 键盘keyup过了一段时间，但是外部还没有刷新组件，手动同步一下value
            props = props || this.props;
            var value = props.value;
            // 外部没有导入value或导入的value和输入框的相同
            if (typeof value == null || value === undefined || value + '' === this.refs.inputbox.value + '') return;
            value = value + '';
            this.___lastFiredValue___ = value;
            this.setState({___value___: value});
            this.refs.inputbox.value = value;
            if (this.___lastCursorPos___ > -1 && this.___lastCursorPos___ < value.length) {
                util.setCursorPosition(this.refs.inputbox, this.___lastCursorPos___);
            }
        },

        ___onCompositionStart___: function (e) {
            this.___imeStart___ = true;
        },
        ___onCompositionEnd___: function (e) {
            this.___imeStart___ = false;
        },
        ___onKeyDown___: function (e) {
            this.___isPressing___ = true;
        },
        ___onKeyUp___: function (e) {
            this.___isPressing___ = false;
            this.___lastCursorPos___ = util.getCursorPosition(e.target);
            e.keyCode === 13 && typeof this.onEnterPress === 'function' && this.onEnterPress();
            clearInterval(this.___workerTimer___);
            if (this.___imeStart___ || this.___lastFiredValue___ === this.refs.inputbox.value) return;
            this.______callDispatch______(e);
        },
        ___onInput___: function (e) {
            // 在window的chrome中：
            // 输入法开启，输入英文，回车，上屏英文，不会触发keyup，也不会触发compositionend，你敢信？
            // 但是会触发input事件，所以这个事件就是为了修复这种非常特殊的情况
            // 这个问题在IE11、mac的chrome、firefox中，完全没有！！！
            if (this.___imeStart___ || this.___lastFiredValue___ === e.target.value) return;
            this.___isPressing___ = false;
            this.___lastCursorPos___ = util.getCursorPosition(e.target);
            this.______callDispatch______(e);
        },
        ___onFocus___: function (e) {
            this.setState({hasFocus: true});
            typeof this.props.onFocus === 'function' && this.props.onFocus(e);
        },
        ___onBlur___: function (e) {
            this.setState({hasFocus: false});
            typeof this.props.onBlur === 'function' && this.props.onBlur(e);
        },
        ______callDispatch______: function (e) {
            var me = this;
            var lastValue = this.___lastFiredValue___;
            e.target = this.refs.container;
            e.target.value = this.___lastFiredValue___ = this.refs.inputbox.value;
            this.___dispatchChange___(e, this.___lastFiredValue___, lastValue);
            this.___workerTimer___ = setInterval(function () {
                clearInterval(me.___workerTimer___);
                me.___syncValue___();
            }, 10);
        }
    };
});
<|endoftext|>