<commit_before>var BASE_URL = "http://himawari8-dl.nict.go.jp/himawari8/img/";
var INFRARED = "INFRARED_FULL";
var VISIBLE_LIGHT = "D531106";
var WIDTH = 550;
var BLOCK_SIZES = [1, 4, 8, 16, 20];

/**
 * Returns an array of objects containing URLs and metadata
 * for Himawari 8 image tiles based on a given date.
 * Options:
 * - date: Date object, Date string (YYYY-MM-DD HH:MM:SSZ), or "latest"
 * - infrared: boolean (optional)
 * - zoom: number (default: 1)
 * - blocks: alternative to zoom, how many images per row/column (default: 1)
 *      Has to be a valid block number (1, 4, 8, 16, 20)
 *
 * @param  {Object}       options
 */
function himawariURLs(options) {
  options = options || {};
  var baseURL = getBaseURL(options.infrared);
  var date = resolveDate(options.date);

  // Normalize our date
  date = normalizeDate(date);

  // Define some image parameters
  var blocks = options.blocks || (options.zoom ? BLOCK_SIZES[options.zoom - 1] : BLOCK_SIZES[0]);
  var level = blocks + 'd';
  var time = [date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()].map(function(s) {return pad(s, 2)}).join("");
  var year = date.getUTCFullYear();
  var month = pad(date.getUTCMonth() + 1, 2);
  var day = pad(date.getUTCDate(), 2);

  // compose URL
  var tilesURL = [baseURL, level, WIDTH, year, month, day, time].join("/");
  var tiles = [];

  for (var y = 0; y < blocks; y++) {
    for (var x = 0; x < blocks; x++) {
      var name = x + "_" + y + ".png";
      var url = tilesURL + "_" + name;

      tiles.push({
        name: name,
        url: getCachedUrl(url),
        x: x,
        y: y
      });
    }
  }

  return {
    tiles: tiles,
    blocks: blocks,
    date: date
  };
}

/**
 * Returns base URL for Himawari-8 images
 * @param   {Boolean}   infrared  returns base URL for infrared images if true
 * @returns {String}              full base URL
 */
function getBaseURL(infrared) {
  var url = BASE_URL;
  if (infrared) {
    url += INFRARED;
  } else {
    url += VISIBLE_LIGHT;
  }
  return url;
}

/**
 * Takes a Date and normalizes it to ten minute intervals.
 * @param   {Date}  input   Date object
 * @returns {Date}          normalized Date object
 */
function normalizeDate(date) {
  date.setMinutes(date.getMinutes() - (date.getMinutes() % 10));
  date.setSeconds(0);
  return date;
}

/**
 * Parses a date.
 * @param   {string | Date} date  Date as string or date object
 * @returns {Date}                Date object
 */
function resolveDate(date) {
  if (typeof date === "string") {
    // Safari is the new IE
    var isChrome = navigator.userAgent.indexOf('Chrome') > -1;
    var isSafari = navigator.userAgent.indexOf("Safari") > -1;
    if ((isChrome)&&(isSafari)) {isSafari=false;}

    if (isSafari) {
      var parts = date.match(/(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})Z/);
      parts[2] -= 1; //months are zero-based
      return new Date(Date.UTC.apply(this, parts.slice(1)));
    }

    return new Date(date);
  } else {
    return date;
  }
}

/**
 * Create a cached URL thanks to our friends at Google.
 * See https://gist.github.com/carlo/5379498
 */
function getCachedUrl(url) {
  // 30 days caching
  return "https://images1-focus-opensocial.googleusercontent.com/gadgets/proxy?url=" + url + "&container=focus&refresh=2592000"
}

/**
 * Pads a number with trailing zeros and makes it a string.
 */
function pad(num, size) {
  var s = num + "";
  while (s.length < size) {
    s = "0" + s;
  }
  return s;
}

/**
 * Get the date of the latest image by making an Ajax request to the servers from nict.go.jp.
 * @param   {boolean}  infrared  gets the latest infrared image
 * @returns {function}           callback function
 */
function getLatestDate(infrared, cb) {
  var baseUrl = getBaseURL(infrared);
  var req = new XMLHttpRequest();
  req.onload = function() {
    var data = JSON.parse(req.responseText);
    var latest = data.query.results.json.date;
    cb(latest + "Z");
  };

  // proxy through yahoo because of same origin restrictions
  var query = "select * from json where url=\"" + baseUrl + "/latest.json\"";
  req.open("GET", "https://query.yahooapis.com/v1/public/yql?q=" + query + "&format=json", true);
  req.send();
}

/**
 * Looks at the screen resolution and figures out a zoom level that returns images at a sufficient resolution.
 */
function getOptimalNumberOfBlocks() {
  var height = window.innerHeight * window.devicePixelRatio;
  var minNumber = height/WIDTH;

  for (var i = 0; i < BLOCK_SIZES.length; i++) {
    var l = BLOCK_SIZES[i];
    if (l > minNumber) {
      return l;
    }
  }

  return BLOCK_SIZES[BLOCK_SIZES.length - 1];
}

/**
 * Creates an image composed of tiles.
 */
function setImages() {
  getLatestDate(false, function(latest) {
    var result = himawariURLs({
      date: latest, //"2016-02-11 2:30:00",
      blocks: getOptimalNumberOfBlocks()
    });

    var el = document.getElementById("wrapper");

    el.setAttribute("class", "wrapper-" + result.blocks);

    el.innerHTML = "";
    for (var i = 0; i < result.tiles.length; i++) {
      var image = document.createElement("img");
      image.setAttribute("src", result.tiles[i].url);
      el.appendChild(image);
    }

    var ago = (Date.now() - result.date.getTime()) / (1000 * 60);
    document.getElementById("time").innerHTML = "" + Math.floor(ago) + " minutes ago";
  });
}

// Refresh every 5 minutes
window.setInterval(setImages, 1000*60*5);
setImages();
<commit_msg>More robust date parsing<commit_after>var BASE_URL = "http://himawari8-dl.nict.go.jp/himawari8/img/";
var INFRARED = "INFRARED_FULL";
var VISIBLE_LIGHT = "D531106";
var WIDTH = 550;
var BLOCK_SIZES = [1, 4, 8, 16, 20];

/**
 * Returns an array of objects containing URLs and metadata
 * for Himawari 8 image tiles based on a given date.
 * Options:
 * - date: Date object, Date string (YYYY-MM-DD HH:MM:SSZ), or "latest"
 * - infrared: boolean (optional)
 * - zoom: number (default: 1)
 * - blocks: alternative to zoom, how many images per row/column (default: 1)
 *      Has to be a valid block number (1, 4, 8, 16, 20)
 *
 * @param  {Object}       options
 */
function himawariURLs(options) {
  options = options || {};
  var baseURL = getBaseURL(options.infrared);
  var date = resolveDate(options.date);

  // Normalize our date
  date = normalizeDate(date);

  // Define some image parameters
  var blocks = options.blocks || (options.zoom ? BLOCK_SIZES[options.zoom - 1] : BLOCK_SIZES[0]);
  var level = blocks + 'd';
  var time = [date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()].map(function(s) {return pad(s, 2)}).join("");
  var year = date.getUTCFullYear();
  var month = pad(date.getUTCMonth() + 1, 2);
  var day = pad(date.getUTCDate(), 2);

  // compose URL
  var tilesURL = [baseURL, level, WIDTH, year, month, day, time].join("/");
  var tiles = [];

  for (var y = 0; y < blocks; y++) {
    for (var x = 0; x < blocks; x++) {
      var name = x + "_" + y + ".png";
      var url = tilesURL + "_" + name;

      tiles.push({
        name: name,
        url: getCachedUrl(url),
        x: x,
        y: y
      });
    }
  }

  return {
    tiles: tiles,
    blocks: blocks,
    date: date
  };
}

/**
 * Returns base URL for Himawari-8 images
 * @param   {Boolean}   infrared  returns base URL for infrared images if true
 * @returns {String}              full base URL
 */
function getBaseURL(infrared) {
  var url = BASE_URL;
  if (infrared) {
    url += INFRARED;
  } else {
    url += VISIBLE_LIGHT;
  }
  return url;
}

/**
 * Takes a Date and normalizes it to ten minute intervals.
 * @param   {Date}  input   Date object
 * @returns {Date}          normalized Date object
 */
function normalizeDate(date) {
  date.setMinutes(date.getMinutes() - (date.getMinutes() % 10));
  date.setSeconds(0);
  return date;
}

/**
 * Parses a date.
 * @param   {string | Date} date  Date as string or date object
 * @returns {Date}                Date object
 */
function resolveDate(date) {
  if (typeof date === "string") {
    // Don't use Date.parse because it doesn't work with YYYY-MM-DD HH:MM:SSZ
    var parts = date.match(/(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})Z/);
    parts[2] -= 1; //months are zero-based
    return new Date(Date.UTC.apply(this, parts.slice(1)));
  } else {
    return date;
  }
}

/**
 * Create a cached URL thanks to our friends at Google.
 * See https://gist.github.com/carlo/5379498
 */
function getCachedUrl(url) {
  // 30 days caching
  return "https://images1-focus-opensocial.googleusercontent.com/gadgets/proxy?url=" + url + "&container=focus&refresh=2592000"
}

/**
 * Pads a number with trailing zeros and makes it a string.
 */
function pad(num, size) {
  var s = num + "";
  while (s.length < size) {
    s = "0" + s;
  }
  return s;
}

/**
 * Get the date of the latest image by making an Ajax request to the servers from nict.go.jp.
 * @param   {boolean}  infrared  gets the latest infrared image
 * @returns {function}           callback function
 */
function getLatestDate(infrared, cb) {
  var baseUrl = getBaseURL(infrared);
  var req = new XMLHttpRequest();
  req.onload = function() {
    var data = JSON.parse(req.responseText);
    var latest = data.query.results.json.date;
    cb(latest + "Z");
  };

  // proxy through yahoo because of same origin restrictions
  var query = "select * from json where url=\"" + baseUrl + "/latest.json\"";
  req.open("GET", "https://query.yahooapis.com/v1/public/yql?q=" + query + "&format=json", true);
  req.send();
}

/**
 * Looks at the screen resolution and figures out a zoom level that returns images at a sufficient resolution.
 */
function getOptimalNumberOfBlocks() {
  var height = window.innerHeight * window.devicePixelRatio;
  var minNumber = height/WIDTH;

  for (var i = 0; i < BLOCK_SIZES.length; i++) {
    var l = BLOCK_SIZES[i];
    if (l > minNumber) {
      return l;
    }
  }

  return BLOCK_SIZES[BLOCK_SIZES.length - 1];
}

/**
 * Creates an image composed of tiles.
 */
function setImages() {
  getLatestDate(false, function(latest) {
    var result = himawariURLs({
      date: latest, //"2016-02-11 2:30:00",
      blocks: getOptimalNumberOfBlocks()
    });

    var el = document.getElementById("wrapper");

    el.setAttribute("class", "wrapper-" + result.blocks);

    el.innerHTML = "";
    for (var i = 0; i < result.tiles.length; i++) {
      var image = document.createElement("img");
      image.setAttribute("src", result.tiles[i].url);
      el.appendChild(image);
    }

    var ago = (Date.now() - result.date.getTime()) / (1000 * 60);
    document.getElementById("time").innerHTML = "" + Math.floor(ago) + " minutes ago";
  });
}

// Refresh every 5 minutes
window.setInterval(setImages, 1000*60*5);
setImages();
<|endoftext|>


<commit_before>// Simple persistence driver that saves data to plain text files

'use strict';

var assign            = require('es5-ext/object/assign')
  , forEach           = require('es5-ext/object/for-each')
  , setPrototypeOf    = require('es5-ext/object/set-prototype-of')
  , toArray           = require('es5-ext/object/to-array')
  , ensureObject      = require('es5-ext/object/valid-object')
  , ensureString      = require('es5-ext/object/validate-stringifiable-value')
  , d                 = require('d')
  , lazy              = require('d/lazy')
  , memoizeMethods    = require('memoizee/methods')
  , deferred          = require('deferred')
  , resolveKeyPath    = require('dbjs/_setup/utils/resolve-key-path')
  , resolve           = require('path').resolve
  , mkdir             = require('fs2/mkdir')
  , readFile          = require('fs2/read-file')
  , readdir           = require('fs2/readdir')
  , rmdir             = require('fs2/rmdir')
  , writeFile         = require('fs2/write-file')
  , PersistenceDriver = require('./abstract')

  , isArray = Array.isArray
  , defineProperty = Object.defineProperty, keys = Object.keys
  , isId = RegExp.prototype.test.bind(/^[a-z0-9][a-z0-9A-Z]*$/)
  , create = Object.create, parse = JSON.parse, stringify = JSON.stringify;

var byStamp = function (a, b) {
	return (this[a].stamp - this[b].stamp) || a.toLowerCase().localeCompare(b.toLowerCase());
};

var resolveObjectMap = function (ownerId, map, keyPaths, result) {
	if (!result) result = create(null);
	forEach(map, function (data, path) {
		if (keyPaths && (path !== '.')) {
			if (!keyPaths.has(resolveKeyPath(path))) return;
		}
		result[(path === '.') ? ownerId : ownerId + '/' + path] = data;
	});
	return result;
};

var TextFileDriver = module.exports = function (dbjs, data) {
	if (!(this instanceof TextFileDriver)) return new TextFileDriver(dbjs, data);
	ensureObject(data);
	this.dirPath = resolve(ensureString(data.path));
	PersistenceDriver.call(this, dbjs, data);
	this.dbDir = mkdir(this.dirPath, { intermediate: true }).aside(null, function (err) {
		this.isClosed = true;
		this.emitError(err);
	}.bind(this));
};
setPrototypeOf(TextFileDriver, PersistenceDriver);

TextFileDriver.prototype = Object.create(PersistenceDriver.prototype, assign({
	constructor: d(TextFileDriver),
	// Any data
	__getRaw: d(function (cat, ns, path) {
		if (cat === 'custom') {
			return this._custom(function (map) {
				return map[ns + (path ? ('/' + path) : '')] || null;
			});
		}
		if (cat === 'computed') {
			return this._getIndexStorage(ns)(function (map) { return map[path] || null; });
		}
		return this._getObjectStorage(ns)(function (map) { return map[path || '.'] || null; });
	}),
	__getRawObject: d(function (ownerId, keyPaths) {
		return this._getObjectStorage(ownerId)(function (map) {
			return resolveObjectMap(ownerId, map, keyPaths);
		});
	}),
	__storeRaw: d(function (cat, ns, path, data) {
		if (cat === 'custom') return this._storeCustom(ns, path, data);
		if (cat === 'computed') {
			return this._getIndexStorage(ns)(function (map) {
				map[path] = data;
				return this._writeStorage('=' + (new Buffer(ns)).toString('base64'), map);
			}.bind(this));
		}
		return this._getObjectStorage(ns)(function (map) {
			map[path || '.'] = data;
			return this._writeStorage(ns, map);
		}.bind(this));
	}),

	// Database data
	__getRawAllDirect: d(function () {
		return this._getAllObjectIds().map(function (ownerId) {
			return this._getObjectStorage(ownerId)(function (map) {
				return { ownerId: ownerId, map: map };
			});
		}, this)(function (maps) {
			var result = create(null);
			maps.forEach(function (data) { resolveObjectMap(data.ownerId, data.map, null, result); });
			return result;
		});
	}),

	// Size tracking
	__searchDirect: d(function (callback) {
		return this._getAllObjectIds().map(function (ownerId) {
			return this._getObjectStorage(ownerId)(function (map) {
				forEach(map, function (data, keyPath) {
					var postfix = keyPath === '.' ? '' : '/' + keyPath;
					callback(ownerId + postfix, data);
				});
			});
		}, this);
	}),
	__searchIndex: d(function (keyPath, callback) {
		return this._getIndexStorage(keyPath)(function (map) {
			forEach(map, function (data, ownerId) { callback(ownerId, data); });
		});
	}),

	// Custom data
	_storeCustom: d(function (ownerId, path, data) {
		return this._custom(function (map) {
			map[ownerId + (path ? ('/' + path) : '')] = data;
			return writeFile(resolve(this.dirPath, '_custom'), stringify(map));
		}.bind(this));
	}),

	// Storage import/export
	__exportAll: d(function (destDriver) {
		var count = 0;
		var promise = this.dbDir()(function () {
			return readdir(this.dirPath, { type: { file: true } }).map(function (filename) {
				var ownerId, path;
				if (isId(filename)) {
					ownerId = filename;
					return this._getObjectStorage(ownerId)(function (map) {
						return deferred.map(keys(map), function (path) {
							var data = this[path];
							if (path === '.') path = null;
							if (!(++count % 1000)) promise.emit('progress');
							return destDriver._storeRaw('direct', ownerId, path, data);
						}, map);
					});
				}
				if (filename[0] === '=') {
					path = String(new Buffer(filename.slice(1), 'base64'));
					return this._getIndexStorage(path)(function (map) {
						return deferred.map(keys(map), function (ownerId) {
							if (!(++count % 1000)) promise.emit('progress');
							return destDriver._storeRaw('computed', path, ownerId, this[ownerId]);
						}, map);
					});
				}
				if (filename === '_custom') {
					this._custom(function (custom) {
						return deferred.map(keys(custom), function (key) {
							var index = key.indexOf('/')
							  , ownerId = (index !== -1) ? key.slice(0, index) : key
							  , path = (index !== -1) ? key.slice(index + 1) : null;
							if (!(++count % 1000)) promise.emit('progress');
							return destDriver._storeRaw('custom', ownerId, path, custom[key]);
						});
					});
				}
			}.bind(this));
		}.bind(this));
		return promise;
	}),
	__clear: d(function () {
		return rmdir(this.dirPath, { recursive: true, force: true })(function () {
			this._getObjectStorage.clear();
			this._getIndexStorage.clear();
			defineProperty(this, '_custom', d(deferred({})));
			return (this.dbDir = mkdir(this.dirPath, { intermediate: true }));
		}.bind(this));
	}),

	// Connection related
	__close: d(function () { return deferred(undefined); }), // Nothing to close

	// Specific to driver
	_getAllObjectIds: d(function () {
		return this.dbDir()(function () {
			return readdir(this.dirPath, { type: { file: true } })(function (data) {
				return data.filter(isId).sort();
			});
		}.bind(this));
	}),
	_writeStorage: d(function (name, map) {
		return this.dbDir()(function () {
			return writeFile(resolve(this.dirPath, name), toArray(map, function (data, id) {
				var value = data.value;
				if (value === '') value = '-';
				else if (isArray(value)) value = stringify(value);
				return id + '\n' + data.stamp + '\n' + value;
			}, this, byStamp).join('\n\n'));
		}.bind(this));
	})
}, lazy({
	_custom: d(function () {
		return this.dbDir()(function () {
			return readFile(resolve(this.dirPath, '_custom'))(function (str) {
				try {
					return parse(String(str));
				} catch (e) { return {}; }
			}, function (err) {
				if (err.code !== 'ENOENT') throw err;
				return {};
			});
		}.bind(this));
	})
}), memoizeMethods({
	_getObjectStorage: d(function (ownerId) {
		return this.dbDir()(function () {
			var map = create(null);
			return readFile(resolve(this.dirPath, ownerId))(function (data) {
				var value;
				try {
					String(data).split('\n\n').forEach(function (data) {
						data = data.split('\n');
						value = data[2];
						if (value === '-') value = '';
						map[data[0]] = {
							stamp: Number(data[1]),
							value: value
						};
					});
				} catch (ignore) {}
				return map;
			}, function (err) {
				if (err.code !== 'ENOENT') throw err;
				return map;
			});
		}.bind(this));
	}, { primitive: true }),
	_getIndexStorage: d(function (keyPath) {
		return this.dbDir()(function () {
			var map = create(null), filename = '=' + (new Buffer(keyPath)).toString('base64');
			return readFile(resolve(this.dirPath, filename))(function (data) {
				var value;
				try {
					String(data).split('\n\n').forEach(function (data) {
						data = data.split('\n');
						value = data[2];
						if (value[0] === '[') value = parse(data[2]);
						else if (value === '-') value = '';
						map[data[0]] = {
							stamp: Number(data[1]),
							value: value
						};
					});
				} catch (ignore) {}
				return map;
			}, function (err) {
				if (err.code !== 'ENOENT') throw err;
				return map;
			});
		}.bind(this));
	}, { primitive: true })
})));
<commit_msg>-- cleanup<commit_after>// Simple persistence driver that saves data to plain text files

'use strict';

var assign            = require('es5-ext/object/assign')
  , forEach           = require('es5-ext/object/for-each')
  , setPrototypeOf    = require('es5-ext/object/set-prototype-of')
  , toArray           = require('es5-ext/object/to-array')
  , ensureObject      = require('es5-ext/object/valid-object')
  , ensureString      = require('es5-ext/object/validate-stringifiable-value')
  , d                 = require('d')
  , lazy              = require('d/lazy')
  , memoizeMethods    = require('memoizee/methods')
  , deferred          = require('deferred')
  , resolveKeyPath    = require('dbjs/_setup/utils/resolve-key-path')
  , resolve           = require('path').resolve
  , mkdir             = require('fs2/mkdir')
  , readFile          = require('fs2/read-file')
  , readdir           = require('fs2/readdir')
  , rmdir             = require('fs2/rmdir')
  , writeFile         = require('fs2/write-file')
  , PersistenceDriver = require('./abstract')

  , isArray = Array.isArray
  , defineProperty = Object.defineProperty, keys = Object.keys
  , isId = RegExp.prototype.test.bind(/^[a-z0-9][a-z0-9A-Z]*$/)
  , create = Object.create, parse = JSON.parse, stringify = JSON.stringify;

var byStamp = function (a, b) {
	return (this[a].stamp - this[b].stamp) || a.toLowerCase().localeCompare(b.toLowerCase());
};

var resolveObjectMap = function (ownerId, map, keyPaths, result) {
	if (!result) result = create(null);
	forEach(map, function (data, path) {
		if (keyPaths && (path !== '.')) {
			if (!keyPaths.has(resolveKeyPath(path))) return;
		}
		result[(path === '.') ? ownerId : ownerId + '/' + path] = data;
	});
	return result;
};

var TextFileDriver = module.exports = function (dbjs, data) {
	if (!(this instanceof TextFileDriver)) return new TextFileDriver(dbjs, data);
	ensureObject(data);
	this.dirPath = resolve(ensureString(data.path));
	PersistenceDriver.call(this, dbjs, data);
	this.dbDir = mkdir(this.dirPath, { intermediate: true }).aside(null, function (err) {
		this.isClosed = true;
		this.emitError(err);
	}.bind(this));
};
setPrototypeOf(TextFileDriver, PersistenceDriver);

TextFileDriver.prototype = Object.create(PersistenceDriver.prototype, assign({
	constructor: d(TextFileDriver),
	// Any data
	__getRaw: d(function (cat, ns, path) {
		if (cat === 'custom') {
			return this._custom(function (map) {
				return map[ns + (path ? ('/' + path) : '')] || null;
			});
		}
		if (cat === 'computed') {
			return this._getIndexStorage(ns)(function (map) { return map[path] || null; });
		}
		return this._getObjectStorage(ns)(function (map) { return map[path || '.'] || null; });
	}),
	__getRawObject: d(function (ownerId, keyPaths) {
		return this._getObjectStorage(ownerId)(function (map) {
			return resolveObjectMap(ownerId, map, keyPaths);
		});
	}),
	__storeRaw: d(function (cat, ns, path, data) {
		if (cat === 'custom') return this._storeCustom(ns, path, data);
		if (cat === 'computed') {
			return this._getIndexStorage(ns)(function (map) {
				map[path] = data;
				return this._writeStorage('=' + (new Buffer(ns)).toString('base64'), map);
			}.bind(this));
		}
		return this._getObjectStorage(ns)(function (map) {
			map[path || '.'] = data;
			return this._writeStorage(ns, map);
		}.bind(this));
	}),

	// Database data
	__getRawAllDirect: d(function () {
		return this._getAllObjectIds().map(function (ownerId) {
			return this._getObjectStorage(ownerId)(function (map) {
				return { ownerId: ownerId, map: map };
			});
		}, this)(function (maps) {
			var result = create(null);
			maps.forEach(function (data) { resolveObjectMap(data.ownerId, data.map, null, result); });
			return result;
		});
	}),

	// Size tracking
	__searchDirect: d(function (callback) {
		return this._getAllObjectIds().map(function (ownerId) {
			return this._getObjectStorage(ownerId)(function (map) {
				forEach(map, function (data, keyPath) {
					var postfix = keyPath === '.' ? '' : '/' + keyPath;
					callback(ownerId + postfix, data);
				});
			});
		}, this);
	}),
	__searchIndex: d(function (keyPath, callback) {
		return this._getIndexStorage(keyPath)(function (map) {
			forEach(map, function (data, ownerId) { callback(ownerId, data); });
		});
	}),

	// Storage import/export
	__exportAll: d(function (destDriver) {
		var count = 0;
		var promise = this.dbDir()(function () {
			return readdir(this.dirPath, { type: { file: true } }).map(function (filename) {
				var ownerId, path;
				if (isId(filename)) {
					ownerId = filename;
					return this._getObjectStorage(ownerId)(function (map) {
						return deferred.map(keys(map), function (path) {
							var data = this[path];
							if (path === '.') path = null;
							if (!(++count % 1000)) promise.emit('progress');
							return destDriver._storeRaw('direct', ownerId, path, data);
						}, map);
					});
				}
				if (filename[0] === '=') {
					path = String(new Buffer(filename.slice(1), 'base64'));
					return this._getIndexStorage(path)(function (map) {
						return deferred.map(keys(map), function (ownerId) {
							if (!(++count % 1000)) promise.emit('progress');
							return destDriver._storeRaw('computed', path, ownerId, this[ownerId]);
						}, map);
					});
				}
				if (filename === '_custom') {
					this._custom(function (custom) {
						return deferred.map(keys(custom), function (key) {
							var index = key.indexOf('/')
							  , ownerId = (index !== -1) ? key.slice(0, index) : key
							  , path = (index !== -1) ? key.slice(index + 1) : null;
							if (!(++count % 1000)) promise.emit('progress');
							return destDriver._storeRaw('custom', ownerId, path, custom[key]);
						});
					});
				}
			}.bind(this));
		}.bind(this));
		return promise;
	}),
	__clear: d(function () {
		return rmdir(this.dirPath, { recursive: true, force: true })(function () {
			this._getObjectStorage.clear();
			this._getIndexStorage.clear();
			defineProperty(this, '_custom', d(deferred({})));
			return (this.dbDir = mkdir(this.dirPath, { intermediate: true }));
		}.bind(this));
	}),

	// Connection related
	__close: d(function () { return deferred(undefined); }), // Nothing to close

	// Specific to driver
	_getAllObjectIds: d(function () {
		return this.dbDir()(function () {
			return readdir(this.dirPath, { type: { file: true } })(function (data) {
				return data.filter(isId).sort();
			});
		}.bind(this));
	}),
	_storeCustom: d(function (ownerId, path, data) {
		return this._custom(function (map) {
			map[ownerId + (path ? ('/' + path) : '')] = data;
			return writeFile(resolve(this.dirPath, '_custom'), stringify(map));
		}.bind(this));
	}),
	_writeStorage: d(function (name, map) {
		return this.dbDir()(function () {
			return writeFile(resolve(this.dirPath, name), toArray(map, function (data, id) {
				var value = data.value;
				if (value === '') value = '-';
				else if (isArray(value)) value = stringify(value);
				return id + '\n' + data.stamp + '\n' + value;
			}, this, byStamp).join('\n\n'));
		}.bind(this));
	})
}, lazy({
	_custom: d(function () {
		return this.dbDir()(function () {
			return readFile(resolve(this.dirPath, '_custom'))(function (str) {
				try {
					return parse(String(str));
				} catch (e) { return {}; }
			}, function (err) {
				if (err.code !== 'ENOENT') throw err;
				return {};
			});
		}.bind(this));
	})
}), memoizeMethods({
	_getObjectStorage: d(function (ownerId) {
		return this.dbDir()(function () {
			var map = create(null);
			return readFile(resolve(this.dirPath, ownerId))(function (data) {
				var value;
				try {
					String(data).split('\n\n').forEach(function (data) {
						data = data.split('\n');
						value = data[2];
						if (value === '-') value = '';
						map[data[0]] = {
							stamp: Number(data[1]),
							value: value
						};
					});
				} catch (ignore) {}
				return map;
			}, function (err) {
				if (err.code !== 'ENOENT') throw err;
				return map;
			});
		}.bind(this));
	}, { primitive: true }),
	_getIndexStorage: d(function (keyPath) {
		return this.dbDir()(function () {
			var map = create(null), filename = '=' + (new Buffer(keyPath)).toString('base64');
			return readFile(resolve(this.dirPath, filename))(function (data) {
				var value;
				try {
					String(data).split('\n\n').forEach(function (data) {
						data = data.split('\n');
						value = data[2];
						if (value[0] === '[') value = parse(data[2]);
						else if (value === '-') value = '';
						map[data[0]] = {
							stamp: Number(data[1]),
							value: value
						};
					});
				} catch (ignore) {}
				return map;
			}, function (err) {
				if (err.code !== 'ENOENT') throw err;
				return map;
			});
		}.bind(this));
	}, { primitive: true })
})));
<|endoftext|>


<commit_before>#!/usr/bin/env node
var fs = require("fs");
var path = require("path");
var exec = require('exec-sync');
var _ = require("lodash");

var HOME = process.env.HOME + "/";
var DOTFILES = HOME + ".dotfiles/";

function parseRecipe(bundle, recipe) {
   var actions = [];

   for (var action in recipe) {
      if (action == "skip") {
         return [];
      }
      var handler = global[action];

      var params = recipe[action];
      if (!Array.isArray(params)) {
         params = [ params ]
      }
      params.reverse();
      params.push(bundle);
      params.reverse();

      actions.push(handler.apply(this, params));
   }

   return actions;
}

function loadConfig() {
   var jsonConfig = require(DOTFILES + "/config.json");
   var config = {};

   for (var bundle in jsonConfig) {
      var recipe = jsonConfig[bundle];

      if (Array.isArray(recipe)) {
         config[bundle] = _(recipe).map(function(step) {
            return parseRecipe(bundle, step);
         }).flatten().value();
      } else {
         config[bundle] = parseRecipe(bundle, recipe);
      }
   }

   return config;
}

global.link = function(bundle, file) {
   var dest = HOME;
   var source = DOTFILES + bundle;

   if (typeof(file) === 'object') {
      if (file.dest) {
         dest = dest + file.dest + "/";
      }
      file = file.files;
   }

   var processFile = function(fileSource, fileDest, remove) {
      if (remove) {
         if (fs.existsSync(fileDest)) {
            console.log("rm " + fileDest);
            fs.unlinkSync(fileDest);
         }
      } else {
         console.log("link " + fileSource + " -> " + fileDest);
         fs.symlinkSync(fileSource, fileDest);
      }
   };

   if (file === null || file !== "*") {
      return function(remove) {
         var fileDest = dest + "." + bundle;
         var fileSource = source;
         if (file) {
            fileSource = fileSource + "/" + file;
            fileDest = dest + "." + file;
         }

         processFile(fileSource, fileDest, remove);
      }
   } else if (file === "*") {
      return function(remove) {
         var files = fs.readdirSync(source);
         files.forEach(function(file) {
            var fileSource = source + "/" + file;
            var fileDest = dest + "." + file;

            processFile(fileSource, fileDest, remove);
         });
      }
   }
}

global.exec = function(bundle, cmd) {
   return function(remove) {
      if (!remove) {
         var command = cmd;
         if (typeof(cmd) === 'object') {
            command = cmd.cmd;
            if (cmd.cwd) {
               command = "cd " + cmd.cwd + " && " + command;
            }
         }
         console.log(command);
         try {
            exec(command);
         } catch (err) {
            console.log(err);
         }
      }
   };
}

global.git = function(orig, repo) {
   var dest = HOME + "." + orig;
   return function(remove) {
      var command = null;
      if (remove) {
         if (fs.existsSync(dest)) {
            command = "rm -r " + dest;

         }
      } else {
         command = "git clone " + repo + " " + dest;
      }
      console.log(command);
      try {
         exec(command);
      } catch (err) {
         console.log(err);
      }
   };
}

function clean() {
   perform(true);
}

function setup() {
   perform(false);
}

function perform(remove) {
   for (key in config) {
      if (config.hasOwnProperty(key)) {
         if (Array.isArray(config[key])) {
            config[key].forEach(function(action) {
               action(remove);
            });
         } else {
            config[key](remove);
         }
      }
   }
}

function init(repository) {
   if (repository != null) {
      exec("git clone " + repository + " " + DOTFILES);
   } else {
      if (!fs.existsSync(DOTFILES)) {
         fs.mkdir(DOTFILES);
      }
      if (!fs.existsSync(DOTFILES + "/.git")) {
         exec("cd " + DOTFILES + " && git init");
      }
   }
}

if (process.argv[2] == "init") {
   init(process.argv[3]);

} else if (process.argv[2] == "install") {
   var config = loadConfig();

   clean();
   console.log("----------");
   setup();
} else {
   console.log("ERROR: Unknown option");
}
<commit_msg>Added a debug mode<commit_after>#!/usr/bin/env node
var fs = require("fs");
var path = require("path");
var exec = require('exec-sync');
var _ = require("lodash");

var HOME = process.env.HOME + "/";
var DOTFILES = HOME + ".dotfiles/";

function parseRecipe(bundle, recipe) {
   var actions = [];

   for (var action in recipe) {
      if (action == "skip") {
         return [];
      }
      var handler = global[action];

      var params = recipe[action];
      if (!Array.isArray(params)) {
         params = [ params ]
      }
      params.reverse();
      params.push(bundle);
      params.reverse();

      actions.push(handler.apply(this, params));
   }

   return actions;
}

function loadConfig() {
   var jsonConfig = require(DOTFILES + "/config.json");
   var config = {};

   for (var bundle in jsonConfig) {
      var recipe = jsonConfig[bundle];

      if (Array.isArray(recipe)) {
         config[bundle] = _(recipe).map(function(step) {
            return parseRecipe(bundle, step);
         }).flatten().value();
      } else {
         config[bundle] = parseRecipe(bundle, recipe);
      }
   }

   return config;
}

global.link = function(bundle, file) {
   var dest = HOME;
   var source = DOTFILES + bundle;

   if (typeof(file) === 'object') {
      if (file.dest) {
         dest = dest + file.dest + "/";
      }
      file = file.files;
   }

   var processFile = function(fileSource, fileDest, remove) {
      if (remove) {
         if (fs.existsSync(fileDest)) {
            executeAction("rm " + fileDest, function() {
               fs.unlinkSync(fileDest);
            });
         }
      } else {
         executeAction("link " + fileSource + " -> " + fileDest, function() {
            fs.symlinkSync(fileSource, fileDest);
         });
      }
   };

   if (file === null || file !== "*") {
      return function(remove) {
         var fileDest = dest + "." + bundle;
         var fileSource = source;
         if (file) {
            fileSource = fileSource + "/" + file;
            fileDest = dest + "." + file;
         }

         processFile(fileSource, fileDest, remove);
      }
   } else if (file === "*") {
      return function(remove) {
         var files = fs.readdirSync(source);
         files.forEach(function(file) {
            var fileSource = source + "/" + file;
            var fileDest = dest + "." + file;

            processFile(fileSource, fileDest, remove);
         });
      }
   }
}

global.exec = function(bundle, cmd) {
   return function(remove) {
      if (!remove) {
         var command = cmd;
         if (typeof(cmd) === 'object') {
            command = cmd.cmd;
            if (cmd.cwd) {
               command = "cd " + cmd.cwd + " && " + command;
            }
         }
         executeAction(command, function() {
            try {
               exec(command);
            } catch (err) {
               console.log(err);
            }
         });
      }
   };
}

global.git = function(orig, repo) {
   var dest = HOME + "." + orig;
   return function(remove) {
      var command = null;
      if (remove) {
         if (fs.existsSync(dest)) {
            command = "rm -r " + dest;

         }
      } else {
         command = "git clone " + repo + " " + dest;
      }
      executeAction(command, function() {
         try {
            exec(command);
         } catch (err) {
            console.log(err);
         }
      });
   };
}

var debugEnabled = false;

function executeAction(message, action) {
   if (debugEnabled) {
      console.log(message);
   } else {
      if (action) {
         action();
      }
   }
}

function debug(enable) {
   debugEnabled = enable;
}

function clean() {
   perform(true);
}

function setup() {
   perform(false);
}

function perform(remove) {
   for (key in config) {
      if (config.hasOwnProperty(key)) {
         if (Array.isArray(config[key])) {
            config[key].forEach(function(action) {
               action(remove);
            });
         } else {
            config[key](remove);
         }
      }
   }
}

function init(repository) {
   if (repository != null) {
      exec("git clone " + repository + " " + DOTFILES);
   } else {
      if (!fs.existsSync(DOTFILES)) {
         fs.mkdir(DOTFILES);
      }
      if (!fs.existsSync(DOTFILES + "/.git")) {
         exec("cd " + DOTFILES + " && git init");
      }
   }
}

if (process.argv[2] == "init") {
   init(process.argv[3]);

} else if (process.argv[2] == "install") {
   var config = loadConfig();

   if (process.argv[3] == "--debug") {
     debug(true);
   }

   clean();
   setup();
} else {
   console.log("ERROR: Unknown option");
}
<|endoftext|>


<commit_before>import AWS from 'aws-sdk'
import http from 'http'
import cheerio from 'cheerio'
import config from './config.js'

function getBlackLotusSrcPromise () {
  return new Promise((resolve, reject) => {
    http.get('http://magiccards.info/al/en/232.html', res => {
      let html = ''
      res.on('data', (chunk) => html += chunk)
      res.on('end', () => {
        let $ = cheerio.load(html)
        let $img = $('table').eq(3).find('img')
        resolve($img.attr('src'))
      })
    })
  })
}

function putSrcToS3Promise (src, key) {
  AWS.config.update(config.credentials)
  let s3 = new AWS.S3()

  return new Promise((resolve, reject) => {
    http.get(src, res => {
      s3.upload({
        Bucket: 'nukr-images',
        Key: key,
        ContentType: 'jpg',
        ACL: 'public-read',
        Body: res
      }, (err, data) => {
        if (err) return reject(err)
        resolve(data)
      })
    })
  })
}

async () => {
  let blackLotusSrc = await getBlackLotusSrcPromise()
  let result = await putSrcToS3Promise(blackLotusSrc, 'mtg/black_lotus.jpg')
  console.log(result)
}().catch(console.log)

<commit_msg>add TODO<commit_after>import AWS from 'aws-sdk'
import http from 'http'
import cheerio from 'cheerio'
import config from './config.js'

function getBlackLotusSrcPromise () {
  return new Promise((resolve, reject) => {
    http.get('http://magiccards.info/al/en/232.html', res => {
      let html = ''
      res.on('data', (chunk) => html += chunk)
      res.on('end', () => {
        let $ = cheerio.load(html)
        let $img = $('table').eq(3).find('img')
        resolve($img.attr('src'))
      })
    })
  })
}

function putSrcToS3Promise (src, key) {
  AWS.config.update(config.credentials)
  let s3 = new AWS.S3()

  return new Promise((resolve, reject) => {
    http.get(src, res => {
      s3.upload({
        Bucket: 'nukr-images',
        Key: key,
        ContentType: 'jpg',
        ACL: 'public-read',
        Body: res
      }, (err, data) => {
        if (err) return reject(err)
        resolve(data)
      })
    })
  })
}

async () => {
  // TODO getImageName
  /**
   * expect shape like
   * {
   *   'http://magiccards.info/al/en/232.html': 'al/en/black lotus.jpg'
   * }
   *
   */
  // let imageName = getImageName(blackLotusSrc)
  /**
   * expect shape like
   * {
   *   'http://magiccards.info/al/en/232.html': 'al/en/black lotus.jpg',
   *   'http://magiccards.info/al/en/233.html': 'al/en/black vise.jpg'
   * }
   *
   */
  // let imageName = getImageName(srcs)

  // let imageNameKeys = Object.keys(imageName)
  // for (var i = 0, len = imageNameKeys.length; i < len; i++) {
  //   let result = await putSrcToS3Promise(imageNameKeys[i], imageName[imageNameKeys[i]])
  // }
  let blackLotusSrc = await getBlackLotusSrcPromise()
  let result = await putSrcToS3Promise(blackLotusSrc, 'al/en/black lotus.jpg')
  console.log(result)
}().catch(console.log)

<|endoftext|>


<commit_before>(function(undefined) {
	var root = this;

	// Weird IE shit, objects do not have hasOwn, but the prototype does...
	var hasOwnProp = Object.prototype.hasOwnProperty;

	// Object cloning function, uses jQuery/Underscore/Object.create depending on what's available

	var clone = function (object) {
		if (typeof Object.hasOwnProperty !== 'undefined') {
			var target = {};
			for (var i in object) {
				if (hasOwnProp.call(object, i)) {
					target[i] = object[i];
				}
			}
			return target;
		}
		if (typeof jQuery !== 'undefined') {
			return jQuery.extend({}, object);
		}
		if (typeof _ !== 'undefined') {
			return _.extend({}, object);
		}
	};

	var Dottie = function() {
		var args = Array.prototype.slice.call(arguments);

		if (args.length == 2) {
			return Dottie.find.apply(this, args);
		}
		return Dottie.transform.apply(this, args);
	};

	// Legacy syntax, changed syntax to have get/set be similar in arg order
	Dottie.find = function(path, object) {
		return Dottie.get(object, path);
	};

	// Traverse object according to path, return value if found - Return undefined if destination is unreachable
	Dottie.get = function(object, path, defaultVal) {
		if ([undefined, null].indexOf(object) > -1) return defaultVal;

		var names = path.split('.').reverse();

		while (names.length && (object = object[names.pop()]) !== undefined && object !== null);

		// Handle cases where accessing a childprop of a null value
		if (object === null && names.length) object = undefined;

		return (object === undefined ? defaultVal : object);
	};

	// Set nested value
	Dottie.set = function(object, path, value) {
		var pieces = path.split('.'), current = object, piece, length = pieces.length;

		for (var index = 0; index < length; index++) {
			piece = pieces[index];
			if (!hasOwnProp.call(current, piece) || current[piece] === undefined) {
				current[piece] = {};
			}

			if (typeof current !== 'object') throw new Error('Target key is not suitable for a nested value (it is either not undefined or not an object)');

			if (index == (length - 1)) {
				current[piece] = value;
			} else {
				current = current[piece];
			}
		}

		current[piece] = value;
	};

	// Set default nested value
	Dottie['default'] = function(object, path, value) {
		if (Dottie.get(object, path) === undefined) {
			Dottie.set(object, path, value);
		}
	};

	// Transform unnested object with .-seperated keys into a nested object.
	Dottie.transform = function Dottie$transformfunction(object, options) {
		if (Array.isArray(object)) {
			return object.map(function(o) {
				return Dottie.transform(o, options);
			});
		}

		options = options || {};
		options.delimiter = options.delimiter || '.';

		var pieces,
			piecesLength,
			piece,
			current,
			transformed = {},
			key,
			keys = Object.keys(object),
			length = keys.length,
			i;

		for (i = 0; i < length; i++) {
			key = keys[i];

			if (key.indexOf(options.delimiter) !== -1) {
				pieces = key.split(options.delimiter);
				piecesLength = pieces.length;
				current = transformed;

				for (var index = 0; index < piecesLength; index++) {
					piece = pieces[index];
					if (index != (piecesLength - 1) && !current.hasOwnProperty(piece)) {
						current[piece] = {};
					}

					if (index == (piecesLength - 1)) {
						current[piece] = object[key];
					}

					current = current[piece];
					if (current === null) {
						break;
					}
				}
			} else {
				transformed[key] = object[key];
			}
		}

		return transformed;
	};

	Dottie.flatten = function(object, seperator) {
		if (typeof seperator === "undefined") seperator = '.';
		var flattened = {},
			current,
			nested;

		for (var key in object) {
			if (hasOwnProp.call(object, key)) {
				current = object[key];
				if (Object.prototype.toString.call(current) === "[object Object]") {
					nested = Dottie.flatten(current, seperator);

					for (var _key in nested) {
						flattened[key+seperator+_key] = nested[_key];
					}
				} else {
					flattened[key] = current;
				}
			}
		}

		return flattened;
	};

	if (typeof module !== 'undefined' && module.exports) {
		exports = module.exports = Dottie;
	} else {
		root['Dottie'] = Dottie;
		root['Dot'] = Dottie; //BC

		if (typeof define === "function") {
			define([], function () { return Dottie; });
		}
	}
})();
<commit_msg>Improve performance of value check<commit_after>(function(undefined) {
	var root = this;

	// Weird IE shit, objects do not have hasOwn, but the prototype does...
	var hasOwnProp = Object.prototype.hasOwnProperty;

	// Object cloning function, uses jQuery/Underscore/Object.create depending on what's available

	var clone = function (object) {
		if (typeof Object.hasOwnProperty !== 'undefined') {
			var target = {};
			for (var i in object) {
				if (hasOwnProp.call(object, i)) {
					target[i] = object[i];
				}
			}
			return target;
		}
		if (typeof jQuery !== 'undefined') {
			return jQuery.extend({}, object);
		}
		if (typeof _ !== 'undefined') {
			return _.extend({}, object);
		}
	};

	var Dottie = function() {
		var args = Array.prototype.slice.call(arguments);

		if (args.length == 2) {
			return Dottie.find.apply(this, args);
		}
		return Dottie.transform.apply(this, args);
	};

	// Legacy syntax, changed syntax to have get/set be similar in arg order
	Dottie.find = function(path, object) {
		return Dottie.get(object, path);
	};

	// Traverse object according to path, return value if found - Return undefined if destination is unreachable
	Dottie.get = function(object, path, defaultVal) {
		if ((object === undefined) || (object === null)) return defaultVal;

		var names = path.split('.').reverse();

		while (names.length && (object = object[names.pop()]) !== undefined && object !== null);

		// Handle cases where accessing a childprop of a null value
		if (object === null && names.length) object = undefined;

		return (object === undefined ? defaultVal : object);
	};

	// Set nested value
	Dottie.set = function(object, path, value) {
		var pieces = path.split('.'), current = object, piece, length = pieces.length;

		for (var index = 0; index < length; index++) {
			piece = pieces[index];
			if (!hasOwnProp.call(current, piece) || current[piece] === undefined) {
				current[piece] = {};
			}

			if (typeof current !== 'object') throw new Error('Target key is not suitable for a nested value (it is either not undefined or not an object)');

			if (index == (length - 1)) {
				current[piece] = value;
			} else {
				current = current[piece];
			}
		}

		current[piece] = value;
	};

	// Set default nested value
	Dottie['default'] = function(object, path, value) {
		if (Dottie.get(object, path) === undefined) {
			Dottie.set(object, path, value);
		}
	};

	// Transform unnested object with .-seperated keys into a nested object.
	Dottie.transform = function Dottie$transformfunction(object, options) {
		if (Array.isArray(object)) {
			return object.map(function(o) {
				return Dottie.transform(o, options);
			});
		}

		options = options || {};
		options.delimiter = options.delimiter || '.';

		var pieces,
			piecesLength,
			piece,
			current,
			transformed = {},
			key,
			keys = Object.keys(object),
			length = keys.length,
			i;

		for (i = 0; i < length; i++) {
			key = keys[i];

			if (key.indexOf(options.delimiter) !== -1) {
				pieces = key.split(options.delimiter);
				piecesLength = pieces.length;
				current = transformed;

				for (var index = 0; index < piecesLength; index++) {
					piece = pieces[index];
					if (index != (piecesLength - 1) && !current.hasOwnProperty(piece)) {
						current[piece] = {};
					}

					if (index == (piecesLength - 1)) {
						current[piece] = object[key];
					}

					current = current[piece];
					if (current === null) {
						break;
					}
				}
			} else {
				transformed[key] = object[key];
			}
		}

		return transformed;
	};

	Dottie.flatten = function(object, seperator) {
		if (typeof seperator === "undefined") seperator = '.';
		var flattened = {},
			current,
			nested;

		for (var key in object) {
			if (hasOwnProp.call(object, key)) {
				current = object[key];
				if (Object.prototype.toString.call(current) === "[object Object]") {
					nested = Dottie.flatten(current, seperator);

					for (var _key in nested) {
						flattened[key+seperator+_key] = nested[_key];
					}
				} else {
					flattened[key] = current;
				}
			}
		}

		return flattened;
	};

	if (typeof module !== 'undefined' && module.exports) {
		exports = module.exports = Dottie;
	} else {
		root['Dottie'] = Dottie;
		root['Dot'] = Dottie; //BC

		if (typeof define === "function") {
			define([], function () { return Dottie; });
		}
	}
})();
<|endoftext|>


<commit_before>'use strict';

const buble = require('buble');

class BrunchBuble {
  constructor(config) {
    this.config = config.plugins.bubleBrunch || {};
  }

  compile(file) {
    try {
      const transform = buble.transform(file.data, this.config);
      return Promise.resolve(transform.code);
    } catch (error) {
      return Promise.reject(error);
    }
  }
}

BrunchBuble.prototype.brunchPlugin = true;
BrunchBuble.prototype.type = 'javascript';
BrunchBuble.prototype.extension = 'js';

module.exports = BrunchBuble;
<commit_msg>bubleBrunch => buble<commit_after>'use strict';

const buble = require('buble');

class BrunchBuble {
  constructor(config) {
    this.config = config.plugins.buble || {};
  }

  compile(file) {
    try {
      const transform = buble.transform(file.data, this.config);
      return Promise.resolve(transform.code);
    } catch (error) {
      return Promise.reject(error);
    }
  }
}

BrunchBuble.prototype.brunchPlugin = true;
BrunchBuble.prototype.type = 'javascript';
BrunchBuble.prototype.extension = 'js';

module.exports = BrunchBuble;
<|endoftext|>


<commit_before>'use strict';

/**
 * Creates a Fibonacci heap.
 *
 * @constructor
 * @param {function} customCompare An optional custom node comparison
 * function.
 */
var FibonacciHeap = function (customCompare) {
  this.minNode = undefined;
  this.nodeCount = 0;

  if (customCompare) {
    this.compare = customCompare;
  }
};

/**
 * Clears the heap's data, making it an empty heap.
 */
FibonacciHeap.prototype.clear = function () {
  this.minNode = undefined;
  this.nodeCount = 0;
};

/**
 * Decreases a key of a node.
 *
 * @param {Node} node The node to decrease the key of.
 * @param {Object} newKey The new key to assign to the node.
 */
FibonacciHeap.prototype.decreaseKey = function (node, newKey) {
  if (typeof node === 'undefined') {
    throw new Error('Cannot decrease key of non-existent node');
  }
  if (this.compare({key: newKey}, {key: node.key}) > 0) {
    throw new Error('New key is larger than old key');
  }

  node.key = newKey;
  var parent = node.parent;
  if (parent && this.compare(node, parent) < 0) {
    cut(node, parent, this.minNode, this.compare);
    cascadingCut(parent, this.minNode, this.compare);
  }
  if (this.compare(node, this.minNode) < 0) {
    this.minNode = node;
  }
};

/**
 * Deletes a node.
 *
 * @param {Node} node The node to delete.
 */
FibonacciHeap.prototype.delete = function (node) {
  // This is a special implementation of decreaseKey that sets the argument to
  // the minimum value. This is necessary to make generic keys work, since there
  // is no MIN_VALUE constant for generic types.
  var parent = node.parent;
  if (parent) {
    cut(node, parent, this.minNode, this.compare);
    cascadingCut(parent, this.minNode, this.compare);
  }
  this.minNode = node;

  this.extractMinimum();
};

/**
 * Extracts and returns the minimum node from the heap.
 *
 * @return {Node} node The heap's minimum node or undefined if the heap is
 * empty.
 */
FibonacciHeap.prototype.extractMinimum = function () {
  var extractedMin = this.minNode;
  if (extractedMin) {
    // Set parent to undefined for the minimum's children
    if (extractedMin.child) {
      var child = extractedMin.child;
      do {
        child.parent = undefined;
        child = child.next;
      } while (child !== extractedMin.child);
    }

    var nextInRootList;
    if (extractedMin.next !== extractedMin) {
      nextInRootList = extractedMin.next;
    }
    // Remove min from root list
    removeNodeFromList(extractedMin);
    this.nodeCount--;

    // Merge the children of the minimum node with the root list
    this.minNode = mergeLists(nextInRootList, extractedMin.child, this.compare);
    if (nextInRootList) {
      this.minNode = nextInRootList;
      this.minNode = consolidate(this.minNode, this.compare);
    }
  }
  return extractedMin;
};

/**
 * Returns the minimum node from the heap.
 *
 * @return {Node} node The heap's minimum node or undefined if the heap is
 * empty.
 */
FibonacciHeap.prototype.findMinimum = function () {
  return this.minNode;
};

/**
 * Inserts a new key-value pair into the heap.
 *
 * @param {Object} key The key to insert.
 * @param {Object} value The value to insert.
 * @return {Node} node The inserted node.
 */
FibonacciHeap.prototype.insert = function (key, value) {
  var node = new Node(key, value);
  this.minNode = mergeLists(this.minNode, node, this.compare);
  this.nodeCount++;
  return node;
};

/**
 * @return {boolean} Whether the heap is empty.
 */
FibonacciHeap.prototype.isEmpty = function () {
  return this.minNode === undefined;
};

/**
 * @return {number} The size of the heap.
 */
FibonacciHeap.prototype.size = function () {
  if (this.isEmpty()) {
    return 0;
  }
  return getNodeListSize(this.minNode);
};

/**
 * Joins another heap to this heap.
 *
 * @param {BinaryHeap} otherHeap The other heap.
 */
FibonacciHeap.prototype.union = function (other) {
  this.minNode = mergeLists(this.minNode, other.minNode, this.compare);
  this.nodeCount += other.nodeCount;
};

/**
 * Compares two nodes with each other.
 *
 * @private
 * @param {Object} a The first key to compare.
 * @param {Object} b The second key to compare.
 * @return {number} -1, 0 or 1 if a < b, a == b or a > b respectively.
 */
FibonacciHeap.prototype.compare = function (a, b) {
  if (a.key > b.key) {
    return 1;
  }
  if (a.key < b.key) {
    return -1;
  }
  return 0;
};

/**
 * Creates an Iterator used to simplify the consolidate() method. It works by
 * making a shallow copy of the nodes in the root list and iterating over the
 * shallow copy instead of the source as the source will be modified.
 *
 * @private
 * @param {Node} start A node from the root list.
 */
var NodeListIterator = function (start) {
  this.index = -1;
  this.items = [];
  var current = start;
  do {
    this.items.push(current);
    current = current.next;
  } while (start !== current);
};

/**
 * @return {boolean} Whether there is a next node in the iterator.
 */
NodeListIterator.prototype.hasNext = function () {
  return this.index < this.items.length - 1;
};

/**
 * @return {Node} The next node.
 */
NodeListIterator.prototype.next = function () {
  return this.items[++this.index];
};

/**
 * Cut the link between a node and its parent, moving the node to the root list.
 *
 * @private
 * @param {Node} node The node being cut.
 * @param {Node} parent The parent of the node being cut.
 * @param {Node} minNode The minimum node in the root list.
 * @param {function} compare The node comparison function to use.
 * @return {Node} The heap's new minimum node.
 */
function cut(node, parent, minNode, compare) {
  parent.degree--;
  if (node.next === node) {
    parent.child = undefined;
  } else {
    parent.child = node.next;
  }
  removeNodeFromList(node);
  minNode = mergeLists(minNode, node, compare);
  node.isMarked = false;
  return minNode;
}

/**
 * Perform a cascading cut on a node; mark the node if it is not marked,
 * otherwise cut the node and perform a cascading cut on its parent.
 *
 * @private
 * @param {Node} node The node being considered to be cut.
 * @param {Node} minNode The minimum node in the root list.
 * @param {function} compare The node comparison function to use.
 * @return {Node} The heap's new minimum node.
 */
function cascadingCut(node, minNode, compare) {
  var parent = node.parent;
  if (parent) {
    if (node.isMarked) {
      minNode = cut(node, parent, minNode, compare);
      minNode = cascadingCut(parent, minNode, compare);
    } else {
      node.isMarked = true;
    }
  }
  return minNode;
}

/**
 * Merge all trees of the same order together until there are no two trees of
 * the same order.
 *
 * @private
 * @param {Node} minNode The current minimum node.
 * @param {function} compare The node comparison function to use.
 * @return {Node} The new minimum node.
 */
function consolidate(minNode, compare) {
  var aux = [];
  var it = new NodeListIterator(minNode);
  while (it.hasNext()) {
    var current = it.next();

    // If there exists another node with the same degree, merge them
    while (aux[current.degree]) {
      if (compare(current, aux[current.degree]) > 0) {
        var temp = current;
        current = aux[current.degree];
        aux[current.degree] = temp;
      }
      linkHeaps(aux[current.degree], current, compare);
      aux[current.degree] = undefined;
      current.degree++;
    }

    aux[current.degree] = current;
  }

  minNode = undefined;
  for (var i = 0; i < aux.length; i++) {
    if (aux[i]) {
      // Remove siblings before merging
      aux[i].next = aux[i];
      aux[i].prev = aux[i];
      minNode = mergeLists(minNode, aux[i], compare);
    }
  }
  return minNode;
}

/**
 * Removes a node from a node list.
 *
 * @private
 * @param {Node} node The node to remove.
 */
function removeNodeFromList(node) {
  var prev = node.prev;
  var next = node.next;
  prev.next = next;
  next.prev = prev;
  node.next = node;
  node.prev = node;
}

/**
 * Links two heaps of the same order together.
 *
 * @private
 * @param {Node} max The heap with the larger root.
 * @param {Node} min The heap with the smaller root.
 * @param {function} compare The node comparison function to use.
 */
function linkHeaps(max, min, compare) {
  removeNodeFromList(max);
  min.child = mergeLists(max, min.child, compare);
  max.parent = min;
  max.isMarked = false;
}

/**
 * Merge two lists of nodes together.
 *
 * @private
 * @param {Node} a The first list to merge.
 * @param {Node} b The second list to merge.
 * @param {function} compare The node comparison function to use.
 * @return {Node} The new minimum node from the two lists.
 */
function mergeLists(a, b, compare) {
  if (!a && !b) {
    return undefined;
  }
  if (!a) {
    return b;
  }
  if (!b) {
    return a;
  }

  var temp = a.next;
  a.next = b.next;
  a.next.prev = a;
  b.next = temp;
  b.next.prev = b;

  return compare(a, b) < 0 ? a : b;
}

/**
 * Gets the size of a node list.
 *
 * @private
 * @param {Node} node A node within the node list.
 * @return {number} The size of the node list.
 */
function getNodeListSize(node) {
  var count = 0;
  var current = node;

  do {
    count++;
    if (current.child) {
      count += getNodeListSize(current.child);
    }
    current = current.next;
  } while (current !== node);

  return count;
}

/**
 * Creates a FibonacciHeap node.
 *
 * @constructor
 * @private
 */
function Node(key, value) {
  this.key = key;
  this.value = value;
  this.prev = this;
  this.next = this;
  this.degree = 0;

  this.parent = undefined;
  this.child = undefined;
  this.isMarked = undefined;
}

module.exports = FibonacciHeap;
<commit_msg>1. link to parent is not remove in cut() 2. incorrect if-statement for consolidate() call, based on assumption that extractedMin.child guaranteed be minimal among siblings in FibonacciHeap.prototype.extractMinimum(). 3. @jsDoc fixed for FibonacciHeap.prototype.union()<commit_after>'use strict';

/**
 * Creates a Fibonacci heap.
 *
 * @constructor
 * @param {function} customCompare An optional custom node comparison
 * function.
 */
var FibonacciHeap = function (customCompare) {
  this.minNode = undefined;
  this.nodeCount = 0;

  if (customCompare) {
    this.compare = customCompare;
  }
};

/**
 * Clears the heap's data, making it an empty heap.
 */
FibonacciHeap.prototype.clear = function () {
  this.minNode = undefined;
  this.nodeCount = 0;
};

/**
 * Decreases a key of a node.
 *
 * @param {Node} node The node to decrease the key of.
 * @param {Object} newKey The new key to assign to the node.
 */
FibonacciHeap.prototype.decreaseKey = function (node, newKey) {
  if (typeof node === 'undefined') {
    throw new Error('Cannot decrease key of non-existent node');
  }
  if (this.compare({key: newKey}, {key: node.key}) > 0) {
    throw new Error('New key is larger than old key');
  }

  node.key = newKey;
  var parent = node.parent;
  if (parent && this.compare(node, parent) < 0) {
    cut(node, parent, this.minNode, this.compare);
    cascadingCut(parent, this.minNode, this.compare);
  }
  if (this.compare(node, this.minNode) < 0) {
    this.minNode = node;
  }
};

/**
 * Deletes a node.
 *
 * @param {Node} node The node to delete.
 */
FibonacciHeap.prototype.delete = function (node) {
  // This is a special implementation of decreaseKey that sets the argument to
  // the minimum value. This is necessary to make generic keys work, since there
  // is no MIN_VALUE constant for generic types.
  var parent = node.parent;
  if (parent) {
    cut(node, parent, this.minNode, this.compare);
    cascadingCut(parent, this.minNode, this.compare);
  }
  this.minNode = node;

  this.extractMinimum();
};

/**
 * Extracts and returns the minimum node from the heap.
 *
 * @return {Node} node The heap's minimum node or undefined if the heap is
 * empty.
 */
FibonacciHeap.prototype.extractMinimum = function () {
  var extractedMin = this.minNode;
  if (extractedMin) {
    // Set parent to undefined for the minimum's children
    if (extractedMin.child) {
      var child = extractedMin.child;
      do {
        child.parent = undefined;
        child = child.next;
      } while (child !== extractedMin.child);
    }

    var nextInRootList;
    if (extractedMin.next !== extractedMin) {
      nextInRootList = extractedMin.next;
    }
    // Remove min from root list
    removeNodeFromList(extractedMin);
    this.nodeCount--;

    // Merge the children of the minimum node with the root list
    this.minNode = mergeLists(nextInRootList, extractedMin.child, this.compare);
    if (this.minNode) {
      this.minNode = nextInRootList;
      this.minNode = consolidate(this.minNode, this.compare);
    }
  }
  return extractedMin;
};

/**
 * Returns the minimum node from the heap.
 *
 * @return {Node} node The heap's minimum node or undefined if the heap is
 * empty.
 */
FibonacciHeap.prototype.findMinimum = function () {
  return this.minNode;
};

/**
 * Inserts a new key-value pair into the heap.
 *
 * @param {Object} key The key to insert.
 * @param {Object} value The value to insert.
 * @return {Node} node The inserted node.
 */
FibonacciHeap.prototype.insert = function (key, value) {
  var node = new Node(key, value);
  this.minNode = mergeLists(this.minNode, node, this.compare);
  this.nodeCount++;
  return node;
};

/**
 * @return {boolean} Whether the heap is empty.
 */
FibonacciHeap.prototype.isEmpty = function () {
  return this.minNode === undefined;
};

/**
 * @return {number} The size of the heap.
 */
FibonacciHeap.prototype.size = function () {
  if (this.isEmpty()) {
    return 0;
  }
  return getNodeListSize(this.minNode);
};

/**
 * Joins another heap to this heap.
 *
 * @param {FibonacciHeap} other The other heap.
 */
FibonacciHeap.prototype.union = function (other) {
  this.minNode = mergeLists(this.minNode, other.minNode, this.compare);
  this.nodeCount += other.nodeCount;
};

/**
 * Compares two nodes with each other.
 *
 * @private
 * @param {Object} a The first key to compare.
 * @param {Object} b The second key to compare.
 * @return {number} -1, 0 or 1 if a < b, a == b or a > b respectively.
 */
FibonacciHeap.prototype.compare = function (a, b) {
  if (a.key > b.key) {
    return 1;
  }
  if (a.key < b.key) {
    return -1;
  }
  return 0;
};

/**
 * Creates an Iterator used to simplify the consolidate() method. It works by
 * making a shallow copy of the nodes in the root list and iterating over the
 * shallow copy instead of the source as the source will be modified.
 *
 * @private
 * @param {Node} start A node from the root list.
 */
var NodeListIterator = function (start) {
  this.index = -1;
  this.items = [];
  var current = start;
  do {
    this.items.push(current);
    current = current.next;
  } while (start !== current);
};

/**
 * @return {boolean} Whether there is a next node in the iterator.
 */
NodeListIterator.prototype.hasNext = function () {
  return this.index < this.items.length - 1;
};

/**
 * @return {Node} The next node.
 */
NodeListIterator.prototype.next = function () {
  return this.items[++this.index];
};

/**
 * Cut the link between a node and its parent, moving the node to the root list.
 *
 * @private
 * @param {Node} node The node being cut.
 * @param {Node} parent The parent of the node being cut.
 * @param {Node} minNode The minimum node in the root list.
 * @param {function} compare The node comparison function to use.
 * @return {Node} The heap's new minimum node.
 */
function cut(node, parent, minNode, compare) {
  node.parent = undefined;
  parent.degree--;
  if (node.next === node) {
    parent.child = undefined;
  } else {
    parent.child = node.next;
  }
  removeNodeFromList(node);
  minNode = mergeLists(minNode, node, compare);
  node.isMarked = false;
  return minNode;
}

/**
 * Perform a cascading cut on a node; mark the node if it is not marked,
 * otherwise cut the node and perform a cascading cut on its parent.
 *
 * @private
 * @param {Node} node The node being considered to be cut.
 * @param {Node} minNode The minimum node in the root list.
 * @param {function} compare The node comparison function to use.
 * @return {Node} The heap's new minimum node.
 */
function cascadingCut(node, minNode, compare) {
  var parent = node.parent;
  if (parent) {
    if (node.isMarked) {
      minNode = cut(node, parent, minNode, compare);
      minNode = cascadingCut(parent, minNode, compare);
    } else {
      node.isMarked = true;
    }
  }
  return minNode;
}

/**
 * Merge all trees of the same order together until there are no two trees of
 * the same order.
 *
 * @private
 * @param {Node} minNode The current minimum node.
 * @param {function} compare The node comparison function to use.
 * @return {Node} The new minimum node.
 */
function consolidate(minNode, compare) {
  var aux = [];
  var it = new NodeListIterator(minNode);
  while (it.hasNext()) {
    var current = it.next();

    // If there exists another node with the same degree, merge them
    while (aux[current.degree]) {
      if (compare(current, aux[current.degree]) > 0) {
        var temp = current;
        current = aux[current.degree];
        aux[current.degree] = temp;
      }
      linkHeaps(aux[current.degree], current, compare);
      aux[current.degree] = undefined;
      current.degree++;
    }

    aux[current.degree] = current;
  }

  minNode = undefined;
  for (var i = 0; i < aux.length; i++) {
    if (aux[i]) {
      // Remove siblings before merging
      aux[i].next = aux[i];
      aux[i].prev = aux[i];
      minNode = mergeLists(minNode, aux[i], compare);
    }
  }
  return minNode;
}

/**
 * Removes a node from a node list.
 *
 * @private
 * @param {Node} node The node to remove.
 */
function removeNodeFromList(node) {
  var prev = node.prev;
  var next = node.next;
  prev.next = next;
  next.prev = prev;
  node.next = node;
  node.prev = node;
}

/**
 * Links two heaps of the same order together.
 *
 * @private
 * @param {Node} max The heap with the larger root.
 * @param {Node} min The heap with the smaller root.
 * @param {function} compare The node comparison function to use.
 */
function linkHeaps(max, min, compare) {
  removeNodeFromList(max);
  min.child = mergeLists(max, min.child, compare);
  max.parent = min;
  max.isMarked = false;
}

/**
 * Merge two lists of nodes together.
 *
 * @private
 * @param {Node} a The first list to merge.
 * @param {Node} b The second list to merge.
 * @param {function} compare The node comparison function to use.
 * @return {Node} The new minimum node from the two lists.
 */
function mergeLists(a, b, compare) {
  if (!a && !b) {
    return undefined;
  }
  if (!a) {
    return b;
  }
  if (!b) {
    return a;
  }

  var temp = a.next;
  a.next = b.next;
  a.next.prev = a;
  b.next = temp;
  b.next.prev = b;

  return compare(a, b) < 0 ? a : b;
}

/**
 * Gets the size of a node list.
 *
 * @private
 * @param {Node} node A node within the node list.
 * @return {number} The size of the node list.
 */
function getNodeListSize(node) {
  var count = 0;
  var current = node;

  do {
    count++;
    if (current.child) {
      count += getNodeListSize(current.child);
    }
    current = current.next;
  } while (current !== node);

  return count;
}

/**
 * Creates a FibonacciHeap node.
 *
 * @constructor
 * @private
 */
function Node(key, value) {
  this.key = key;
  this.value = value;
  this.prev = this;
  this.next = this;
  this.degree = 0;

  this.parent = undefined;
  this.child = undefined;
  this.isMarked = undefined;
}

module.exports = FibonacciHeap;
<|endoftext|>


<commit_before>const _ircServer = "irc.chat.twitch.tv";
const _ircPort = 6667;
const _irc = require( 'slate-irc' );
const _net = require( 'net' );
const _streamWrapper = require( './src/stream-wrapper.js' );

// key:type
const _requiredParams =
{
	user : 'string',
	pass : 'string',
};

const _optionalParams =
{
	channel : 'object',
	data : 'function',
	done : 'function'
};

const _verifyOptions = function( options )
{
	for( var index in _requiredParams )
	{
		if( typeof options[ index ] === "undefined" )
			throw "Missing '" + index + "' from options";

		if( typeof options[ index ] !== _requiredParams[ index ] )
			throw "'" + index + "' must be of type '" + _requiredParams[ index ] + "'";
	}

	for( var index in _optionalParams )
	{
		if( typeof options[ index ] !== "undefined" && typeof options[ index ] !== _optionalParams[ index ] )
			throw "'" + index + "' must be of type '" + _optionalParams[ index ] + "'";
	}
};

const _processDataPacket = function( packet )
{
	return {
		user 	: packet.prefix.split( '!' )[ 0 ],
		message : packet.trailing,
		channel : packet.params.slice( 1 )
	};
};

const _logger = function( options )
{
	return function( irc )
	{
		irc.on( 'data', function( data )
		{
			if( data.prefix === 'tmi.twitch.tv' || data.prefix === options.user + '.tmi.twitch.tv' || data.trailing.length === 0 || data.prefix.split( '!' )[ 0 ].length === 0 )
				return;

			options.data( _processDataPacket( data ) );
		});
	};
};

const _pong = function()
{
	return function( irc )
	{
		irc.on('data', function( msg )
		{
			if ( 'PING' != msg.command )
				return;

			irc.write( 'PONG :tmi.twitch.tv' );
		});
	};
};

exports.connect = function( options )
{
	_verifyOptions( options );

	const stream = _net.connect({
		port: _ircPort,
		host: _ircServer
	});

	const client = new _streamWrapper( _irc( stream ) );

	client.pass( options.pass );
	client.nick( options.user );
	client.user( options.user, options.user );

	client.join( options.channel );

	client.use( _pong() );

	if( typeof options.data !== "undefined" )
		client.use( _logger( options ) );

	if( typeof options.done !== "undefined" )
		options.done( client );
};
<commit_msg>Added 'close' and error' options<commit_after>const _ircServer = "irc.chat.twitch.tv";
const _ircPort = 6667;
const _irc = require( 'slate-irc' );
const _net = require( 'net' );
const _streamWrapper = require( './src/stream-wrapper.js' );

// key:type
const _requiredParams =
{
	user : 'string',
	pass : 'string',
};

const _optionalParams =
{
	channel : 'object',
	data : 'function',
	done : 'function'
};

const _verifyOptions = function( options )
{
	for( var index in _requiredParams )
	{
		if( typeof options[ index ] === "undefined" )
			throw "Missing '" + index + "' from options";

		if( typeof options[ index ] !== _requiredParams[ index ] )
			throw "'" + index + "' must be of type '" + _requiredParams[ index ] + "'";
	}

	for( var index in _optionalParams )
	{
		if( typeof options[ index ] !== "undefined" && typeof options[ index ] !== _optionalParams[ index ] )
			throw "'" + index + "' must be of type '" + _optionalParams[ index ] + "'";
	}
};

const _processDataPacket = function( packet )
{
	return {
		user 	: packet.prefix.split( '!' )[ 0 ],
		message : packet.trailing,
		channel : packet.params.slice( 1 )
	};
};

const _logger = function( options )
{
	return function( irc )
	{
		irc.on( 'data', function( data )
		{
			if( data.prefix === 'tmi.twitch.tv' || data.prefix === options.user + '.tmi.twitch.tv' || data.trailing.length === 0 || data.prefix.split( '!' )[ 0 ].length === 0 )
				return;

			options.data( _processDataPacket( data ) );
		});
	};
};

const _pong = function()
{
	return function( irc )
	{
		irc.on('data', function( msg )
		{
			if ( 'PING' != msg.command )
				return;

			irc.write( 'PONG :tmi.twitch.tv' );
		});
	};
};

exports.connect = function( options )
{
	_verifyOptions( options );

	const stream = _net.connect({
		port: _ircPort,
		host: _ircServer
	});

	if( typeof options.close !== "undefined" )
		stream.on( 'close', options.close );

	if( typeof options.error !== "undefined" )
		stream.on( 'error', options.error );

	const client = new _streamWrapper( _irc( stream ) );

	client.pass( options.pass );
	client.nick( options.user );
	client.user( options.user, options.user );

	client.join( options.channel );

	client.use( _pong() );

	if( typeof options.data !== "undefined" )
		client.use( _logger( options ) );

	if( typeof options.done !== "undefined" )
		options.done( client );
};
<|endoftext|>


<commit_before>'use strict';

/**
 * This microservice generates a thumbnail when an image is uploaded to an S3 bucket.
 *
 * @author Sam Verschueren      <sam.verschueren@gmail.com>
 * @since  11 Aug. 2015
 */

// module dependencies
var AWS = require('aws-sdk'),
    gm = require('gm').subClass({ imageMagick: true }),
    util = require('util'),
    Q = require('q');

// Create a new S3 object
var s3 = new AWS.S3();

// Generate a 150x150 square image
var SIZE = 150,
    DEST_DIR = 'thumbs',
    WHITELIST = ['image/jpeg', 'image/jpg', 'image/png'];

/**
 * Main entrypoint of the service.
 *
 * @param {object}  event       The data regarding the event.
 * @param {object}  context     The AWS Lambda execution context.
 */
exports.handler = function(event, context) {
    var bucket = event.Records[0].s3.bucket.name,
        source = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));

    Q.fcall(function() {
        // Retrieve the object
        return getObject({Bucket: bucket, Key: source});
    }).then(function(response) {
        if(WHITELIST.indexOf(response.ContentType.split(';').shift()) === -1) {
            // If the mimetype is not in the whitelist, throw an error
            throw new TypeError('This type of file could not be converted.');
        }

        // Scale and crop the image
        return [response.ContentType, scale(response.Body)];
    }).spread(function(contentType, buffer) {
        // Determine the destination of the thumbnail
        var dest = source.split('/');
        dest.shift();
        dest.unshift(DEST_DIR);

        // Store the image and the correct location
        return putObject({Bucket: bucket, Key: dest.join('/'), Body: buffer, ContentType: contentType});
    }).then(function() {
        // Everything went well
        context.succeed();
    }).catch(function(err) {
        // Log the error
        console.error(err);

        // Let the function fail
        context.fail(err);
    });

    function getObject(obj) {
        return Q.Promise(function(resolve, reject) {
            // Retrieve the object
            s3.getObject(obj, function(err, result) {
                if(err) {
                    // Reject because something went wrong
                    return reject(err);
                }

                // We retrieved the object successfully
                resolve(result);
            });
        });
    };

    function putObject(obj) {
        return Q.Promise(function(resolve, reject) {
            // Retrieve the object
            s3.putObject(obj, function(err, result) {
                if(err) {
                    // Reject because something went wrong
                    return reject(err);
                }

                // We retrieved the object successfully
                resolve(result);
            });
        });
    };

    function scale(img) {
        return Q.Promise(function(resolve, reject) {
            // Retrieve the size of the img
            gm(img).size(function(err, size) {
                if(err) {
                    // Reject the promise if an error occurred
                    return reject(err);
                }

                // Calculate the maximum square we can extract
                var square = Math.min(size.width, size.height),
                    x = (size.width / 2) - (square / 2),
                    y = (size.height / 2) - (square / 2);

                // Extract the middle square and resize to the SIZE defined
                gm(img).crop(square, square, x, y).resize(SIZE, SIZE).autoOrient().toBuffer(function(err, buffer) {
                    if(err) {
                        // Reject the promise if an error occurred
                        return reject(err);
                    }

                    // Resolve the buffer if everything went well
                    resolve(buffer);
                });
            });
        });
    }
};<commit_msg>Not throwing an error now but do proper handling<commit_after>'use strict';

/**
 * This microservice generates a thumbnail when an image is uploaded to an S3 bucket.
 *
 * @author Sam Verschueren      <sam.verschueren@gmail.com>
 * @since  11 Aug. 2015
 */

// module dependencies
var AWS = require('aws-sdk'),
    gm = require('gm').subClass({ imageMagick: true }),
    util = require('util'),
    Q = require('q');

// Create a new S3 object
var s3 = new AWS.S3();

// Generate a 150x150 square image
var SIZE = 150,
    DEST_DIR = 'thumbs',
    WHITELIST = ['image/jpeg', 'image/jpg', 'image/png'];

/**
 * Main entrypoint of the service.
 *
 * @param {object}  event       The data regarding the event.
 * @param {object}  context     The AWS Lambda execution context.
 */
exports.handler = function(event, context) {
    var bucket = event.Records[0].s3.bucket.name,
        source = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));

    Q.fcall(function() {
        // Retrieve the object
        return getObject({Bucket: bucket, Key: source});
    }).then(function(response) {
        if(WHITELIST.indexOf(response.ContentType.split(';').shift()) === -1) {
            // Log the error
            console.error(response.ContentType + ' could not be parsed');

            // If the mimetype is not in the whitelist, pass it to the following step
            return [response.ContentType, response.Body];
        }

        // Scale and crop the image
        return [response.ContentType, scale(response.Body)];
    }).spread(function(contentType, buffer) {
        // Determine the destination of the thumbnail
        var dest = source.split('/');
        dest.shift();
        dest.unshift(DEST_DIR);

        // Store the image and the correct location
        return putObject({Bucket: bucket, Key: dest.join('/'), Body: buffer, ContentType: contentType});
    }).then(function() {
        // Everything went well
        context.succeed();
    }).catch(function(err) {
        // Log the error
        console.error(err);

        // Let the function fail
        context.fail(err);
    });

    function getObject(obj) {
        return Q.Promise(function(resolve, reject) {
            // Retrieve the object
            s3.getObject(obj, function(err, result) {
                if(err) {
                    // Reject because something went wrong
                    return reject(err);
                }

                // We retrieved the object successfully
                resolve(result);
            });
        });
    };

    function putObject(obj) {
        return Q.Promise(function(resolve, reject) {
            // Retrieve the object
            s3.putObject(obj, function(err, result) {
                if(err) {
                    // Reject because something went wrong
                    return reject(err);
                }

                // We retrieved the object successfully
                resolve(result);
            });
        });
    };

    function scale(img) {
        return Q.Promise(function(resolve, reject) {
            // Retrieve the size of the img
            gm(img).size(function(err, size) {
                if(err) {
                    // Reject the promise if an error occurred
                    return reject(err);
                }

                // Calculate the maximum square we can extract
                var square = Math.min(size.width, size.height),
                    x = (size.width / 2) - (square / 2),
                    y = (size.height / 2) - (square / 2);

                // Extract the middle square and resize to the SIZE defined
                gm(img).crop(square, square, x, y).resize(SIZE, SIZE).autoOrient().toBuffer(function(err, buffer) {
                    if(err) {
                        // Reject the promise if an error occurred
                        return reject(err);
                    }

                    // Resolve the buffer if everything went well
                    resolve(buffer);
                });
            });
        });
    }
};<|endoftext|>


<commit_before>'use strict';

var fs = require('fs')
var through = require('through2')
var path = require('path')
var CRMWebAPI = require('./CRMWebAPI');
var adal = require('adal-node');

var CRMWebResourceManager = (function () {
function CRMWebResourceManager() {

		return this;
	}
});

CRMWebResourceManager._Authenticate = function(config)
{
  return new Promise(function (resolve, reject) {

    var   authorityHostUrl = 'https://login.windows.net/common';
    var  clientId = '3e4ef8f4-24ba-4709-a60d-27ee21fdfba9';

    if (config.AccessToken != null)
    {
        resolve(config.AccessToken);
    }
    else
    {
        if ((config.Server == null) || (config.User == null) || (config.Password == null))
        {
            reject("You must provide Server, User and Password if not providing a valid AccessToken");
        }
        else
        {
            var context = new  adal.AuthenticationContext(authorityHostUrl);

            context.acquireTokenWithUsernamePassword(config.Server, config.User, config.Password, clientId, function(err, tokenResponse) {
            if (err) {
                reject(err);
            } else {

                resolve(tokenResponse.accessToken);
            }
        });
        }
    }
  });

}

CRMWebResourceManager.Upload = function (config) {

        return through.obj(function(file, enc, cb) {

           var uniqueName = null;
           config.WebResources.forEach(function(wrconfig) {

               if (wrconfig.Path == path.relative(__dirname.replace('node_modules\\gulp-webresource',''),file.path))
                 uniqueName = wrconfig.UniqueName;
           })
           if (uniqueName == null)
           {
               console.log('File Skipped - Not Configured : ' + path.relative(__dirname.replace('node_modules\\gulp-webresource',''),file.path) );
               return cb();
           }
           var queryOption = {
            	Filter:"name  eq '"+ uniqueName +"'",
	            Select:['webresourceid'],
            };
            CRMWebResourceManager._Authenticate(config).then(function(accessToken){

            var apiconfig = { APIUrl: config.Server + '/api/data/v8.0/', AccessToken: accessToken };

            var crmAPI = new CRMWebAPI(apiconfig);

            crmAPI.GetList('webresourceset', queryOption).then(function (queryResult)
            {
                if (queryResult.List.length > 0)
                {
                    var wrContent = file.contents.toString();

                    var wrUpdate = {};
                    wrUpdate.webresourceid = queryResult.List[0].webresourceid;
                    wrUpdate.content = new Buffer(wrContent).toString('base64');
                    crmAPI.Update("webresourceset",wrUpdate.webresourceid,wrUpdate).then(function(){
                       console.log(uniqueName + " updated.")
                       var publishParms = {ParameterXml:"<importexportxml><webresources><webresource>{" +
                                        wrUpdate.webresourceid + "}</webresource></webresources></importexportxml>"}

                       crmAPI.ExecuteAction("PublishXml",publishParms).then(
                          function(){
                                console.log(uniqueName +" published.")
                                return cb();
                            },
                          function(error){
                              console.log("Error publishing " + uniqueName +" Error:" + error);

                              return cb();
                            })

                      },function(error){
                        console.log("error updating " + uniqueName + "Error " + error );
                         return cb();
                    })

                }
                else{
                    console.log(uniqueName + " Must be configured in CRM ")
                }
            }
            ,function(error)
            {	console.log(error);
            });
          },function(error)
          {
              if (error.stack.indexOf('administrator has not consented') != -1)
                {
                        console.log('administrator must visit http://bit.ly/1Vpj6O2 to consent to use first');
                }
                else
                console.log(error)
          });

        });

 }

module.exports = CRMWebResourceManager;
<commit_msg>Use cross-platform paths<commit_after>'use strict';

var fs = require('fs')
var through = require('through2')
var path = require('path')
var CRMWebAPI = require('./CRMWebAPI');
var adal = require('adal-node');

var CRMWebResourceManager = (function () {
function CRMWebResourceManager() {

		return this;
	}
});

CRMWebResourceManager._Authenticate = function(config)
{
  return new Promise(function (resolve, reject) {

    var   authorityHostUrl = 'https://login.windows.net/common';
    var  clientId = '3e4ef8f4-24ba-4709-a60d-27ee21fdfba9';

    if (config.AccessToken != null)
    {
        resolve(config.AccessToken);
    }
    else
    {
        if ((config.Server == null) || (config.User == null) || (config.Password == null))
        {
            reject("You must provide Server, User and Password if not providing a valid AccessToken");
        }
        else
        {
            var context = new  adal.AuthenticationContext(authorityHostUrl);

            context.acquireTokenWithUsernamePassword(config.Server, config.User, config.Password, clientId, function(err, tokenResponse) {
            if (err) {
                reject(err);
            } else {

                resolve(tokenResponse.accessToken);
            }
        });
        }
    }
  });

}

CRMWebResourceManager.Upload = function (config) {

        return through.obj(function(file, enc, cb) {

           var normalizedPath = path.relative(__dirname.replace(
             path.join('node_modules', 'gulp-webresource'), ''),file.path);
           var uniqueName = null;
           config.WebResources.forEach(function(wrconfig) {

               if (wrconfig.Path == normalizedPath)
                 uniqueName = wrconfig.UniqueName;
           })
           if (uniqueName == null)
           {
               console.log('File Skipped - Not Configured : ' + normalizedPath);
               return cb();
           }
           var queryOption = {
            	Filter:"name  eq '"+ uniqueName +"'",
	            Select:['webresourceid'],
            };
            CRMWebResourceManager._Authenticate(config).then(function(accessToken){

            var apiconfig = { APIUrl: config.Server + '/api/data/v8.0/', AccessToken: accessToken };

            var crmAPI = new CRMWebAPI(apiconfig);

            crmAPI.GetList('webresourceset', queryOption).then(function (queryResult)
            {
                if (queryResult.List.length > 0)
                {
                    var wrContent = file.contents.toString();

                    var wrUpdate = {};
                    wrUpdate.webresourceid = queryResult.List[0].webresourceid;
                    wrUpdate.content = new Buffer(wrContent).toString('base64');
                    crmAPI.Update("webresourceset",wrUpdate.webresourceid,wrUpdate).then(function(){
                       console.log(uniqueName + " updated.")
                       var publishParms = {ParameterXml:"<importexportxml><webresources><webresource>{" +
                                        wrUpdate.webresourceid + "}</webresource></webresources></importexportxml>"}

                       crmAPI.ExecuteAction("PublishXml",publishParms).then(
                          function(){
                                console.log(uniqueName +" published.")
                                return cb();
                            },
                          function(error){
                              console.log("Error publishing " + uniqueName +" Error:" + error);

                              return cb();
                            })

                      },function(error){
                        console.log("error updating " + uniqueName + "Error " + error );
                         return cb();
                    })

                }
                else{
                    console.log(uniqueName + " Must be configured in CRM ")
                }
            }
            ,function(error)
            {	console.log(error);
            });
          },function(error)
          {
              if (error.stack.indexOf('administrator has not consented') != -1)
                {
                        console.log('administrator must visit http://bit.ly/1Vpj6O2 to consent to use first');
                }
                else
                console.log(error)
          });

        });

 }

module.exports = CRMWebResourceManager;
<|endoftext|>


<commit_before>const styledoc = require('./build').default;
styledoc.init = require('./build/init').default;
styledoc.write = require('./build/write').default;

Object.assign(styledoc, require('./build/constant').default);
module.exports = styledoc;
<commit_msg>Remove init.js<commit_after>const styledoc = require('./build').default;
styledoc.write = require('./build/write').default;

Object.assign(styledoc, require('./build/constant').default);
module.exports = styledoc;
<|endoftext|>


<commit_before>'use strict';

const aws = require('aws-sdk');
const fs = require('fs-extra');
const path = require('path');
const crontab = require('crontab');
const _ = require('lodash');
const which = require('which');

function Mirri(iamClient) {
	this.iamClient = iamClient;
}
Mirri.prototype.Rotate = function(profile, force) {
	let p = Promise.resolve();
	if (force) {
		p = p.then(() => this.Cleanup(profile));
	}
	return p.then(() => this.iamClient.createAccessKey().promise())
	.then(results => {
		var currentAccessKey = aws.config.credentials.accessKeyId;
		var currentSecretKey = aws.config.credentials.secretAccessKey;
		let accessKeyId = results.AccessKey.AccessKeyId;
		let secretAccessKey = results.AccessKey.SecretAccessKey;

		// update the credentials file ~/.aws/credentials (linux) or %USERPROFILE%/.aws/credentials (windows)
		let credentialsFile = `${process.env.HOME || process.env.USERPROFILE}/.aws/credentials`;
		var accessKeyRE = new RegExp(_.escapeRegExp(currentAccessKey), 'g');
		var secretKeyRE = new RegExp(_.escapeRegExp(currentSecretKey), 'g');
		return new Promise((s, f) => { fs.readFile(credentialsFile, 'UTF-8', (error, data) => { error ? f(error) : s(data)}); })
		.then(fileInfo => fileInfo.replace(accessKeyRE, accessKeyId).replace(secretKeyRE, secretAccessKey))
		.then(fileInfo => {
			return new Promise((s, f) => { fs.outputFile(credentialsFile, fileInfo, (error) => error ? f(error) : s(null)); });
		})
		.then(() => {
			return this.iamClient.updateAccessKey({AccessKeyId: currentAccessKey, Status: 'Inactive'}).promise();
		});
	})
	.catch(failure => {
		if(failure.code && failure.code.match('InvalidClientTokenId')) {
			console.log('The access key saved in your credentials file is not valid. If you just rotated your access key, please wait 10 seconds before rerunning this command again.');
			return Promise.reject('InvalidAccessKey');
		}
		if(failure.code && failure.code.match('LimitExceeded')) {
			console.log('You already have the maximum number of keys for this user. Rotating requires a free slot, either run cleanup, or pass the force flag');
			return Promise.reject('LimitExceeded');
		}
		console.log(failure);
		return Promise.reject(failure);
	});
};

Mirri.prototype.Cleanup = function(profile) {
	// checks the current access key, deletes the other ones, and then rotates.
	return this.iamClient.listAccessKeys().promise()
	.then(data => {
		if(data.AccessKeyMetadata.length === 1) {
			return null;
		}
		let accessKeyId = data.AccessKeyMetadata.filter(key => key.AccessKeyId !== aws.config.credentials.accessKeyId)[0].AccessKeyId;
		return this.iamClient.deleteAccessKey({AccessKeyId: accessKeyId}).promise();
	});
};

Mirri.prototype.Schedule = function(profile, frequency, useFullPath) {
	let mirrorResolvedPathPromise = new Promise((s, f) => which('mirri', (error, resolvedPath) => error ? f(error) : s(resolvedPath)));
	let cronProviderPomise = new Promise((s, f) => crontab.load((error, cronProvider) => error ? f(error) : s(cronProvider)));
	return Promise.all([mirrorResolvedPathPromise, cronProviderPomise])
	.then(results => {
		let mirriPath = useFullPath ? results[0] : 'mirri';
		let cronProvider = results[1];
		let command = `${mirriPath} rotate --force ${profile}`;
		cronProvider.remove({command: command});
		cronProvider.create(command, frequency, 'Managed by Mirri.js');
		return new Promise((s, f) => cronProvider.save((error, result) => error ? f(error) : s(result)));
	});
};
module.exports = Mirri;<commit_msg>Handle node path as well.<commit_after>'use strict';

const aws = require('aws-sdk');
const fs = require('fs-extra');
const path = require('path');
const crontab = require('crontab');
const _ = require('lodash');
const which = require('which');

function Mirri(iamClient) {
	this.iamClient = iamClient;
}
Mirri.prototype.Rotate = function(profile, force) {
	let p = Promise.resolve();
	if (force) {
		p = p.then(() => this.Cleanup(profile));
	}
	return p.then(() => this.iamClient.createAccessKey().promise())
	.then(results => {
		var currentAccessKey = aws.config.credentials.accessKeyId;
		var currentSecretKey = aws.config.credentials.secretAccessKey;
		let accessKeyId = results.AccessKey.AccessKeyId;
		let secretAccessKey = results.AccessKey.SecretAccessKey;

		// update the credentials file ~/.aws/credentials (linux) or %USERPROFILE%/.aws/credentials (windows)
		let credentialsFile = `${process.env.HOME || process.env.USERPROFILE}/.aws/credentials`;
		var accessKeyRE = new RegExp(_.escapeRegExp(currentAccessKey), 'g');
		var secretKeyRE = new RegExp(_.escapeRegExp(currentSecretKey), 'g');
		return new Promise((s, f) => { fs.readFile(credentialsFile, 'UTF-8', (error, data) => { error ? f(error) : s(data)}); })
		.then(fileInfo => fileInfo.replace(accessKeyRE, accessKeyId).replace(secretKeyRE, secretAccessKey))
		.then(fileInfo => {
			return new Promise((s, f) => { fs.outputFile(credentialsFile, fileInfo, (error) => error ? f(error) : s(null)); });
		})
		.then(() => {
			return this.iamClient.updateAccessKey({AccessKeyId: currentAccessKey, Status: 'Inactive'}).promise();
		});
	})
	.catch(failure => {
		if(failure.code && failure.code.match('InvalidClientTokenId')) {
			console.log('The access key saved in your credentials file is not valid. If you just rotated your access key, please wait 10 seconds before rerunning this command again.');
			return Promise.reject('InvalidAccessKey');
		}
		if(failure.code && failure.code.match('LimitExceeded')) {
			console.log('You already have the maximum number of keys for this user. Rotating requires a free slot, either run cleanup, or pass the force flag');
			return Promise.reject('LimitExceeded');
		}
		console.log(failure);
		return Promise.reject(failure);
	});
};

Mirri.prototype.Cleanup = function(profile) {
	// checks the current access key, deletes the other ones, and then rotates.
	return this.iamClient.listAccessKeys().promise()
	.then(data => {
		if(data.AccessKeyMetadata.length === 1) {
			return null;
		}
		let accessKeyId = data.AccessKeyMetadata.filter(key => key.AccessKeyId !== aws.config.credentials.accessKeyId)[0].AccessKeyId;
		return this.iamClient.deleteAccessKey({AccessKeyId: accessKeyId}).promise();
	});
};

Mirri.prototype.Schedule = function(profile, frequency, useFullPath) {
	let mirrorResolvedPathPromise = new Promise((s, f) => which('mirri', (error, resolvedPath) => error ? f(error) : s(resolvedPath)));
	let cronProviderPomise = new Promise((s, f) => crontab.load((error, cronProvider) => error ? f(error) : s(cronProvider)));
	let nodeResolvedPathPromise = new Promise((s, f) => which('node', (error, resolvedPath) => error ? f(error) : s(resolvedPath)));
	return Promise.all([mirrorResolvedPathPromise, cronProviderPomise, nodeResolvedPathPromise])
	.then(results => {
		let mirriPath = useFullPath ? `${results[2]} ${results[0]}` : 'mirri';
		let cronProvider = results[1];
		let command = `${mirriPath} rotate --force ${profile}`;
		cronProvider.remove({command: command});
		cronProvider.create(command, frequency, 'Managed by Mirri.js');
		return new Promise((s, f) => cronProvider.save((error, result) => error ? f(error) : s(result)));
	});
};
module.exports = Mirri;<|endoftext|>