<commit_before>"use strict";

(function() {

	/**
	 * A simple buffer to abstract data types away
	 *
	 * @constructor
	 * @param {Array.<number>=} arr
	 */
	function Buffer(arr) {
		this.buffer = arr ? arr : [];

	}
	Object.defineProperty(Buffer.prototype, 'length', {get: function() { return this.buffer.length; },
	                               		   			   enumerable : false});
	/**
	 * @param {Array.<number>} arr
	 */
	Buffer.prototype.appendArray = function(arr) {
		for (var i=0; i < arr.length; ++i) {
			this.buffer.push(arr[i]);
		}
	};

	/**
	 * @param {number} idx
	 * @param {number} num
	 */
	Buffer.prototype.writeShort = function(idx, num) {
		this.buffer[idx] = num & 255;
		this.buffer[idx + 1] = (num >> 8) & 255;
	};

	/**
	 * @param {number} idx
	 * @param {number} num
	 */
	Buffer.prototype.writeInt = function(idx, num) {
		this.buffer[idx] = num & 255;
		this.buffer[idx + 1] = (num >> 8) & 255;
		this.buffer[idx + 2] = (num >> 16) & 255;
		this.buffer[idx + 3] = (num >> 24) & 255;
	};

	/**
	 * @param {number} idx
	 * @param {number} num
	 */
	Buffer.prototype.writeLong = function(idx, num) {
		this.buffer[idx] = num & 255;
		this.buffer[idx + 1] = (num >> 8) & 255;
		this.buffer[idx + 2] = (num >> 16) & 255;
		this.buffer[idx + 3] = (num >> 24) & 255;
		this.buffer[idx + 4] = 0;
		this.buffer[idx + 5] = 0;
		this.buffer[idx + 6] = 0;
		this.buffer[idx + 7] = 0;
	};

	/**
	 * @param {number} idx
	 * @param {string} str
	 */
	Buffer.prototype.writeString = function(idx, str) {
		for (var i=0; i < str.length; ++i) {
			this.buffer[idx + i] = str.charCodeAt(i) & 255;
		}
	};

	/**
	 * @param {number} idx
	 * @param {Buffer} buf
	 */
	Buffer.prototype.writeBuffer = function(idx, buf) {
		var len = buf.length;
		var myBuf = this.buffer;
		var remBuf = buf.buffer;
		for (var i=0; i < len;) {
			myBuf[idx++] = remBuf[i++];
		}
	};

	/**
	 * @constructor
	 * @param {string} id
	 */
	function Chunk(id) {
		this.id = id;
		this.data = new Buffer();
	};

	Chunk.prototype.getBuffer = function() {
		var buffer = new Buffer();
		buffer.writeString(0, this.id);
		buffer.writeBuffer(8, this.data);
		if (this.data.length % 2 == 0) {
			buffer.writeInt(4, this.data.length);
		} else {
			buffer.writeInt(4, this.data.length + 1);
			buffer.appendArray([0]);
		}
		return buffer;
	};

	/**
	 * @constructor
 	 * @param {string} type
	 */
	function List(type) {
		this.type = type;
		this.elements = [];
	};

	List.prototype.getBuffer = function() {
		var buffer = new Buffer();
		buffer.writeString(0, 'LIST');
		buffer.writeString(8, this.type);

		var len = 4;
		for (var i=0; i < this.elements.length; ++i) {
			var buf = this.elements[i].getBuffer();
			buffer.writeBuffer(len + 8, buf);
			len += buf.length;
		}

		buffer.writeInt(4, len);
		return buffer;
	};

	/**
	 * @constructor
	 */
	function AVIJS() {
		this.settings = {
			width: 0,
			height: 0
		};

		this.streams = [];
	};

	AVIJS.prototype.getBuffer = function() {
		var buffer = new Buffer();
		buffer.writeString(0, 'RIFF');
		buffer.writeString(8, 'AVI ');
		var len = 4;

		var movi = new List('movi'); // Generate movi part here because we need the data offset in the index header
		var indexEntries = {};
		var offset = 0;
		for (var i=0; i < this.streams.length; ++i) {
			var buf = this.streams[i].getDataBuffer(i);
			indexEntries[(i < 10 ? '0' + i : i) + 'db'] = offset;
			movi.elements.push.apply(movi.elements, buf);
			offset += buf.length;
		}

		var moviBuf = movi.getBuffer();

		var frames = 0;
		for (var i=0; i < this.streams.length; ++i) {
			frames += this.streams[i].frames.length;
		}

		var hdrl = new List('hdrl');
		var avih = new Chunk('avih');
		avih.data.writeInt(0, 66665);
		avih.data.writeInt(4, 0); // MaxBytesPerSec
		avih.data.writeInt(8, 2); // Padding (in bytes)
		avih.data.writeInt(12, 0); // Flags
		avih.data.writeInt(16, frames); // Total Frames
		avih.data.writeInt(20, 0); // Initial Frames
		avih.data.writeInt(24, this.streams.length); // Total Streams
		avih.data.writeInt(28, 0); // Suggested Buffer size
		avih.data.writeInt(32, this.settings.width); // pixel width
		avih.data.writeInt(36, this.settings.height); // pixel height
		avih.data.writeInt(40, 0); // Reserved int[4]
		avih.data.writeInt(44, 0);
		avih.data.writeInt(48, 0);
		avih.data.writeInt(52, 0);
		hdrl.elements.push(avih);

		for (var i=0; i < this.streams.length; ++i) {
			hdrl.elements.push(this.streams[i].getHeaderBuffer(i));
		}
		var hdrlBuf = hdrl.getBuffer();
		buffer.writeBuffer(8 + len, hdrlBuf);
		len += hdrlBuf.length;

		buffer.writeBuffer(8 + len, moviBuf); // write movi part afterwards
		len += moviBuf.length;

		buffer.writeInt(4, len);
		var blob = new BlobBuilder();
		blob.append((new Uint8Array(buffer.buffer)).buffer);
		return blob.getBlob('video/avi');
	};

	/**
	 * @constructor
 	 * @param {number} fps
	 */
	AVIJS.Stream = function(fps, width, height) {
		this.fps = fps;
		this.width = width;
		this.height = height;
		this.frames = [];
	};

	AVIJS.Stream.prototype.addRGBAFrame = function(imgData) {
		var frame = [];
		for (var i=0; i < imgData.length; i += 4) {
			frame.push(imgData[i+1], imgData[i+2], imgData[i]);
		}
		this.frames.push(frame);
	};

	AVIJS.Stream.prototype.getHeaderBuffer = function(idx) {
		var list = new List('strl');
		var strh = new Chunk('strh');
		strh.data.writeString(0, 'vids'); // fourCC
		strh.data.writeString(4, 'DIB '); // Uncompressed
		strh.data.writeInt(8, 0); // Flags
		strh.data.writeShort(12, 1); // Priority
		strh.data.writeShort(14, 0); // Language
		strh.data.writeInt(16, 0); // Initial frames
		strh.data.writeInt(20, 1); // Scale
		strh.data.writeInt(24, this.fps); // Rate
		strh.data.writeInt(28, 0); // Startdelay
		strh.data.writeInt(32, this.frames.length); // Length
		strh.data.writeInt(36, this.width * this.height * 3); // suggested buffer size
		strh.data.writeInt(40, -1); // quality
		strh.data.writeInt(44, 0); // sampleSize
		strh.data.writeShort(48, 0); // Rect left
		strh.data.writeShort(50, 0); // Rect top
		strh.data.writeShort(52, this.width); // Rect width
		strh.data.writeShort(54, this.height); // Rect height
		list.elements.push(strh);

		var strf = new Chunk('strf');
		strf.data.writeInt(0, 40); // struct size
		strf.data.writeInt(4, this.width); // width
		strf.data.writeInt(8, -this.height); // height
		strf.data.writeShort(12, 1); // planes
		strf.data.writeShort(14, 24); // bits per pixel
		strf.data.writeInt(16, 0); // compression
		strf.data.writeInt(20, 0); // image size
		strf.data.writeInt(24, 0); // x pixels per meter
		strf.data.writeInt(28, 0); // y pixels per meter
		strf.data.writeInt(32, 0); // colortable used
		strf.data.writeInt(36, 0); // colortable important
		list.elements.push(strf);

		var indx = new Chunk('indx');
		indx.data.writeShort(0, 2); // LongsPerEntry
		indx.data.appendArray([0, 0x01]); // indexSubType + indexType
		indx.data.writeInt(4, this.frames.length); // numIndexEntries
		indx.data.writeString(8, (idx < 10 ? '0' + idx : idx) + 'db'); // chunkID
		indx.data.writeLong(12, 1056); // data offset
		indx.data.writeInt(20, 0); // reserved

		var offset = 0;
		for (var i=0; i < this.frames.length; ++i) { // index entries
			indx.data.writeInt(24 + i * 8, offset); // offset
			indx.data.writeInt(28 + i * 8, this.frames[i].length + 12); // size
			offset += this.frames[i].length + 8;
		}
		list.elements.push(indx);

		return list;
	};

	AVIJS.Stream.prototype.getDataBuffer = function(idx) {
		var chunks = [];
		for (var i=0; i < this.frames.length; ++i) {
			var chk = new Chunk((idx < 10 ? '0' + idx : idx) + 'db');
			chk.data.appendArray(this.frames[i]);
			chunks.push(chk);
		}
		return chunks;
	};

	window['AVIJS'] = AVIJS;
})();<commit_msg>Extended the bits per pixel to 32 again to debug index creation easier.<commit_after>"use strict";

(function() {

	/**
	 * A simple buffer to abstract data types away
	 *
	 * @constructor
	 * @param {Array.<number>=} arr
	 */
	function Buffer(arr) {
		this.buffer = arr ? arr : [];

	}
	Object.defineProperty(Buffer.prototype, 'length', {get: function() { return this.buffer.length; },
	                               		   			   enumerable : false});
	/**
	 * @param {Array.<number>} arr
	 */
	Buffer.prototype.appendArray = function(arr) {
		for (var i=0; i < arr.length; ++i) {
			this.buffer.push(arr[i]);
		}
	};

	/**
	 * @param {number} idx
	 * @param {number} num
	 */
	Buffer.prototype.writeShort = function(idx, num) {
		this.buffer[idx] = num & 255;
		this.buffer[idx + 1] = (num >> 8) & 255;
	};

	/**
	 * @param {number} idx
	 * @param {number} num
	 */
	Buffer.prototype.writeInt = function(idx, num) {
		this.buffer[idx] = num & 255;
		this.buffer[idx + 1] = (num >> 8) & 255;
		this.buffer[idx + 2] = (num >> 16) & 255;
		this.buffer[idx + 3] = (num >> 24) & 255;
	};

	/**
	 * @param {number} idx
	 * @param {number} num
	 */
	Buffer.prototype.writeLong = function(idx, num) {
		this.buffer[idx] = num & 255;
		this.buffer[idx + 1] = (num >> 8) & 255;
		this.buffer[idx + 2] = (num >> 16) & 255;
		this.buffer[idx + 3] = (num >> 24) & 255;
		this.buffer[idx + 4] = 0;
		this.buffer[idx + 5] = 0;
		this.buffer[idx + 6] = 0;
		this.buffer[idx + 7] = 0;
	};

	/**
	 * @param {number} idx
	 * @param {string} str
	 */
	Buffer.prototype.writeString = function(idx, str) {
		for (var i=0; i < str.length; ++i) {
			this.buffer[idx + i] = str.charCodeAt(i) & 255;
		}
	};

	/**
	 * @param {number} idx
	 * @param {Buffer} buf
	 */
	Buffer.prototype.writeBuffer = function(idx, buf) {
		var len = buf.length;
		var myBuf = this.buffer;
		var remBuf = buf.buffer;
		for (var i=0; i < len;) {
			myBuf[idx++] = remBuf[i++];
		}
	};

	/**
	 * @constructor
	 * @param {string} id
	 */
	function Chunk(id) {
		this.id = id;
		this.data = new Buffer();
	};

	Chunk.prototype.getBuffer = function() {
		var buffer = new Buffer();
		buffer.writeString(0, this.id);
		buffer.writeBuffer(8, this.data);
		if (this.data.length % 2 == 0) {
			buffer.writeInt(4, this.data.length);
		} else {
			buffer.writeInt(4, this.data.length + 1);
			buffer.appendArray([0]);
		}
		return buffer;
	};

	/**
	 * @constructor
 	 * @param {string} type
	 */
	function List(type) {
		this.type = type;
		this.elements = [];
	};

	List.prototype.getBuffer = function() {
		var buffer = new Buffer();
		buffer.writeString(0, 'LIST');
		buffer.writeString(8, this.type);

		var len = 4;
		for (var i=0; i < this.elements.length; ++i) {
			var buf = this.elements[i].getBuffer();
			buffer.writeBuffer(len + 8, buf);
			len += buf.length;
		}

		buffer.writeInt(4, len);
		return buffer;
	};

	/**
	 * @constructor
	 */
	function AVIJS() {
		this.settings = {
			width: 0,
			height: 0
		};

		this.streams = [];
	};

	AVIJS.prototype.getBuffer = function() {
		var buffer = new Buffer();
		buffer.writeString(0, 'RIFF');
		buffer.writeString(8, 'AVI ');
		var len = 4;

		var movi = new List('movi'); // Generate movi part here because we need the data offset in the index header
		var indexEntries = {};
		var offset = 0;
		for (var i=0; i < this.streams.length; ++i) {
			var buf = this.streams[i].getDataBuffer(i);
			indexEntries[(i < 10 ? '0' + i : i) + 'db'] = offset;
			movi.elements.push.apply(movi.elements, buf);
			offset += buf.length;
		}

		var moviBuf = movi.getBuffer();

		var frames = 0;
		for (var i=0; i < this.streams.length; ++i) {
			frames += this.streams[i].frames.length;
		}

		var hdrl = new List('hdrl');
		var avih = new Chunk('avih');
		avih.data.writeInt(0, 66665);
		avih.data.writeInt(4, 0); // MaxBytesPerSec
		avih.data.writeInt(8, 2); // Padding (in bytes)
		avih.data.writeInt(12, 0); // Flags
		avih.data.writeInt(16, frames); // Total Frames
		avih.data.writeInt(20, 0); // Initial Frames
		avih.data.writeInt(24, this.streams.length); // Total Streams
		avih.data.writeInt(28, 0); // Suggested Buffer size
		avih.data.writeInt(32, this.settings.width); // pixel width
		avih.data.writeInt(36, this.settings.height); // pixel height
		avih.data.writeInt(40, 0); // Reserved int[4]
		avih.data.writeInt(44, 0);
		avih.data.writeInt(48, 0);
		avih.data.writeInt(52, 0);
		hdrl.elements.push(avih);

		for (var i=0; i < this.streams.length; ++i) {
			hdrl.elements.push(this.streams[i].getHeaderBuffer(i));
		}
		var hdrlBuf = hdrl.getBuffer();
		buffer.writeBuffer(8 + len, hdrlBuf);
		len += hdrlBuf.length;

		buffer.writeBuffer(8 + len, moviBuf); // write movi part afterwards
		len += moviBuf.length;

		buffer.writeInt(4, len);
		var blob = new BlobBuilder();
		blob.append((new Uint8Array(buffer.buffer)).buffer);
		return blob.getBlob('video/avi');
	};

	/**
	 * @constructor
 	 * @param {number} fps
	 */
	AVIJS.Stream = function(fps, width, height) {
		this.fps = fps;
		this.width = width;
		this.height = height;
		this.frames = [];
	};

	AVIJS.Stream.prototype.addRGBAFrame = function(imgData) {
		var frame = [];
		for (var i=0; i < imgData.length; i += 4) {
			frame.push(imgData[i+1], imgData[i+2], imgData[i],0);
		}
		this.frames.push(frame);
	};

	AVIJS.Stream.prototype.getHeaderBuffer = function(idx) {
		var list = new List('strl');
		var strh = new Chunk('strh');
		strh.data.writeString(0, 'vids'); // fourCC
		strh.data.writeString(4, 'DIB '); // Uncompressed
		strh.data.writeInt(8, 0); // Flags
		strh.data.writeShort(12, 1); // Priority
		strh.data.writeShort(14, 0); // Language
		strh.data.writeInt(16, 0); // Initial frames
		strh.data.writeInt(20, 1); // Scale
		strh.data.writeInt(24, this.fps); // Rate
		strh.data.writeInt(28, 0); // Startdelay
		strh.data.writeInt(32, this.frames.length); // Length
		strh.data.writeInt(36, this.width * this.height * 3); // suggested buffer size
		strh.data.writeInt(40, -1); // quality
		strh.data.writeInt(44, 0); // sampleSize
		strh.data.writeShort(48, 0); // Rect left
		strh.data.writeShort(50, 0); // Rect top
		strh.data.writeShort(52, this.width); // Rect width
		strh.data.writeShort(54, this.height); // Rect height
		list.elements.push(strh);

		var strf = new Chunk('strf');
		strf.data.writeInt(0, 40); // struct size
		strf.data.writeInt(4, this.width); // width
		strf.data.writeInt(8, -this.height); // height
		strf.data.writeShort(12, 1); // planes
		strf.data.writeShort(14, 32); // bits per pixel
		strf.data.writeInt(16, 0); // compression
		strf.data.writeInt(20, 0); // image size
		strf.data.writeInt(24, 0); // x pixels per meter
		strf.data.writeInt(28, 0); // y pixels per meter
		strf.data.writeInt(32, 0); // colortable used
		strf.data.writeInt(36, 0); // colortable important
		list.elements.push(strf);

		var indx = new Chunk('indx');
		indx.data.writeShort(0, 2); // LongsPerEntry
		indx.data.appendArray([0, 0x01]); // indexSubType + indexType
		indx.data.writeInt(4, this.frames.length); // numIndexEntries
		indx.data.writeString(8, (idx < 10 ? '0' + idx : idx) + 'db'); // chunkID
		indx.data.writeLong(12, 1056); // data offset
		indx.data.writeInt(20, 0); // reserved

		var offset = 0;
		for (var i=0; i < this.frames.length; ++i) { // index entries
			indx.data.writeInt(24 + i * 8, offset); // offset
			indx.data.writeInt(28 + i * 8, this.frames[i].length + 8); // size
			offset += this.frames[i].length + 8;
		}
		list.elements.push(indx);

		return list;
	};

	AVIJS.Stream.prototype.getDataBuffer = function(idx) {
		var chunks = [];
		for (var i=0; i < this.frames.length; ++i) {
			var chk = new Chunk((idx < 10 ? '0' + idx : idx) + 'db');
			chk.data.appendArray(this.frames[i]);
			chunks.push(chk);
		}
		return chunks;
	};

	window['AVIJS'] = AVIJS;
})();<|endoftext|>


<commit_before>"use strict";

(function() {

	/**
	 * A simple buffer to abstract data types away
	 *
	 * @constructor
	 * @param {Array.<number>=} arr
	 */
	function Buffer(arr) {
		this.buffer = arr ? arr : [];

	}
	Object.defineProperty(Buffer.prototype, 'length', {get: function() { return this.buffer.length; },
	                               		   			   enumerable : false});
	/**
	 * @param {Array.<number>} arr
	 */
	Buffer.prototype.appendArray = function(arr) {
		for (var i=0; i < arr.length; ++i) {
			this.buffer.push(arr[i]);
		}
	};

	/**
	 * @param {number} idx
	 * @param {number} num
	 */
	Buffer.prototype.writeShort = function(idx, num) {
		this.buffer[idx] = num & 255;
		this.buffer[idx + 1] = (num >> 8) & 255;
	};

	/**
	 * @param {number} idx
	 * @param {number} num
	 */
	Buffer.prototype.writeInt = function(idx, num) {
		this.buffer[idx] = num & 255;
		this.buffer[idx + 1] = (num >> 8) & 255;
		this.buffer[idx + 2] = (num >> 16) & 255;
		this.buffer[idx + 3] = (num >> 24) & 255;
	};

	/**
	 * @param {number} idx
	 * @param {number} num
	 */
	Buffer.prototype.writeLong = function(idx, num) {
		this.buffer[idx] = num & 255;
		this.buffer[idx + 1] = (num >> 8) & 255;
		this.buffer[idx + 2] = (num >> 16) & 255;
		this.buffer[idx + 3] = (num >> 24) & 255;
		this.buffer[idx + 4] = 0;
		this.buffer[idx + 5] = 0;
		this.buffer[idx + 6] = 0;
		this.buffer[idx + 7] = 0;
	};

	/**
	 * @param {number} idx
	 * @param {string} str
	 */
	Buffer.prototype.writeString = function(idx, str) {
		for (var i=0; i < str.length; ++i) {
			this.buffer[idx + i] = str.charCodeAt(i) & 255;
		}
	};

	/**
	 * @param {number} idx
	 * @param {Buffer} buf
	 */
	Buffer.prototype.writeBuffer = function(idx, buf) {
		var len = buf.length;
		var myBuf = this.buffer;
		var remBuf = buf.buffer;
		for (var i=0; i < len;) {
			myBuf[idx++] = remBuf[i++];
		}
	};

	/**
	 * @constructor
	 * @param {string} id
	 */
	function Chunk(id) {
		this.id = id;
		this.data = new Buffer();
	};

	Chunk.prototype.getBuffer = function() {
		var buffer = new Buffer();
		buffer.writeString(0, this.id);
		buffer.writeBuffer(8, this.data);
		if (this.data.length % 2 == 0) {
			buffer.writeInt(4, this.data.length);
		} else {
			buffer.writeInt(4, this.data.length + 1);
			buffer.appendArray([0]);
		}
		return buffer;
	};

	/**
	 * @constructor
 	 * @param {string} type
	 */
	function List(type) {
		this.type = type;
		this.elements = [];
	};

	List.prototype.getBuffer = function() {
		var buffer = new Buffer();
		buffer.writeString(0, 'LIST');
		buffer.writeString(8, this.type);

		var len = 4;
		for (var i=0; i < this.elements.length; ++i) {
			var buf = this.elements[i].getBuffer();
			buffer.writeBuffer(len + 8, buf);
			len += buf.length;
		}

		buffer.writeInt(4, len);
		return buffer;
	};

	/**
	 * @constructor
	 */
	function AVIJS() {
		this.settings = {
			width: 0,
			height: 0
		};

		this.streams = [];
	};

	AVIJS.prototype.getBuffer = function() {
		var buffer = new Buffer();
		buffer.writeString(0, 'RIFF');
		buffer.writeString(8, 'AVI ');
		var len = 4;

		var movi = new List('movi'); // Generate movi part here because we need the data offset in the index header
		var indexEntries = {};
		var offset = 0;
		for (var i=0; i < this.streams.length; ++i) {
			var buf = this.streams[i].getDataBuffer(i);
			indexEntries[(i < 10 ? '0' + i : i) + 'db'] = offset;
			movi.elements.push.apply(movi.elements, buf);
			offset += buf.length;
		}

		var moviBuf = movi.getBuffer();

		var frames = 0;
		for (var i=0; i < this.streams.length; ++i) {
			frames += this.streams[i].frames.length;
		}

		var hdrl = new List('hdrl');
		var avih = new Chunk('avih');
		avih.data.writeInt(0, 66665);
		avih.data.writeInt(4, 0); // MaxBytesPerSec
		avih.data.writeInt(8, 2); // Padding (in bytes)
		avih.data.writeInt(12, 0); // Flags
		avih.data.writeInt(16, frames); // Total Frames
		avih.data.writeInt(20, 0); // Initial Frames
		avih.data.writeInt(24, this.streams.length); // Total Streams
		avih.data.writeInt(28, 0); // Suggested Buffer size
		avih.data.writeInt(32, this.settings.width); // pixel width
		avih.data.writeInt(36, this.settings.height); // pixel height
		avih.data.writeInt(40, 0); // Reserved int[4]
		avih.data.writeInt(44, 0);
		avih.data.writeInt(48, 0);
		avih.data.writeInt(52, 0);
		hdrl.elements.push(avih);

		for (var i=0; i < this.streams.length; ++i) {
			hdrl.elements.push(this.streams[i].getHeaderBuffer(i));
		}
		var hdrlBuf = hdrl.getBuffer();
		buffer.writeBuffer(8 + len, hdrlBuf);
		len += hdrlBuf.length;

		buffer.writeBuffer(8 + len, moviBuf); // write movi part afterwards
		len += moviBuf.length;

		buffer.writeInt(4, len);
		var blob = new BlobBuilder();
		blob.append((new Uint8Array(buffer.buffer)).buffer);
		return blob.getBlob('video/avi');
	};

	/**
	 * @constructor
 	 * @param {number} fps
	 */
	AVIJS.Stream = function(fps, width, height) {
		this.fps = fps;
		this.width = width;
		this.height = height;
		this.frames = [];
	};

	AVIJS.Stream.prototype.addRGBAFrame = function(imgData) {
		var frame = [];
		for (var i=0; i < imgData.length; i += 4) {
			frame.push(imgData[i+1], imgData[i+2], imgData[i],0);
		}
		this.frames.push(frame);
	};

	AVIJS.Stream.prototype.getHeaderBuffer = function(idx) {
		var list = new List('strl');
		var strh = new Chunk('strh');
		strh.data.writeString(0, 'vids'); // fourCC
		strh.data.writeString(4, 'DIB '); // Uncompressed
		strh.data.writeInt(8, 0); // Flags
		strh.data.writeShort(12, 1); // Priority
		strh.data.writeShort(14, 0); // Language
		strh.data.writeInt(16, 0); // Initial frames
		strh.data.writeInt(20, 1); // Scale
		strh.data.writeInt(24, this.fps); // Rate
		strh.data.writeInt(28, 0); // Startdelay
		strh.data.writeInt(32, this.frames.length); // Length
		strh.data.writeInt(36, this.width * this.height * 3); // suggested buffer size
		strh.data.writeInt(40, -1); // quality
		strh.data.writeInt(44, 0); // sampleSize
		strh.data.writeShort(48, 0); // Rect left
		strh.data.writeShort(50, 0); // Rect top
		strh.data.writeShort(52, this.width); // Rect width
		strh.data.writeShort(54, this.height); // Rect height
		list.elements.push(strh);

		var strf = new Chunk('strf');
		strf.data.writeInt(0, 40); // struct size
		strf.data.writeInt(4, this.width); // width
		strf.data.writeInt(8, -this.height); // height
		strf.data.writeShort(12, 1); // planes
		strf.data.writeShort(14, 32); // bits per pixel
		strf.data.writeInt(16, 0); // compression
		strf.data.writeInt(20, 0); // image size
		strf.data.writeInt(24, 0); // x pixels per meter
		strf.data.writeInt(28, 0); // y pixels per meter
		strf.data.writeInt(32, 0); // colortable used
		strf.data.writeInt(36, 0); // colortable important
		list.elements.push(strf);

		var indx = new Chunk('indx');
		indx.data.writeShort(0, 2); // LongsPerEntry
		indx.data.appendArray([0, 0x01]); // indexSubType + indexType
		indx.data.writeInt(4, this.frames.length); // numIndexEntries
		indx.data.writeString(8, (idx < 10 ? '0' + idx : idx) + 'db'); // chunkID
		indx.data.writeLong(12, 1056); // data offset
		indx.data.writeInt(20, 0); // reserved

		var offset = 0;
		for (var i=0; i < this.frames.length; ++i) { // index entries
			indx.data.writeInt(24 + i * 8, offset); // offset
			indx.data.writeInt(28 + i * 8, this.frames[i].length + 8); // size
			offset += this.frames[i].length + 8;
		}
		list.elements.push(indx);

		return list;
	};

	AVIJS.Stream.prototype.getDataBuffer = function(idx) {
		var chunks = [];
		for (var i=0; i < this.frames.length; ++i) {
			var chk = new Chunk((idx < 10 ? '0' + idx : idx) + 'db');
			chk.data.appendArray(this.frames[i]);
			chunks.push(chk);
		}
		return chunks;
	};

	window['AVIJS'] = AVIJS;
})();<commit_msg>Finally fixed the color palette.<commit_after>"use strict";

(function() {

	/**
	 * A simple buffer to abstract data types away
	 *
	 * @constructor
	 * @param {Array.<number>=} arr
	 */
	function Buffer(arr) {
		this.buffer = arr ? arr : [];

	}
	Object.defineProperty(Buffer.prototype, 'length', {get: function() { return this.buffer.length; },
	                               		   			   enumerable : false});
	/**
	 * @param {Array.<number>} arr
	 */
	Buffer.prototype.appendArray = function(arr) {
		for (var i=0; i < arr.length; ++i) {
			this.buffer.push(arr[i]);
		}
	};

	/**
	 * @param {number} idx
	 * @param {number} num
	 */
	Buffer.prototype.writeShort = function(idx, num) {
		this.buffer[idx] = num & 255;
		this.buffer[idx + 1] = (num >> 8) & 255;
	};

	/**
	 * @param {number} idx
	 * @param {number} num
	 */
	Buffer.prototype.writeInt = function(idx, num) {
		this.buffer[idx] = num & 255;
		this.buffer[idx + 1] = (num >> 8) & 255;
		this.buffer[idx + 2] = (num >> 16) & 255;
		this.buffer[idx + 3] = (num >> 24) & 255;
	};

	/**
	 * @param {number} idx
	 * @param {number} num
	 */
	Buffer.prototype.writeLong = function(idx, num) {
		this.buffer[idx] = num & 255;
		this.buffer[idx + 1] = (num >> 8) & 255;
		this.buffer[idx + 2] = (num >> 16) & 255;
		this.buffer[idx + 3] = (num >> 24) & 255;
		this.buffer[idx + 4] = 0;
		this.buffer[idx + 5] = 0;
		this.buffer[idx + 6] = 0;
		this.buffer[idx + 7] = 0;
	};

	/**
	 * @param {number} idx
	 * @param {string} str
	 */
	Buffer.prototype.writeString = function(idx, str) {
		for (var i=0; i < str.length; ++i) {
			this.buffer[idx + i] = str.charCodeAt(i) & 255;
		}
	};

	/**
	 * @param {number} idx
	 * @param {Buffer} buf
	 */
	Buffer.prototype.writeBuffer = function(idx, buf) {
		var len = buf.length;
		var myBuf = this.buffer;
		var remBuf = buf.buffer;
		for (var i=0; i < len;) {
			myBuf[idx++] = remBuf[i++];
		}
	};

	/**
	 * @constructor
	 * @param {string} id
	 */
	function Chunk(id) {
		this.id = id;
		this.data = new Buffer();
	};

	Chunk.prototype.getBuffer = function() {
		var buffer = new Buffer();
		buffer.writeString(0, this.id);
		buffer.writeBuffer(8, this.data);
		if (this.data.length % 2 == 0) {
			buffer.writeInt(4, this.data.length);
		} else {
			buffer.writeInt(4, this.data.length + 1);
			buffer.appendArray([0]);
		}
		return buffer;
	};

	/**
	 * @constructor
 	 * @param {string} type
	 */
	function List(type) {
		this.type = type;
		this.elements = [];
	};

	List.prototype.getBuffer = function() {
		var buffer = new Buffer();
		buffer.writeString(0, 'LIST');
		buffer.writeString(8, this.type);

		var len = 4;
		for (var i=0; i < this.elements.length; ++i) {
			var buf = this.elements[i].getBuffer();
			buffer.writeBuffer(len + 8, buf);
			len += buf.length;
		}

		buffer.writeInt(4, len);
		return buffer;
	};

	/**
	 * @constructor
	 */
	function AVIJS() {
		this.settings = {
			width: 0,
			height: 0
		};

		this.streams = [];
	};

	AVIJS.prototype.getBuffer = function() {
		var buffer = new Buffer();
		buffer.writeString(0, 'RIFF');
		buffer.writeString(8, 'AVI ');
		var len = 4;

		var movi = new List('movi'); // Generate movi part here because we need the data offset in the index header
		var indexEntries = {};
		var offset = 0;
		for (var i=0; i < this.streams.length; ++i) {
			var buf = this.streams[i].getDataBuffer(i);
			indexEntries[(i < 10 ? '0' + i : i) + 'db'] = offset;
			movi.elements.push.apply(movi.elements, buf);
			offset += buf.length;
		}

		var moviBuf = movi.getBuffer();

		var frames = 0;
		for (var i=0; i < this.streams.length; ++i) {
			frames += this.streams[i].frames.length;
		}

		var hdrl = new List('hdrl');
		var avih = new Chunk('avih');
		avih.data.writeInt(0, 66665);
		avih.data.writeInt(4, 0); // MaxBytesPerSec
		avih.data.writeInt(8, 2); // Padding (in bytes)
		avih.data.writeInt(12, 0); // Flags
		avih.data.writeInt(16, frames); // Total Frames
		avih.data.writeInt(20, 0); // Initial Frames
		avih.data.writeInt(24, this.streams.length); // Total Streams
		avih.data.writeInt(28, 0); // Suggested Buffer size
		avih.data.writeInt(32, this.settings.width); // pixel width
		avih.data.writeInt(36, this.settings.height); // pixel height
		avih.data.writeInt(40, 0); // Reserved int[4]
		avih.data.writeInt(44, 0);
		avih.data.writeInt(48, 0);
		avih.data.writeInt(52, 0);
		hdrl.elements.push(avih);

		for (var i=0; i < this.streams.length; ++i) {
			hdrl.elements.push(this.streams[i].getHeaderBuffer(i));
		}
		var hdrlBuf = hdrl.getBuffer();
		buffer.writeBuffer(8 + len, hdrlBuf);
		len += hdrlBuf.length;

		buffer.writeBuffer(8 + len, moviBuf); // write movi part afterwards
		len += moviBuf.length;

		buffer.writeInt(4, len);
		var blob = new BlobBuilder();
		blob.append((new Uint8Array(buffer.buffer)).buffer);
		return blob.getBlob('video/avi');
	};

	/**
	 * @constructor
 	 * @param {number} fps
	 */
	AVIJS.Stream = function(fps, width, height) {
		this.fps = fps;
		this.width = width;
		this.height = height;
		this.frames = [];
	};

	AVIJS.Stream.prototype.addRGBAFrame = function(imgData) {
		var frame = [];
		for (var i=0; i < imgData.length; i += 4) {
			frame.push(imgData[i+2], imgData[i+1], imgData[i],0);
		}
		this.frames.push(frame);
	};

	AVIJS.Stream.prototype.getHeaderBuffer = function(idx) {
		var list = new List('strl');
		var strh = new Chunk('strh');
		strh.data.writeString(0, 'vids'); // fourCC
		strh.data.writeString(4, 'DIB '); // Uncompressed
		strh.data.writeInt(8, 0); // Flags
		strh.data.writeShort(12, 1); // Priority
		strh.data.writeShort(14, 0); // Language
		strh.data.writeInt(16, 0); // Initial frames
		strh.data.writeInt(20, 1); // Scale
		strh.data.writeInt(24, this.fps); // Rate
		strh.data.writeInt(28, 0); // Startdelay
		strh.data.writeInt(32, this.frames.length); // Length
		strh.data.writeInt(36, this.width * this.height * 3); // suggested buffer size
		strh.data.writeInt(40, -1); // quality
		strh.data.writeInt(44, 0); // sampleSize
		strh.data.writeShort(48, 0); // Rect left
		strh.data.writeShort(50, 0); // Rect top
		strh.data.writeShort(52, this.width); // Rect width
		strh.data.writeShort(54, this.height); // Rect height
		list.elements.push(strh);

		var strf = new Chunk('strf');
		strf.data.writeInt(0, 40); // struct size
		strf.data.writeInt(4, this.width); // width
		strf.data.writeInt(8, -this.height); // height
		strf.data.writeShort(12, 1); // planes
		strf.data.writeShort(14, 32); // bits per pixel
		strf.data.writeInt(16, 0); // compression
		strf.data.writeInt(20, 0); // image size
		strf.data.writeInt(24, 0); // x pixels per meter
		strf.data.writeInt(28, 0); // y pixels per meter
		strf.data.writeInt(32, 0); // colortable used
		strf.data.writeInt(36, 0); // colortable important
		list.elements.push(strf);

		var indx = new Chunk('indx');
		indx.data.writeShort(0, 2); // LongsPerEntry
		indx.data.appendArray([0, 0x01]); // indexSubType + indexType
		indx.data.writeInt(4, this.frames.length); // numIndexEntries
		indx.data.writeString(8, (idx < 10 ? '0' + idx : idx) + 'db'); // chunkID
		indx.data.writeLong(12, 1056); // data offset
		indx.data.writeInt(20, 0); // reserved

		var offset = 0;
		for (var i=0; i < this.frames.length; ++i) { // index entries
			indx.data.writeInt(24 + i * 8, offset); // offset
			indx.data.writeInt(28 + i * 8, this.frames[i].length + 8); // size
			offset += this.frames[i].length + 8;
		}
		list.elements.push(indx);

		return list;
	};

	AVIJS.Stream.prototype.getDataBuffer = function(idx) {
		var chunks = [];
		for (var i=0; i < this.frames.length; ++i) {
			var chk = new Chunk((idx < 10 ? '0' + idx : idx) + 'db');
			chk.data.appendArray(this.frames[i]);
			chunks.push(chk);
		}
		return chunks;
	};

	window['AVIJS'] = AVIJS;
})();<|endoftext|>


<commit_before>import React, { Component } from 'react';

// Components
import Button from "./components/button";

// Functions
import Addition from "./functions/addition";
import Subtract from "./functions/subtract";
import Multiply from "./functions/multiply";
import Divide from "./functions/divide";

import './App.css';
import './Color.css';

class App extends Component {

  constructor(props) {
    super(props);

    this.state = {
      input: "",
      math: null,
      sum: null,
      resetNext: false,
      firstEntry: true,
      theme: "red",
    };

    this.buttons = ["C", "(-)", "<", "/", 1, 2, 3, "*", 4, 5, 6, "-", 7 ,8, 9, "+", 0, ".", "="];
  }

  // Run when app is loaded
  componentWillMount() {
    // this.getLocalStorage();
  }

  handleInputClick(input) {
        this.setState({whatevz:false});

    if (typeof input === "number") {

      if (this.state.resetNext) {
        // reset input if resetNext = true
        this.setState({input: input.toString(), resetNext: false});
      } else {

        // Concatenate input string
        this.setState({input : this.state.input + input.toString()});
      }

    } else if (input === "(-)") {
      // If user input negative (-)
      this.handelNegative();

    } else if (input === ".") {
      // If user input negative (-)
      this.handelComma();

    } else if (input === "C" || input.toUpperCase() === "C") {
      // If user input C
      this.handelClear();

    } else if (input === "=") {
      // If user input =
      this.handelEqual();

    } else if (input === "<") {
      // If user input < (backspace)
      this.handelBackspace();

    } else {
      // If user input +, -, *, /...
      this.setState({resetNext: true});

      if (input !== this.state.math && this.state.math && this.state.math !== "=") {
        // If the user switch between +, -, *, /
        this.handelMathSwitch(input);

      } else {
        this.handelMath(input);
      }

    }
  }

  // ---------------------
  // Handle negative input, only allow one minus key
  // ---------------------
  handelNegative() {
    if (this.state.resetNext) {
      // reset input if resetNext = true
      this.setState({input: "-", resetNext: false});
    } else if (this.state.input.includes("-")) {
      return;
    } else {
        this.setState({input: "-" + this.state.input});
    }
  }

  // ---------------------
  // Handle comma input, only allow one comma key
  // ---------------------
  handelComma() {
    if (this.state.resetNext || this.state.input === "") {
      // reset input if resetNext = true
      this.setState({input: "0.", resetNext: false});
    } else {
      this.setState({input: this.state.input + "."});
    }
  }

  // ---------------------
  // Reset state to original
  // ---------------------
  handelClear() {
    this.setState({
      input: "",
      math: null,
      sum: null,
      resetNext: false,
      firstEntry: true,
    });
  }

  // ---------------------
  // Delete the last number in string, backspace
  // ---------------------
  handelBackspace() {
    this.setState({input: this.state.input.slice(0, -1)});
  }

  // ---------------------
  // Handle equal: handle math, set new state
  // ---------------------
  handelEqual() {
    this.handelMath(this.state.math);
    this.setState({
      firstEntry: true,
      math: "=",
      resetNext: true,
      sum: null,
      whatevz: true
    });
  }

  // ---------------------
  // Handle math switch: handle math and set new state
  // ---------------------
  handelMathSwitch(input) {
    this.handelMath(this.state.math);
    this.setState({
      firstEntry: false,
      math: input,
      resetNext: true
    });
  }

  // ---------------------
  // Save state to localStorage
  // ---------------------
  postLocalStorage() {
    const jsonString = JSON.stringify(this.state);
    localStorage.setItem('calc', jsonString);
  }

  // ---------------------
  // Load state from localStorage
  // ---------------------
  getLocalStorage() {
    const savedState = JSON.parse(localStorage.getItem('calc'));
    this.setState(savedState);
  }

  // ---------------------
  // Handle all math, set new state
  // ---------------------
  handelMath(input) {
    if (this.state.firstEntry) {
      // This only moves the input to state.sum
      this.setState({
        sum: this.state.input,
        math: input,
        firstEntry: false,
      });
    } else {
      switch(input) {
        case "+":
          this.setState({
            input: Addition(this.state.sum, this.state.input).toString(),
            sum: Addition(this.state.sum, this.state.input),
            math: "+",
          });
          break;
        case "-":
          this.setState({
            input: Subtract(this.state.sum, this.state.input).toString(),
            sum: Subtract(this.state.sum, this.state.input),
            math: "-"
          });
          break;
        case "*":
          this.setState({
            input: Multiply(this.state.sum, this.state.input).toString(),
            sum: Multiply(this.state.sum, this.state.input),
            math: "*"
          });
          break;
        case "/":
          this.setState({
            input: Divide(this.state.sum, this.state.input).toString(),
            sum: Divide(this.state.sum, this.state.input),
            math: "/"
          });
          break;
        default:
          break;
      }
    }
  }

  handelChangeTheme() {
    const newTheme = this.state.theme === "red" ? "blue" : "red";
    this.setState({theme: newTheme});
  }

  // React, render to DOM
  render() {
    // this.postLocalStorage();
    return (

        <div className={`calculator ${this.state.theme}`}>

            <button className="themes" onClick={() => this.handelChangeTheme()}>∞</button>

calc

          <div className={`input ${this.state.whatevz ? "animationz" : ""}`}>
            {this.state.input ? this.state.input : 0}

          {/*

            {this.handelHistory()}

 */}

            {this.buttons.map((int) => <Button key={int} onClick={this.handleInputClick.bind(this)} math={this.state.math}>{int}</Button>)}

    );
  }
}
export default App;
<commit_msg>fixa comma<commit_after>
import React, { Component } from 'react';

// Components
import Button from "./components/button";

// Functions
import Addition from "./functions/addition";
import Subtract from "./functions/subtract";
import Multiply from "./functions/multiply";
import Divide from "./functions/divide";
import Rotation from 'react-rotation'

import './App.css';
import './Color.css';

class App extends Component {

  state = {
      input: "0",
      math: null,
      sum: null,
      resetNext: false,
      firstEntry: true,
      theme: "red",
    };

    buttons = ["C", "(-)", "<", "/", 1, 2, 3, "*", 4, 5, 6, "-", 7 ,8, 9, "+", 0, ".", "="];

  // Run when app is loaded
  componentWillMount() {
    // this.getLocalStorage();
  }

  handleInputClick(input) {
        this.setState({whatevz:false});

    if (typeof input === "number") {

      if (this.state.resetNext) {
        // reset input if resetNext = true
        this.setState({input: input.toString(), resetNext: false});
      } else {

        // Concatenate input string
        this.setState({input : this.state.input + input.toString()});
      }

    } else if (input === "(-)") {
      // If user input negative (-)
      this.handelNegative();

    } else if (input === ".") {
      // If user input negative (-)
      this.handelComma();

    } else if (input === "C" || input.toUpperCase() === "C") {
      // If user input C
      this.handelClear();

    } else if (input === "=") {
      // If user input =
      this.handelEqual();

    } else if (input === "<") {
      // If user input < (backspace)
      this.handelBackspace();

    } else {
      // If user input +, -, *, /...
      this.setState({resetNext: true});

      if (input !== this.state.math && this.state.math && this.state.math !== "=") {
        // If the user switch between +, -, *, /
        this.handelMathSwitch(input);

      } else {
        this.handelMath(input);
      }

    }
  }

  // ---------------------
  // Handle negative input, only allow one minus key
  // ---------------------
  handelNegative() {
    if (this.state.resetNext) {
      // reset input if resetNext = true
      this.setState({input: "-", resetNext: false});
    } else if (this.state.input.includes("-")) {
      return;
    } else {
        this.setState({input: "-" + this.state.input});
    }
  }

  // ---------------------
  // Handel comma input, only allow one comma key
  // ---------------------
  handelComma() {
    if (this.state.resetNext || this.state.input === "") {
      // reset input if resetNext = true
      this.setState({input: "0.", resetNext: false});
    } else {
      var reg = new RegExp("[.]");
      reg= reg.test(this.state.input);
      this.setState({input: (reg) ? this.state.input.toString() : this.state.input + "."});
    }
  }

  // ---------------------
  // Reset state to original
  // ---------------------
  handelClear() {
    this.setState({
      input: "",
      math: null,
      sum: null,
      resetNext: false,
      firstEntry: true,
    });
  }

  // ---------------------
  // Delete the last number in string, backspace
  // ---------------------
  handelBackspace() {
    this.setState({input: this.state.input.slice(0, -1)});
  }

  // ---------------------
  // Handel equal: handel math, set new state
  // ---------------------
  handelEqual() {
    this.handelMath(this.state.math);
    this.setState({
      firstEntry: true,
      math: "=",
      resetNext: true,
      sum: null,
      whatevz: true
    });
  }

  // ---------------------
  // Handel math switch: handel math and set new state
  // ---------------------
  handelMathSwitch(input) {
    this.handelMath(this.state.math);
    this.setState({
      firstEntry: false,
      math: input,
      resetNext: true
    });
  }

  // ---------------------
  // Save state to localStorage
  // ---------------------
  postLocalStorage() {
    const jsonString = JSON.stringify(this.state);
    localStorage.setItem('calc', jsonString);
  }

  // ---------------------
  // Load state from localStorage
  // ---------------------
  getLocalStorage() {
    const savedState = JSON.parse(localStorage.getItem('calc'));
    this.setState(savedState);
  }

  // ---------------------
  // Handle all math, set new state
  // ---------------------
  handelMath(input) {
    if (this.state.firstEntry) {
      // This only moves the input to state.sum
      this.setState({
        sum: this.state.input,
        math: input,
        firstEntry: false,
      });
    } else {
      switch(input) {
        case "+":
          this.setState({
            input: Addition(this.state.sum, this.state.input).toString(),
            sum: Addition(this.state.sum, this.state.input),
            math: "+",
          });
          break;
        case "-":
          this.setState({
            input: Subtract(this.state.sum, this.state.input).toString(),
            sum: Subtract(this.state.sum, this.state.input),
            math: "-"
          });
          break;
        case "*":
          this.setState({
            input: Multiply(this.state.sum, this.state.input).toString(),
            sum: Multiply(this.state.sum, this.state.input),
            math: "*"
          });
          break;
        case "/":
          this.setState({
            input: Divide(this.state.sum, this.state.input).toString(),
            sum: Divide(this.state.sum, this.state.input),
            math: "/"
          });
          break;
        default:
          break;
      }
    }
  }

  handelChangeTheme() {
    const newTheme = this.state.theme === "red" ? "blue" : "red";
    this.setState({theme: newTheme});
  }

  // React, render to DOM
  render() {
    // this.postLocalStorage();
    return (

        <div className={`calculator ${this.state.theme}`}>

            <button className="themes" onClick={() => this.handelChangeTheme()}>∞</button>

calc

          <div className={`input ${this.state.whatevz ? "animationz" : ""}`}>
            {this.state.input ? this.state.input : 0}

          {/*

            {this.handelHistory()}

 */}

            {this.buttons.map((int) => <Button key={int} onClick={this.handleInputClick.bind(this)} math={this.state.math}>{int}</Button>)}

    );
  }
}
export default App;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import NotificationSystem from 'react-notification-system';
import ProjectInfo from './ProjectInfo.js';
import Charts from './Charts.js';
import { loadData, loadStats } from './data.js';
import Refreshed from './Refreshed.js';

const REFRESH_STATS_TIMEOUT = 5000;
const CELEBRATE_BACKER_TIMEOUT = 400;
const NEW_BACKER_AUDIO = '/audio/newbacker.wav';
const NOTIFICATION_AUTO_DISMISS = 60;
const ERROR_NOTIFICATION_AUTO_DISMISS = 5000;

const notificationStyle = {
  NotificationItem: {
    DefaultStyle: { // Applied to every notification, regardless of the notification level
      borderTop: '',
      boxShadow: '0px 0px 7px 0px rgba(0,0,0,0.5)',
      color: '#020621'
    },
    success: { // Applied only to the success notification item
      backgroundColor: '#0BD318'
    }
  },
  Title: {
    DefaultStyle: {
      color: '#020621'
    }
  }
};

export default class App extends Component {
  state = {
    project: location.pathname
  };
  notificationSystem = null;
  newBackers = [];
  celebratingBackers = false;

  componentDidMount() {
    if (this.state.project === '/') {
      this.showError(
        'Please specify project in url',
        'Use part after https://kickstarter.com/projects/',
        0
      );
    } else {
      this.loadProjectData();
      this.refreshStats();
    }
  }
  componentWillUnmount() {
    clearTimeout(this.refreshTimeout);
    clearTimeout(this.celebrateNewBackerTimeout);
    if (this.loadStatsCancelablePromise) {
      this.loadStatsCancelablePromise.cancel();
    }
    if (this.loadDataCancelablePromise) {
      this.loadDataCancelablePromise.cancel();
    }
  }

  loadProjectData = () => {
    this.loadDataCancelablePromise = loadData(this.state.project);
    this.loadDataCancelablePromise.promise
    .then(data => {
      this.setState({
        projectData: data
      });
    })
    .catch(err => this.showError('Couldn\'t load project data', err.message, 5));
  }

  refreshStats = () => {
    this.loadStatsCancelablePromise = loadStats(this.state.project);
    this.loadStatsCancelablePromise.promise
    .then(data => {
      if (data.error) {
        this.showError('Couldn\'t refresh stats', data.error, 5);
      } else {
        this.setStats(data.project);
        this.refreshedMessage.show();
      }
      this.refreshTimeout = setTimeout(this.refreshStats, REFRESH_STATS_TIMEOUT);
    })
    .catch(err => {
      this.showError('Couldn\'t refresh stats', err.message, 5);
      this.refreshTimeout = setTimeout(this.refreshStats, REFRESH_STATS_TIMEOUT);
    });
  }

  setStats = (data) => {
    this.celebrateNewBackers(data);
    this.setState({
      projectData: {
        ...this.state.projectData,
        backers_count: data.backers_count,
        pledged: parseFloat(data.pledged)
      }
    });
  }
  celebrateNewBackers = (data) => {
    if (!this.state.projectData) return;
    const prevBackersCount = this.state.projectData.backers_count;
    const newBackersCount = data.backers_count;
    for (let count = prevBackersCount; count < newBackersCount; count++) {
      this.newBackers.push(count + 1);
    }
    if (!this.celebratingBackers) {
      this.celebratingBackers = true;
      this.celebrateNewBacker();
    }
  }
  celebrateNewBacker = () => {
    const backer = this.newBackers.shift();
    if (!backer) {
      this.celebratingBackers = false;
      return;
    }
    this.notificationSystem.addNotification({
      level: 'success',
      title: 'New backer!',
      message: `#${backer}`,
      autoDismiss: NOTIFICATION_AUTO_DISMISS,
      dismissible: false,
      position: 'br'
    });
    const newBackerAudio = new Audio(NEW_BACKER_AUDIO);
    newBackerAudio.play();
    if (this.newBackers.length > 0) {
      clearTimeout(this.celebrateNewBackerTimeout);
      this.celebrateNewBackerTimeout = setTimeout(this.celebrateNewBacker, CELEBRATE_BACKER_TIMEOUT);
    } else {
      this.celebratingBackers = false;
    }
  }

  showError = (title, message, autoDismiss = ERROR_NOTIFICATION_AUTO_DISMISS) => {
    this.notificationSystem.addNotification({
      level: 'error',
      title,
      message,
      autoDismiss,
      dismissible: true,
      position: 'br'
    });
  }

  render() {
    const { projectData, project } = this.state;
    // To refresh graph images every hour we generate a different
    // url every hour, causing them to reload every hour
    const hour = new Date().getHours();
    return (

        {projectData ? <ProjectInfo projectData={projectData} /> : null}
        {projectData ? <Charts project={project} updateSeed={hour} /> : null}
        <Refreshed ref={c => this.refreshedMessage = c} />
        <NotificationSystem ref={c => this.notificationSystem = c} style={notificationStyle} />

    );
  }
}
<commit_msg>Keep trying to load project<commit_after>import React, { Component } from 'react';
import NotificationSystem from 'react-notification-system';
import ProjectInfo from './ProjectInfo.js';
import Charts from './Charts.js';
import { loadData, loadStats } from './data.js';
import Refreshed from './Refreshed.js';

const REFRESH_STATS_TIMEOUT = 5000;
const CELEBRATE_BACKER_TIMEOUT = 400;
const NEW_BACKER_AUDIO = '/audio/newbacker.wav';
const NOTIFICATION_AUTO_DISMISS = 60;
const ERROR_NOTIFICATION_AUTO_DISMISS = 5000;
const RETRY_TIMEOUT = 5000;

const notificationStyle = {
  NotificationItem: {
    DefaultStyle: { // Applied to every notification, regardless of the notification level
      borderTop: '',
      boxShadow: '0px 0px 7px 0px rgba(0,0,0,0.5)',
      color: '#020621'
    },
    success: { // Applied only to the success notification item
      backgroundColor: '#0BD318'
    }
  },
  Title: {
    DefaultStyle: {
      color: '#020621'
    }
  }
};

export default class App extends Component {
  state = {
    project: location.pathname
  };
  notificationSystem = null;
  newBackers = [];
  celebratingBackers = false;

  componentDidMount() {
    if (this.state.project === '/') {
      this.showError(
        'Please specify project in url',
        'Use part after https://kickstarter.com/projects/',
        0
      );
    } else {
      this.loadProjectData();
      this.refreshStats();
    }
  }
  componentWillUnmount() {
    clearTimeout(this.refreshTimeout);
    clearTimeout(this.retryTimeout);
    clearTimeout(this.celebrateNewBackerTimeout);
    if (this.loadStatsCancelablePromise) {
      this.loadStatsCancelablePromise.cancel();
    }
    if (this.loadDataCancelablePromise) {
      this.loadDataCancelablePromise.cancel();
    }
  }

  loadProjectData = () => {
    this.loadDataCancelablePromise = loadData(this.state.project);
    this.loadDataCancelablePromise.promise
    .then(data => {
      this.setState({
        projectData: data
      });
    })
    .catch(err => {
      this.showError('Couldn\'t load project data', err.message, 5);
      this.retryTimeout = setTimeout(this.loadProjectData, RETRY_TIMEOUT);
    });
  }

  refreshStats = () => {
    this.loadStatsCancelablePromise = loadStats(this.state.project);
    this.loadStatsCancelablePromise.promise
    .then(data => {
      if (data.error) {
        this.showError('Couldn\'t refresh stats', data.error, 5);
      } else {
        this.setStats(data.project);
        this.refreshedMessage.show();
      }
      this.refreshTimeout = setTimeout(this.refreshStats, REFRESH_STATS_TIMEOUT);
    })
    .catch(err => {
      this.showError('Couldn\'t refresh stats', err.message, 5);
      this.refreshTimeout = setTimeout(this.refreshStats, REFRESH_STATS_TIMEOUT);
    });
  }

  setStats = (data) => {
    this.celebrateNewBackers(data);
    this.setState({
      projectData: {
        ...this.state.projectData,
        backers_count: data.backers_count,
        pledged: parseFloat(data.pledged)
      }
    });
  }
  celebrateNewBackers = (data) => {
    if (!this.state.projectData) return;
    const prevBackersCount = this.state.projectData.backers_count;
    const newBackersCount = data.backers_count;
    for (let count = prevBackersCount; count < newBackersCount; count++) {
      this.newBackers.push(count + 1);
    }
    if (!this.celebratingBackers) {
      this.celebratingBackers = true;
      this.celebrateNewBacker();
    }
  }
  celebrateNewBacker = () => {
    const backer = this.newBackers.shift();
    if (!backer) {
      this.celebratingBackers = false;
      return;
    }
    this.notificationSystem.addNotification({
      level: 'success',
      title: 'New backer!',
      message: `#${backer}`,
      autoDismiss: NOTIFICATION_AUTO_DISMISS,
      dismissible: false,
      position: 'br'
    });
    const newBackerAudio = new Audio(NEW_BACKER_AUDIO);
    newBackerAudio.play();
    if (this.newBackers.length > 0) {
      clearTimeout(this.celebrateNewBackerTimeout);
      this.celebrateNewBackerTimeout = setTimeout(this.celebrateNewBacker, CELEBRATE_BACKER_TIMEOUT);
    } else {
      this.celebratingBackers = false;
    }
  }

  showError = (title, message, autoDismiss = ERROR_NOTIFICATION_AUTO_DISMISS) => {
    this.notificationSystem.addNotification({
      level: 'error',
      title,
      message,
      autoDismiss,
      dismissible: true,
      position: 'br'
    });
  }

  render() {
    const { projectData, project } = this.state;
    // To refresh graph images every hour we generate a different
    // url every hour, causing them to reload every hour
    const hour = new Date().getHours();
    return (

        {projectData ? <ProjectInfo projectData={projectData} /> : null}
        {projectData ? <Charts project={project} updateSeed={hour} /> : null}
        <Refreshed ref={c => this.refreshedMessage = c} />
        <NotificationSystem ref={c => this.notificationSystem = c} style={notificationStyle} />

    );
  }
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name        PHP SDK Entity generator
// @namespace   php
// @description Generates php class that can be used in SDK
// @include     https://start.exactonline.nl/docs/HlpRestAPIResourcesDetails.aspx?*
// @version     1
// @grant       none
// ==/UserScript==

(function() {
  /** Add textarea to display php code **/
  // Push current content to the left.
  $('body > form').css('float', 'left');
  $('body > form').css('width', '50%');
  $('body > form').css('overflow', 'auto');

  // Add textarea to body, css might need some work.
  $('<textarea/>', {
    id : 'php',
    style: 'min-height:800px; width: 47%; margin-left:10px;'
  }).appendTo('body');

  /** Initialize variables **/
  var primarykey = 'ID';
  var data = {};
  // Fetch entity URL and strip '/api/v1/{division}/'
  var url = $('#serviceUri').text().replace(/^\/api\/v[0-9]\/[^/]+\//, '');
  var classname = url.replace(/.+\/(.+?)s?$/,'$1'); // Last part after slash should be the (plural) classname.

  /** Fetch attribute information **/
  $('#referencetable tr input').each(function() {
    data[$(this).attr('name')] = {
      'type' : $(this).attr('data-type').replace('Edm.', ''),
      'description' : $(this).parent().siblings('td:last-child').text().trim()
    };

    // Set primarykey when found. Should be first itteration.
    if ($(this).attr('data-key') == "True") {
      primarykey = $(this).attr('name');
    }
  });

  /** Build php code **/
  phptxt = "<?php namespace Picqer\\Financials\\Exact;\n\n/**";

  // Build docblock
  phptxt += "\n * Class " + classname;
  phptxt += "\n *\n * @package Picqer\\Financials\\Exact";
  phptxt += "\n * @see " + window.location.href;
  phptxt += "\n *";
  $.each(data,function(attribute, info){
    phptxt += "\n * @property " + info.type + " $" + attribute + " " + info.description;
  });
  phptxt += "\n */";

  // Build class
  phptxt += "\nclass " + classname + " extends Model\n{\n\n    use Query\\Findable;\n    use Persistance\\Storable;";
  if (primarykey != 'ID') {
    phptxt += "\n\n    protected $primaryKey = " + primarykey + ";";
  }
  phptxt += "\n\n    protected $fillable = [";
  $.each(Object.keys(data), function(){
    phptxt += "\n        '" + this + "',";
  });
  phptxt += "\n    ];";
  phptxt += "\n\n    protected $url = '" + url + "';";
  phptxt += "\n\n}";

  // Display php code
  $('#php').text(phptxt);

})();<commit_msg>primaryKey property should be a string<commit_after>// ==UserScript==
// @name        PHP SDK Entity generator
// @namespace   php
// @description Generates php class that can be used in SDK
// @include     https://start.exactonline.nl/docs/HlpRestAPIResourcesDetails.aspx?*
// @version     1
// @grant       none
// ==/UserScript==

(function() {
  /** Add textarea to display php code **/
  // Push current content to the left.
  $('body > form').css('float', 'left');
  $('body > form').css('width', '50%');
  $('body > form').css('overflow', 'auto');

  // Add textarea to body, css might need some work.
  $('<textarea/>', {
    id : 'php',
    style: 'min-height:800px; width: 47%; margin-left:10px;'
  }).appendTo('body');

  /** Initialize variables **/
  var primarykey = 'ID';
  var data = {};
  // Fetch entity URL and strip '/api/v1/{division}/'
  var url = $('#serviceUri').text().replace(/^\/api\/v[0-9]\/[^/]+\//, '');
  var classname = url.replace(/.+\/(.+?)s?$/,'$1'); // Last part after slash should be the (plural) classname.

  /** Fetch attribute information **/
  $('#referencetable tr input').each(function() {
    data[$(this).attr('name')] = {
      'type' : $(this).attr('data-type').replace('Edm.', ''),
      'description' : $(this).parent().siblings('td:last-child').text().trim()
    };

    // Set primarykey when found. Should be first itteration.
    if ($(this).attr('data-key') == "True") {
      primarykey = $(this).attr('name');
    }
  });

  /** Build php code **/
  phptxt = "<?php namespace Picqer\\Financials\\Exact;\n\n/**";

  // Build docblock
  phptxt += "\n * Class " + classname;
  phptxt += "\n *\n * @package Picqer\\Financials\\Exact";
  phptxt += "\n * @see " + window.location.href;
  phptxt += "\n *";
  $.each(data,function(attribute, info){
    phptxt += "\n * @property " + info.type + " $" + attribute + " " + info.description;
  });
  phptxt += "\n */";

  // Build class
  phptxt += "\nclass " + classname + " extends Model\n{\n\n    use Query\\Findable;\n    use Persistance\\Storable;";
  if (primarykey != 'ID') {
    phptxt += "\n\n    protected $primaryKey = '" + primarykey + "';";
  }
  phptxt += "\n\n    protected $fillable = [";
  $.each(Object.keys(data), function(){
    phptxt += "\n        '" + this + "',";
  });
  phptxt += "\n    ];";
  phptxt += "\n\n    protected $url = '" + url + "';";
  phptxt += "\n\n}";

  // Display php code
  $('#php').text(phptxt);

})();<|endoftext|>


<commit_before>import React from 'react';
import { Link } from 'react-router'

import getMuiTheme from 'material-ui/styles/getMuiTheme';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import RaisedButton from 'material-ui/RaisedButton';
import {Card, CardActions, CardHeader, CardMedia, CardTitle, CardText} from 'material-ui/Card';
import TextField from 'material-ui/TextField';
import FlatButton from 'material-ui/FlatButton';
import keycode from 'keycode';
import {Tabs, Tab} from 'material-ui/Tabs';
import {Toolbar, ToolbarGroup, ToolbarSeparator, ToolbarTitle} from 'material-ui/Toolbar';
import Paper from 'material-ui/Paper';
import Snackbar from 'material-ui/Snackbar';

import Repo from './RepoPanel';
import RepoOps from './RepoOps';
import CommitTree from './CommitTreePanel';
import StagingArea from './StagingAreaPanel';

// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
import injectTapEventPlugin from 'react-tap-event-plugin';

import Git from 'nodegit';

const darkMuiTheme = getMuiTheme(darkBaseTheme);

const constStyles = {
  fontFamily: `apple-system,
          BlinkMacSystemFont,"Segoe UI",
          Roboto,Helvetica,Arial,sans-serif,
          "Apple Color Emoji","Segoe UI Emoji",
          "Segoe UI Symbol"`,
  darkRed: '#b60a0a',
};

class gitFunctions {
  static repoExists(path) {
    const pathToRepo = require('path').resolve(path);

    return Git.Repository.open(pathToRepo);
  }
}

class MainToolbar extends React.Component {
  constructor(props) {
    super(props);
    this.state={
      toggle: false
    };
  }

  changeToolbar = (label) => {
    this.props.changeToolbar(label);
  }

  render = () => {
    const styles = {
      toolbar:{
        display: 'flex',
        alignItems: 'center',
        backgroundColor: '#EAEAEA',
        padding: 12,
        paddingLeft: '5%',
        border: '2px solid #EAEAEA',
        height: 40,
      },
      button: {
        position: 'relative',
        margin: 35,
        borderRadius: 4,
        marginRight: 5,
        marginLeft: 5,
        fontFamily: `'Oswald', sans-serif`,
        fontSize: 17,
        maxWidth: 140,
        textOverflow: 'ellipsis',
        overflow: 'hidden',
        whiteSpace: 'nowrap',
        textTransform: 'uppercase',
        color: '#656565',
        textDecoration: 'none',
        padding: 7,
        paddingLeft: 13,
        paddingRight: 13,
        backgroundColor: '#ffffff',
      }
    };

    return (

          <Link style={styles.button}
          to='/repo'>
            {'Repos'}
          </Link>

          {this.props.repoName?
          <Link to='/repoOps'
          style={styles.button}>
            {this.props.repoName}
          </Link>
            :
}

    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currRepoIndex: -1,
      repos: [],
      openWrongDirSnackBar: false,
    };
  }

  handleKeyPressChange = (passedPath) => {
    //TODO: Check if passed path is valid or not
    //extracts the name of the repo from the path name
    const repoName = passedPath.slice(passedPath.lastIndexOf('/')+1);
    let flag = false;
    let pos;

    this.state.repos.forEach( (repo, index) => {

      //if repo already exists in the state
      if(repo.path === passedPath) {
        pos = index;
        flag = true;
      }
    });

    if( flag ) {
      this.setState({
        currRepoIndex: pos
      });
    }
    else
    {
      //checks if the folder contains a git repo
      let promise = gitFunctions.repoExists(passedPath);
      promise.then( () => {
        let repos = this.state.repos;
        repos.push({
          name: repoName,
          path: passedPath
        });
        let repoIndex = repos.length - 1;

        this.setState({
          currRepoIndex: repoIndex,
          repos: repos
        });
        this.changeToolbar(repoName);
      })
      .catch( (failure) => {
        console.log('Could not find a git repository in the folder',
          'Make sure you have selected the correct folder');
        console.log('failure',failure);
        this.setState({
          openWrongDirSnackBar: true
        });
      });
    }
  }

  handleRepoClick = (index) => {
    window.setTimeout( () => {
      this.setState({
        currRepoIndex: index
      });
      this.changeToolbar(this.state.repos[index].name);
    },0);
  }

  changeToolbar = (label) => {

  }

  handleRequestClose = () => {
    this.setState({
      openWrongDirSnackBar: false
    });
  }

  componentWillMount = () => {
    injectTapEventPlugin();
    this.handleKeyPressChange('../dummy-repo');
  }

  componentWillReceiveProps = (newprops) => {
  }

  //for dev prurposes only
  componentDidMount = () => {
  }

  render() {

    const styles = {
      mainPanel: {
        height:500,
        // border: '1px solid blue',
        overflow: 'hidden',
      },
      repos: {
      },
      tabs: {
        overflow: 'hidden',
        width: '50%',
      },
      font: {
        fontFamily: '"Roboto", sans-serif',
      },
    };

    const wrongDirError = 'Could not find a git repository in the folder. Make sure you have selected the correct folder';

    let renderRepo = this.state.repos[this.state.currRepoIndex]?this.state.repos[this.state.currRepoIndex]:null;

    let children = React.Children.map( this.props.children, child => {
      if(child.type === Repo) {

        return React.cloneElement(child, {
          repos: this.state.repos,
          pathToRepo: renderRepo? renderRepo.path: '',
          selectRepo: this.handleRepoClick,
          onKeyPress: this.handleKeyPressChange,
        });

      }
      else if(child.type === RepoOps) {

        return React.cloneElement(child, {
          repo: renderRepo,
        });

      }
    });

    return (
      <MuiThemeProvider muiTheme={getMuiTheme()}>

          <MainToolbar repoName={renderRepo? renderRepo.name: ''} />

          <Snackbar open={this.state.openWrongDirSnackBar} message={wrongDirError} autoHideDuration={4000}
          style={styles.font} onRequestClose={this.handleRequestClose}/>
          {children || <Repo style={styles.repos} repos={this.state.repos} pathToRepo={renderRepo? renderRepo.path: ''}
            selectRepo={this.handleRepoClick} onKeyPress={this.handleKeyPressChange}/>}

      </MuiThemeProvider>
    )
  }

}

export default App;<commit_msg>Misc: Removed unused styles<commit_after>import React from 'react';
import { Link } from 'react-router'

import getMuiTheme from 'material-ui/styles/getMuiTheme';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import RaisedButton from 'material-ui/RaisedButton';
import {Card, CardActions, CardHeader, CardMedia, CardTitle, CardText} from 'material-ui/Card';
import TextField from 'material-ui/TextField';
import FlatButton from 'material-ui/FlatButton';
import keycode from 'keycode';
import {Tabs, Tab} from 'material-ui/Tabs';
import {Toolbar, ToolbarGroup, ToolbarSeparator, ToolbarTitle} from 'material-ui/Toolbar';
import Paper from 'material-ui/Paper';
import Snackbar from 'material-ui/Snackbar';

import Repo from './RepoPanel';
import RepoOps from './RepoOps';
import CommitTree from './CommitTreePanel';
import StagingArea from './StagingAreaPanel';

// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
import injectTapEventPlugin from 'react-tap-event-plugin';

import Git from 'nodegit';

const darkMuiTheme = getMuiTheme(darkBaseTheme);

const constStyles = {
  fontFamily: `apple-system,
          BlinkMacSystemFont,"Segoe UI",
          Roboto,Helvetica,Arial,sans-serif,
          "Apple Color Emoji","Segoe UI Emoji",
          "Segoe UI Symbol"`,
  darkRed: '#b60a0a',
};

class gitFunctions {
  static repoExists(path) {
    const pathToRepo = require('path').resolve(path);

    return Git.Repository.open(pathToRepo);
  }
}

class MainToolbar extends React.Component {
  constructor(props) {
    super(props);
    this.state={
      toggle: false
    };
  }

  changeToolbar = (label) => {
    this.props.changeToolbar(label);
  }

  render = () => {
    const styles = {
      toolbar:{
        display: 'flex',
        alignItems: 'center',
        backgroundColor: '#EAEAEA',
        padding: 12,
        paddingLeft: '5%',
        border: '2px solid #EAEAEA',
        height: 40,
      },
      button: {
        position: 'relative',
        margin: 35,
        borderRadius: 4,
        marginRight: 5,
        marginLeft: 5,
        fontFamily: `'Oswald', sans-serif`,
        fontSize: 17,
        maxWidth: 140,
        textOverflow: 'ellipsis',
        overflow: 'hidden',
        whiteSpace: 'nowrap',
        textTransform: 'uppercase',
        color: '#656565',
        textDecoration: 'none',
        padding: 7,
        paddingLeft: 13,
        paddingRight: 13,
        backgroundColor: '#ffffff',
      }
    };

    return (

          <Link style={styles.button}
          to='/repo'>
            {'Repos'}
          </Link>

          {this.props.repoName?
          <Link to='/repoOps'
          style={styles.button}>
            {this.props.repoName}
          </Link>
            :
}

    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currRepoIndex: -1,
      repos: [],
      openWrongDirSnackBar: false,
    };
  }

  handleKeyPressChange = (passedPath) => {
    //TODO: Check if passed path is valid or not
    //extracts the name of the repo from the path name
    const repoName = passedPath.slice(passedPath.lastIndexOf('/')+1);
    let flag = false;
    let pos;

    this.state.repos.forEach( (repo, index) => {

      //if repo already exists in the state
      if(repo.path === passedPath) {
        pos = index;
        flag = true;
      }
    });

    if( flag ) {
      this.setState({
        currRepoIndex: pos
      });
    }
    else
    {
      //checks if the folder contains a git repo
      let promise = gitFunctions.repoExists(passedPath);
      promise.then( () => {
        let repos = this.state.repos;
        repos.push({
          name: repoName,
          path: passedPath
        });
        let repoIndex = repos.length - 1;

        this.setState({
          currRepoIndex: repoIndex,
          repos: repos
        });
        this.changeToolbar(repoName);
      })
      .catch( (failure) => {
        console.log('Could not find a git repository in the folder',
          'Make sure you have selected the correct folder');
        console.log('failure',failure);
        this.setState({
          openWrongDirSnackBar: true
        });
      });
    }
  }

  handleRepoClick = (index) => {
    window.setTimeout( () => {
      this.setState({
        currRepoIndex: index
      });
      this.changeToolbar(this.state.repos[index].name);
    },0);
  }

  changeToolbar = (label) => {

  }

  handleRequestClose = () => {
    this.setState({
      openWrongDirSnackBar: false
    });
  }

  componentWillMount = () => {
    injectTapEventPlugin();
    this.handleKeyPressChange('../dummy-repo');
  }

  componentWillReceiveProps = (newprops) => {
  }

  //for dev prurposes only
  componentDidMount = () => {
  }

  render() {

    const styles = {
      mainPanel: {
        height:500,
        // border: '1px solid blue',
        overflow: 'hidden',
      },
      font: {
        fontFamily: '"Roboto", sans-serif',
      },
    };

    const wrongDirError = 'Could not find a git repository in the folder. Make sure you have selected the correct folder';

    let renderRepo = this.state.repos[this.state.currRepoIndex]?this.state.repos[this.state.currRepoIndex]:null;

    let children = React.Children.map( this.props.children, child => {
      if(child.type === Repo) {

        return React.cloneElement(child, {
          repos: this.state.repos,
          pathToRepo: renderRepo? renderRepo.path: '',
          selectRepo: this.handleRepoClick,
          onKeyPress: this.handleKeyPressChange,
        });

      }
      else if(child.type === RepoOps) {

        return React.cloneElement(child, {
          repo: renderRepo,
        });

      }
    });

    return (
      <MuiThemeProvider muiTheme={getMuiTheme()}>

          <MainToolbar repoName={renderRepo? renderRepo.name: ''} />

          <Snackbar open={this.state.openWrongDirSnackBar} message={wrongDirError} autoHideDuration={4000}
          style={styles.font} onRequestClose={this.handleRequestClose}/>
          {children || <Repo repos={this.state.repos} pathToRepo={renderRepo? renderRepo.path: ''}
            selectRepo={this.handleRepoClick} onKeyPress={this.handleKeyPressChange}/>}

      </MuiThemeProvider>
    )
  }

}

export default App;<|endoftext|>


<commit_before>console.log('DadaTube: userscript.js loaded');

// https://github.com/DVLP/localStorageDB#you-can-use-it-as-a-one-liner-in-your-js-code
!function(){function e(t,o){return n?void(n.transaction("s").objectStore("s").get(t).onsuccess=function(e){var t=e.target.result&&e.target.result.v||null;o(t)}):void setTimeout(function(){e(t,o)},100)}var t=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB;if(!t)return void console.error("indexDB not supported");var n,o={k:"",v:""},r=t.open("d2",1);r.onsuccess=function(e){n=this.result},r.onerror=function(e){console.error("indexedDB request error"),console.log(e)},r.onupgradeneeded=function(e){n=null;var t=e.target.result.createObjectStore("s",{keyPath:"k"});t.transaction.oncomplete=function(e){n=e.target.db}},window.ldb={get:e,set:function(e,t){o.k=e,o.v=t,n.transaction("s","readwrite").objectStore("s").put(o)}}}();

$(function () {
    'use strict';

    console.log('DadaTube: userscript.js ready');

    var options = {
        hiddenOpacity: 0.1,
        removeJunkStrategy: 'remove'
    };

    function addGlobalStyle(css) {
        var head, style;
        head = document.getElementsByTagName('head')[0];
        if (!head) {
            throw 'no head?!';
        }
        style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = css;
        head.appendChild(style);
    }

    var hiddenClass = 'dnthHidden';

    addGlobalStyle('.' + hiddenClass + ' { opacity: ' + options.hiddenOpacity + '; transition: opacity 0.2s ease-in-out; }');

    /**
     * Show/hide hidables in the view
     */
    var hidableView = {
        hide: function ($hidables, onComplete) {
            $hidables.addClass(hiddenClass);

            if (onComplete) {
                onComplete();
            }
        },
        show: function ($hidables, onComplete) {
            $hidables.removeClass(hiddenClass);

            if (onComplete) {
                onComplete();
            }
        }
    };

    var hidablesController = {
        showAll: function () {
            hidablesController.show($hidables);
        },
        hideAll: function () {
            hidablesController.hide($hidables);
        },
        show: function ($hidables) {
            $hidables.each(function () {
                hiddenHidablesStorage.remove(identifyHidable($(this)));
            });

            hidableView.show($hidables);
        },
        hide: function ($hidables) {
            $hidables.each(function () {
                hiddenHidablesStorage.add(identifyHidable($(this)));
            });

            hidableView.hide($hidables);
        },
        toggleVisibility: function ($hidable) {
            if ($hidable.hasClass(hiddenClass)) {
                hidablesController.show($hidable);
            } else {
                hidablesController.hide($hidable);
            }
        }
    };

    var HidablesStorage = function (storageDriver, prefix) {
        this.has = function (id, callback) {
            if (!id) {
                callback(false);
            }

            ldb.get(prefix + id, function (value) {
                console.log('HidablesStorage get', prefix + id, value);
                callback(value ? true : false);
            });
            // callback(storageDriver[prefix + id] ? true : false);
        };

        this.add = function (id) {
            console.log('HidablesStorage.add(' + id + ') called');

            ldb.set(prefix + id, (new Date()).toJSON());

            ldb.get(prefix + id, function (value) {
                console.log('value for "' + prefix + id + '" was set: "' + value + '"');
            });

            // storageDriver[prefix + id] = (new Date()).toJSON();
        };

        this.remove = function (id) {
            this.has(id, function (has) {
                if (has) {
                    ldb.set(prefix + id, null);
                    // storageDriver.removeItem(prefix + id);
                }
            });
        };
    }; // eo Storage

    /**
     * Hidables IDs storage helper.
     * Keys have prefix to avoid collisions and easily find items.
     * Key hold hidable IDs, values have the date they were hidden.
     */
    var hiddenHidablesStorage = new HidablesStorage(localStorage, 'dnthHiddenHidable_');

    /**
     * Gets hidable identifying data
     */
    var identifyHidable = function ($hidable) {
        return $hidable
            .find('a.thumb-link')
            .attr('href')
            .match('/watch\\?v=(.*)')[1];
    };

    /**
     * Items to hide
     *
     * We look in related items on single video player page.
     * First item is a playlist, we skip it.
     */
    var $hidables = $('#watch-related')
        .find('.related-list-item:not(:first-child)');

    // $hidables.each(function () {
    //     console.log('hidable on start', identifyHidable($(this)));
    // });

    /**
     * Clicking on a table row (hidable), hides it.
     */
    $hidables.click(function () {
        console.log('hidable clicked');

        hidablesController.toggleVisibility($(this));
    });

    function selectHidablesFromStorage(returnResultCallback) {
        var selectedIds = [];

        var hidablesLength = $hidables.length;
        var hidablesProcessed = 0;

        $hidables.each(function (index, value) {
            var id = identifyHidable($(value));

            hiddenHidablesStorage.has(id, function (has) {
                hidablesProcessed++;

                if (has) {
                    selectedIds.push(id);
                }

                if (hidablesProcessed === hidablesLength) {
                    document.selectedIds = selectedIds;

                    document.hids = $hidables;

                    var $result = $hidables.filter(function () {
                        return !$.inArray(
                            identifyHidable($(this)),
                            selectedIds
                        );
                    });

                    returnResultCallback($result);
                }
            });
        });
    }

    /**
     * Page loaded: removing elements already hidden and saved to localStorage
     */
    selectHidablesFromStorage(function ($found) {
        console.log('found to remove on start', $found);

        hidableView.hide($found);
        // $found.remove();
    });

    /**
     * Hide/remove from storage when space is hit
     */
    var removedAfterSpace = false;
    $(document).keydown(function (event) {
        if (32 == event.keyCode) {
            console.log('space was hit');

            selectHidablesFromStorage(function ($found) {
                if (removedAfterSpace) {
                    hidableView.hide($found);
                } else {
                    hidableView.hide($found);
                    // $found.remove();

                    removedAfterSpace = true;
                }
            });
        }
    });

    $('<button>hide all and close</button>')
        .addClass('yt-uix-button yt-uix-button-size-default yt-uix-button-expander')
        .insertAfter('#watch-more-related-button')
        .click(function () {
            hidablesController.hideAll();

            window.close();
        });
});
<commit_msg>space hiding disabled for a while<commit_after>console.log('DadaTube: userscript.js loaded');

// https://github.com/DVLP/localStorageDB#you-can-use-it-as-a-one-liner-in-your-js-code
!function(){function e(t,o){return n?void(n.transaction("s").objectStore("s").get(t).onsuccess=function(e){var t=e.target.result&&e.target.result.v||null;o(t)}):void setTimeout(function(){e(t,o)},100)}var t=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB;if(!t)return void console.error("indexDB not supported");var n,o={k:"",v:""},r=t.open("d2",1);r.onsuccess=function(e){n=this.result},r.onerror=function(e){console.error("indexedDB request error"),console.log(e)},r.onupgradeneeded=function(e){n=null;var t=e.target.result.createObjectStore("s",{keyPath:"k"});t.transaction.oncomplete=function(e){n=e.target.db}},window.ldb={get:e,set:function(e,t){o.k=e,o.v=t,n.transaction("s","readwrite").objectStore("s").put(o)}}}();

$(function () {
    'use strict';

    console.log('DadaTube: userscript.js ready');

    var options = {
        hiddenOpacity: 0.1,
        removeJunkStrategy: 'remove'
    };

    function addGlobalStyle(css) {
        var head, style;
        head = document.getElementsByTagName('head')[0];
        if (!head) {
            throw 'no head?!';
        }
        style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = css;
        head.appendChild(style);
    }

    var hiddenClass = 'dnthHidden';

    addGlobalStyle('.' + hiddenClass + ' { opacity: ' + options.hiddenOpacity + '; transition: opacity 0.2s ease-in-out; }');

    /**
     * Show/hide hidables in the view
     */
    var hidableView = {
        hide: function ($hidables, onComplete) {
            $hidables.addClass(hiddenClass);

            if (onComplete) {
                onComplete();
            }
        },
        show: function ($hidables, onComplete) {
            $hidables.removeClass(hiddenClass);

            if (onComplete) {
                onComplete();
            }
        }
    };

    var hidablesController = {
        showAll: function () {
            hidablesController.show($hidables);
        },
        hideAll: function () {
            hidablesController.hide($hidables);
        },
        show: function ($hidables) {
            $hidables.each(function () {
                hiddenHidablesStorage.remove(identifyHidable($(this)));
            });

            hidableView.show($hidables);
        },
        hide: function ($hidables) {
            $hidables.each(function () {
                hiddenHidablesStorage.add(identifyHidable($(this)));
            });

            hidableView.hide($hidables);
        },
        toggleVisibility: function ($hidable) {
            if ($hidable.hasClass(hiddenClass)) {
                hidablesController.show($hidable);
            } else {
                hidablesController.hide($hidable);
            }
        }
    };

    var HidablesStorage = function (storageDriver, prefix) {
        this.has = function (id, callback) {
            if (!id) {
                callback(false);
            }

            ldb.get(prefix + id, function (value) {
                console.log('HidablesStorage get', prefix + id, value);
                callback(value ? true : false);
            });
            // callback(storageDriver[prefix + id] ? true : false);
        };

        this.add = function (id) {
            console.log('HidablesStorage.add(' + id + ') called');

            ldb.set(prefix + id, (new Date()).toJSON());

            ldb.get(prefix + id, function (value) {
                console.log('value for "' + prefix + id + '" was set: "' + value + '"');
            });

            // storageDriver[prefix + id] = (new Date()).toJSON();
        };

        this.remove = function (id) {
            this.has(id, function (has) {
                if (has) {
                    ldb.set(prefix + id, null);
                    // storageDriver.removeItem(prefix + id);
                }
            });
        };
    }; // eo Storage

    /**
     * Hidables IDs storage helper.
     * Keys have prefix to avoid collisions and easily find items.
     * Key hold hidable IDs, values have the date they were hidden.
     */
    var hiddenHidablesStorage = new HidablesStorage(localStorage, 'dnthHiddenHidable_');

    /**
     * Gets hidable identifying data
     */
    var identifyHidable = function ($hidable) {
        return $hidable
            .find('a.thumb-link')
            .attr('href')
            .match('/watch\\?v=(.*)')[1];
    };

    /**
     * Items to hide
     *
     * We look in related items on single video player page.
     * First item is a playlist, we skip it.
     */
    var $hidables = $('#watch-related')
        .find('.related-list-item:not(:first-child)');

    // $hidables.each(function () {
    //     console.log('hidable on start', identifyHidable($(this)));
    // });

    /**
     * Clicking on a table row (hidable), hides it.
     */
    $hidables.click(function () {
        console.log('hidable clicked');

        hidablesController.toggleVisibility($(this));
    });

    function selectHidablesFromStorage(returnResultCallback) {
        var selectedIds = [];

        var hidablesLength = $hidables.length;
        var hidablesProcessed = 0;

        $hidables.each(function (index, value) {
            var id = identifyHidable($(value));

            hiddenHidablesStorage.has(id, function (has) {
                hidablesProcessed++;

                if (has) {
                    selectedIds.push(id);
                }

                if (hidablesProcessed === hidablesLength) {
                    document.selectedIds = selectedIds;

                    document.hids = $hidables;

                    var $result = $hidables.filter(function () {
                        return !$.inArray(
                            identifyHidable($(this)),
                            selectedIds
                        );
                    });

                    returnResultCallback($result);
                }
            });
        });
    }

    /**
     * Page loaded: removing elements already hidden and saved to localStorage
     */
    selectHidablesFromStorage(function ($found) {
        console.log('found to remove on start', $found);

        hidableView.hide($found);
        // $found.remove();
    });

    /**
     * Hide/remove from storage when space is hit
     */
    // var removedAfterSpace = false;
    // $(document).keydown(function (event) {
    //     if (32 == event.keyCode) {
    //         console.log('space was hit');
    //
    //         selectHidablesFromStorage(function ($found) {
    //             if (removedAfterSpace) {
    //                 hidableView.hide($found);
    //             } else {
    //                 hidableView.hide($found);
    //                 // $found.remove();
    //
    //                 removedAfterSpace = true;
    //             }
    //         });
    //     }
    // });

    $('<button>hide all and close</button>')
        .addClass('yt-uix-button yt-uix-button-size-default yt-uix-button-expander')
        .insertAfter('#watch-more-related-button')
        .click(function () {
            hidablesController.hideAll();

            window.close();
        });
});
<|endoftext|>