<commit_before>/**
 * This class lets you encode animated GIF files
 * Base class :  http://www.java2s.com/Code/Java/2D-Graphics-GUI/AnimatedGifEncoder.htm
 * @author Kevin Weiner (original Java version - kweiner@fmsware.com)
 * @author Thibault Imbert (AS3 version - bytearray.org)
 * @version 0.1 AS3 implementation
 */

GIFEncoder = function() {

	for (var i = 0, chr = {}; i < 256; i++)
		chr[i] = String.fromCharCode(i);

	function ByteArray() {
		this.bin = [];
	}

	ByteArray.prototype.getData = function() {
		for (var v = '', l = this.bin.length, i = 0; i < l; i++)
			v += chr[this.bin[i]];
		return v;
	};

	ByteArray.prototype.writeByte = function(val) {
		this.bin.push(val);
	};

	ByteArray.prototype.writeUTFBytes = function(string) {
		for (var l = string.length, i = 0; i < l; i++)
			this.writeByte(string.charCodeAt(i));
	};

	ByteArray.prototype.writeBytes = function(array, offset, length) {
		for (var l = length || array.length, i = offset || 0; i < l; i++)
			this.writeByte(array[i]);
	};

	var exports = {};
	var width; // image size
	var height;
	var transparent = null; // transparent color if given
	var transIndex; // transparent index in color table
	var repeat = -1; // no repeat
	var delay = 0; // frame delay (hundredths)
	var started = false; // ready to output frames
	var out;
	var image; // current frame
	var pixels; // BGR byte array from frame
	var indexedPixels; // converted frame indexed to palette
	var colorDepth; // number of bit planes
	var colorTab; // RGB palette
	var usedEntry = []; // active palette entries
	var palSize = 7; // color table size (bits-1)
	var dispose = -1; // disposal code (-1 = use default)
	var closeStream = false; // close stream when finished
	var firstFrame = true;
	var sizeSet = false; // if false, get size from first frame
	var sample = 10; // default sample interval for quantizer
	var comment = "Generated by jsgif (https://github.com/antimatter15/jsgif/)"; // default comment for generated gif

	/**
	 * Sets the delay time between each frame, or changes it for subsequent frames
	 * (applies to last frame added)
	 * int delay time in milliseconds
	 * @param ms
	 */

	var setDelay = exports.setDelay = function setDelay(ms) {
		delay = Math.round(ms / 10);
	};

	/**
	 * Sets the GIF frame disposal code for the last added frame and any
	 *
	 * subsequent frames. Default is 0 if no transparent color has been set,
	 * otherwise 2.
	 * @param code
	 * int disposal code.
	 */

	var setDispose = exports.setDispose = function setDispose(code) {
		if (code >= 0) dispose = code;
	};

	/**
	 * Sets the number of times the set of GIF frames should be played. Default is
	 * 1; 0 means play indefinitely. Must be invoked before the first image is
	 * added.
	 *
	 * @param iter
	 * int number of iterations.
	 * @return
	 */

	var setRepeat = exports.setRepeat = function setRepeat(iter) {
		if (iter >= 0) repeat = iter;
	};

	/**
	 * Sets the transparent color for the last added frame and any subsequent
	 * frames. Since all colors are subject to modification in the quantization
	 * process, the color in the final palette for each frame closest to the given
	 * color becomes the transparent color for that frame. May be set to null to
	 * indicate no transparent color.
	 * @param
	 * Color to be treated as transparent on display.
	 */

	var setTransparent = exports.setTransparent = function setTransparent(c) {
		transparent = c;
	};

	/**
	 * Sets the comment for the block comment
	 * @param
	 * string to be insterted as comment
	 */

	var setComment = exports.setComment = function setComment(c) {
		comment = c;
	};

	/**
	 * The addFrame method takes an incoming BitmapData object to create each frames
	 * @param
	 * BitmapData object to be treated as a GIF's frame
	 */

	var addFrame = exports.addFrame = function addFrame(im, is_imageData) {

		if ((im === null) || !started || out === null) {
			throw new Error("Please call start method before calling addFrame");
			return false;
		}

		var ok = true;

		try {
			if (!is_imageData) {
				image = im.getImageData(0, 0, im.canvas.width, im.canvas.height).data;
				if (!sizeSet) setSize(im.canvas.width, im.canvas.height);
			} else {
				image = im;
			}
			getImagePixels(); // convert to correct format if necessary
			analyzePixels(); // build color table & map pixels

			if (firstFrame) {
				writeLSD(); // logical screen descriptior
				writePalette(); // global color table
				if (repeat >= 0) {
					// use NS app extension to indicate reps
					writeNetscapeExt();
				}
			}

			writeGraphicCtrlExt(); // write graphic control extension
			if (comment !== '') {
				writeCommentExt(); // write comment extension
			}
			writeImageDesc(); // image descriptor
			if (!firstFrame) writePalette(); // local color table
			writePixels(); // encode and write pixel data
			firstFrame = false;
		} catch (e) {
			ok = false;
		}

		return ok;
	};

	/**
	 * Adds final trailer to the GIF stream, if you don't call the finish method
	 * the GIF stream will not be valid.
	 */

	var finish = exports.finish = function finish() {

		if (!started) return false;

		var ok = true;
		started = false;

		try {
			out.writeByte(0x3b); // gif trailer
		} catch (e) {
			ok = false;
		}

		return ok;
	};

	/**
	 * Resets some members so that a new stream can be started.
	 * This method is actually called by the start method
	 */

	var reset = function reset() {

		// reset for subsequent use
		transIndex = 0;
		image = null;
		pixels = null;
		indexedPixels = null;
		colorTab = null;
		closeStream = false;
		firstFrame = true;
	};

	/**
	 * * Sets frame rate in frames per second. Equivalent to
	 * setDelay(1000/fps).
	 * @param fps
	 * float frame rate (frames per second)
	 */

	var setFrameRate = exports.setFrameRate = function setFrameRate(fps) {
		if (fps != 0xf) delay = Math.round(100 / fps);
	};

	/**
	 * Sets quality of color quantization (conversion of images to the maximum 256
	 * colors allowed by the GIF specification). Lower values (minimum = 1)
	 * produce better colors, but slow processing significantly. 10 is the
	 * default, and produces good color mapping at reasonable speeds. Values
	 * greater than 20 do not yield significant improvements in speed.
	 * @param quality
	 * int greater than 0.
	 * @return
	 */

	var setQuality = exports.setQuality = function setQuality(quality) {
		if (quality < 1) quality = 1;
		sample = quality;
	};

	/**
	 * Sets the GIF frame size. The default size is the size of the first frame
	 * added if this method is not invoked.
	 * @param w
	 * int frame width.
	 * @param h
	 * int frame width.
	 */

	var setSize = exports.setSize = function setSize(w, h) {

		if (started && !firstFrame) return;
		width = w;
		height = h;
		if (width < 1) width = 320;
		if (height < 1) height = 240;
		sizeSet = true;
	};

	/**
	 * Initiates GIF file creation on the given stream.
	 * @param os
	 * OutputStream on which GIF images are written.
	 * @return false if initial write failed.
	 *
	 */

	var start = exports.start = function start() {

		reset();
		var ok = true;
		closeStream = false;
		out = new ByteArray();
		try {
			out.writeUTFBytes("GIF89a"); // header
		} catch (e) {
			ok = false;
		}

		return started = ok;
	};

	var cont = exports.cont = function cont() {

		reset();
		var ok = true;
		closeStream = false;
		out = new ByteArray();

		return started = ok;
	};

	/**
	 * Analyzes image colors and creates color map.
	 */

	var analyzePixels = function analyzePixels() {

		var len = pixels.length;
		var nPix = len / 3;
		indexedPixels = [];
		var nq = new NeuQuant(pixels, len, sample);

		// initialize quantizer
		colorTab = nq.process(); // create reduced palette

		// map image pixels to new palette
		var k = 0;
		for (var j = 0; j < nPix; j++) {
			var index = nq.map(pixels[k++] & 0xff, pixels[k++] & 0xff, pixels[k++] & 0xff);
			usedEntry[index] = true;
			indexedPixels[j] = index;
		}

		pixels = null;
		colorDepth = 8;
		palSize = 7;

		// get closest match to transparent color if specified
		if (transparent !== null) {
			transIndex = findClosest(transparent);
		}
	};

	/**
	 * Returns index of palette color closest to c
	 *
	 */

	var findClosest = function findClosest(c) {

		if (colorTab === null) return -1;
		var r = (c & 0xFF0000) >> 16;
		var g = (c & 0x00FF00) >> 8;
		var b = (c & 0x0000FF);
		var minpos = 0;
		var dmin = 256 * 256 * 256;
		var len = colorTab.length;

		for (var i = 0; i < len;) {
			var dr = r - (colorTab[i++] & 0xff);
			var dg = g - (colorTab[i++] & 0xff);
			var db = b - (colorTab[i] & 0xff);
			var d = dr * dr + dg * dg + db * db;
			var index = i / 3;
			if (usedEntry[index] && (d < dmin)) {
				dmin = d;
				minpos = index;
			}
			i++;
		}
		return minpos;
	};

	/**
	 * Extracts image pixels into byte array "pixels
	 */

	var getImagePixels = function getImagePixels() {
		var w = width;
		var h = height;
		pixels = [];
		var data = image;
		var count = 0;

		for (var i = 0; i < h; i++) {

			for (var j = 0; j < w; j++) {

				var b = (i * w * 4) + j * 4;
				pixels[count++] = data[b];
				pixels[count++] = data[b + 1];
				pixels[count++] = data[b + 2];

			}

		}
	};

	/**
	 * Writes Graphic Control Extension
	 */

	var writeGraphicCtrlExt = function writeGraphicCtrlExt() {
		out.writeByte(0x21); // extension introducer
		out.writeByte(0xf9); // GCE label
		out.writeByte(4); // data block size
		var transp;
		var disp;
		if (transparent === null) {
			transp = 0;
			disp = 0; // dispose = no action
		} else {
			transp = 1;
			disp = 2; // force clear if using transparent color
		}
		if (dispose >= 0) {
			disp = dispose & 7; // user override
		}
		disp <<= 2;
		// packed fields
		out.writeByte(0 | // 1:3 reserved
			disp | // 4:6 disposal
			0 | // 7 user input - 0 = none
			transp); // 8 transparency flag

		WriteShort(delay); // delay x 1/100 sec
		out.writeByte(transIndex); // transparent color index
		out.writeByte(0); // block terminator
	};

	/**
	 * Writes Comment Extention
	 */

	var writeCommentExt = function writeCommentExt() {
		out.writeByte(0x21); // extension introducer
		out.writeByte(0xfe); // comment label
		out.writeByte(comment.length); // Block Size (s)
		out.writeUTFBytes(comment);
		out.writeByte(0); // block terminator
	};

	/**
	 * Writes Image Descriptor
	 */

	var writeImageDesc = function writeImageDesc() {

		out.writeByte(0x2c); // image separator
		WriteShort(0); // image position x,y = 0,0
		WriteShort(0);
		WriteShort(width); // image size
		WriteShort(height);

		// packed fields
		if (firstFrame) {
			// no LCT - GCT is used for first (or only) frame
			out.writeByte(0);
		} else {
			// specify normal LCT
			out.writeByte(0x80 | // 1 local color table 1=yes
				0 | // 2 interlace - 0=no
				0 | // 3 sorted - 0=no
				0 | // 4-5 reserved
				palSize); // 6-8 size of color table
		}
	};

	/**
	 * Writes Logical Screen Descriptor
	 */

	var writeLSD = function writeLSD() {

		// logical screen size
		WriteShort(width);
		WriteShort(height);
		// packed fields
		out.writeByte((0x80 | // 1 : global color table flag = 1 (gct used)
			0x70 | // 2-4 : color resolution = 7
			0x00 | // 5 : gct sort flag = 0
			palSize)); // 6-8 : gct size

		out.writeByte(0); // background color index
		out.writeByte(0); // pixel aspect ratio - assume 1:1
	};

	/**
	 * Writes Netscape application extension to define repeat count.
	 */

	var writeNetscapeExt = function writeNetscapeExt() {
		out.writeByte(0x21); // extension introducer
		out.writeByte(0xff); // app extension label
		out.writeByte(11); // block size
		out.writeUTFBytes("NETSCAPE" + "2.0"); // app id + auth code
		out.writeByte(3); // sub-block size
		out.writeByte(1); // loop sub-block id
		WriteShort(repeat); // loop count (extra iterations, 0=repeat forever)
		out.writeByte(0); // block terminator
	};

	/**
	 * Writes color table
	 */

	var writePalette = function writePalette() {
		out.writeBytes(colorTab);
		var n = (3 * 256) - colorTab.length;
		for (var i = 0; i < n; i++) out.writeByte(0);
	};

	var WriteShort = function WriteShort(pValue) {
		out.writeByte(pValue & 0xFF);
		out.writeByte((pValue >> 8) & 0xFF);
	};

	/**
	 * Encodes and writes pixel data
	 */

	var writePixels = function writePixels() {
		var myencoder = new LZWEncoder(width, height, indexedPixels, colorDepth);
		myencoder.encode(out);
	};

	/**
	 * retrieves the GIF stream
	 */

	var stream = exports.stream = function stream() {
		return out;
	};

	var setProperties = exports.setProperties = function setProperties(has_start, is_first) {
		started = has_start;
		firstFrame = is_first;
	};

	return exports;

};<commit_msg>Improve minor comment inconsistencies.<commit_after>/**
 * This class lets you encode animated GIF files
 * Base class :  http://www.java2s.com/Code/Java/2D-Graphics-GUI/AnimatedGifEncoder.htm
 * @author Kevin Weiner (original Java version - kweiner@fmsware.com)
 * @author Thibault Imbert (AS3 version - bytearray.org)
 * @version 0.1 AS3 implementation
 */

GIFEncoder = function() {

	for (var i = 0, chr = {}; i < 256; i++)
		chr[i] = String.fromCharCode(i);

	function ByteArray() {
		this.bin = [];
	}

	ByteArray.prototype.getData = function() {
		for (var v = '', l = this.bin.length, i = 0; i < l; i++)
			v += chr[this.bin[i]];
		return v;
	};

	ByteArray.prototype.writeByte = function(val) {
		this.bin.push(val);
	};

	ByteArray.prototype.writeUTFBytes = function(string) {
		for (var l = string.length, i = 0; i < l; i++)
			this.writeByte(string.charCodeAt(i));
	};

	ByteArray.prototype.writeBytes = function(array, offset, length) {
		for (var l = length || array.length, i = offset || 0; i < l; i++)
			this.writeByte(array[i]);
	};

	var exports = {};
	var width; // image size
	var height;
	var transparent = null; // transparent color if given
	var transIndex; // transparent index in color table
	var repeat = -1; // no repeat
	var delay = 0; // frame delay (hundredths)
	var started = false; // ready to output frames
	var out;
	var image; // current frame
	var pixels; // BGR byte array from frame
	var indexedPixels; // converted frame indexed to palette
	var colorDepth; // number of bit planes
	var colorTab; // RGB palette
	var usedEntry = []; // active palette entries
	var palSize = 7; // color table size (bits-1)
	var dispose = -1; // disposal code (-1 = use default)
	var closeStream = false; // close stream when finished
	var firstFrame = true;
	var sizeSet = false; // if false, get size from first frame
	var sample = 10; // default sample interval for quantizer
	var comment = "Generated by jsgif (https://github.com/antimatter15/jsgif/)"; // default comment for generated gif

	/**
	 * Sets the delay time between each frame, or changes it for subsequent frames
	 * (applies to last frame added)
	 * int delay time in milliseconds
	 * @param ms
	 */

	var setDelay = exports.setDelay = function setDelay(ms) {
		delay = Math.round(ms / 10);
	};

	/**
	 * Sets the GIF frame disposal code for the last added frame and any
	 *
	 * subsequent frames. Default is 0 if no transparent color has been set,
	 * otherwise 2.
	 * @param code
	 * int disposal code.
	 */

	var setDispose = exports.setDispose = function setDispose(code) {
		if (code >= 0) dispose = code;
	};

	/**
	 * Sets the number of times the set of GIF frames should be played. Default is
	 * 1; 0 means play indefinitely. Must be invoked before the first image is
	 * added.
	 *
	 * @param iter
	 * int number of iterations.
	 * @return
	 */

	var setRepeat = exports.setRepeat = function setRepeat(iter) {
		if (iter >= 0) repeat = iter;
	};

	/**
	 * Sets the transparent color for the last added frame and any subsequent
	 * frames. Since all colors are subject to modification in the quantization
	 * process, the color in the final palette for each frame closest to the given
	 * color becomes the transparent color for that frame. May be set to null to
	 * indicate no transparent color.
	 * @param
	 * Color to be treated as transparent on display.
	 */

	var setTransparent = exports.setTransparent = function setTransparent(c) {
		transparent = c;
	};

	/**
	 * Sets the comment for the block comment
	 * @param
	 * string to be insterted as comment
	 */

	var setComment = exports.setComment = function setComment(c) {
		comment = c;
	};

	/**
	 * The addFrame method takes an incoming BitmapData object to create each frames
	 * @param
	 * BitmapData object to be treated as a GIF's frame
	 */

	var addFrame = exports.addFrame = function addFrame(im, is_imageData) {

		if ((im === null) || !started || out === null) {
			throw new Error("Please call start method before calling addFrame");
			return false;
		}

		var ok = true;

		try {
			if (!is_imageData) {
				image = im.getImageData(0, 0, im.canvas.width, im.canvas.height).data;
				if (!sizeSet) setSize(im.canvas.width, im.canvas.height);
			} else {
				image = im;
			}
			getImagePixels(); // convert to correct format if necessary
			analyzePixels(); // build color table & map pixels

			if (firstFrame) {
				writeLSD(); // logical screen descriptior
				writePalette(); // global color table
				if (repeat >= 0) {
					// use NS app extension to indicate reps
					writeNetscapeExt();
				}
			}

			writeGraphicCtrlExt(); // write graphic control extension
			if (comment !== '') {
				writeCommentExt(); // write comment extension
			}
			writeImageDesc(); // image descriptor
			if (!firstFrame) writePalette(); // local color table
			writePixels(); // encode and write pixel data
			firstFrame = false;
		} catch (e) {
			ok = false;
		}

		return ok;
	};

	/**
	 * Adds final trailer to the GIF stream, if you don't call the finish method
	 * the GIF stream will not be valid.
	 */

	var finish = exports.finish = function finish() {

		if (!started) return false;

		var ok = true;
		started = false;

		try {
			out.writeByte(0x3b); // gif trailer
		} catch (e) {
			ok = false;
		}

		return ok;
	};

	/**
	 * Resets some members so that a new stream can be started.
	 * This method is actually called by the start method
	 */

	var reset = function reset() {

		// reset for subsequent use
		transIndex = 0;
		image = null;
		pixels = null;
		indexedPixels = null;
		colorTab = null;
		closeStream = false;
		firstFrame = true;
	};

	/**
	 * * Sets frame rate in frames per second. Equivalent to
	 * setDelay(1000/fps).
	 * @param fps
	 * float frame rate (frames per second)
	 */

	var setFrameRate = exports.setFrameRate = function setFrameRate(fps) {
		if (fps != 0xf) delay = Math.round(100 / fps);
	};

	/**
	 * Sets quality of color quantization (conversion of images to the maximum 256
	 * colors allowed by the GIF specification). Lower values (minimum = 1)
	 * produce better colors, but slow processing significantly. 10 is the
	 * default, and produces good color mapping at reasonable speeds. Values
	 * greater than 20 do not yield significant improvements in speed.
	 * @param quality
	 * int greater than 0.
	 * @return
	 */

	var setQuality = exports.setQuality = function setQuality(quality) {
		if (quality < 1) quality = 1;
		sample = quality;
	};

	/**
	 * Sets the GIF frame size. The default size is the size of the first frame
	 * added if this method is not invoked.
	 * @param w
	 * int frame width.
	 * @param h
	 * int frame width.
	 */

	var setSize = exports.setSize = function setSize(w, h) {

		if (started && !firstFrame) return;
		width = w;
		height = h;
		if (width < 1) width = 320;
		if (height < 1) height = 240;
		sizeSet = true;
	};

	/**
	 * Initiates GIF file creation on the given stream.
	 * @param os
	 * OutputStream on which GIF images are written.
	 * @return false if initial write failed.
	 */

	var start = exports.start = function start() {

		reset();
		var ok = true;
		closeStream = false;
		out = new ByteArray();
		try {
			out.writeUTFBytes("GIF89a"); // header
		} catch (e) {
			ok = false;
		}

		return started = ok;
	};

	var cont = exports.cont = function cont() {

		reset();
		var ok = true;
		closeStream = false;
		out = new ByteArray();

		return started = ok;
	};

	/**
	 * Analyzes image colors and creates color map.
	 */

	var analyzePixels = function analyzePixels() {

		var len = pixels.length;
		var nPix = len / 3;
		indexedPixels = [];
		var nq = new NeuQuant(pixels, len, sample);

		// initialize quantizer
		colorTab = nq.process(); // create reduced palette

		// map image pixels to new palette
		var k = 0;
		for (var j = 0; j < nPix; j++) {
			var index = nq.map(pixels[k++] & 0xff, pixels[k++] & 0xff, pixels[k++] & 0xff);
			usedEntry[index] = true;
			indexedPixels[j] = index;
		}

		pixels = null;
		colorDepth = 8;
		palSize = 7;

		// get closest match to transparent color if specified
		if (transparent !== null) {
			transIndex = findClosest(transparent);
		}
	};

	/**
	 * Returns index of palette color closest to c
	 */

	var findClosest = function findClosest(c) {

		if (colorTab === null) return -1;
		var r = (c & 0xFF0000) >> 16;
		var g = (c & 0x00FF00) >> 8;
		var b = (c & 0x0000FF);
		var minpos = 0;
		var dmin = 256 * 256 * 256;
		var len = colorTab.length;

		for (var i = 0; i < len;) {
			var dr = r - (colorTab[i++] & 0xff);
			var dg = g - (colorTab[i++] & 0xff);
			var db = b - (colorTab[i] & 0xff);
			var d = dr * dr + dg * dg + db * db;
			var index = i / 3;
			if (usedEntry[index] && (d < dmin)) {
				dmin = d;
				minpos = index;
			}
			i++;
		}
		return minpos;
	};

	/**
	 * Extracts image pixels into byte array "pixels
	 */

	var getImagePixels = function getImagePixels() {
		var w = width;
		var h = height;
		pixels = [];
		var data = image;
		var count = 0;

		for (var i = 0; i < h; i++) {

			for (var j = 0; j < w; j++) {

				var b = (i * w * 4) + j * 4;
				pixels[count++] = data[b];
				pixels[count++] = data[b + 1];
				pixels[count++] = data[b + 2];

			}

		}
	};

	/**
	 * Writes Graphic Control Extension
	 */

	var writeGraphicCtrlExt = function writeGraphicCtrlExt() {
		out.writeByte(0x21); // extension introducer
		out.writeByte(0xf9); // GCE label
		out.writeByte(4); // data block size
		var transp;
		var disp;
		if (transparent === null) {
			transp = 0;
			disp = 0; // dispose = no action
		} else {
			transp = 1;
			disp = 2; // force clear if using transparent color
		}
		if (dispose >= 0) {
			disp = dispose & 7; // user override
		}
		disp <<= 2;
		// packed fields
		out.writeByte(0 | // 1:3 reserved
			disp | // 4:6 disposal
			0 | // 7 user input - 0 = none
			transp); // 8 transparency flag

		WriteShort(delay); // delay x 1/100 sec
		out.writeByte(transIndex); // transparent color index
		out.writeByte(0); // block terminator
	};

	/**
	 * Writes Comment Extention
	 */

	var writeCommentExt = function writeCommentExt() {
		out.writeByte(0x21); // extension introducer
		out.writeByte(0xfe); // comment label
		out.writeByte(comment.length); // Block Size (s)
		out.writeUTFBytes(comment);
		out.writeByte(0); // block terminator
	};

	/**
	 * Writes Image Descriptor
	 */

	var writeImageDesc = function writeImageDesc() {

		out.writeByte(0x2c); // image separator
		WriteShort(0); // image position x,y = 0,0
		WriteShort(0);
		WriteShort(width); // image size
		WriteShort(height);

		// packed fields
		if (firstFrame) {
			// no LCT - GCT is used for first (or only) frame
			out.writeByte(0);
		} else {
			// specify normal LCT
			out.writeByte(0x80 | // 1 local color table 1=yes
				0 | // 2 interlace - 0=no
				0 | // 3 sorted - 0=no
				0 | // 4-5 reserved
				palSize); // 6-8 size of color table
		}
	};

	/**
	 * Writes Logical Screen Descriptor
	 */

	var writeLSD = function writeLSD() {

		// logical screen size
		WriteShort(width);
		WriteShort(height);
		// packed fields
		out.writeByte((0x80 | // 1 : global color table flag = 1 (gct used)
			0x70 | // 2-4 : color resolution = 7
			0x00 | // 5 : gct sort flag = 0
			palSize)); // 6-8 : gct size

		out.writeByte(0); // background color index
		out.writeByte(0); // pixel aspect ratio - assume 1:1
	};

	/**
	 * Writes Netscape application extension to define repeat count.
	 */

	var writeNetscapeExt = function writeNetscapeExt() {
		out.writeByte(0x21); // extension introducer
		out.writeByte(0xff); // app extension label
		out.writeByte(11); // block size
		out.writeUTFBytes("NETSCAPE" + "2.0"); // app id + auth code
		out.writeByte(3); // sub-block size
		out.writeByte(1); // loop sub-block id
		WriteShort(repeat); // loop count (extra iterations, 0=repeat forever)
		out.writeByte(0); // block terminator
	};

	/**
	 * Writes color table
	 */

	var writePalette = function writePalette() {
		out.writeBytes(colorTab);
		var n = (3 * 256) - colorTab.length;
		for (var i = 0; i < n; i++) out.writeByte(0);
	};

	var WriteShort = function WriteShort(pValue) {
		out.writeByte(pValue & 0xFF);
		out.writeByte((pValue >> 8) & 0xFF);
	};

	/**
	 * Encodes and writes pixel data
	 */

	var writePixels = function writePixels() {
		var myencoder = new LZWEncoder(width, height, indexedPixels, colorDepth);
		myencoder.encode(out);
	};

	/**
	 * Retrieves the GIF stream
	 */

	var stream = exports.stream = function stream() {
		return out;
	};

	var setProperties = exports.setProperties = function setProperties(has_start, is_first) {
		started = has_start;
		firstFrame = is_first;
	};

	return exports;

};<|endoftext|>


<commit_before>var wanLink="em4.703";
var lanLink="p2p1";
var child_process=require("child_process");
var StringDecoder = require('string_decoder').StringDecoder;
var decoder = new StringDecoder('utf8');
module.exports = function(RED) {
    var child_process=require("child_process");
    var StringDecoder = require('string_decoder').StringDecoder;
    var decoder = new StringDecoder('utf8');
    function createInterface(container,link,mac,eth){
        var cmd="pipework "+link+" -i eth"+eth+" "+container+" udhcpc  "+mac;
        var outcome=child_process.execSync(cmd);
        var strOutcome=decoder.write(outcome);
        console.log(cmd+":"+strOutcome);
    }
    function createInterfaceStatic(container,link,mac,eth){
        var cmd="pipework "+link+" -i eth"+eth+" "+container+" 192.168.1.254/24  "+mac;
        var outcome=child_process.execSync(cmd);
        var strOutcome=decoder.write(outcome);
        console.log(cmd+":"+strOutcome);
    }
    function InterfacesNode(config) {
        RED.nodes.createNode(this,config);
        var node = this;
        this.on('input', function(msg) {
            var container=msg.payload.Service+"_"+msg.payload.S_Tag+"_"+msg.payload.C_Tag;
            var i;
            var interfaces=msg.payload.Interfaces;
            if(interfaces.indexOf("wan")>=0){
               createInterface(container,wanLink,"",interfaces.indexOf("wan"));
               console.log("built wan interface");
            }

            for(i=0;i<interfaces.length;i++){

                switch(interfaces[i]){
                   case "lan":
                      console.log("lan interface");
                      var link=lanLink+"."+msg.payload.S_Tag+"."+msg.payload.C_Tag;
                      if(msg.payload.Service.toLowerCase()=="vsg")
                         createInterface(container,link,"76:eb:27:f6:47:f1",i);
                      else
                         createInterface(container,link,"",i);
                      break;

                   case "wan":
                      //if multiple interfaces wan should always go first
                      console.log("already constructed wan interface");
                      break;

                   case "vxlan":
                      console.log("vxlan interface");
                      break;

                   default:
                      var error="unknown interface type :"+interfaces[i];
                      console.log(error);
                      msg.payload.error=error;
                      break;
                 }
            }

            node.send(msg);
        });
    }
    RED.nodes.registerType("interfaces",InterfacesNode);
}

<commit_msg>convert to async<commit_after>var wanLink="";
var lanLink="";
var child_process=require("child_process");
var StringDecoder = require('string_decoder').StringDecoder;
var decoder = new StringDecoder('utf8');
module.exports = function(RED) {
    var child_process=require("child_process");
    var StringDecoder = require('string_decoder').StringDecoder;
    var decoder = new StringDecoder('utf8');

    function createInterface(container,link,mac,eth){
        var cmd="pipework "+link+" -i eth"+eth+" "+container+" udhcpc  "+mac;
        child_process.exec(cmd,function(error,stdout,stderr){
              if(error!=null){
                 console.log(cmd+"  "+stderr);
              }else{
                 console.log(cmd+" "+stdout);
              }
        });
    }
    function createInterfaceStatic(container,link,mac,eth){
        var cmd="pipework "+link+" -i eth"+eth+" "+container+" 192.168.1.254/24  "+mac;
        child_process.exec(cmd,function(error,stdout,stderr){
              if(error!=null){
                 console.log(cmd+"  "+stderr);
              }else{
                 console.log(cmd+" "+stdout);
              }
        });
    }
    function InterfacesNode(config) {
        this.context = {global:RED.settings.functionGlobalContext || {}};
        RED.nodes.createNode(this,config);
        var node = this;
        this.on('input', function(msg) {
            var hostInterfaces=this.context.global.interfaces;

            var container=msg.payload.Service+"_"+msg.payload.S_Tag+"_"+msg.payload.C_Tag;
            var hostInterfaces=this.context.global.interfaces;
            var interfaces=msg.payload.Interfaces;
            if(interfaces.indexOf("wan")>=0){
               createInterface(container,hostInterfaces["wan"],"",interfaces.indexOf("wan"));
               console.log("built wan interface");
            }

            for(i=0;i<interfaces.length;i++){

                switch(interfaces[i]){
                   case "lan":
                      console.log("lan interface");
                      var link=hostInterfaces["lan"]+"."+msg.payload.S_Tag+"."+msg.payload.C_Tag;
                      if(msg.payload.Service.toLowerCase()=="vsg")
                         createInterfaceStatic(container,link,"76:eb:27:f6:47:f1",i);
                      else
                         createInterface(container,link,"",i);
                      break;

                   case "wan":
                      //if multiple interfaces wan should always go first
                      console.log("already constructed wan interface");
                      break;

                   case "vxlan":
                      console.log("vxlan interface");
                      break;

                   default:
                      var error="unknown interface type :"+interfaces[i];
                      console.log(error);
                      msg.payload.error=error;
                      break;
                 }
            }

            node.send(msg);
        });
    }
    RED.nodes.registerType("interfaces",InterfacesNode);
}

<|endoftext|>


<commit_before>/*
        MIT License http://www.opensource.org/licenses/mit-license.php
        Author & (c) 2014 Sebastian Kreissl
	https://github.com/circy
*/

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(["jquery"], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS
        module.exports = factory(require("jquery"));
    } else {
        // Browser globals
        root.UILink = factory(root.jQuery);
    }
}(this, function ($) {
	function AddUILink(toParseObject, area) {
		var elements = area.find("[data-uilinkname]");
		elements.each(function(idx) {
			var item = elements.eq(idx);
			var name = item.data("uilinkname");
			var upperCaseName = name.substr(0, 1).toUpperCase() + name.substr(1);
			var event = item.data("uilinkevent");

			toParseObject["_" + name] = item;

			if(event) {
				var functionName = item.data("uilinkeventfunc");
				if(functionName) {
					bindEvent(toParseObject, event, functionName);
				} else {
					throw new Error("No data-uilinkeventfunc attribute found");
				}
			} else {
				for(var propertyName in toParseObject) {
					if(/^[oO]n/.test(propertyName) && propertyName.substr(-name.length) === upperCaseName) {
						event = propertyName.substr(2, propertyName.length - name.length - 2).toLowerCase();
						bindEvent(toParseObject, event, propertyName);
					}
				}
			}
			function bindEvent(toParseObject, eventName, propertyName) {
				item.on(eventName, function(event) {
					toParseObject[propertyName](item, event);
				});
			}
		});
	}

	if($ && $.fn) $.fn.uiLink = function(toParseObject) {
		AddUILink(toParseObject, this);
	};

	return function(toParseObject, area) {
		var item = {};
		area.on("UILinkUpdate", item.Update = function() {
			AddUILink(toParseObject, area);
		});
		toParseObject._UILink = item;
		return item;
	}
}));
<commit_msg>Update UILink.js<commit_after>/*
        MIT License http://www.opensource.org/licenses/mit-license.php
        Author & (c) 2014 Sebastian Kreissl
	https://github.com/circy
*/
(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(["jquery"], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS
        module.exports = factory(require("jquery"));
    } else {
        // Browser globals
        root.UILink = factory(root.jQuery);
    }
}(this, function ($) {
	function AddUILink(toParseObject, area) {
		var elements = area.find("[data-uilinkname]");
		elements.each(function(idx) {
			var item = elements.eq(idx);
			var name = item.data("uilinkname");
			var upperCaseName = name.substr(0, 1).toUpperCase() + name.substr(1);
			var event = item.data("uilinkevent");

			toParseObject["_" + name] = item;

			if(event) {
				var functionName = item.data("uilinkeventfunc");
				if(functionName) {
					bindEvent(toParseObject, event, functionName);
				} else {
					throw new Error("No data-uilinkeventfunc attribute found");
				}
			} else {
				for(var propertyName in toParseObject) {
					if(/^[oO]n/.test(propertyName) && propertyName.substr(-name.length) === upperCaseName) {
						event = propertyName.substr(2, propertyName.length - name.length - 2).toLowerCase();
						bindEvent(toParseObject, event, propertyName);
					}
				}
			}
			function bindEvent(toParseObject, eventName, propertyName) {
				item.on(eventName, function(event) {
					toParseObject[propertyName](item, event);
				});
			}
		});
	}

	if($ && $.fn) $.fn.uiLink = function(toParseObject) {
		AddUILink(toParseObject, this);
	};

	return function(toParseObject, area) {
		var item = {};
		area.on("UILinkUpdate", item.Update = function() {
			AddUILink(toParseObject, area);
		});
		toParseObject._UILink = item;
		return item;
	}
}));
<|endoftext|>


<commit_before>'use strict';

const OPERATOR_REGEX = /^(-|\+|\*{1,2}|\\|\/|#|&|!|_|\?|'*<=*|'*>=*|'*\[|'*\]{1,2}|\(|\)|'*=|'|\${1,2}|\^|,|:|@)/;
const STRING_REGEX = /^("+)/;
const CHARACTER_REGEX = /^([A-Za-z0-9\.]+)/;

class LineTokens {
    constructor(line, index) {
        this.line = line;
        this.index = index;
        this.tokenize();
    }
    tokenize() {
        // First, pull any existing, valid comment out of the line
        this.findComments();

        // Next with the comment out of the way, determine the current indentation of this line
        this.findIndentation();

        // Split the remainder of the line by whitespace to determine the macro-token groups
        this.createTokenGroups();
    }
    findComments() {
        let index = 0;
        let isString = false;
        while (index < this.line.length) {
            if (this.line[index] === '"') {
                isString = !isString;
            } else if (this.line[index] === ';' && !isString) {
                this.comment = this.line.slice(index + 1).trim();
                this.line = this.line.slice(0, index).trim();
                break;
            }
            index += 1;
        }
    }
    findIndentation() {
        this.indentation = 0;
        let index = 0;
        while ((index < this.line.length) && (!/\w/.test(this.line[index]))) {
            if ((this.line[index] === ' ') && (this.indentation < 1)) {
                this.indentation = 1;
            } else if ((this.line[index] === '.') && (this.indentation >= 1)) {
                this.indentation += 1;
            }

            index += 1;
        }
        this.line = ((index < this.line.length) ? this.line.slice(index) : '');
    }
    createChunks(line) {
        // We want to split a line of text by spaces, but we also want to ignore the split if
        // those spaces are caught in-between quotation marks. So we implement our own special
        // split function that handles quote-captured spaces. The strategy here is to iterate
        // one character at a time and build substrings as we go, noting the "is string" state
        // as we iterate
        let chunks = [];
        let index = 0;
        let quoteCount = 0;
        let currChunk = '';
        while (index < line.length) {
            // If the current character is a quote mark, keep track of the quote and append the
            // character
            if (line[index] === '"') {
                currChunk += line[index];
                quoteCount += 1;
            }

            // If the current character is a space, then check if we're "in quotes" and capturing
            // spaces. If so, just append, otherwise, add the current substring to the list of
            // chunks, if the string isn't empty.
            else if (line[index] === ' ') {
                if (quoteCount % 2 !== 0) {
                    currChunk += line[index];
                }
                else if (currChunk !== '') {
                    chunks.push(currChunk);
                    currChunk = '';
                }
            }
            else {
                currChunk += line[index];
            }
            index += 1;
        }
        if (currChunk !== '') {
            chunks.push(currChunk);
        }
        return chunks;
    }
    createTokenGroups() {
        this.chunks = this.createChunks(this.line);
        // console.log(this.chunks);
        this.tokenGroups = this.chunks.map((chunk) => {
            const tokens = [];
            let currChunk = chunk;

            while (currChunk.length > 0) {
                // Perform a regex match search for valid MUMPS operators.
                const operatorMatch = currChunk.match(OPERATOR_REGEX);
                if (operatorMatch) {
                    const value = operatorMatch[0];
                    tokens.push({
                        value,
                        type: 'OPERATOR',
                    });

                    currChunk = currChunk.slice(value.length);
                }

                // Perform a regex match search for alphanumeric characters at the start of the
                // current string. If we found something, we save the value as either a literal
                // or a number, depending on an 'isNaN' check.
                const charMatch = currChunk.match(CHARACTER_REGEX);
                if (charMatch) {
                    const value = charMatch[0];
                    const type = isNaN(value) ? 'LITERAL' : 'NUMERIC';
                    tokens.push({
                        value,
                        type,
                    });

                    currChunk = currChunk.slice(value.length);
                }

                // Perform a regex match search for MUMPS string literals. The rub here is that
                // literal quotation marks can be represented in a MUMPS string literal by 2
                // consecutive double-quote marks. To mitigate this feature, once we find a group
                // of double-quotes, we capture until we find a matching set (that is, the quote
                // count become even). Then whatever we've captured until then is a string.
                const stringMatch = currChunk.match(STRING_REGEX);
                if (stringMatch) {
                    let value = stringMatch[0];
                    let quoteCount = value.length;
                    currChunk = currChunk.slice(value.length);

                    while (quoteCount % 2 !== 0) {
                        if (currChunk.length === 0) {
                            throw new Error(`Mismatched string error, line ${this.index}: ${chunk}`);
                        }

                        const endStringMatch = currChunk.match(STRING_REGEX);
                        if (endStringMatch) {
                            const endValue = endStringMatch[0];
                            quoteCount += endValue.length;
                            value += endValue;
                            currChunk = currChunk.slice(endValue.length);
                        }
                        else {
                            value += currChunk[0];
                            currChunk = currChunk.slice(1);
                        }
                    }

                    tokens.push({
                        value,
                        type: 'STRING',
                    })
                }

                if (!operatorMatch && !stringMatch && !charMatch) {
                    throw new Error(`Invalid syntax error, line ${this.index}: ${this.line}`);
                }
            }
            return tokens;
        });
    }
}

module.exports = LineTokens;
<commit_msg>Fix line splitter to account for multi-space separators<commit_after>'use strict';

const OPERATOR_REGEX = /^(-|\+|\*{1,2}|\\|\/|#|&|!|_|\?|'*<=*|'*>=*|'*\[|'*\]{1,2}|\(|\)|'*=|'|\${1,2}|\^|,|:|@)/;
const STRING_REGEX = /^("+)/;
const CHARACTER_REGEX = /^([A-Za-z0-9\.%]+)/;
const SPACE_REGEX = /^(\s+)/;

class LineTokens {
    constructor(line, index) {
        this.line = line;
        this.index = index;
        this.tokenize();
    }
    tokenize() {
        // First, pull any existing, valid comment out of the line
        this.findComments();

        // Next with the comment out of the way, determine the current indentation of this line
        this.findIndentation();

        // Split the remainder of the line by whitespace to determine the macro-token groups
        this.createTokenGroups();
    }
    findComments() {
        let index = 0;
        let isString = false;
        while (index < this.line.length) {
            if (this.line[index] === '"') {
                isString = !isString;
            } else if (this.line[index] === ';' && !isString) {
                this.comment = this.line.slice(index + 1).trim();
                this.line = this.line.slice(0, index).trim();
                break;
            }
            index += 1;
        }
    }
    findIndentation() {
        this.indentation = 0;
        let index = 0;
        while ((index < this.line.length) && (!/\w/.test(this.line[index]))) {
            if ((this.line[index] === ' ') && (this.indentation < 1)) {
                this.indentation = 1;
            } else if ((this.line[index] === '.') && (this.indentation >= 1)) {
                this.indentation += 1;
            }

            index += 1;
        }
        this.line = ((index < this.line.length) ? this.line.slice(index) : '');
    }
    createChunks(line) {
        // We want to split a line of text by spaces, but we also want to ignore the split if
        // those spaces are caught in-between quotation marks. So we implement our own special
        // split function that handles quote-captured spaces. The strategy here is to iterate
        // one character at a time and build substrings as we go, noting the "is string" state
        // as we iterate
        let currLine = line;
        let chunks = [];
        let quoteCount = 0;
        let currChunk = '';

        while (currLine.length > 0) {
            const currChar = currLine[0];
            if (currChar === '"') {
                const quoteMatch = currLine.match(STRING_REGEX);
                const quotes = quoteMatch[0];

                currChunk += quotes;
                quoteCount += quotes.length;
                currLine = currLine.slice(quotes.length);
            }

            // If the current character is a space, then check if we're "in quotes" and capturing
            // spaces. If so, just append, otherwise, add the current substring to the list of
            // chunks, if the string isn't empty.
            else if (currChar === ' ') {
                const spaceMatch = currLine.match(SPACE_REGEX);
                const spaces = spaceMatch[0];

                if (quoteCount % 2 === 0) {
                    chunks.push(currChunk);
                    if (spaces.length > 1) {
                        chunks.push(spaces);
                    }
                    currChunk = '';
                }
                else {
                    currChunk += spaces;
                }

                currLine = currLine.slice(spaces.length);
            }

            else {
                currChunk += currChar;
                currLine = currLine.slice(1);
            }
        }
        if (currChunk !== '') {
            chunks.push(currChunk);
        }
        return chunks;
    }
    createTokenGroups() {
        this.chunks = this.createChunks(this.line);
        // console.log(this.chunks);
        this.tokenGroups = this.chunks.map((chunk) => {
            const tokens = [];
            let currChunk = chunk;

            while (currChunk.length > 0) {
                // Perform a regex match search for valid MUMPS operators.
                const operatorMatch = currChunk.match(OPERATOR_REGEX);
                if (operatorMatch) {
                    const value = operatorMatch[0];
                    tokens.push({
                        value,
                        type: 'OPERATOR',
                    });

                    currChunk = currChunk.slice(value.length);
                }

                // Perform a regex match search for alphanumeric characters at the start of the
                // current string. If we found something, we save the value as either a literal
                // or a number, depending on an 'isNaN' check.
                const charMatch = currChunk.match(CHARACTER_REGEX);
                if (charMatch) {
                    const value = charMatch[0];
                    const type = isNaN(value) ? 'LITERAL' : 'NUMERIC';
                    tokens.push({
                        value,
                        type,
                    });

                    currChunk = currChunk.slice(value.length);
                }

                // Perform a regex match search for MUMPS string literals. The rub here is that
                // literal quotation marks can be represented in a MUMPS string literal by 2
                // consecutive double-quote marks. To mitigate this feature, once we find a group
                // of double-quotes, we capture until we find a matching set (that is, the quote
                // count become even). Then whatever we've captured until then is a string.
                const stringMatch = currChunk.match(STRING_REGEX);
                if (stringMatch) {
                    let value = stringMatch[0];
                    let quoteCount = value.length;
                    currChunk = currChunk.slice(value.length);

                    while (quoteCount % 2 !== 0) {
                        if (currChunk.length === 0) {
                            throw new Error(`Mismatched string error, line ${this.index}: ${chunk}`);
                        }

                        const endStringMatch = currChunk.match(STRING_REGEX);
                        if (endStringMatch) {
                            const endValue = endStringMatch[0];
                            quoteCount += endValue.length;
                            value += endValue;
                            currChunk = currChunk.slice(endValue.length);
                        }
                        else {
                            value += currChunk[0];
                            currChunk = currChunk.slice(1);
                        }
                    }

                    tokens.push({
                        value,
                        type: 'STRING',
                    })
                }

                const spaceMatch = (currChunk[0] === ' ');
                if (spaceMatch) {
                    tokens.push({
                        value: '',
                        type: 'SEPARATOR',
                    });
                    currChunk = '';
                }

                if (!operatorMatch && !stringMatch && !charMatch && !spaceMatch) {
                    throw new Error(`Invalid syntax error, line ${this.index}: ${this.line} ${JSON.stringify(tokens)}`);
                }
            }
            return tokens;
        });
    }
}

module.exports = LineTokens;
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var path = require('path'),
  fs = require('fs'),
  mongoose = require('mongoose'),
  multer = require('multer'),
  config = require(path.resolve('./config/config')),
  File = mongoose.model('File'),
  aws_client = require('aws-sdk'),
  fs = require('fs'),
  errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller'));

var bucket_names = ["cloudbucketnextgen","cloudbucketnextgenbackup"];

function get_file_from_s3(s3, bucket_names, i, key) {
  var params = {Bucket : bucket_names[i], Key : key};
  s3.getObject(params, function(err, data) {
    if (err) {
      if (i === bucket_names.length) {
        return [err, false];
      }
      else {
        get_file_from_s3(bucket_names, i + 1, key);
      }
    }
    else {
      return [data, true];
    }
  });
}

/**
 * Upload a file
 */
exports.create = function (req, res) {
  var user = req.user;
  var upload = multer(config.uploads.s3FileUpload).single('fileItem');

  var bucket_name = bucket_names[0];
  var s3 = new aws_client.S3();

  if (user) {
    // upload file to Amazon S3
    upload(req, res, function (uploadError) {
      if(uploadError) {
        return res.status(400).send({
          message: 'Error occurred while uploading file'
        });
      }
      else {
        var file = new File(req.file);
        file.user = user;
        fs.readFile(file.path, function(err, data) {
          if (err) {
            return res.status(400).send({
              message: "failed to read file locally"
            });
          }
          else {
            console.log("data file was stored into memory");
            console.log("bucket_name:" + bucket_name);
            console.log("key:" + file.user._id + "/" + file.filename);
            //  console.log("data:" + data);
          //  for(var i=0; i<bucket_names.length; ++i) {
              var params = {Bucket : bucket_names[0], Key : file.user._id + "/" + file.filename, Body : data };

              s3.putObject(params, function(err, data) {
                if (err) {
                  return res.status(400).send({
                    message: err
                  });
                }
                else {
                  //  object saved in s3 - store metadata in mongodb
                  // save file details
                  console.log("file uploaded to s3");
                  file.save(function (err) {
                    if (err) {
                      return res.status(400).send({
                        message: errorHandler.getErrorMessage(err)
                      });
                    }
                    else {
                      fs.unlink(file.path);
                      res.json(file);
                    }
                  });
                }
              });
            //}

            for(var i=1; i<bucket_names.length; ++i) {
              var parameters = {Bucket : bucket_names[i], Key : file.user._id + "/" + file.filename, Body : data };
              s3.putObject(parameters, function(err, data) {
                if (err) {
                  // should we return a 400 here?
                  return res.status(400).send({
                    message: err
                  });
                }
              });
            }
          }
        });
      }
    });
  }
};

/**
 * Show the current file
 */
exports.read = function (req, res) {

    // data from s3
    // fs.write(file.path)
  var user = req.user;
  var file = req.file;
  var s3 = new aws_client.S3();
  if (user) {
    var i=0;
    var bucket_name = bucket_names[0];
    var params = {Bucket : bucket_names[0], Key : file.user._id + "/" + file.filename};
    s3.getObject(params, function(err, data) {
      if (err) {
        console.log("coiuld not retrieve file from primary!");
        var params2 = {Bucket : bucket_names[1], Key : file.user._id + "/" + file.filename};
        s3.getObject(params2, function(err, data){
          if (err) {
            console.log("error in second access!");
            return res.status(400).send({
              message: err
            });
          }
          else {
            console.log("retreived file from secondary!");
            fs.writeFile(file.path, data, function(err, data) {
              if (err) {
                return res.status(400).send({
                  message: err
                });
              }
              else {
                console.log("file retrieved from secondary and saved!");
              }
            });
          }
        });
      }
      else {
        console.log("file retrieved from primary!" + data);
        fs.writeFile(req.file.path, data, function(err, data) {
          if (err) {
            return res.status(400).send({
              message: err
            });
          }
          else {
            console.log("file retrieved from primary and saved!");
          }
        });

      }
    });
  }
  res.json(req.file);
};

/**
 * Update a file
 */
exports.update = function (req, res) {
  var file = req.file;

  file.title = req.body.title;
  file.content = req.body.content;

  file.save(function (err) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(file);
    }
  });
};

/**
 * Delete an file
 */
exports.delete = function (req, res) {
  var file = req.file;

  file.remove(function (err) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      fs.unlink(file.path);
      res.json(file);
    }
  });
};

/**
 * List of Files
 */
exports.list = function (req, res) {
  File.find().sort('-created').populate('user', 'displayName').exec(function (err, files) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(files);
    }
  });
};

/**
 * File middleware
 */
exports.fileByID = function (req, res, next, id) {

  if (!mongoose.Types.ObjectId.isValid(id)) {
    return res.status(400).send({
      message: 'File is invalid'
    });
  }

  File.findById(id).populate('user', 'displayName').exec(function (err, file) {
    if (err) {
      return next(err);
    } else if (!file) {
      return res.status(404).send({
        message: 'No file with that identifier has been found'
      });
    }
    req.file = file;
    next();
  });
};
<commit_msg>add copying file to n S3 buckets<commit_after>'use strict';

/**
 * Module dependencies.
 */
var path = require('path'),
  fs = require('fs'),
  mongoose = require('mongoose'),
  multer = require('multer'),
  config = require(path.resolve('./config/config')),
  File = mongoose.model('File'),
  aws_client = require('aws-sdk'),
  fs = require('fs'),
  errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller'));

var bucket_names = ["cloudbucketnextgen","cloudbucketnextgenbackup"];

function get_file_from_s3(s3, bucket_names, i, key) {
  var params = {Bucket : bucket_names[i], Key : key};
  s3.getObject(params, function(err, data) {
    if (err) {
      if (i === bucket_names.length) {
        return [err, false];
      }
      else {
        get_file_from_s3(bucket_names, i + 1, key);
      }
    }
    else {
      return [data, true];
    }
  });
}

/**
 * Upload a file
 */
exports.create = function (req, res) {
  var user = req.user;
  var upload = multer(config.uploads.s3FileUpload).single('fileItem');

  var bucket_name = bucket_names[0];
  var s3 = new aws_client.S3();

  if (user) {
    // upload file to Amazon S3
    upload(req, res, function (uploadError) {
      if(uploadError) {
        return res.status(400).send({
          message: 'Error occurred while uploading file'
        });
      }
      else {
        var file = new File(req.file);
        file.user = user;
        fs.readFile(file.path, function(err, data) {
          if (err) {
            return res.status(400).send({
              message: "failed to read file locally"
            });
          } else {
            // file read success
            var file_data = data;

            var bucket_index = 0;
            var success = false;

            // file into all buckets
            (function uploadFileToS3Bucket() {
              if (bucket_index < bucket_names.length) {
                var params = {Bucket : bucket_names[bucket_index], Key : file.user._id + "/" + file.filename, Body : data };
                s3.putObject(params, function(err, data) {
                  if (err && bucket_index < bucket_names.length - 1) {
                    // do nothing
                  } else if (err && !success && bucket_index === bucket_names.length - 1) {
                    return res.status(400).send({
                      message: errorHandler.getErrorMessage(err)
                    });
                  } else {
                    //  object saved in s3 - store metadata in mongodb
                    // save file reference only once
                    if (!success) {
                      file.save(function (err) {
                        if (err) {
                          return res.status(400).send({
                            message: err
                          });
                        } else {
                          // file metadata save in mongodb success
                          res.json(file);
                          success = true;
                        }
                      });
                    }
                  }
                  // increment bucket and recurse
                  bucket_index++;
                  uploadFileToS3Bucket();
                });
              }
            }());
          }
        });
      }
    });
  }
};

/**
 * Show the current file
 */
exports.read = function (req, res) {

    // data from s3
    // fs.write(file.path)
  var user = req.user;
  var file = req.file;
  var s3 = new aws_client.S3();
  if (user) {
    var i=0;
    var bucket_name = bucket_names[0];
    var params = {Bucket : bucket_names[0], Key : file.user._id + "/" + file.filename};
    s3.getObject(params, function(err, data) {
      if (err) {
        console.log("could not retrieve file from primary!");
        var params2 = {Bucket : bucket_names[1], Key : file.user._id + "/" + file.filename};
        s3.getObject(params2, function(err, data){
          if (err) {
            console.log("error in second access!");
            return res.status(400).send({
              message: err
            });
          } else {
            console.log("retreived file from secondary!");
            fs.writeFile(file.path, data, function(err, data) {
              if (err) {
                return res.status(400).send({
                  message: err
                });
              } else {
                console.log("file retrieved from secondary and saved!");
              }
            });
          }
        });
      } else {
        console.log("file retrieved from primary!" + data);
        fs.writeFile(req.file.path, data, function(err, data) {
          if (err) {
            return res.status(400).send({
              message: err
            });
          } else {
            console.log("file retrieved from primary and saved!");
          }
        });

      }
    });
  }
  res.json(req.file);
};

/**
 * Update a file
 */
exports.update = function (req, res) {
  var file = req.file;

  file.title = req.body.title;
  file.content = req.body.content;

  file.save(function (err) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(file);
    }
  });
};

/**
 * Delete an file
 */
exports.delete = function (req, res) {
  var file = req.file;

  file.remove(function (err) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      fs.unlink(file.path, function(err) {
        if (err) {
          console.log("unable to delete file: " + file.path);
        }
      });

      res.json(file);
    }
  });
};

/**
 * List of Files
 */
exports.list = function (req, res) {
  File.find().sort('-created').populate('user', 'displayName').exec(function (err, files) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(files);
    }
  });
};

/**
 * File middleware
 */
exports.fileByID = function (req, res, next, id) {

  if (!mongoose.Types.ObjectId.isValid(id)) {
    return res.status(400).send({
      message: 'File is invalid'
    });
  }

  File.findById(id).populate('user', 'displayName').exec(function (err, file) {
    if (err) {
      return next(err);
    } else if (!file) {
      return res.status(404).send({
        message: 'No file with that identifier has been found'
      });
    }
    req.file = file;
    next();
  });
};
<|endoftext|>


<commit_before>/**
 *
 * KLEO Posts REST API
 * @version 1.0
 * @author Andriy Ermolenko
 * @license MIT
 *
 */

'use strict';

var path = require('path'),
  mongoose = require('mongoose'),
  Post = mongoose.model('Post'),
  _ = require('lodash'),
  errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller'));

/**
 * Check if user is admin
 * @param user
 */
var isAdmin = function(user) {
  return user.roles.indexOf('admin') !== -1;
};

/**
 * Create a post/article/announcement
 */
exports.create = function (req, res) {

  if (!isAdmin(req.user)) {
    if (req.body.showMain || req.body.showGlobal) {
      return res.status(403).send({
        message: 'You need administrator rights to make this action'
      });
    }
  }

  var post = new Post(req.body);
  post.user = req.user;

  post.save(function (err) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(post);
    }
  });
};

/**
 * Show the current post
 * @deprecated
 */
exports.read = function (req, res) {
  res.json(req.post);
};

/**
 * Update a post/article/announcement
 */
exports.update = function (req, res) {
  if (!isAdmin(req.user)) {
    if (req.body.showMain != req.post.showMain || req.body.showGlobal != req.post.showGlobal) {
      return res.status(403).send({
        message: 'You need administrator rights to make this action'
      });
    }
  }

  var post = req.post;

  var updateFields = {
    title: req.body.title,
    preview: req.body.preview,
    content: req.body.content,
    tags: req.body.tags,
    showMain: req.body.showMain,
    showGlobal: req.body.showGlobal
  };

  post = _.extend(post, updateFields);

  post.save(function(err, post) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    }
    else {
      res.json(post);
    }
  });
};

/**
 * Delete a post/news/announcement
 */
exports.delete = function (req, res) {
  var post = req.post;

  post.remove(function (err) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(post);
    }
  });
};

/**
 * List of all types posts/news/announcements
 */
exports.list = function (req, res) {
  Post.find().sort('-created').populate('user', 'displayName').exec(function (err, posts) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(posts);
    }
  });
};

/**
 * Get selected post/news/announcement by ID
 */
exports.postByID = function (req, res, next, id) {

  if (!mongoose.Types.ObjectId.isValid(id)) {
    return res.status(400).send({
      message: 'Post is invalid'
    });
  }

  Post.findById(id).populate('user', 'displayName').exec(function (err, post) {
    if (err) {
      return next(err);
    } else if (!post) {
      return res.status(404).send({
        message: 'No post with that identifier has been found'
      });
    }
    req.post = post;
    next();
  });
};

/**
 * Get list of posts for selected domain
 */
exports.getPostsForDomain = function(req, res) {
  Post.find({
    //domain: null,
    showGlobal: true
  }).sort('-created').populate('user', 'displayName').exec(function (err, posts) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(posts);
    }
  });
};<commit_msg>#3 Make strong check<commit_after>/**
 *
 * KLEO Posts REST API
 * @version 1.0
 * @author Andriy Ermolenko
 * @license MIT
 *
 */

'use strict';

var path = require('path'),
  mongoose = require('mongoose'),
  Post = mongoose.model('Post'),
  _ = require('lodash'),
  errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller'));

/**
 * Check if user is admin
 * @param user
 */
var isAdmin = function(user) {
  return user.roles.indexOf('admin') !== -1;
};

/**
 * Create a post/article/announcement
 */
exports.create = function (req, res) {

  if (!isAdmin(req.user)) {
    if (req.body.showMain || req.body.showGlobal) {
      return res.status(403).send({
        message: 'You need administrator rights to make this action'
      });
    }
  }

  var post = new Post(req.body);
  post.user = req.user;

  post.save(function (err) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(post);
    }
  });
};

/**
 * Show the current post
 * @deprecated
 */
exports.read = function (req, res) {
  res.json(req.post);
};

/**
 * Update a post/article/announcement
 */
exports.update = function (req, res) {
  if (!isAdmin(req.user)) {
    if (req.body.showMain !== req.post.showMain || req.body.showGlobal !== req.post.showGlobal) {
      return res.status(403).send({
        message: 'You need administrator rights to make this action'
      });
    }
  }

  var post = req.post;

  var updateFields = {
    title: req.body.title,
    preview: req.body.preview,
    content: req.body.content,
    tags: req.body.tags,
    showMain: req.body.showMain,
    showGlobal: req.body.showGlobal
  };

  post = _.extend(post, updateFields);

  post.save(function(err, post) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    }
    else {
      res.json(post);
    }
  });
};

/**
 * Delete a post/news/announcement
 */
exports.delete = function (req, res) {
  var post = req.post;

  post.remove(function (err) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(post);
    }
  });
};

/**
 * List of all types posts/news/announcements
 */
exports.list = function (req, res) {
  Post.find().sort('-created').populate('user', 'displayName').exec(function (err, posts) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(posts);
    }
  });
};

/**
 * Get selected post/news/announcement by ID
 */
exports.postByID = function (req, res, next, id) {

  if (!mongoose.Types.ObjectId.isValid(id)) {
    return res.status(400).send({
      message: 'Post is invalid'
    });
  }

  Post.findById(id).populate('user', 'displayName').exec(function (err, post) {
    if (err) {
      return next(err);
    } else if (!post) {
      return res.status(404).send({
        message: 'No post with that identifier has been found'
      });
    }
    req.post = post;
    next();
  });
};

/**
 * Get list of posts for selected domain
 */
exports.getPostsForDomain = function(req, res) {
  Post.find({
    //domain: null,
    showGlobal: true
  }).sort('-created').populate('user', 'displayName').exec(function (err, posts) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(posts);
    }
  });
};<|endoftext|>


<commit_before>class UserInterface {
  constructor(p_xSizeAndPos){
    this.sizeAndPosition = p_xSizeAndPos;
    this.dialog = UserInterface.DIALOG_NONE;
    this.screen = undefined;
    this.keyHandler = undefined;

    this.marginX = 25;
    this.initDefaultDialog();
    this.initKeyboardInput();
    this.initButtons();
  }

  get x(){ return this.sizeAndPosition.x; }
  get y(){ return this.sizeAndPosition.y; }
  get width(){ return this.sizeAndPosition.width; }
  get height(){ return this.sizeAndPosition.height; }

  static get SCREEN_INTRO() { return 0; }
  static get SCREEN_INPUT() { return 1; }

  static get DIALOG_NONE() { return 0; }
  static get DIALOG_SHARE() { return 1; }

  initKeyboardInput(){
    this.keyboardInput = createInput();
    console.log('created input');
    this.keyboardInput.position(-500,-500);
  }

  initButtons(){
    let layoutPos = createVector();
    layoutPos.x = this.x + this.marginX;
    layoutPos.y = this.y + 5;
    this.shareButton = createButton("Share");
    this.shareButton.position(layoutPos.x, layoutPos.y);
    this.shareButton.mousePressed(this.handleShareButton);
    this.shareButton.hide();

    layoutPos.x += this.shareButton.width + this.marginX;
    this.clearButton = createButton("Clear");
    this.clearButton.position(layoutPos.x, layoutPos.y);
    this.clearButton.mousePressed(this.handleClearButton);
    this.clearButton.hide();
  }

  showMainButtons(){
    this.shareButton.show();
    this.clearButton.show();
  }

  handleKeyPressed(){
   if (ui.isShowingDialog()){
      if (key == 'Escape') {
        return this.handleEscapeKey();
      }
    } else {
      ui.showMainButtons();
      this.screen = UserInterface.SCREEN_INPUT;
      this.keyHandler.handleKeyPressed();
    }
  }

  handleKeyReleased(){
    if (this.isShowingDialog()){
      // Do nothing
    } else {
      this.keyHandler.handleKeyReleased();
    }
  }

  handleTouchEnded(){
    if (this.isShowingDialog()){
      // do nothing
    } else {
      this.screen = UserInterface.SCREEN_INPUT;
      nfTypeset.requestFullRedraw();
      this.keyboardInput.elt.focus();
    }
  }

  handleWindowResized(){
    if (this.screen == UserInterface.SCREEN_INTRO){
      this.showIntroScreen();
    } else {
      nfTypeset.textSize(0.1 * height);
      nfTypeset.requestFullRedraw();
    }
  }

  handleShareButton(){
    console.log('share button pressed');
    ui.showDialog(UserInterface.DIALOG_SHARE);
  }

  handleClearButton(){
    nfTypeset.clearPrintBuffer();
  }

  handleEscapeKey(){
    if (this.dialog){
      this.closeDialog();
    }
  }

  isShowingDialog(){
    return this.dialog !== UserInterface.DIALOG_NONE;
  }

  showDialog(dialog){
    this.dialog = dialog;
    this.dialogRender = this.renderDialogUpload;
  }

  closeDialog(){
    this.dialog = UserInterface.DIALOG_NONE;

    if (this.shareInput !== undefined){
      this.shareInput.remove();
      this.shareInput = undefined;
    }
    this.initialRender();
    nfTypeset.requestFullRedraw();
  }

  renderCurrentDialog(){
    switch (this.dialog) {
      case UserInterface.DIALOG_SHARE: return this.renderShareDialog();
    }
  }

  initDefaultDialog(){
    const dialogWidth = 0.6 * width;
    const dialogHeight = 0.3 * height;
    this.dialogRect = new Rect((width - dialogWidth) / 2,
                               height / 2 - dialogHeight / 2,
                               dialogWidth, dialogHeight);
  }

  renderShareDialog(){
    push();
    fill(255);
    let dialogRect
    P5JsUtils.drawRect(this.dialogRect);

    fill(0);
    textSize(20);
    textAlign(LEFT);
    text('Copy the URL', this.dialogRect.x + this.marginX, this.dialogRect.y + this.marginX,
                         this.dialogRect.width, 25);

    if (this.shareInput === undefined){
      let url = this.buildShareURL();
      this.shareInput = createInput('');
      this.shareInput.position(this.dialogRect.x + this.marginX, this.dialogRect.y + 3 * this.marginX);
      this.shareInput.size(this.dialogRect.width - 2 * this.marginX);
      this.shareInput.value(url);
    }
    pop();
  }

  buildShareURL(){
    let blocks64 = nfTypeset.getPrintBlocksInBase64();
    let fullUrl = window.location.href;
    let baseUrl = fullUrl.split("?")[0];
    let currentParams = getURLParams();
    let paramNames = Object.keys(currentParams);

    let otherParams = paramNames.filter(p => {return p != 'blocks';})
                                .map(p => `${p}=${currentParams[p]}`)
                                .join('&');
    otherParams = (otherParams) ? '&' + otherParams : '';

    return  baseUrl + "?blocks=" + blocks64 + otherParams;
  }

  initialRender(){}

  showIntroScreen(){
    this.screen = UserInterface.SCREEN_INTRO;

    background(50);
    fill(230);
    textFont('Verdana');
    textAlign(CENTER, TOP);
    const marginX = (width > 667) ? 0.2 * width : 0.05 * width;
    const lineHeight = 40;
    let yPos =  0.15 * height;
    let flagSize = 0.8 * width / (7 * 1.1);

    nfTypeset.push();
    nfTypeset.textSize(flagSize);
    nfTypeset.text('WELCOME', 0.1 * width, yPos, 0.8 * width);
    nfTypeset.pop();

    textSize(32);
    yPos += 1.5 * flagSize;
    text('Welcome', marginX, yPos, width - 2 * marginX, lineHeight);

    const instr1 = 'Type to see the corresponding nautical flags.';
    const instr2 = 'Press SHIFT + P to download an image of what you\'ve typed.';
    const instr3 = 'Click the SHARE button to get a shareable link to send a message to friend.';

    let lineSpacer = (width > 667) ? "\n\n" : "\n\n";
    let instructions;
    if (width > 667) {
      instructions = instr1 + lineSpacer + instr2 + lineSpacer + instr3;
    } else {
      instructions = instr1 + lineSpacer + instr3;
    }
    textSize(20);
    yPos += (width > 667) ? lineHeight * 2 : lineHeight;
    const mainBlockHeight = height - yPos;
    text(instructions, marginX, yPos, width - 2 * marginX, mainBlockHeight);
  }

  render(){
    this.renderCurrentDialog();
  }
}
<commit_msg>p5js/nautical-flags-02 - Add a Close button to the dialog<commit_after>class UserInterface {
  constructor(p_xSizeAndPos){
    this.sizeAndPosition = p_xSizeAndPos;
    this.dialog = UserInterface.DIALOG_NONE;
    this.screen = undefined;
    this.keyHandler = undefined;

    this.marginX = 25;
    this.initDefaultDialog();
    this.initKeyboardInput();
    this.initButtons();
  }

  get x(){ return this.sizeAndPosition.x; }
  get y(){ return this.sizeAndPosition.y; }
  get width(){ return this.sizeAndPosition.width; }
  get height(){ return this.sizeAndPosition.height; }

  static get SCREEN_INTRO() { return 0; }
  static get SCREEN_INPUT() { return 1; }

  static get DIALOG_NONE() { return 0; }
  static get DIALOG_SHARE() { return 1; }

  initKeyboardInput(){
    this.keyboardInput = createInput();
    console.log('created input');
    this.keyboardInput.position(-500,-500);
  }

  initButtons(){
    let layoutPos = createVector();
    layoutPos.x = this.x + this.marginX;
    layoutPos.y = this.y + 5;
    this.shareButton = createButton("Share");
    this.shareButton.position(layoutPos.x, layoutPos.y);
    this.shareButton.mousePressed(this.handleShareButton);
    this.shareButton.hide();

    layoutPos.x += this.shareButton.width + this.marginX;
    this.clearButton = createButton("Clear");
    this.clearButton.position(layoutPos.x, layoutPos.y);
    this.clearButton.mousePressed(this.handleClearButton);
    this.clearButton.hide();

    this.dialogCloseButton = createButton("Close");
    this.dialogCloseButton.mousePressed(this.handleDialogCloseButton);
    this.dialogCloseButton.hide();
  }

  showMainButtons(){
    this.shareButton.show();
    this.clearButton.show();
  }

  handleKeyPressed(){
   if (ui.isShowingDialog()){
      if (key == 'Escape') {
        return this.handleEscapeKey();
      }
    } else {
      ui.showMainButtons();
      this.screen = UserInterface.SCREEN_INPUT;
      this.keyHandler.handleKeyPressed();
    }
  }

  handleKeyReleased(){
    if (this.isShowingDialog()){
      // Do nothing
    } else {
      this.keyHandler.handleKeyReleased();
    }
  }

  handleTouchEnded(){
    if (this.isShowingDialog()){
      // do nothing
    } else {
      this.screen = UserInterface.SCREEN_INPUT;
      nfTypeset.requestFullRedraw();
      this.keyboardInput.elt.focus();
    }
  }

  handleWindowResized(){
    if (this.screen == UserInterface.SCREEN_INTRO){
      this.showIntroScreen();
    } else {
      nfTypeset.textSize(0.1 * height);
      nfTypeset.requestFullRedraw();
    }
  }

  handleShareButton(){
    console.log('share button pressed');
    ui.showDialog(UserInterface.DIALOG_SHARE);
  }

  handleClearButton(){
    nfTypeset.clearPrintBuffer();
  }

  handleDialogCloseButton(){
    ui.closeDialog();
  }

  handleEscapeKey(){
    if (this.dialog){
      this.closeDialog();
    }
  }

  isShowingDialog(){
    return this.dialog !== UserInterface.DIALOG_NONE;
  }

  showDialog(dialog){
    this.dialog = dialog;
    this.dialogRender = this.renderDialogUpload;
  }

  closeDialog(){
    this.dialog = UserInterface.DIALOG_NONE;
    this.dialogCloseButton.hide();

    if (this.shareInput !== undefined){
      this.shareInput.remove();
      this.shareInput = undefined;
    }
    this.initialRender();
    nfTypeset.requestFullRedraw();
  }

  renderCurrentDialog(){
    switch (this.dialog) {
      case UserInterface.DIALOG_SHARE: return this.renderShareDialog();
    }
  }

  initDefaultDialog(){
    const dialogWidth = 0.6 * width;
    const dialogHeight = 0.3 * height;
    this.dialogRect = new Rect((width - dialogWidth) / 2,
                               height / 2 - dialogHeight / 2,
                               dialogWidth, dialogHeight);
  }

  renderShareDialog(){
    push();
    fill(255);
    let dialogRect
    P5JsUtils.drawRect(this.dialogRect);

    fill(0);
    textSize(20);
    textAlign(LEFT);
    text('Copy the URL', this.dialogRect.x + this.marginX, this.dialogRect.y + this.marginX,
                         this.dialogRect.width, 25);

    if (this.shareInput === undefined){
      let url = this.buildShareURL();
      this.shareInput = createInput('');
      this.shareInput.position(this.dialogRect.x + this.marginX - 3, this.dialogRect.y + 3 * this.marginX);
      this.shareWidth = this.dialogRect.width - 2 * this.marginX - 3;
      this.shareInput.size(this.shareWidth);
      this.shareInput.value(url);
    }

    this.dialogCloseButton.position(this.dialogRect.maxX - this.dialogCloseButton.width - this.marginX,
                                    this.dialogRect.maxY - 40);
    this.dialogCloseButton.show();
    pop();
  }

  buildShareURL(){
    let blocks64 = nfTypeset.getPrintBlocksInBase64();
    let fullUrl = window.location.href;
    let baseUrl = fullUrl.split("?")[0];
    let currentParams = getURLParams();
    let paramNames = Object.keys(currentParams);

    let otherParams = paramNames.filter(p => {return p != 'blocks';})
                                .map(p => `${p}=${currentParams[p]}`)
                                .join('&');
    otherParams = (otherParams) ? '&' + otherParams : '';

    return  baseUrl + "?blocks=" + blocks64 + otherParams;
  }

  initialRender(){}

  showIntroScreen(){
    this.screen = UserInterface.SCREEN_INTRO;

    background(50);
    fill(230);
    textFont('Verdana');
    textAlign(CENTER, TOP);
    const marginX = (width > 667) ? 0.2 * width : 0.05 * width;
    const lineHeight = 40;
    let yPos =  0.15 * height;
    let flagSize = 0.8 * width / (7 * 1.1);

    nfTypeset.push();
    nfTypeset.textSize(flagSize);
    nfTypeset.text('WELCOME', 0.1 * width, yPos, 0.8 * width);
    nfTypeset.pop();

    textSize(32);
    yPos += 1.5 * flagSize;
    text('Welcome', marginX, yPos, width - 2 * marginX, lineHeight);

    const instr1 = 'Type to see the corresponding nautical flags.';
    const instr2 = 'Press SHIFT + P to download an image of what you\'ve typed.';
    const instr3 = 'Click the SHARE button to get a shareable link to send a message to friend.';

    let lineSpacer = (width > 667) ? "\n\n" : "\n\n";
    let instructions;
    if (width > 667) {
      instructions = instr1 + lineSpacer + instr2 + lineSpacer + instr3;
    } else {
      instructions = instr1 + lineSpacer + instr3;
    }
    textSize(20);
    yPos += (width > 667) ? lineHeight * 2 : lineHeight;
    const mainBlockHeight = height - yPos;
    text(instructions, marginX, yPos, width - 2 * marginX, mainBlockHeight);
  }

  render(){
    this.renderCurrentDialog();
  }
}
<|endoftext|>


<commit_before>var express = require('express'),
    load = require('express-load'),
    path = require('path'),
    favicon = require('serve-favicon'),
    logger = require('morgan'),
    cookieParser = require('cookie-parser'),
    bodyParser = require('body-parser'),
    session = require('express-session'),
    mongoose = require('mongoose'),
    flash = require('express-flash'),
    moment = require('moment');

//conexão com o mongodb
mongoose.connect('mongodb://localhost/portal', function (err) {
    'use strict';
    if (err) {
        console.log("Erro ao conectar mongodb: " + err);
    } else {
        console.log('Mongodb Conectado');
    }
})

var app = express();

//middleware
var erros = require('./middleware/erros');

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(cookieParser());
app.use(session({secret: 'portal', resave: false, saveUninitialized: true}));
app.use(express.static(path.join(__dirname, '/public')));
app.use(flash());

//HELPERS
app.use(function(req, res, next){
    res.locals.moment= moment;
    next();
});

load('models')
    .then('controllers')
    .then('routes')
    .into(app);
//middleware
app.use(erros.notfound);
app.use(erros.serverError);

app.listen(3000, function () {
    'use strict';
    console.log('Express server listening on port 3000');
});<commit_msg>Update app.js<commit_after>var express = require('express'),
    load = require('express-load'),
    path = require('path'),
    favicon = require('serve-favicon'),
    logger = require('morgan'),
    cookieParser = require('cookie-parser'),
    bodyParser = require('body-parser'),
    session = require('express-session'),
    mongoose = require('mongoose'),
    flash = require('express-flash'),
    moment = require('moment');

//conexão com o mongodb
mongoose.connect('mongodb://localhost/portal', function (err) {
    'use strict';
    if (err) {
        console.log("Erro ao conectar mongodb: " + err);
    } else {
        console.log('Mongodb Conectado');
    }
})

var app = express();

//middleware
var erros = require('./middleware/erros');

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(cookieParser());
app.use(session({secret: 'portal', resave: false, saveUninitialized: true}));
app.use(express.static(path.join(__dirname, '/public')));
app.use(flash());

//HELPERS
app.use(function(req, res, next){
    res.locals.moment= moment;
    next();
});

load('models')
    .then('controllers')
    .then('routes')
    .into(app);
//middleware
app.use(erros.notfound);
app.use(erros.serverError);

var env = process.env.PORT || 8080;

app.listen(env, function () {
    "use strict";
    console.log("Portal no ar." + "\nPorta: " + env);
});
<|endoftext|>


<commit_before>if (mw.config.get('wgPageName') === 'Wikipedia:用戶查核請求') {
	for (var i = 2; $(".tocsection-"+i)[0] !== undefined; i++) {
		var sectiontext = $(".tocsection-"+i)[0].children[0].children[1];
		sectiontext.style["color"] = $("h3").next().find(":nth-child(1)")[i-2].style.background;
		sectiontext.style["font-weight"] = "bold";
	}
}
<commit_msg>RFCU-status: fixes<commit_after>if (mw.config.get('wgPageName') === 'Wikipedia:元維基用戶查核協助請求') {
	for (var i = 2; $(".tocsection-"+i)[0] !== undefined; i++) {
		var sectiontext = $(".tocsection-"+i)[0].children[0].children[1];
		sectiontext.style["color"] = $("h3").next().find("span:nth-child(1)")[i-2].style.background;
		sectiontext.style["font-weight"] = "bold";
	}
}
<|endoftext|>


<commit_before>/**
* Copyright (c) Microsoft.  All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

var _ = require('underscore');
var async = require('async');
var es = require('event-stream');

var encoding = require('./token-cache-encoding');
var credStore = require('./win-credstore');

/**
 * Constructs a new token cache that stores credentials
 * in the Windows credential store.
 * @constructor
 */
 function CredStoreTokenCache() {
  this._entries = null;
 }

 //
// Internal helper functions for serializing and
// deserializing cache entries.
//

function deserializeBool(str) {
  return str.toLowerCase() === 'true';
}

function deserializeDate(str) {
  return new Date(str);
}

function deserializeNum(str) {
  return +str;
}

// Mapping of field names that need special handling
// on deserialization (typically type conversions)
// to the appropriate deserializer functions.
var fieldsToConvert = {
  expiresIn: deserializeNum,
  expiresOn: deserializeDate,
  isUserIdDisplayable: deserializeBool,
  isMRRT: deserializeBool
};

function deserializeEntry(entry) {
  return _.chain(entry)
    .pairs()
    .map(function (pair) {
      var key = pair[0], value = pair[1];
      if (_.has(fieldsToConvert, key)) {
        return [key, fieldsToConvert[key](value)];
      }
      return pair;
    })
    .object()
    .value();
}

_.extend(CredStoreTokenCache.prototype, {
  /**
  * Load the cache entries. Does a lazy load,
  * loads from OS on first request, otherwise
  * returns in-memory copy.
  *
  * @param {function(err, Array)} callback callback
  *                               receiving cache entries.
  */
  _loadEntries: function (callback) {
    var self = this;
    if (self._entries !== null) {
      return callback(null, self._entries);
    }

    var entries = [];
    credStore.list()
      .pipe(es.mapSync(function (entry) {
        // Most fields are stored in targetName,
        // access token and refresh token are stored in
        // credentials.
        var authResult = encoding.decodeObject(entry.targetName);
        var credential = encoding.decodeObject(new Buffer(entry.credential, 'hex').toString('utf8'));
        authResult.accessToken = credential.a;
        authResult.refreshToken = credential.r;

        return deserializeEntry(authResult);
      }))
      .on('data', function (entry) {
        entries.push(entry);
      })
      .on('end', function (err) {
        if (!err) {
          self._entries = entries;
        }
        callback(err, entries);
      });
  },

  /**
   * Removes a collection of entries from the cache in a single batch operation.
   * @param  {Array}   entries  An array of cache entries to remove.
   * @param  {Function} callback This function is called when the operation is complete.  Any error is provided as the
   *                             first parameter.
   */
  remove: function remove(entries, callback) {
    var self = this;

    function shouldKeep(entry) {
      if (_.findWhere(entry, entries)) {
        return false;
      }
      return true;
    }

    self._loadEntries(function (err, _entries) {
      if (err) { return callback(err); }

      var grouped = _.groupBy(_entries, shouldKeep);
      var entriesToRemove = grouped[false];
      var entriesToKeep = grouped[true];

      function removeEntry(entry, callback) {
        var targetName = encoding.encodeObject(_.omit(entry, ['accessToken', 'refreshToken']));
        credStore.remove(targetName, callback);
      }

      async.eachSeries(entriesToRemove, removeEntry, function (err) {
        if (err) { return callback(err); }
        self._entries = entriesToKeep;
        callback();
      });
    });
  },

  /**
   * Adds a collection of entries to the cache in a single batch operation.
   * @param {Array}   entries  An array of entries to add to the cache.
   * @param  {Function} callback This function is called when the operation is complete.  Any error is provided as the
   *                             first parameter.
   */
  add: function add(entries, callback) {
    var self = this;

    self._loadEntries(function (err, _entries) {
      if (err) { return callback(err); }

      // Remove any entries that are duplicates of the existing
      // cache elements.
      _.each(_entries, function(element) {
        _.each(entries, function(addElement, index) {
          if (_.isEqual(element, addElement)) {
            entries[index] = null;
          }
        });
      });

      // Add the new entries to the end of the cache.
      entries = _.compact(entries);

      // Add the new entries to the credstore
      function addToCredStore(entry, callback) {
        var targetName = encoding.encodeObject(_.omit(entry, ['accessToken', 'refreshToken']));
        var credential = encoding.encodeObject({a: entry.accessToken, r: entry.refreshToken});
        credStore.set(targetName, credential, function (err) {
          if (!err) {
            self._entries.push(entry);
          }
          callback(err);
        });
      }

      async.eachSeries(entries, addToCredStore, callback);
    });
  },

  /**
   * Finds all entries in the cache that match all of the passed in values.
   * @param  {object}   query    This object will be compared to each entry in the cache.  Any entries that
   *                             match all of the values in this object will be returned.  All the values
   *                             in the passed in object must match values in a potentialy returned object
   *                             exactly.  The returned object may have more values than the passed in query
   *                             object.
   * @param  {TokenCacheFindCallback} callback
   */
  find: function find(query, callback) {
    var self = this;

    self._loadEntries(function (err, _entries) {
      if (err) { return callback(err); }

      var results = _.where(_entries, query);
      callback(null, results);
    });
  }
});

module.exports = CredStoreTokenCache;
<commit_msg>Fixed crash on logout<commit_after>/**
* Copyright (c) Microsoft.  All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

var _ = require('underscore');
var async = require('async');
var es = require('event-stream');

var encoding = require('./token-cache-encoding');
var credStore = require('./win-credstore');

/**
 * Constructs a new token cache that stores credentials
 * in the Windows credential store.
 * @constructor
 */
 function CredStoreTokenCache() {
  this._entries = null;
 }

 //
// Internal helper functions for serializing and
// deserializing cache entries.
//

function deserializeBool(str) {
  return str.toLowerCase() === 'true';
}

function deserializeDate(str) {
  return new Date(str);
}

function deserializeNum(str) {
  return +str;
}

// Mapping of field names that need special handling
// on deserialization (typically type conversions)
// to the appropriate deserializer functions.
var fieldsToConvert = {
  expiresIn: deserializeNum,
  expiresOn: deserializeDate,
  isUserIdDisplayable: deserializeBool,
  isMRRT: deserializeBool
};

function deserializeEntry(entry) {
  return _.chain(entry)
    .pairs()
    .map(function (pair) {
      var key = pair[0], value = pair[1];
      if (_.has(fieldsToConvert, key)) {
        return [key, fieldsToConvert[key](value)];
      }
      return pair;
    })
    .object()
    .value();
}

_.extend(CredStoreTokenCache.prototype, {
  /**
  * Load the cache entries. Does a lazy load,
  * loads from OS on first request, otherwise
  * returns in-memory copy.
  *
  * @param {function(err, Array)} callback callback
  *                               receiving cache entries.
  */
  _loadEntries: function (callback) {
    var self = this;
    if (self._entries !== null) {
      return callback(null, self._entries);
    }

    var entries = [];
    credStore.list()
      .pipe(es.mapSync(function (entry) {
        // Most fields are stored in targetName,
        // access token and refresh token are stored in
        // credentials.
        var authResult = encoding.decodeObject(entry.targetName);
        var credential = encoding.decodeObject(new Buffer(entry.credential, 'hex').toString('utf8'));
        authResult.accessToken = credential.a;
        authResult.refreshToken = credential.r;

        return deserializeEntry(authResult);
      }))
      .on('data', function (entry) {
        entries.push(entry);
      })
      .on('end', function (err) {
        if (!err) {
          self._entries = entries;
        }
        callback(err, entries);
      });
  },

  /**
   * Removes a collection of entries from the cache in a single batch operation.
   * @param  {Array}   entries  An array of cache entries to remove.
   * @param  {Function} callback This function is called when the operation is complete.  Any error is provided as the
   *                             first parameter.
   */
  remove: function remove(entries, callback) {
    var self = this;

    function shouldKeep(entry) {
      if (_.findWhere(entry, entries)) {
        return false;
      }
      return true;
    }

    self._loadEntries(function (err, _entries) {
      if (err) { return callback(err); }

      var grouped = _.groupBy(_entries, shouldKeep);
      var entriesToRemove = grouped[false] || [];
      var entriesToKeep = grouped[true] || [];

      function removeEntry(entry, callback) {
        var targetName = encoding.encodeObject(_.omit(entry, ['accessToken', 'refreshToken']));
        credStore.remove(targetName, callback);
      }

      async.eachSeries(entriesToRemove, removeEntry, function (err) {
        if (err) { return callback(err); }
        self._entries = entriesToKeep;
        callback();
      });
    });
  },

  /**
   * Adds a collection of entries to the cache in a single batch operation.
   * @param {Array}   entries  An array of entries to add to the cache.
   * @param  {Function} callback This function is called when the operation is complete.  Any error is provided as the
   *                             first parameter.
   */
  add: function add(entries, callback) {
    var self = this;

    self._loadEntries(function (err, _entries) {
      if (err) { return callback(err); }

      // Remove any entries that are duplicates of the existing
      // cache elements.
      _.each(_entries, function(element) {
        _.each(entries, function(addElement, index) {
          if (_.isEqual(element, addElement)) {
            entries[index] = null;
          }
        });
      });

      // Add the new entries to the end of the cache.
      entries = _.compact(entries);

      // Add the new entries to the credstore
      function addToCredStore(entry, callback) {
        var targetName = encoding.encodeObject(_.omit(entry, ['accessToken', 'refreshToken']));
        var credential = encoding.encodeObject({a: entry.accessToken, r: entry.refreshToken});
        credStore.set(targetName, credential, function (err) {
          if (!err) {
            self._entries.push(entry);
          }
          callback(err);
        });
      }

      async.eachSeries(entries, addToCredStore, callback);
    });
  },

  /**
   * Finds all entries in the cache that match all of the passed in values.
   * @param  {object}   query    This object will be compared to each entry in the cache.  Any entries that
   *                             match all of the values in this object will be returned.  All the values
   *                             in the passed in object must match values in a potentialy returned object
   *                             exactly.  The returned object may have more values than the passed in query
   *                             object.
   * @param  {TokenCacheFindCallback} callback
   */
  find: function find(query, callback) {
    var self = this;

    self._loadEntries(function (err, _entries) {
      if (err) { return callback(err); }

      var results = _.where(_entries, query);
      callback(null, results);
    });
  }
});

module.exports = CredStoreTokenCache;
<|endoftext|>