/*
main class: Seriously
352021
function Seriously(options) {

		//if called without 'new', make a new object and return that
		if (window === this || !(this instanceof Seriously)) {
			return new Seriously(options);
		}

		//initialize object, private properties
		var seriously = this,
			nodes = [],
			nodesById = {},
			nodeId = 0,
			sources = [],
			targets = [],
			transforms = [],
			effects = [],
			aliases = {},
			preCallbacks = [],
			postCallbacks = [],
			glCanvas,
			gl,
			rectangleModel,
			baseShader,
			baseVertexShader, baseFragmentShader,
			Node, SourceNode, EffectNode, TransformNode, TargetNode,
			Effect, Source, Transform, Target,
			auto = false,
			isDestroyed = false,
			rafId;

		function makeGlModel(shape, gl) {
			var vertex, index, texCoord;

			if (!gl) {
				return false;
			}

			vertex = gl.createBuffer();
			gl.bindBuffer(gl.ARRAY_BUFFER, vertex);
			gl.bufferData(gl.ARRAY_BUFFER, shape.vertices, gl.STATIC_DRAW);
			vertex.size = 3;

			index = gl.createBuffer();
			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index);
			gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, shape.indices, gl.STATIC_DRAW);

			texCoord = gl.createBuffer();
			gl.bindBuffer(gl.ARRAY_BUFFER, texCoord);
			gl.bufferData(gl.ARRAY_BUFFER, shape.coords, gl.STATIC_DRAW);
			texCoord.size = 2;

			return {
				vertex: vertex,
				index: index,
				texCoord: texCoord,
				length: shape.indices.length,
				mode: shape.mode || gl.TRIANGLES
			};
		}

		function buildRectangleModel(gl) {
			var shape = {};

			shape.vertices = new Float32Array([
				-1, -1, 0,
				1, -1, 0,
				1, 1, 0,
				-1, 1, 0
			]);

			shape.indices = new Uint16Array([
				0, 1, 2,
				0, 2, 3	// Front face
			]);

			shape.coords = new Float32Array([
				0, 0,
				1, 0,
				1, 1,
				0, 1
			]);

			return makeGlModel(shape, gl);
		}

		function attachContext(context) {
			var i, node;

			gl = context;
			glCanvas = context.canvas;

			rectangleModel = buildRectangleModel(gl);

			baseShader = new ShaderProgram(gl, baseVertexShader, baseFragmentShader);

			for (i = 0; i < effects.length; i++) {
				node = effects[i];

				node.gl = gl;

				if (node.initialized) {
					node.buildShader();
				}
			}

			for (i = 0; i < sources.length; i++) {
				node = sources[i];
				node.initialize();
			}

			for (i = 0; i < targets.length; i++) {
				node = targets[i];

				if (!node.model) {
					node.model = rectangleModel;
				}

				//todo: initialize frame buffer if not main canvas
			}
		}

		/*
		runs on every frame, as long as there are media sources (img, video, canvas, etc.) to check,
		dirty target nodes or pre/post callbacks to run. any sources that are updated are set to dirty,
		forcing all dependent nodes to render
		*/
		function renderDaemon() {
			var i, node, media,
				keepRunning = false;

			rafId = null;

			if (preCallbacks.length) {
				keepRunning = true;
				for (i = 0; i < preCallbacks.length; i++) {
					preCallbacks[i].call(seriously);
				}
			}

			if (sources && sources.length) {
				keepRunning = true;
				for (i = 0; i < sources.length; i++) {
					node = sources[i];

					media = node.source;
					if (node.lastRenderTime === undefined ||
							node.dirty ||
							media.currentTime !== undefined && node.lastRenderTime !== media.currentTime) {
						node.dirty = false;
						node.setDirty();
					}
				}
			}

			for (i = 0; i < targets.length; i++) {
				node = targets[i];
				if (node.auto && node.dirty) {
					node.render();
				}
			}

			if (postCallbacks.length) {
				keepRunning = true;
				for (i = 0; i < postCallbacks.length; i++) {
					postCallbacks[i].call(seriously);
				}
			}

			//rafId may have been set again by a callback or in target.setDirty()
			if (keepRunning && !rafId) {
				rafId = requestAnimationFrame(renderDaemon);
			}
		}

		function draw(shader, model, uniforms, frameBuffer, node, options) {
			var numTextures = 0,
				name, value, shaderUniform,
				width, height,
				nodeGl = (node && node.gl) || gl;

			if (!nodeGl) {
				return;
			}

			if (node) {
				width = options && options.width || node.width || nodeGl.canvas.width;
				height = options && options.height || node.height || nodeGl.canvas.height;
			} else {
				width = options && options.width || nodeGl.canvas.width;
				height = options && options.height || nodeGl.canvas.height;
			}

			shader.use();

			nodeGl.viewport(0, 0, width, height);

			nodeGl.bindFramebuffer(nodeGl.FRAMEBUFFER, frameBuffer);

			/* todo: do this all only once at the beginning, since we only have one model? */
			nodeGl.enableVertexAttribArray(shader.location.position);
			nodeGl.enableVertexAttribArray(shader.location.texCoord);

			if (model.texCoord) {
				nodeGl.bindBuffer(nodeGl.ARRAY_BUFFER, model.texCoord);
				nodeGl.vertexAttribPointer(shader.location.texCoord, model.texCoord.size, nodeGl.FLOAT, false, 0, 0);
			}

			nodeGl.bindBuffer(nodeGl.ARRAY_BUFFER, model.vertex);
			nodeGl.vertexAttribPointer(shader.location.position, model.vertex.size, nodeGl.FLOAT, false, 0, 0);

			nodeGl.bindBuffer(nodeGl.ELEMENT_ARRAY_BUFFER, model.index);

			//default for depth is disable
			if (options && options.depth) {
				gl.enable(gl.DEPTH_TEST);
			} else {
				gl.disable(gl.DEPTH_TEST);
			}

			//default for blend is enable
			if (!options || options.blend === undefined || options.blend) {
				gl.enable(gl.BLEND);
				gl.blendFunc(
					options && options.srcRGB || gl.SRC_ALPHA,
					options && options.dstRGB || gl.ONE_MINUS_SRC_ALPHA
				);

				/*
				gl.blendFuncSeparate(
					options && options.srcRGB || gl.SRC_ALPHA,
					options && options.dstRGB || gl.ONE_MINUS_SRC_ALPHA,
					options && options.srcAlpha || gl.SRC_ALPHA,
					options && options.dstAlpha || gl.DST_ALPHA
				);
				*/
				gl.blendEquation(options && options.blendEquation || gl.FUNC_ADD);
			} else {
				gl.disable(gl.BLEND);
			}

			/* set uniforms to current values */
			for (name in uniforms) {
				if (uniforms.hasOwnProperty(name)) {
					value = uniforms[name];
					shaderUniform = shader.uniforms[name];
					if (shaderUniform) {
						if (value instanceof WebGLTexture) {
							nodeGl.activeTexture(nodeGl.TEXTURE0 + numTextures);
							nodeGl.bindTexture(nodeGl.TEXTURE_2D, value);
							shaderUniform.set(numTextures);
							numTextures++;
						} else if (value instanceof SourceNode ||
								value instanceof EffectNode ||
								value instanceof TransformNode) {
							if (value.texture) {
								nodeGl.activeTexture(nodeGl.TEXTURE0 + numTextures);
								nodeGl.bindTexture(nodeGl.TEXTURE_2D, value.texture);
								shaderUniform.set(numTextures);
								numTextures++;
							}
						} else if(value !== undefined && value !== null) {
							shaderUniform.set(value);
						}
					}
				}
			}

			//default for clear is true
			if (!options || options.clear === undefined || options.clear) {
				nodeGl.clearColor(0.0, 0.0, 0.0, 0.0);
				nodeGl.clear(nodeGl.COLOR_BUFFER_BIT | nodeGl.DEPTH_BUFFER_BIT);
			}

			// draw!
			nodeGl.drawElements(model.mode, model.length, nodeGl.UNSIGNED_SHORT, 0);

			//to protect other 3D libraries that may not remember to turn their depth tests on
			gl.enable(gl.DEPTH_TEST);
		}

		function findInputNode(source, options) {
			var node, i;

			if (source instanceof SourceNode ||
					source instanceof EffectNode ||
					source instanceof TransformNode) {
				node = source;
			} else if (source instanceof Effect ||
					source instanceof Source ||
					source instanceof Transform) {
				node = nodesById[source.id];

				if (!node) {
					throw 'Cannot connect a foreign node';
				}
			} else {
				if (typeof source === 'string' && isNaN(source)) {
					source = getElement(source, ['canvas', 'img', 'video']);
				}

				for (i = 0; i < sources.length; i++) {
					if (sources[i].source === source) {
						return sources[i];
					}
				}

				node = new SourceNode(source, options);
			}

			return node;
		}

		//trace back all sources to make sure we're not making a cyclical connection
		function traceSources(node, original) {
			var i,
				source,
				sources;

			if (!(node instanceof EffectNode) && !(node instanceof TransformNode)) {
				return false;
			}

			sources = node.sources;

			for (i in sources) {
				if (sources.hasOwnProperty(i)) {
					source = sources[i];

					if (source === original || traceSources(source, original)) {
						return true;
					}
				}
			}

			return false;
		}

		Node = function () {
			this.width = 1;
			this.height = 1;

			this.gl = gl;

			this.uniforms = {
				resolution: [this.width, this.height],
				transform: null
			};

			this.dirty = true;
			this.isDestroyed = false;

			this.seriously = seriously;

			this.id = nodeId;
			nodes.push(this);
			nodesById[nodeId] = this;
			nodeId++;
		};

		Node.prototype.setDirty = function () {
			//loop through all targets calling setDirty (depth-first)
			var i;

			if (!this.dirty) {
				this.dirty = true;
				if (this.targets) {
					for (i = 0; i < this.targets.length; i++) {
						this.targets[i].setDirty();
					}
				}
			}
		};

		Node.prototype.initFrameBuffer = function (useFloat) {
			if (gl) {
				this.frameBuffer = new FrameBuffer(gl, this.width, this.height, useFloat);
			}
		};

		Node.prototype.readPixels = function (x, y, width, height, dest) {

			if (!gl) {
				//todo: is this the best approach?
				throw 'Cannot read pixels until a canvas is connected';
			}

			//todo: check on x, y, width, height

			if (!this.frameBuffer) {
				this.initFrameBuffer();
			}

			//todo: should we render here?
			this.render();

			//todo: figure out formats and types
			if (dest === undefined) {
				dest = new Uint8Array(width * height * 4);
			} else if (!dest instanceof Uint8Array) {
				throw 'Incompatible array type';
			}

			gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer.frameBuffer); //todo: are we sure about this?
			gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, dest);

			return dest;
		};

		Node.prototype.resize = function () {
			var width,
				height;

			if (this.source) {
				width = this.source.width;
				height = this.source.height;
			} else if (this.sources && this.sources.source) {
				width = this.sources.source.width;
				height = this.sources.source.height;
			} else if (this.inputs && this.inputs.width) {
				width = this.inputs.width;
				height = this.inputs.height || width;
			} else if (this.inputs && this.inputs.height) {
				width = height = this.inputs.height;
			} else {
				//this node will be responsible for calculating its own size
				width = 1;
				height = 1;
			}

			if (this.width !== width || this.height !== height) {
				this.width = width;
				this.height = height;

				this.setDirty();
			}

			if (this.uniforms && this.uniforms.resolution) {
				this.uniforms.resolution[0] = width;
				this.uniforms.resolution[1] = height;
			}

			if (this.frameBuffer && this.frameBuffer.resize) {
				this.frameBuffer.resize(width, height);
			}
		};

		Node.prototype.destroy = function () {
			var i;

			delete this.gl;
			delete this.seriously;

			//clear out uniforms
			for (i in this.uniforms) {
				if (this.uniforms.hasOwnProperty(i)) {
					delete this.uniforms[i];
				}
			}

			//clear out list of targets and disconnect each
			if (this.targets) {
				delete this.targets;
			}

			//clear out frameBuffer
			if (this.frameBuffer && this.frameBuffer.destroy) {
				this.frameBuffer.destroy();
				delete this.frameBuffer;
			}

			//remove from main nodes index
			i = nodes.indexOf(this);
			if (i >= 0) {
				nodes.splice(i, 1);
			}
			delete nodesById[this.id];

			this.isDestroyed = true;
		};

		Effect = function (effectNode) {
			var name, me = effectNode;

			function arrayToHex(color) {
				var i, val, s = '#';
				for (i = 0; i < 4; i++) {
					val = Math.min(255, Math.round(color[i] * 255 || 0));
					s += val.toString(16);
				}
				return s;
			}

			function setInput(inputName, input) {
				var lookup, value, effectInput, i;

				effectInput = me.effect.inputs[inputName];

				lookup = me.inputElements[inputName];

				if (typeof input === 'string' && isNaN(input)) {
					if (effectInput.type === 'enum') {
						if (effectInput.options && effectInput.options.filter) {
							i = String(input).toLowerCase();
							value = effectInput.options.filter(function (e) {
								return (typeof e === 'string' && e.toLowerCase() === i) ||
									(e.length && typeof e[0] === 'string' && e[0].toLowerCase() === i);
							});

							value = value.length;
						}

						if (!value) {
							input = getElement(input, ['select']);
						}

					} else if (effectInput.type === 'number' || effectInput.type === 'boolean') {
						input = getElement(input, ['input', 'select']);
					} else if (effectInput.type === 'image') {
						input = getElement(input, ['canvas', 'img', 'video']);
					}
					//todo: color? date/time?
				}

				if (input instanceof HTMLInputElement || input instanceof HTMLSelectElement) {
					value = input.value;

					if (lookup && lookup.element !== input) {
						lookup.element.removeEventListener('change', lookup.listener, true);
						lookup.element.removeEventListener('input', lookup.listener, true);
						delete me.inputElements[inputName];
						lookup = null;
					}

					if (!lookup) {
						lookup = {
							element: input,
							listener: (function (name, element) {
								return function () {
									var oldValue, newValue;

									if (input.type === 'checkbox') {
										//special case for check box
										oldValue = input.checked;
									} else {
										oldValue = element.value;
									}
									newValue = me.setInput(name, oldValue);

									//special case for color type
									if (effectInput.type === 'color') {
										newValue = arrayToHex(newValue);
									}

									//if input validator changes our value, update HTML Element
									//todo: make this optional...somehow
									if (newValue !== oldValue) {
										element.value = newValue;
									}
								};
							}(inputName, input))
						};

						me.inputElements[inputName] = lookup;
						if (input.type === 'range') {
							input.addEventListener('input', lookup.listener, true);
							input.addEventListener('change', lookup.listener, true);
						} else {
							input.addEventListener('change', lookup.listener, true);
						}
					}

					if (lookup && input.type === 'checkbox') {
						value = input.checked;
					}
				} else {
					if (lookup) {
						lookup.element.removeEventListener('change', lookup.listener, true);
						lookup.element.removeEventListener('input', lookup.listener, true);
						delete me.inputElements[inputName];
					}
					value = input;
				}

				me.setInput(inputName, value);
				return me.inputs[inputName];
			}

			function makeImageSetter(inputName) {
				return function (value) {
					var val = setInput(inputName, value);
					return val && val.pub;
				};
			}

			function makeImageGetter(inputName) {
				return function () {
					var val = me.inputs[inputName];
					return val && val.pub;
				};
			}

			function makeSetter(inputName) {
				return function (value) {
					return setInput(inputName, value);
				};
			}

			function makeGetter(inputName) {
				return function () {
					return me.inputs[inputName];
				};
			}

			//priveleged publicly accessible methods/setters/getters
			//todo: provide an alternate method
			for (name in me.effect.inputs) {
				if (me.effect.inputs.hasOwnProperty(name)) {
					if (this[name] === undefined) {
						if (me.effect.inputs[name].type === 'image') {
							Object.defineProperty(this, name, {
								configurable: true,
								enumerable: true,
								get: makeImageGetter(name),
								set: makeImageSetter(name)
							});
						} else {
							Object.defineProperty(this, name, {
								configurable: true,
								enumerable: true,
								get: makeGetter(name),
								set: makeSetter(name)
							});
						}
					} else {
						//todo: this is temporary. get rid of it.
						throw 'Cannot overwrite Seriously.' + name;
					}
				}
			}

			Object.defineProperties(this, {
				inputs: {
					enumerable: true,
					configurable: true,
					get: function () {
						return {
							source: {
								type: 'image'
							}
						};
					}
				},
				original: {
					enumerable: true,
					configurable: true,
					get: function () {
						return me.source;
					}
				},
				width: {
					enumerable: true,
					configurable: true,
					get: function () {
						return me.width;
					}
				},
				height: {
					enumerable: true,
					configurable: true,
					get: function () {
						return me.height;
					}
				},
				id: {
					enumerable: true,
					configurable: true,
					get: function () {
						return me.id;
					}
				}
			});

			this.render = function () {
				me.render();
				return this;
			};

			this.readPixels = function (x, y, width, height, dest) {
				return me.readPixels(x, y, width, height, dest);
			};

			this.alias = function (inputName, aliasName) {
				me.alias(inputName, aliasName);
				return this;
			};

			this.matte = function (polygons) {
				me.matte(polygons);
			};

			this.destroy = function () {
				var i,
					descriptor;

				me.destroy();

				for (i in this) {
					if (this.hasOwnProperty(i) && i !== 'isDestroyed') {
						descriptor = Object.getOwnPropertyDescriptor(this, i);
						if (descriptor.get || descriptor.set ||
								typeof this[i] !== 'function') {
							delete this[i];
						} else {
							this[i] = nop;
						}
					}
				}
			};

			this.isDestroyed = function () {
				return me.isDestroyed;
			};
		};

		EffectNode = function (hook, options) {
			var key, name, input;

			Node.call(this, options);

			this.effectRef = seriousEffects[hook];
			this.sources = {};
			this.targets = [];
			this.inputElements = {};
			this.dirty = true;
			this.shaderDirty = true;
			this.hook = hook;
			this.options = options;
			this.transform = null;

			if (this.effectRef.definition) {
				this.effect = this.effectRef.definition.call(this, options);
				/*
				todo: copy over inputs object separately in case some are specified
				in advance and some are specified in definition function
				*/
				for (key in this.effectRef) {
					if (this.effectRef.hasOwnProperty(key) && !this.effect[key]) {
						this.effect[key] = this.effectRef[key];
					}
				}
				if (this.effect.inputs !== this.effectRef.inputs) {
					validateInputSpecs(this.effect);
				}
			} else {
				this.effect = extend({}, this.effectRef);
			}

			//todo: set up frame buffer(s), inputs, transforms, stencils, draw method. allow plugin to override

			this.uniforms.transform = identity;
			this.inputs = {};
			for (name in this.effect.inputs) {
				if (this.effect.inputs.hasOwnProperty(name)) {
					input = this.effect.inputs[name];

					this.inputs[name] = input.defaultValue;
					if (input.uniform) {
						this.uniforms[input.uniform] = input.defaultValue;
					}
				}
			}

			if (gl) {
				this.buildShader();
			}

			this.inPlace = this.effect.inPlace;

			this.pub = new Effect(this);

			effects.push(this);

			allEffectsByHook[hook].push(this);
		};

		extend(EffectNode, Node);

		EffectNode.prototype.initialize = function () {
			if (!this.initialized) {
				var that = this;

				if (this.shape) {
					this.model = makeGlModel(this.shape, this.gl);
				} else {
					this.model = rectangleModel;
				}

				if (typeof this.effect.initialize === 'function') {
					this.effect.initialize.call(this, function () {
						that.initFrameBuffer(true);
					}, gl);
				} else {
					this.initFrameBuffer(true);
				}

				if (this.frameBuffer) {
					this.texture = this.frameBuffer.texture;
				}

				this.initialized = true;
			}
		};

		EffectNode.prototype.resize = function () {
			var i;

			Node.prototype.resize.call(this);

			if (this.effect.resize) {
				this.effect.resize.call(this);
			}

			for (i = 0; i < this.targets.length; i++) {
				this.targets[i].resize();
			}
		};

		EffectNode.prototype.setTarget = function (target) {
			var i;
			for (i = 0; i < this.targets.length; i++) {
				if (this.targets[i] === target) {
					return;
				}
			}

			this.targets.push(target);
		};

		EffectNode.prototype.removeTarget = function (target) {
			var i = this.targets && this.targets.indexOf(target);
			if (i >= 0) {
				this.targets.splice(i, 1);
			}
		};

		EffectNode.prototype.removeSource = function (source) {
			var i, pub = source && source.pub;

			for (i in this.inputs) {
				if (this.inputs.hasOwnProperty(i) &&
					(this.inputs[i] === source || this.inputs[i] === pub)) {
					this.inputs[i] = null;
				}
			}

			for (i in this.sources) {
				if (this.sources.hasOwnProperty(i) &&
					(this.sources[i] === source || this.sources[i] === pub)) {
					this.sources[i] = null;
				}
			}
		};

		EffectNode.prototype.buildShader = function () {
			var shader, effect = this.effect;
			if (this.shaderDirty) {
				if (effect.shader) {
					shader = effect.shader.call(this, this.inputs, {
						vertex: baseVertexShader,
						fragment: baseFragmentShader
					}, Seriously.util);

					if (shader instanceof ShaderProgram) {
						this.shader = shader;
					} else if (shader && shader.vertex && shader.fragment) {
						this.shader = new ShaderProgram(gl, shader.vertex, shader.fragment);
					} else {
						this.shader = baseShader;
					}
				} else {
					this.shader = baseShader;
				}

				this.shaderDirty = false;
			}
		};

		EffectNode.prototype.render = function () {
			var i,
				frameBuffer,
				effect = this.effect,
				that = this,
				inPlace;

			function drawFn(shader, model, uniforms, frameBuffer, node, options) {
				draw(shader, model, uniforms, frameBuffer, node || that, options);
			}

			if (!this.initialized) {
				this.initialize();
			}

			if (this.shaderDirty) {
				this.buildShader();
			}

			if (this.dirty) {
				for (i in this.sources) {
					if (this.sources.hasOwnProperty(i) &&
						(!effect.requires || effect.requires.call(this, i, this.inputs))) {

						//todo: set source texture
						//sourcetexture = this.sources[i].render() || this.sources[i].texture

						inPlace = typeof this.inPlace === 'function' ? this.inPlace(i) : this.inPlace;
						this.sources[i].render(!inPlace);
					}
				}

				if (this.frameBuffer) {
					frameBuffer = this.frameBuffer.frameBuffer;
				}

				if (typeof effect.draw === 'function') {
					effect.draw.call(this, this.shader, this.model, this.uniforms, frameBuffer, drawFn);
				} else if (frameBuffer) {
					draw(this.shader, this.model, this.uniforms, frameBuffer, this);
				}

				this.dirty = false;
			}

			return this.texture;
		};

		EffectNode.prototype.setInput = function (name, value) {
			var input, uniform,
				sourceKeys,
				source;

			if (this.effect.inputs.hasOwnProperty(name)) {
				input = this.effect.inputs[name];
				if (input.type === 'image') {
					//&& !(value instanceof Effect) && !(value instanceof Source)) {

					if (value) {
						value = findInputNode(value);

						if (value !== this.sources[name]) {
							if (this.sources[name]) {
								this.sources[name].removeTarget(this);
							}

							if (traceSources(value, this)) {
								throw 'Attempt to make cyclical connection.';
							}

							this.sources[name] = value;
							value.setTarget(this);
						}
					} else {
						delete this.sources[name];
						value = false;
					}

					uniform = this.sources[name];

					sourceKeys = Object.keys(this.sources);
					if (this.inPlace === true && sourceKeys.length === 1) {
						source = this.sources[sourceKeys[0]];
						this.uniforms.transform = source && source.cumulativeMatrix || identity;
					} else {
						this.uniforms.transform = identity;
					}

					this.resize();
				} else {
					value = input.validate.call(this, value, input, this.inputs[name]);
					uniform = value;
				}

				if (this.inputs[name] === value && input.type !== 'color' && input.type !== 'vector') {
					return value;
				}

				this.inputs[name] = value;

				if (input.uniform) {
					this.uniforms[input.uniform] = uniform;
				}

				if (input.shaderDirty) {
					this.shaderDirty = true;
				}

				this.setDirty();

				if (input.update) {
					input.update.call(this, value);
				}

				return value;
			}
		};

		EffectNode.prototype.alias = function (inputName, aliasName) {
			var that = this;

			if (reservedNames.indexOf(aliasName) >= 0) {
				throw aliasName + ' is a reserved name and cannot be used as an alias.';
			}

			if (this.effect.inputs.hasOwnProperty(inputName)) {
				if (!aliasName) {
					aliasName = inputName;
				}

				seriously.removeAlias(aliasName);

				aliases[aliasName] = {
					node: this,
					input: inputName
				};

				Object.defineProperty(seriously, aliasName, {
					configurable: true,
					enumerable: true,
					get: function () {
						return that.inputs[inputName];
					},
					set: function (value) {
						return that.setInput(inputName, value);
					}
				});
			}

			return this;
		};

		/*
		matte function to be assigned as a method to EffectNode and TargetNode
		*/
		EffectNode.prototype.matte = function (poly) {
			var polys,
				polygons = [],
				polygon,
				vertices = [],
				i, j, v,
				vert, prev,
				//triangles = [],
				shape = {};

			//detect whether it's multiple polygons or what
			function makePolygonsArray(poly) {
				if (!poly || !poly.length || !Array.isArray(poly)) {
					return [];
				}

				if (!Array.isArray(poly[0])) {
					return [poly];
				}

				if (Array.isArray(poly[0]) && !isNaN(poly[0][0])) {
					return [poly];
				}

				return poly;
			}

			function linesIntersect(a1, a2, b1, b2) {
				var ua_t, ub_t, u_b, ua, ub;
				ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x);
				ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x);
				u_b = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);
				if (u_b) {
					ua = ua_t / u_b;
					ub = ub_t / u_b;
					if (ua > 0 && ua <= 1 && ub > 0 && ub <= 1) {
						return {
							x: a1.x + ua * (a2.x - a1.x),
							y: a1.y + ua * (a2.y - a1.y)
						};
					}
				}
				return false;
			}

			function makeSimple(poly) {
				/*
				this uses a slow, naive approach to detecting line intersections.
				Use Bentley-Ottmann Algorithm
				see: http://softsurfer.com/Archive/algorithm_0108/algorithm_0108.htm#Bentley-Ottmann Algorithm
				see: https://github.com/tokumine/sweepline
				*/
				var i, j,
					edge1, edge2,
					intersect,
					intersections = [],
					newPoly,
					head, point,
					newPolygons,
					point1, point2;

				if (poly.simple) {
					return;
				}

				for (i = 0; i < poly.edges.length; i++) {
					edge1 = poly.edges[i];
					for (j = i + 1; j < poly.edges.length; j++) {
						edge2 = poly.edges[j];
						intersect = linesIntersect(edge1[0], edge1[1], edge2[0], edge2[1]);
						if (intersect) {
							intersect.edge1 = edge1;
							intersect.edge2 = edge2;
							intersections.push(intersect);
						}
					}
				}

				if (intersections.length) {
					newPolygons = [];

					for (i = 0; i < intersections.length; i++) {
						intersect = intersections[i];
						edge1 = intersect.edge1;
						edge2 = intersect.edge2;

						//make new points
						//todo: set ids for points
						point1 = {
							x: intersect.x,
							y: intersect.y,
							prev: edge1[0],
							next: edge2[1],
							id: vertices.length
						};
						poly.vertices.push(point1);
						vertices.push(point1);

						point2 = {
							x: intersect.x,
							y: intersect.y,
							prev: edge2[0],
							next: edge1[1],
							id: vertices.length
						};
						poly.vertices.push(point2);
						vertices.push(point1);

						//modify old points
						point1.prev.next = point1;
						point1.next.prev = point1;
						point2.prev.next = point2;
						point2.next.prev = point2;

						//don't bother modifying the old edges. we're just gonna throw them out
					}

					//make new polygons
					do {
						newPoly = {
							edges: [],
							vertices: [],
							simple: true
						};
						newPolygons.push(newPoly);
						point = poly.vertices[0];
						head = point;
						//while (point.next !== head && poly.vertices.length) {
						do {
							i = poly.vertices.indexOf(point);
							poly.vertices.splice(i, 1);
							newPoly.edges.push([point, point.next]);
							newPoly.vertices.push(point);
							point = point.next;
						} while (point !== head);
					} while (poly.vertices.length);

					//remove original polygon from list
					i = polygons.indexOf(poly);
					polygons.splice(i, 1);

					//add new polygons to list
					for (i = 0; i < newPolygons.length; i++) {
						polygons.push(newPolygons[i]);
					}
				} else {
					poly.simple = true;
				}
			}

			function clockWise(poly) {
				var p, q, n = poly.vertices.length,
					pv, qv, sum = 0;
				for (p = n - 1, q = 0; q < n; p = q, q++) {
					pv = poly.vertices[p];
					qv = poly.vertices[q];
					//sum += (next.x - v.x) * (next.y + v.y);
					//sum += (v.next.x + v.x) * (v.next.y - v.y);
					sum += pv.x * qv.y - qv.x * pv.y;
				}
				return sum > 0;
			}

			function triangulate(poly) {
				var v, points = poly.vertices,
					n, V = [], indices = [],
					nv, count, m, u, w,

					//todo: give these variables much better names
					a, b, c, s, t;

				function pointInTriangle(a, b, c, p) {
					var ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy,
						cXap, bXcp, aXbp;

					ax = c.x - b.x;
					ay = c.y - b.y;
					bx = a.x - c.x;
					by = a.y - c.y;
					cx = b.x - a.x;
					cy = b.y - a.y;
					apx = p.x - a.x;
					apy = p.y - a.y;
					bpx = p.x - b.x;
					bpy = p.y - b.y;
					cpx = p.x - c.x;
					cpy = p.y - c.y;

					aXbp = ax * bpy - ay * bpx;
					cXap = cx * apy - cy * apx;
					bXcp = bx * cpy - by * cpx;

					return aXbp >= 0 && bXcp >=0 && cXap >=0;
				}

				function snip(u, v, w, n, V) {
					var p, a, b, c, point;
					a = points[V[u]];
					b = points[V[v]];
					c = points[V[w]];
					if (0 > (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) {
						return false;
					}
					for (p = 0; p < n; p++) {
						if (!(p === u || p === v || p === w)) {
							point = points[V[p]];
							if (pointInTriangle(a, b, c, point)) {
								return false;
							}
						}
					}
					return true;
				}

				//copy points
				//for (v = 0; v < poly.vertices.length; v++) {
				//	points.push(poly.vertices[v]);
				//}
				n = points.length;

				if (poly.clockWise) {
					for (v = 0; v < n; v++) {
						V[v] = v;
					}
				} else {
					for (v = 0; v < n; v++) {
						V[v] = (n - 1) - v;
					}
				}

				nv = n;
				count = 2 * nv;
				m = 0;
				v = nv - 1;
				while (nv > 2) {
					if ((count--) <= 0) {
						return indices;
					}

					u = v;
					if (nv <= u) {
						u = 0;
					}

					v = u + 1;
					if (nv <= v) {
						v = 0;
					}

					w = v + 1;
					if (nv < w) {
						w = 0;
					}

					if (snip(u, v, w, nv, V)) {
						a = V[u];
						b = V[v];
						c = V[w];
						if (poly.clockWise) {
							indices.push(points[a]);
							indices.push(points[b]);
							indices.push(points[c]);
						} else {
							indices.push(points[c]);
							indices.push(points[b]);
							indices.push(points[a]);
						}
						m++;
						for (s = v, t = v + 1; t < nv; s++, t++) {
							V[s] = V[t];
						}
						nv--;
						count = 2 * nv;
					}
				}

				polygon.indices = indices;
			}

			polys = makePolygonsArray(poly);

			for (i = 0; i < polys.length; i++) {
				poly = polys[i];
				prev = null;
				polygon = {
					vertices: [],
					edges: []
				};

				for (j = 0; j < poly.length; j++) {
					v = poly[j];
					if (typeof v ==='object' && !isNaN(v.x) && !isNaN(v.y)) {
						vert = {
							x: v.x,
							y: v.y,
							id: vertices.length
						};
					} else if (v.length >= 2 && !isNaN(v[0]) && !isNaN(v[1])) {
						vert = {
							x: v[0],
							y: v[1],
							id: vertices.length
						};
					}
					if (vert) {
						if (prev) {
							prev.next = vert;
							vert.prev = prev;
							vert.next = polygon.vertices[0];
							polygon.vertices[0].prev = vert;
						} else {
							polygon.head = vert;
							vert.next = vert;
							vert.prev = vert;
						}
						vertices.push(vert);
						polygon.vertices.push(vert);
						prev = vert;
					}
				}

				if (polygon.vertices.length > 2) {
					if (polygon.vertices.length === 3) {
						polygon.simple = true;
					}

					polygons.push(polygon);

					//save edges
					for (j = 0; j < polygon.vertices.length; j++) {
						vert = polygon.vertices[j];
						polygon.edges.push([
							vert, vert.next
						]);
					}
				}
			}

			for (i = polygons.length - 1; i >= 0; i--) {
				polygon = polygons[i];
				makeSimple(polygon);
			}

			for (i = 0; i < polygons.length; i++) {
				polygon = polygons[i];
				polygon.clockWise = clockWise(polygon);
				triangulate(polygon);
			}

			//build shape
			shape.vertices = [];
			shape.coords = [];
			for (i = 0; i < vertices.length; i++) {
				v = vertices[i];
				shape.vertices.push(v.x * 2 - 1);
				shape.vertices.push(v.y * -2 + 1);
				shape.vertices.push(-1);

				shape.coords.push(v.x);
				shape.coords.push(v.y * -1 + 1);
			}
			shape.vertices = new Float32Array(shape.vertices);
			shape.coords = new Float32Array(shape.coords);

			shape.indices = [];
			for (i = 0; i < polygons.length; i++) {
				polygon = polygons[i];
				for (j = 0; j < polygon.indices.length; j++) {
					v = polygon.indices[j];
					shape.indices.push(v.id);
					//shape.indices.push(v[1].id);
					//shape.indices.push(v[2].id);
				}
			}
			shape.indices = new Uint16Array(shape.indices);

			this.shape = shape;
			if (this.gl) {
				makeGlModel(shape, this.gl);
			}
		};

		EffectNode.prototype.destroy = function () {
			var i, key, item, hook = this.hook;

			//let effect destroy itself
			if (this.effect.destroy && typeof this.effect.destroy === 'function') {
				this.effect.destroy.call(this);
			}
			delete this.effect;

			//shader
			if (this.shader && this.shader.destroy && this.shader !== baseShader) {
				this.shader.destroy();
			}
			delete this.shader;

			//stop watching any input elements
			for (key in this.inputElements) {
				if (this.inputElements.hasOwnProperty(key)) {
					item = this.inputElements[key];
					item.element.removeEventListener('change', item.listener, true);
					item.element.removeEventListener('input', item.listener, true);
				}
			}

			//sources
			for (key in this.sources) {
				if (this.sources.hasOwnProperty(key)) {
					item = this.sources[key];
					if (item && item.removeTarget) {
						item.removeTarget(this);
					}
					delete this.sources[key];
				}
			}

			//targets
			while (this.targets.length) {
				item = this.targets.pop();
				if (item && item.removeSource) {
					item.removeSource(this);
				}
			}

			for (i in this) {
				if (this.hasOwnProperty(key) && key !== 'id') {
					delete this[key];
				}
			}

			//remove any aliases
			for (key in aliases) {
				if (aliases.hasOwnProperty(key)) {
					item = aliases[key];
					if (item.node === this) {
						seriously.removeAlias(key);
					}
				}
			}

			//remove self from master list of effects
			i = effects.indexOf(this);
			if (i >= 0) {
				effects.splice(i, 1);
			}

			i = allEffectsByHook[hook].indexOf(this);
			if (i >= 0) {
				allEffectsByHook[hook].splice(i, 1);
			}

			Node.prototype.destroy.call(this);
		};

		Source = function (sourceNode) {
			var me = sourceNode;

			//priveleged accessor methods
			Object.defineProperties(this, {
				original: {
					enumerable: true,
					configurable: true,
					get: function () {
						return me.source;
					}
				},
				id: {
					enumerable: true,
					configurable: true,
					get: function () {
						return me.id;
					}
				}
			});

			this.render = function () {
				me.render();
			};

			this.update = function () {
				me.setDirty();
			};

			this.readPixels = function (x, y, width, height, dest) {
				return me.readPixels(x, y, width, height, dest);
			};

			this.destroy = function () {
				var i,
					descriptor;

				me.destroy();

				for (i in this) {
					if (this.hasOwnProperty(i) && i !== 'isDestroyed') {
						descriptor = Object.getOwnPropertyDescriptor(this, i);
						if (descriptor.get || descriptor.set ||
								typeof this[i] !== 'function') {
							delete this[i];
						} else {
							this[i] = nop;
						}
					}
				}
			};

			this.isDestroyed = function () {
				return me.isDestroyed;
			};
		};

		/*
			possible sources: img, video, canvas (2d or 3d), texture, ImageData, array, typed array
		*/
		SourceNode = function (source, options) {
			var opts = options || {},
				flip = opts.flip === undefined ? true : opts.flip,
				width = opts.width,
				height = opts.height,
				deferTexture = false,
				that = this,
				matchedType = false;

			Node.call(this);

			if (typeof source === 'string' && isNaN(source)) {
				source = getElement(source, ['canvas', 'img', 'video']);
			}

			if (source instanceof HTMLElement) {
				if (source.tagName === 'CANVAS') {
					this.width = source.width;
					this.height = source.height;

					this.render = this.renderImageCanvas;
				} else if (source.tagName === 'IMG') {
					this.width = source.naturalWidth || 1;
					this.height = source.naturalHeight || 1;

					if (!source.complete) {
						deferTexture = true;

						source.addEventListener('load', function () {
							that.width = source.naturalWidth;
							that.height = source.naturalHeight;
							that.resize();
							that.initialize();
						}, true);
					}

					this.render = this.renderImageCanvas;
				} else if (source.tagName === 'VIDEO') {
					this.width = source.videoWidth || 1;
					this.height = source.videoHeight || 1;

					if (!source.readyState) {
						deferTexture = true;

						source.addEventListener('loadedmetadata', function () {
							that.width = source.videoWidth;
							that.height = source.videoHeight;
							that.resize();
							that.initialize();
						}, true);
					}

					this.render = this.renderVideo;
				} else {
					throw 'Not a valid HTML element: ' + source.tagName + ' (must be img, video or canvas)';
				}
				matchedType = true;

			} else if (source instanceof Object && source.data &&
				source.width && source.height &&
				source.width * source.height * 4 === source.data.length
				) {

				//Because of this bug, Firefox doesn't recognize ImageData, so we have to duck type
				//https://bugzilla.mozilla.org/show_bug.cgi?id=637077

				this.width = source.width;
				this.height = source.height;
				matchedType = true;

				this.render = this.renderImageCanvas;
			} else if (isArrayLike(source)) {
				if (!width || !height) {
					throw 'Height and width must be provided with an Array';
				}

				if (width * height * 4 !== source.length) {
					throw 'Array length must be height x width x 4.';
				}

				this.width = width;
				this.height = height;

				matchedType = true;

				//use opposite default for flip
				if (opts.flip === undefined) {
					flip = false;
				}

				if (!(source instanceof Uint8Array)) {
					source = new Uint8Array(source);
				}
				this.render = this.renderTypedArray;
			} else if (source instanceof WebGLTexture) {
				if (gl && !gl.isTexture(source)) {
					throw 'Not a valid WebGL texture.';
				}

				//different defaults
				if (!isNaN(width)) {
					if (isNaN(height)) {
						height = width;
					}
				} else if (!isNaN(height)) {
					width = height;
				}/* else {
					//todo: guess based on dimensions of target canvas
					//throw 'Must specify width and height when using a WebGL texture as a source';
				}*/

				this.width = width;
				this.height = height;

				if (opts.flip === undefined) {
					flip = false;
				}
				matchedType = true;

				this.texture = source;
				this.initialized = true;

				//todo: if WebGLTexture source is from a different context render it and copy it over
				this.render = function () {};
			}

			if (!matchedType) {
				throw 'Unknown source type';
			}

			this.source = source;
			this.flip = flip;

			this.targets = [];

			if (!deferTexture) {
				this.resize();
				this.initialize();
			}

			this.pub = new Source(this);

			sources.push(this);

			if (sources.length && !rafId) {
				renderDaemon();
			}
		};

		extend(SourceNode, Node);

		SourceNode.prototype.initialize = function () {
			if (!gl || this.texture) {
				return;
			}

			var texture = gl.createTexture();
			gl.bindTexture(gl.TEXTURE_2D, texture);
			gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
			gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
			gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
			gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
			gl.bindTexture(gl.TEXTURE_2D, null);

			this.texture = texture;
			this.initialized = true;
			this.allowRefresh = true;
			this.setDirty();
		};

		SourceNode.prototype.initFrameBuffer = function (useFloat) {
			if (gl) {
				this.frameBuffer = new FrameBuffer(gl, this.width, this.height, {
					texture: this.texture,
					useFloat: useFloat
				});
			}
		};

		SourceNode.prototype.setTarget = function (target) {
			var i;
			for (i = 0; i < this.targets.length; i++) {
				if (this.targets[i] === target) {
					return;
				}
			}

			this.targets.push(target);
		};

		SourceNode.prototype.removeTarget = function (target) {
			var i = this.targets && this.targets.indexOf(target);
			if (i >= 0) {
				this.targets.splice(i, 1);
			}
		};

		SourceNode.prototype.resize = function () {
			var i,
				target;

			this.uniforms.resolution[0] = this.width;
			this.uniforms.resolution[1] = this.height;

			if (this.framebuffer) {
				this.framebuffer.resize(this.width, this.height);
			}

			this.setDirty();

			for (i = 0; i < this.targets.length; i++) {
				target = this.targets[i];
				target.resize();
				if (target.setTransformDirty) {
					target.setTransformDirty();
				}
			}
		};

		SourceNode.prototype.renderVideo = function () {
			var video = this.source;

			if (!gl || !video || !video.videoHeight || !video.videoWidth || video.readyState < 2) {
				return;
			}

			if (!this.initialized) {
				this.initialize();
			}

			if (!this.allowRefresh) {
				return;
			}

			if (this.dirty ||
				this.lastRenderFrame !== video.mozPresentedFrames ||
				this.lastRenderTime !== video.currentTime) {

				gl.bindTexture(gl.TEXTURE_2D, this.texture);
				gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this.flip);
				try {
					gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video);
				} catch (securityError) {
					if (securityError.name === 'SECURITY_ERR') {
						this.allowRefresh = false;
						console.log('Unable to access cross-domain image');
					}
				}

				// Render a few extra times because the canvas takes a while to catch up
				if (Date.now() - 100 > this.lastRenderTimeStamp) {
					this.lastRenderTime = video.currentTime;
				}
				this.lastRenderFrame = video.mozPresentedFrames;
				this.lastRenderTimeStamp = Date.now();
				this.dirty = false;
			}
		};

		SourceNode.prototype.renderImageCanvas = function () {
			var media = this.source;

			if (!gl || !media || !media.height || !media.width) {
				return;
			}

			if (!this.initialized) {
				this.initialize();
			}

			if (!this.allowRefresh) {
				return;
			}

			if (this.dirty) {
				gl.bindTexture(gl.TEXTURE_2D, this.texture);
				gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this.flip);
				try {
					gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, media);
				} catch (securityError) {
					if (securityError.name === 'SECURITY_ERR') {
						this.allowRefresh = false;
						console.log('Unable to access cross-domain image');
					}
				}

				this.lastRenderTime = Date.now() / 1000;
				this.dirty = false;
			}
		};

		SourceNode.prototype.renderTypedArray = function () {
			var media = this.source;

			if (!gl || !media || !media.length) {
				return;
			}

			if (!this.initialized) {
				this.initialize();
			}

			//this.currentTime = media.currentTime || 0;

			if (!this.allowRefresh) {
				return;
			}

			if (this.dirty) {
				gl.bindTexture(gl.TEXTURE_2D, this.texture);
				gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this.flip);
				gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, media);

				this.lastRenderTime = Date.now() / 1000;
				this.dirty = false;
			}
		};

		SourceNode.prototype.destroy = function () {
			var i, key, item;

			if (this.gl && this.texture) {
				this.gl.deleteTexture(this.texture);
			}

			//targets
			while (this.targets.length) {
				item = this.targets.pop();
				if (item && item.removeSource) {
					item.removeSource(this);
				}
			}

			//remove self from master list of sources
			i = sources.indexOf(this);
			if (i >= 0) {
				sources.splice(i, 1);
			}

			for (key in this) {
				if (this.hasOwnProperty(key) && key !== 'id') {
					delete this[key];
				}
			}

			Node.prototype.destroy.call(this);
		};

		//todo: implement render for array and typed array

		Target = function (targetNode) {
			var me = targetNode;

			//priveleged accessor methods
			Object.defineProperties(this, {
				inputs: {
					enumerable: true,
					configurable: true,
					get: function () {
						return {
							source: {
								type: 'image'
							}
						};
					}
				},
				source: {
					enumerable: true,
					configurable: true,
					get: function () {
						if (me.source) {
							return me.source.pub;
						}
					},
					set: function (value) {
						me.setSource(value);
					}
				},
				original: {
					enumerable: true,
					configurable: true,
					get: function () {
						return me.target;
					}
				},
				width: {
					enumerable: true,
					configurable: true,
					get: function () {
						return me.width;
					},
					set: function (value) {
						if (!isNaN(value) && value >0 && me.width !== value) {
							me.width = me.desiredWidth = value;
							me.target.width = value;

							me.setTransformDirty();
							/*
							if (this.source && this.source.resize) {
								this.source.resize(value);

								//todo: for secondary webgl nodes, we need a new array
								//if (this.pixels && this.pixels.length !== (this.width * this.height * 4)) {
								//	delete this.pixels;
								//}
							}
							*/
						}
					}
				},
				height: {
					enumerable: true,
					configurable: true,
					get: function () {
						return me.height;
					},
					set: function (value) {
						if (!isNaN(value) && value >0 && me.height !== value) {
							me.height = me.desiredHeight = value;
							me.target.height = value;

							me.setTransformDirty();

							/*
							if (this.source && this.source.resize) {
								this.source.resize(undefined, value);

								//for secondary webgl nodes, we need a new array
								//if (this.pixels && this.pixels.length !== (this.width * this.height * 4)) {
								//	delete this.pixels;
								//}
							}
							*/
						}
					}
				},
				id: {
					enumerable: true,
					configurable: true,
					get: function () {
						return me.id;
					}
				}
			});

			this.render = function () {
				me.render();
			};

			this.readPixels = function (x, y, width, height, dest) {
				return me.readPixels(x, y, width, height, dest);
			};

			this.go = function (options) {
				me.go(options);
			};

			this.stop = function () {
				me.stop();
			};

			this.getTexture = function () {
				return me.frameBuffer.texture;
			};

			this.destroy = function () {
				var i,
					descriptor;

				me.destroy();

				for (i in this) {
					if (this.hasOwnProperty(i) && i !== 'isDestroyed') {
						descriptor = Object.getOwnPropertyDescriptor(this, i);
						if (descriptor.get || descriptor.set ||
								typeof this[i] !== 'function') {
							delete this[i];
						} else {
							this[i] = nop;
						}
					}
				}
			};

			this.isDestroyed = function () {
				return me.isDestroyed;
			};
		};

		/*
			possible targets: canvas (2d or 3d), gl render buffer (must be same canvas)
		*/
		TargetNode = function (target, options) {
			var opts = options || {},
				flip = opts.flip === undefined ? true : opts.flip,
				width = parseInt(opts.width, 10),
				height = parseInt(opts.height, 10),
				matchedType = false,
				i, element, elements, context,
				frameBuffer;

			Node.call(this, opts);

			this.renderToTexture = opts.renderToTexture;

			if (typeof target === 'string') {
				elements = document.querySelectorAll(target);

				for (i = 0; i < elements.length; i++) {
					element = elements[i];
					if (element.tagName === 'CANVAS') {
						break;
					}
				}

				if (i >= elements.length) {
					throw 'not a valid HTML element (must be image, video or canvas)';
				}

				target = element;
			} else if (target instanceof WebGLFramebuffer) {

				frameBuffer = target;

				if (opts instanceof HTMLCanvasElement) {
					target = opts;
				} else if (opts instanceof WebGLRenderingContext) {
					target = opts.canvas;
				} else if (opts.canvas instanceof HTMLCanvasElement) {
					target = opts.canvas;
				} else if (opts.context instanceof WebGLRenderingContext) {
					target = opts.context.canvas;
				} else {
					//todo: search all canvases for matching contexts?
					throw "Must provide a canvas with WebGLFramebuffer target";
				}
			}

			if (target instanceof HTMLElement && target.tagName === 'CANVAS') {
				width = target.width;
				height = target.height;

				//todo: try to get a webgl context. if not, get a 2d context, and set up a different render function
				try {
					if (window.WebGLDebugUtils) {
						context = window.WebGLDebugUtils.makeDebugContext(target.getContext('experimental-webgl', {
							alpha: true,
							premultipliedAlpha: false,
							preserveDrawingBuffer: true,
							stencil: true
						}));
					} else {
						context = target.getContext('experimental-webgl', {
							alpha: true,
							premultipliedAlpha: false,
							preserveDrawingBuffer: true,
							stencil: true
						});
					}
				} catch (expError) {
				}

				if (!context) {
					try {
						context = target.getContext('webgl', {
							alpha: true,
							premultipliedAlpha: false,
							preserveDrawingBuffer: true,
							stencil: true
						});
					} catch (error) {

					}
				}

				if (!context) {
					context = target.getContext('2d');
					//todo: set up ImageData and alternative drawing method (or drawImage)
					this.render = this.render2D;
					this.use2D = true;
				} else if (!gl || gl === context) {
					//this is our main WebGL canvas
					if (!gl) {
						attachContext(context);
					}
					this.render = this.renderWebGL;
					if (opts.renderToTexture) {
						this.frameBuffer = new FrameBuffer(gl, width, height, false);
					} else {
						this.frameBuffer = {
							frameBuffer: frameBuffer || null
						};
					}
				} else if (context !== gl) {
					//set up alternative drawing method using ArrayBufferView
					this.gl = context;
					//this.pixels = new Uint8Array(width * height * 4);
					//todo: probably need another framebuffer for renderToTexture
					if (frameBuffer) {
						this.frameBuffer = {
							frameBuffer: frameBuffer
						};
					} else {
						this.frameBuffer = new FrameBuffer(this.gl, width, height, false);
					}
					this.shader = new ShaderProgram(this.gl, baseVertexShader, baseFragmentShader);
					this.model = buildRectangleModel.call(this, this.gl);

					this.texture = this.gl.createTexture();
					this.gl.bindTexture(gl.TEXTURE_2D, this.texture);
					this.gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
					this.gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
					this.gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
					this.gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

					this.render = this.renderSecondaryWebGL;
				} else {
					//todo: this should theoretically never happen
				}

				matchedType = true;
			}

			if (!matchedType) {
				throw 'Unknown target type';
			}

			this.target = target;
			this.transform = null;
			this.transformDirty = true;
			this.flip = flip;
			this.width = width;
			this.height = height;

			this.uniforms.resolution[0] = this.width;
			this.uniforms.resolution[1] = this.height;

			if (opts.auto !== undefined) {
				this.auto = opts.auto;
			} else {
				this.auto = auto;
			}
			this.frames = 0;

			this.pub = new Target(this);

			targets.push(this);
		};

		extend(TargetNode, Node);

		TargetNode.prototype.setSource = function (source) {
			var newSource;

			//todo: what if source is null/undefined/false

			newSource = findInputNode(source);

			//todo: check for cycles

			if (newSource !== this.source) {
				if (this.source) {
					this.source.removeTarget(this);
				}
				this.source = newSource;
				newSource.setTarget(this);

				this.setDirty();
			}
		};

		TargetNode.prototype.setDirty = function () {
			this.dirty = true;

			if (this.auto && !rafId) {
				rafId = requestAnimationFrame(renderDaemon);
			}
		};

		TargetNode.prototype.resize = function () {
			//if target is a canvas, reset size to canvas size
			if (this.target instanceof HTMLCanvasElement &&
					(this.width !== this.target.width || this.height !== this.target.height)) {
				this.width = this.target.width;
				this.height = this.target.height;
				this.uniforms.resolution[0] = this.width;
				this.uniforms.resolution[1] = this.height;
				this.setTransformDirty();
			}

			if (this.source &&
				(this.source.width !== this.width || this.source.height !== this.height)) {
				if (!this.transform) {
					this.transform = new Float32Array(16);
				}
			}
		};

		TargetNode.prototype.setTransformDirty = function () {
			this.transformDirty = true;
			this.setDirty();
		};

		TargetNode.prototype.go = function () {
			this.auto = true;
			this.setDirty();
		};

		TargetNode.prototype.stop = function () {
			this.auto = false;
		};

		TargetNode.prototype.renderWebGL = function () {
			var matrix, x, y;

			this.resize();

			if (this.dirty) {
				if (!this.source) {
					return;
				}

				this.source.render();

				this.uniforms.source = this.source.texture;

				if (this.source.width === this.width && this.source.height === this.height) {
					this.uniforms.transform = this.source.cumulativeMatrix || identity;
				} else if (this.transformDirty) {
					matrix = this.transform;
					mat4.copy(matrix, this.source.cumulativeMatrix || identity);
					x = this.source.width / this.width;
					y = this.source.height / this.height;
					matrix[0] *= x;
					matrix[1] *= x;
					matrix[2] *= x;
					matrix[3] *= x;
					matrix[4] *= y;
					matrix[5] *= y;
					matrix[6] *= y;
					matrix[7] *= y;
					this.uniforms.transform = matrix;
					this.transformDirty = false;
				}

				draw(baseShader, rectangleModel, this.uniforms, this.frameBuffer.frameBuffer, this);

				this.dirty = false;
			}
		};

		TargetNode.prototype.renderSecondaryWebGL = function () {
			if (this.dirty && this.source) {
				this.source.render();

				var width = this.source.width,
					height = this.source.height;

				if (!this.pixels || this.pixels.length !== width * height * 4) {
					this.pixels = new Uint8Array(width * height * 4);
				}

				this.source.readPixels(0, 0, this.source.width, this.source.height, this.pixels);

				this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, width, height, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, this.pixels);

				this.uniforms.source = this.texture;
				draw(this.shader, this.model, this.uniforms, null, this);

				this.dirty = false;
			}
		};

		TargetNode.prototype.render2D = function () {
			//todo: make this actually do something?
		};

		TargetNode.prototype.removeSource = function (source) {
			if (this.source === source || this.source === source.pub) {
				this.source = null;
			}
		};

		TargetNode.prototype.destroy = function () {
			var i;

			//source
			if (this.source && this.source.removeTarget) {
				this.source.removeTarget(this);
			}
			delete this.source;
			delete this.target;
			delete this.pub;
			delete this.uniforms;
			delete this.pixels;
			delete this.auto;

			//remove self from master list of targets
			i = targets.indexOf(this);
			if (i >= 0) {
				targets.splice(i, 1);
			}

			Node.prototype.destroy.call(this);
		};

		Transform = function (transformNode) {
			var me = transformNode,
				self = this,
				key;

			function setProperty(name, def) {
				// todo: validate value passed to 'set'
				Object.defineProperty(self, name, {
					configurable: true,
					enumerable: true,
					get: function () {
						return def.get.call(me);
					},
					set: function (val) {
						if (def.set.call(me, val)) {
							me.setTransformDirty();
						}
					}
				});
			}

			function makeMethod(method) {
				return function () {
					if (method.apply(me, arguments)) {
						me.setTransformDirty();
					}
				};
			}

			//priveleged accessor methods
			Object.defineProperties(this, {
				id: {
					enumerable: true,
					configurable: true,
					get: function () {
						return me.id;
					}
				},
				source: {
					enumerable: true,
					configurable: true,
					get: function () {
						return me.source.pub;
					},
					set: function (source) {
						me.setSource(source);
					}
				}
			});

			// attach methods
			for (key in me.methods) {
				if (me.methods.hasOwnProperty(key)) {
					this[key] = makeMethod(me.methods[key].bind(me));
				}
			}

			for (key in me.inputs) {
				if (me.inputs.hasOwnProperty(key)) {
					setProperty(key, me.inputs[key]);
				}
			}

			this.update = function () {
				me.setDirty();
			};

			this.alias = function (inputName, aliasName) {
				me.alias(inputName, aliasName);
				return this;
			};

			this.destroy = function () {
				var i,
					descriptor;

				me.destroy();

				for (i in this) {
					if (this.hasOwnProperty(i) && i !== 'isDestroyed') {
						//todo: probably can simplify this if the only setter/getter is id
						descriptor = Object.getOwnPropertyDescriptor(this, i);
						if (descriptor.get || descriptor.set ||
								typeof this[i] !== 'function') {
							delete this[i];
						} else {
							this[i] = nop;
						}
					}
				}
			};

			this.isDestroyed = function () {
				return me.isDestroyed;
			};
		};

		TransformNode = function (hook, options) {
			var key,
				input;

			this.matrix = new Float32Array(16);
			this.cumulativeMatrix = new Float32Array(16);

			this.width = 1;
			this.height = 1;

			this.seriously = seriously;

			this.transformRef = seriousTransforms[hook];
			this.hook = hook;
			this.id = nodeId;
			nodes.push(this);
			nodesById[nodeId] = this;
			nodeId++;

			this.options = options;
			this.sources = null;
			this.targets = [];
			this.inputElements = {};
			this.inputs = {};
			this.methods = {};

			this.texture = null;
			this.frameBuffer = null;
			this.uniforms = null;

			this.dirty = true;
			this.transformDirty = true;
			this.renderDirty = false;
			this.isDestroyed = false;
			this.transformed = false;

			if (this.transformRef.definition) {
				this.plugin = this.transformRef.definition.call(this, options);
				for (key in this.transformRef) {
					if (this.transformRef.hasOwnProperty(key) && !this.plugin[key]) {
						this.plugin[key] = this.transformRef[key];
					}
				}

				/*
				todo: validate method definitions, check against reserved names
				if (this.plugin.inputs !== this.transformRef.inputs) {
					validateInputSpecs(this.plugin);
				}
				*/
			} else {
				this.plugin = extend({}, this.transformRef);
			}

			for (key in this.plugin.inputs) {
				if (this.plugin.inputs.hasOwnProperty(key)) {
					input = this.plugin.inputs[key];

					if (input.method && typeof input.method === 'function') {
						this.methods[key] = input.method;
					} else if (typeof input.set === 'function' && typeof input.get === 'function') {
						this.inputs[key] = input;
					}
				}
			}

			this.pub = new Transform(this);

			transforms.push(this);

			allTransformsByHook[hook].push(this);
		};

		TransformNode.prototype.setDirty = function () {
			this.renderDirty = true;
			Node.prototype.setDirty.call(this);
		};

		TransformNode.prototype.setTransformDirty = function () {
			var i,
				target;
			this.transformDirty = true;
			this.dirty = true;
			this.renderDirty = true;
			for (i = 0; i < this.targets.length; i++) {
				target = this.targets[i];
				if (target.setTransformDirty) {
					target.setTransformDirty();
				} else {
					target.setDirty();
				}
			}
		};

		TransformNode.prototype.resize = function () {
			var i;

			Node.prototype.resize.call(this);

			for (i = 0; i < this.targets.length; i++) {
				this.targets[i].resize();
			}

			this.setTransformDirty();
		};

		TransformNode.prototype.setSource = function (source) {
			var newSource;

			//todo: what if source is null/undefined/false

			newSource = findInputNode(source);

			if (newSource === this.source) {
				return;
			}

			if (traceSources(newSource, this)) {
				throw 'Attempt to make cyclical connection.';
			}

			if (this.source) {
				this.source.removeTarget(this);
			}
			this.source = newSource;
			newSource.setTarget(this);

			this.resize();
		};

		TransformNode.prototype.setTarget = function (target) {
			var i;
			for (i = 0; i < this.targets.length; i++) {
				if (this.targets[i] === target) {
					return;
				}
			}

			this.targets.push(target);
		};

		TransformNode.prototype.removeTarget = function (target) {
			var i = this.targets && this.targets.indexOf(target);
			if (i >= 0) {
				this.targets.splice(i, 1);
			}

			if (this.targets && this.targets.length) {
				this.resize();
			}
		};

		TransformNode.prototype.alias = function (inputName, aliasName) {
			var me = this,
				input,
				def;

			if (reservedNames.indexOf(aliasName) >= 0) {
				throw aliasName + ' is a reserved name and cannot be used as an alias.';
			}

			if (this.plugin.inputs.hasOwnProperty(inputName)) {
				if (!aliasName) {
					aliasName = inputName;
				}

				seriously.removeAlias(aliasName);

				input = this.inputs[inputName];
				if (input) {
					def = me.inputs[inputName];
					Object.defineProperty(seriously, aliasName, {
						configurable: true,
						enumerable: true,
						get: function () {
							return def.get.call(me);
						},
						set: function (val) {
							if (def.set.call(me, val)) {
								me.setTransformDirty();
							}
						}
					});
				} else {
					input = this.methods[inputName];
					if (input) {
						def = input;
						seriously[aliasName] = function () {
							if (def.apply(me, arguments)) {
								me.setTransformDirty();
							}
						};
					}
				}

				if (input) {
					aliases[aliasName] = {
						node: this,
						input: inputName
					};
				}
			}

			return this;
		};

		TransformNode.prototype.render = function (renderTransform) {
			if (!this.source) {
				if (this.transformDirty) {
					mat4.copy(this.cumulativeMatrix, this.matrix);
					this.transformDirty = false;
				}
				this.texture = null;
				this.dirty = false;

				return;
			}

			this.source.render();

			if (this.transformDirty) {
				if (this.transformed) {
					//use this.matrix
					if (this.source.cumulativeMatrix) {
						mat4.multiply(this.cumulativeMatrix, this.matrix, this.source.cumulativeMatrix);
					} else {
						mat4.copy(this.cumulativeMatrix, this.matrix);
					}
				} else {
					//copy source.cumulativeMatrix
					mat4.copy(this.cumulativeMatrix, this.source.cumulativeMatrix || identity);
				}

				this.transformDirty = false;
			}

			if (renderTransform && gl) {
				if (this.renderDirty) {
					if (!this.frameBuffer) {
						this.uniforms = {
							resolution: [this.width, this.height]
						};
						this.frameBuffer = new FrameBuffer(gl, this.width, this.height);
					}

					this.uniforms.source = this.source.texture;
					this.uniforms.transform = this.cumulativeMatrix || identity;
					draw(baseShader, rectangleModel, this.uniforms, this.frameBuffer.frameBuffer, this);

					this.renderDirty = false;
				}
				this.texture = this.frameBuffer.texture;
			} else if (this.source) {
				this.texture = this.source.texture;
			} else {
				this.texture = null;
			}

			this.dirty = false;

			return this.texture;
		};

		TransformNode.prototype.destroy = function () {
			var i, key, item, hook = this.hook;

			//let effect destroy itself
			if (this.plugin.destroy && typeof this.plugin.destroy === 'function') {
				this.plugin.destroy.call(this);
			}
			delete this.effect;

			//stop watching any input elements
			for (i in this.inputElements) {
				if (this.inputElements.hasOwnProperty(i)) {
					item = this.inputElements[i];
					item.element.removeEventListener('change', item.listener, true);
					item.element.removeEventListener('input', item.listener, true);
				}
			}

			//sources
			if (this.source) {
				this.source.removeTarget(this);
			}

			//targets
			while (this.targets.length) {
				item = this.targets.pop();
				if (item && item.removeSource) {
					item.removeSource(this);
				}
			}

			for (key in this) {
				if (this.hasOwnProperty(key) && key !== 'id') {
					delete this[key];
				}
			}

			//remove any aliases
			for (key in aliases) {
				if (aliases.hasOwnProperty(key)) {
					item = aliases[key];
					if (item.node === this) {
						seriously.removeAlias(key);
					}
				}
			}

			//remove self from master list of effects
			i = transforms.indexOf(this);
			if (i >= 0) {
				transforms.splice(i, 1);
			}

			i = allTransformsByHook[hook].indexOf(this);
			if (i >= 0) {
				allTransformsByHook[hook].splice(i, 1);
			}

			Node.prototype.destroy.call(this);
		};

		/*
		Initialize Seriously object based on options
		*/

		if (options instanceof HTMLCanvasElement) {
			options = {
				canvas: options
			};
		} else {
			options = options || {};
		}

		if (options.canvas) {
		}

		/*
		priveleged methods
		*/
		this.effect = function (hook, options) {
			if (!seriousEffects[hook]) {
				throw 'Unknown effect: ' + hook;
			}

			var effectNode = new EffectNode(hook, options);
			return effectNode.pub;
		};

		this.source = function (source, options) {
			var sourceNode = findInputNode(source, options);
			//var sourceNode = new SourceNode(source, options);
			return sourceNode.pub;
		};

		this.transform = function (hook, opts) {
			var transformNode;

			if (typeof hook !== 'string') {
				opts = hook;
				hook = false;
			}

			if (hook) {
				if (!seriousTransforms[hook]) {
					throw 'Unknown transforms: ' + hook;
				}
			} else {
				hook = options && options.defaultTransform || '2d';
				if (!seriousTransforms[hook]) {
					throw 'No transform specified';
				}
			}

			transformNode = new TransformNode(hook, opts);
			return transformNode.pub;
		};

		this.target = function (target, options) {
			var targetNode, i;

			for (i = 0; i < targets.length; i++) {
				if (targets[i] === target || targets[i].target === target) {
					if (!!(options && options.renderToTexture) === !!targets[i].renderToTexture) {
						return targets[i].pub;
					}
				}
			}

			targetNode = new TargetNode(target, options);

			return targetNode.pub;
		};

		this.aliases = function () {
			return Object.keys(aliases);
		};

		this.removeAlias = function (name) {
			if (aliases[name]) {
				delete this[name];
				delete aliases[name];
			}
		};

		this.go = function (pre, post) {
			var i;

			if (typeof pre === 'function' && preCallbacks.indexOf(pre) < 0) {
				preCallbacks.push(pre);
			}

			if (typeof post === 'function' && postCallbacks.indexOf(post) < 0) {
				postCallbacks.push(post);
			}

			auto = true;
			for (i = 0; i < targets.length; i++) {
				targets[i].go();
			}

			if (!rafId && (preCallbacks.length || postCallbacks.length)) {
				renderDaemon();
			}
		};

		this.stop = function () {
			preCallbacks.length = 0;
			postCallbacks.length = 0;
			cancelAnimFrame(rafId);
			rafId = null;
		};

		this.render = function () {
			var i;
			for (i = 0; i < targets.length; i++) {
				targets[i].render(options);
			}
		};

		this.destroy = function () {
			var i,
				node,
				descriptor;

			while (nodes.length) {
				node = nodes.shift();
				node.destroy();
			}

			if (baseShader) {
				baseShader.destroy();
				baseShader = null;
			}

			//clean up rectangleModel
			if (gl) {
				gl.deleteBuffer(rectangleModel.vertex);
				gl.deleteBuffer(rectangleModel.texCoord);
				gl.deleteBuffer(rectangleModel.index);
			}

			if (rectangleModel) {
				delete rectangleModel.vertex;
				delete rectangleModel.texCoord;
				delete rectangleModel.index;
			}

			for (i in this) {
				if (this.hasOwnProperty(i) && i !== 'isDestroyed') {
					descriptor = Object.getOwnPropertyDescriptor(this, i);
					if (descriptor.get || descriptor.set ||
							typeof this[i] !== 'function') {
						delete this[i];
					} else {
						this[i] = nop;
					}
				}
			}

			baseFragmentShader = null;
			baseVertexShader = null;
			rectangleModel = null;
			gl = null;
			seriously = null;
			sources = [];
			targets = [];
			effects = [];
			nodes = [];
			preCallbacks.length = 0;
			postCallbacks.length = 0;
			cancelAnimFrame(rafId);
			rafId = null;


			isDestroyed = true;
		};

		this.isDestroyed = function () {
			return isDestroyed;
		};

		this.incompatible = function (pluginHook) {
			var i,
				plugin,
				failure = false;

			failure = Seriously.incompatible(pluginHook);

			if (failure) {
				return failure;
			}

			if (!pluginHook) {
				for (i in allEffectsByHook) {
					if (allEffectsByHook.hasOwnProperty(i) && allEffectsByHook[i].length) {
						plugin = seriousEffects[i];
						if (plugin && typeof plugin.compatible === 'function' &&
							!plugin.compatible.call(this)) {

							return 'plugin-' + i;
						}
					}
				}
			}

			return false;
		};

		//todo: load, save, find

		baseVertexShader = [
			'#ifdef GL_ES',
			'precision mediump float;',
			'#endif',

			'attribute vec4 position;',
			'attribute vec2 texCoord;',

			'uniform vec2 resolution;',
			'uniform mat4 transform;',

			'varying vec2 vTexCoord;',
			'varying vec4 vPosition;',

			'void main(void) {',
			// first convert to screen space
			'	vec4 screenPosition = vec4(position.xy * resolution / 2.0, position.z, position.w);',
			'	screenPosition = transform * screenPosition;',

			// convert back to OpenGL coords
			'	gl_Position.xy = screenPosition.xy * 2.0 / resolution;',
			'	gl_Position.z = screenPosition.z * 2.0 / (resolution.x / resolution.y);',
			'	gl_Position.w = screenPosition.w;',
			'	vTexCoord = texCoord;',
			'	vPosition = gl_Position;',
			'}\n'
		].join('\n');

		baseFragmentShader = [
			'#ifdef GL_ES',
			'precision mediump float;',
			'#endif',
			'varying vec2 vTexCoord;',
			'varying vec4 vPosition;',
			'uniform sampler2D source;',
			'void main(void) {',
			/*
			'	if (any(lessThan(vTexCoord, vec2(0.0))) || any(greaterThanEqual(vTexCoord, vec2(1.0)))) {',
			'		gl_FragColor = vec4(0.0);',
			'	} else {',
			*/
			'		gl_FragColor = texture2D(source, vTexCoord);',
			//'	}',
			'}'
		].join('\n');
	}
163804
public static void main(String[] s) {
		JFrame frame = new JFrame("JCalendar");

		JCalendar jcalendar = new JCalendar();
		frame.getContentPane().add(jcalendar);
		frame.pack();
		frame.setVisible(true);
	}
515144
public function main()
    {
        $this->validateAttributes();

        if ($this->file !== null) {
            if ($this->file->exists()) {
                if ($this->destFile === null) {
                    $this->destFile = new PhingFile($this->destDir, (string) $this->file->getName());
                }
                if ($this->overwrite === true || ($this->file->lastModified() > $this->destFile->lastModified())) {
                    $this->fileCopyMap[$this->file->getAbsolutePath()] = $this->destFile->getAbsolutePath();
                } else {
                    $this->log($this->file->getName() . " omitted, " . $this->destFile->getName() . " is up to date");
                }
            } else {
                // terminate build
                $this->logError("Could not find file " . $this->file->__toString() . " to copy.");
            }
        }

        $project = $this->getProject();

        // process filelists
        foreach ($this->filelists as $fl) {
            $fromDir = $fl->getDir($project);
            $srcFiles = $fl->getFiles($project);
            $srcDirs = [$fl->getDir($project)];

            if (!$this->flatten && $this->mapperElement === null) {
                $this->completeDirMap[$fromDir->getAbsolutePath()] = $this->destDir->getAbsolutePath();
            }

            $this->_scan($fromDir, $this->destDir, $srcFiles, $srcDirs);
        }

        foreach ($this->dirsets as $dirset) {
            try {
                $ds = $dirset->getDirectoryScanner($project);
                $fromDir = $dirset->getDir($project);
                $srcDirs = $ds->getIncludedDirectories();

                $srcFiles = [];
                foreach ($srcDirs as $srcDir) {
                    $srcFiles[] = $srcDir;
                }

                if (!$this->flatten && $this->mapperElement === null && $ds->isEverythingIncluded()
                ) {
                    $this->completeDirMap[$fromDir->getAbsolutePath()] = $this->destDir->getAbsolutePath();
                }

                $this->_scan($fromDir, $this->destDir, $srcFiles, $srcDirs);
            } catch (BuildException $e) {
                if ($this->haltonerror === true) {
                    throw $e;
                }

                $this->logError($e->getMessage());
            }
        }

        // process filesets
        foreach ($this->filesets as $fs) {
            try {
                $ds = $fs->getDirectoryScanner($project);
                $fromDir = $fs->getDir($project);
                $srcFiles = $ds->getIncludedFiles();
                $srcDirs = $ds->getIncludedDirectories();

                if (!$this->flatten && $this->mapperElement === null
                    && $ds->isEverythingIncluded()
                ) {
                    $this->completeDirMap[$fromDir->getAbsolutePath()] = $this->destDir->getAbsolutePath();
                }

                $this->_scan($fromDir, $this->destDir, $srcFiles, $srcDirs);
            } catch (BuildException $e) {
                if ($this->haltonerror == true) {
                    throw $e;
                }

                $this->logError($e->getMessage());
            }
        }

        // go and copy the stuff
        $this->doWork();

        if ($this->destFile !== null) {
            $this->destDir = null;
        }
    }
258210
function _main() {
  const {guides: acGuidePaths, images: acGuideImagesPaths, examples: acExamplePaths} = getPathsFromAioContent();
  const {guides: coGuidePaths, images: coGuideImagesPaths, examples: coExamplePaths} = getPathsFromCodeowners();

  const guidesDiff = arrayDiff(acGuidePaths, coGuidePaths);
  const imagesDiff = arrayDiff(acGuideImagesPaths, coGuideImagesPaths);
  const examplesDiff = arrayDiff(acExamplePaths, coExamplePaths);
  const hasDiff = !!(guidesDiff.diffCount || imagesDiff.diffCount || examplesDiff.diffCount);

  if (hasDiff) {
    const expectedGuidesSrc = path.relative(PROJECT_ROOT_DIR, AIO_GUIDES_DIR);
    const expectedImagesSrc = path.relative(PROJECT_ROOT_DIR, AIO_GUIDE_IMAGES_DIR);
    const expectedExamplesSrc = path.relative(PROJECT_ROOT_DIR, AIO_GUIDE_EXAMPLES_DIR);
    const actualSrc = path.relative(PROJECT_ROOT_DIR, CODEOWNERS_PATH);

    reportDiff(guidesDiff, expectedGuidesSrc, actualSrc);
    reportDiff(imagesDiff, expectedImagesSrc, actualSrc);
    reportDiff(examplesDiff, expectedExamplesSrc, actualSrc);
  }

  process.exit(hasDiff ? 1 : 0);
}
1218927
public function main()
    {

        // Call Phing on the file set with the attribute "phingfile"
        if ($this->phingFile !== null or $this->dir !== null) {
            $this->processFile();
        }

        // if no filesets are given stop here; else process filesets
        if (!empty($this->filesets)) {
            // preserve old settings
            $savedDir = $this->dir;
            $savedPhingFile = $this->phingFile;
            $savedTarget = $this->newTarget;

            // set no specific target for files in filesets
            // [HL] I'm commenting this out; I don't know why this should not be supported!
            // $this->newTarget = null;

            foreach ($this->filesets as $fs) {
                $ds = $fs->getDirectoryScanner($this->project);

                $fromDir = $fs->getDir($this->project);
                $srcFiles = $ds->getIncludedFiles();

                foreach ($srcFiles as $fname) {
                    $f = new PhingFile($ds->getbasedir(), $fname);
                    $f = $f->getAbsoluteFile();
                    $this->phingFile = $f->getAbsolutePath();
                    $this->dir = $f->getParentFile();
                    $this->processFile(); // run Phing!
                }
            }

            // side effect free programming ;-)
            $this->dir = $savedDir;
            $this->phingFile = $savedPhingFile;
            $this->newTarget = $savedTarget;

            // [HL] change back to correct dir
            if ($this->dir !== null) {
                chdir($this->dir->getAbsolutePath());
            }
        }

        // Remove any dangling references to help the GC
        foreach ($this->properties as $property) {
            $property->setFallback(null);
        }
    }
1188129
function main() {
    this.prior = this.current;
    this.current = this.current.apply(this, arguments) || this.current;
    // Call user transition function, if defined
    if (this.transition) {
        this.transition.apply(this, arguments);
    }
}
337162
public function main()
    {
        $buffer = '';
        $registry = GeneralUtility::makeInstance('KayStrobach\Dyncss\Configuration\BeRegistry');
        $handlers = $registry->getAllFileHandler();
        if (count($handlers)) {
            foreach ($handlers as $extension => $class) {
                /** @var AbstractParser $parser */
                $parser = new $class();
                $buffer .= '<tr><td>*.'.$extension.'</td>';
                $buffer .= '<td>'.$class.'</td>';
                $buffer .= '<td><a href="'.$parser->getParserHomepage().'" target="_blank">'.$parser->getParserName().'</a></td>';
                $buffer .= '<td>'.$parser->getVersion().'</td>';
                $buffer .= '</tr>';
            }
            /** @var FlashMessage $flashMessage */
            $flashMessage = GeneralUtility::makeInstance(
                FlashMessage::class,
                'Congrats, you have '.count($handlers).' handlers registered.',
                '',
                FlashMessage::OK,
                true
            );
            $this->addFlashMessage($flashMessage);
            $buffer = '<table class="t3-table table"><thead><tr><th>extension</th><th>class</th><th>name</th><th>version</th></tr></thead>'.$buffer.'</table>';
        } else {
            /** @var FlashMessage $flashMessage */
            $flashMessage = GeneralUtility::makeInstance(
                FlashMessage::class,
                'Please install one of the dyncss_* extensions',
                'No handler registered! - No dynamic css is handled at all ;/',
                FlashMessage::WARNING,
                true
            );
            $this->addFlashMessage($flashMessage);
            return $this->renderFlashMessage();
        }
        $renderedFlashMessages = $this->renderFlashMessage();
        return $renderedFlashMessages . $buffer;
    }
917635
function main()
    {
        $lem = new PHP_ParserGenerator_Data;

        $this->OptInit($_SERVER['argv']);
        if ($this->_version) {
            echo "Lemon version 1.0/PHP_ParserGenerator port version @package_version@\n";
            //exit(0); 
            return;
        }
        if ($this->OptNArgs($_SERVER['argv']) != 1) {
            echo "Exactly one filename argument is required.\n";
            //exit(1);
            return;
        }
        $lem->errorcnt = 0;
        $lem->parser_template = $this->_parser_template;

        /* Initialize the machine */
        $lem->argv0 = $_SERVER['argv'][0];
        $lem->filename = $this->_optArg(0, $_SERVER['argv']);
        $a = pathinfo($lem->filename);
        if (isset($a['extension'])) {
            $ext = '.' . $a['extension'];
            $lem->filenosuffix = substr($lem->filename, 0, strlen($lem->filename) - strlen($ext));
        } else {
            $lem->filenosuffix = $lem->filename;
        }
        $lem->basisflag = $this->_basisflag;
        $lem->has_fallback = 0;
        $lem->nconflict = 0;
        $lem->name = $lem->include_code = $lem->include_classcode = $lem->arg = $lem->tokentype = $lem->start = 0;
        $lem->vartype = 0;
        $lem->stacksize = 0;
        $lem->error = $lem->overflow = $lem->failure = $lem->accept = $lem->tokendest = $lem->tokenprefix = $lem->outname = $lem->extracode = 0;
        $lem->vardest = 0;
        $lem->tablesize = 0;
        PHP_ParserGenerator_Symbol::Symbol_new("$");
        $lem->errsym = PHP_ParserGenerator_Symbol::Symbol_new("error");

        /* Parse the input file */
        $parser = new PHP_ParserGenerator_Parser($this);
        $parser->Parse($lem);
        if ($lem->errorcnt) {
            return;
            // exit($lem->errorcnt);
        }
        if ($lem->rule === 0) {
            printf("Empty grammar.\n");
            return;
            //exit(1);
        }

        /* Count and index the symbols of the grammar */
        $lem->nsymbol = PHP_ParserGenerator_Symbol::Symbol_count();
        PHP_ParserGenerator_Symbol::Symbol_new("{default}");
        $lem->symbols = PHP_ParserGenerator_Symbol::Symbol_arrayof();
        for ($i = 0; $i <= $lem->nsymbol; $i++) {
            $lem->symbols[$i]->index = $i;
        }
        usort($lem->symbols, array('PHP_ParserGenerator_Symbol', 'sortSymbols'));
        for ($i = 0; $i <= $lem->nsymbol; $i++) {
            $lem->symbols[$i]->index = $i;
        }
        // find the first lower-case symbol
        for ($i = 1; ord($lem->symbols[$i]->name[0]) <= ord('Z'); $i++);
        $lem->nterminal = $i;

        /* Generate a reprint of the grammar, if requested on the command line */
        if ($this->_rpflag) {
            $this->Reprint();
        } else {
            /* Initialize the size for all follow and first sets */
            $this->SetSize($lem->nterminal);

            /* Find the precedence for every production rule (that has one) */
            $lem->FindRulePrecedences();

            /* Compute the lambda-nonterminals and the first-sets for every
            ** nonterminal */
            $lem->FindFirstSets();

            /* Compute all LR(0) states.  Also record follow-set propagation
            ** links so that the follow-set can be computed later */
            $lem->nstate = 0;
            $lem->FindStates();
            $lem->sorted = PHP_ParserGenerator_State::State_arrayof();

            /* Tie up loose ends on the propagation links */
            $lem->FindLinks();

            /* Compute the follow set of every reducible configuration */
            $lem->FindFollowSets();

            /* Compute the action tables */
            $lem->FindActions();

            /* Compress the action tables */
            if ($this->_compress===0) {
                $lem->CompressTables();
            }

            /* Reorder and renumber the states so that states with fewer choices
            ** occur at the end. */
            $lem->ResortStates();

            /* Generate a report of the parser generated.  (the "y.output" file) */
            if (!$this->_quiet) {
                $lem->ReportOutput();
            }

            /* Generate the source code for the parser */
            $lem->ReportTable($this->_mhflag);

            /* Produce a header file for use by the scanner.  (This step is
            ** omitted if the "-m" option is used because makeheaders will
            ** generate the file for us.) */
            //if (!$this->_mhflag) {
            //    $this->ReportHeader();
            //}
        }
        if ($this->_statistics) {
            printf(
                "Parser statistics: %d terminals, %d nonterminals, %d rules\n",
                $lem->nterminal,
                $lem->nsymbol - $lem->nterminal,
                $lem->nrule
            );
            printf(
                "                   %d states, %d parser table entries, %d conflicts\n",
                $lem->nstate,
                $lem->tablesize,
                $lem->nconflict
            );
        }
        if ($lem->nconflict) {
            printf("%d parsing conflicts.\n", $lem->nconflict);
        }
        //exit($lem->errorcnt + $lem->nconflict);
        echo $lem->errorcnt + $lem->nconflict;
        return ($lem->errorcnt + $lem->nconflict);
    }
661196
function main() {
    console.log("Will create symlink from " + languageDir + " to " + baseDir);
    let relativeLanguageDir = path.relative(currentDir, languageDir);
    let relativeBaseDir = path.relative(currentDir, baseDir);
    console.log("Using relative paths " + relativeLanguageDir + " to " + relativeBaseDir);
    symlinkOrCopySync(relativeLanguageDir, relativeBaseDir);

    // clean out elm-stuff cache
    glob(path.join(currentDir, "/elm-stuff/**/user/project/*/"+argv.rootModule+"*"), function(er, files) {
        files.forEach(function(file) {
            console.log("clearing out cache at", file);
            fs.removeSync(file);
        });
        if (argv.output) {
            build(argv.output);
        }
    });
}
1301106
function main(env, print, cb) {
    var dir = env.opts.directory || path.resolve(env.cwd, 'artifacts/jslint'),
        lines = [],
        count = 0,
        total = 0;

    function perOffense(o) {
        var evidence = o.evidence.trim();

        count += 1;
        total += 1;

        lines.push(fmt('  #%d %d,%d: %s', count, o.line, o.col, o.msg));
        if (evidence) {
            lines.push('     ' + evidence);
        }
    }

    /**
     * invoked by lintifier.doneYet()
     * @param {object|string|null} offenses
     * @param {string} msg "Done. no lint found..."
     */
    function reporter(offenses, msg) {
        var files,
            summary,
            writeErr;

        if (('string' === typeof offenses) || offenses instanceof Error) {
            cb(offenses);
            return;
        }

        function perFile(pathname) {
            count = 0;
            lines.push(pathname);
            offenses[pathname].forEach(perOffense);
            lines.push(''); // blank line
        }

        if (offenses) {
            // accumulate report in lines array
            files = Object.keys(offenses);
            files.forEach(perFile);
            summary = getSummary(total, files.length);

            if (env.opts.print) {
                lines.unshift('JSLint Report', '');
                print(lines.join(EOL));

            } else {
                writeErr = writeHtmlFile(dir, getHtml(lines, summary));
            }

            // has errors
            cb(writeErr || summary);

        } else {
            // is lint free
            cb(null, msg);
        }
    }

    return reporter;
}
965292
public static void main(String[] args) {
    for (int i = 0; i < args.length; i++)
      System.out.println("'" + args[i] + "' becomes '" + obfuscate(args[i]) + "'");
  }

  /**
   * Takes a string and returns an obfuscated string with no more than 2x a many characters as the
   * original. Only works in the DEV environment.
   */
  public static String obfuscate(String plaintext) {
    String blargtext = StringMan.encodeBytesToString(mangleArray(plaintext.getBytes()));
    blargtext = StringMan.compressHexString(blargtext);
    return blargtext;
  }

  /** Opposite of {@link #obfuscate(String)} */
  public static String clarify(String blargtext) {
    if (blargtext == null)
      return null;
    byte blargBytes[] = decodeStringToBytes(blargtext);
    String plaintext = new String(mangleArray(blargBytes));
    return plaintext;
  }

  /** Inlined from StringManipulator due to static init circular references, called by clarify */
  private static byte[] decodeStringToBytes(String hex) {
    hex = decompressHexString(hex);
    int stringLength = hex.length();
    byte[] b = new byte[stringLength / 2];
    for (int i = 0, j = 0; i < stringLength; i += 2, j++) {
      int high = charToNibble(hex.charAt(i));
      int low = charToNibble(hex.charAt(i + 1));
      b[j] = (byte) ((high << 4) | low);
    }
    return b;
  }

  /** Inlined from StringManipulator due to static init circular references, called by clarify */
  private static int charToNibble(char c) {
    if ('0' <= c && c <= '9')
      return c - '0';
    else if ('a' <= c && c <= 'f')
      return c - 'a' + 0xa;
    else if ('A' <= c && c <= 'F')
      return c - 'A' + 0xa;
    else
      throw new IllegalArgumentException("Invalid hex character: " + c);
  }

  /** Inlined from StringManipulator due to static init circular references, called by clarify */
  private static String decompressHexString(String in) {
    StringBuffer out = new StringBuffer();
    for (int i = 0; i < in.length(); i++) {
      char thisChar = in.charAt(i);
      if (thisChar != '^') {
        out.append(thisChar);
      } else {
        thisChar = in.charAt(i + 1);
        int count = "abcdefghijklmnopqrstuvwxyz01234567890".indexOf(in.charAt(i + 2));
        for (int j = 0; j < count; j++)
          out.append(thisChar);
        i += 2;
      }
    }
    return out.toString();
  }

  /**
   * Takes a given byte array and mangles it by XOR'ing it with a secret garbage hash. It is
   * reversible, so calling mangleArray(mangleArray(blah)) will return the original array.
   * 
   * @return the mangled array (Same size as the input array)
   */
  private static byte[] mangleArray(byte plainBytes[]) {
    if (plainBytes == null)
      return null;
    byte mangled[] = new byte[plainBytes.length];
    byte hash[] = SUPER_SECRET_MANGLE_STRING.getBytes();
    for (int i = 0; i < plainBytes.length; i++) {
      byte current = (byte) (plainBytes[i] ^ hash[i % hash.length]);
      mangled[i] = current;
    }
    return mangled;
  }

}
562213
function main(sources) {
    const intents = intent(sources)
    const state$ = model(intents.inputValue$, intents.messages$)
    return {
      // Send the virtual tree to the real DOM
      DOM: view(state$),
      // Send our messages to the horizon server
      horizon: intents.writeOps$$,
    }
  }
648964
function main() {
	// TODO: move loading of inputs into main function
	check(lookupQType(typeDecl.global,[]), {key: snapshot.global}, '', false, null, '<global>');
	if (program.missing) {
		findSuggestions()
	}
	if (program.coverage) {
		printCoverage();
	}
	if (program.stats) {
		console.log("# heap objects = " + snapshot.heap.length)
		console.log("# call signatures = " + num_callsigs_analyzed)
	}
}
1064370
function(input) {
  var code = 'var $_parsers = {\n';
  var parsernames = Object.keys(parsers);
  for (var i = 0; i < parsernames.length; i++) {
    code += '  ' + JSON.stringify(parsernames[i]) + ': ' +
      parsers[parsernames[i]].toString() + ',\n';
  };
  code += '}\n';
  code += compile(input) + '\nif (typeof $_end === "function") {$_end();}';
  var script = new vm.Script(code, {timeout: 4 * 60 * 1000});
  var runner = function(scope) {
    var output = '';
    var pipeOpen = false;
    var ended = false;
    var stream = new Readable({
      encoding: 'utf8',
      read: function() {
        pipeOpen = true;
        if (ended && output === '') {
          pipeOpen = this.push(null);
        } else if (output !== '') {
          pipeOpen = this.push(output);
          output = '';
        }
      },
    });
    scope.$_scope = scope;
    scope.$_write = function(data) {
      output += '' + data;
      if (pipeOpen && output !== '') {
        pipeOpen = stream.push(output);
        output = '';
      }
    };
    scope.$_end = function() {
      ended = true;
      if (pipeOpen) { stream.push(null); }
    };
    script.runInNewContext(scope)
    return stream;
  };
  runner.code = code;
  return runner;
}
1152395
function _main() {
  // Detect path to `tsconfig.app.json`.
  const ngConfig = parse(readFileSync(NG_JSON, 'utf8'));
  const tsConfigPath = join(ROOT_DIR, ngConfig.projects.site.architect.build.options.tsConfig);

  // Enable Ivy in TS config.
  console.log(`\nModifying \`${tsConfigPath}\`...`);
  const oldTsConfigStr = readFileSync(tsConfigPath, 'utf8');
  const oldTsConfigObj = parse(oldTsConfigStr);
  const newTsConfigObj = extend(true, oldTsConfigObj, NG_COMPILER_OPTS);
  const newTsConfigStr = `${JSON.stringify(newTsConfigObj, null, 2)}\n`;
  console.log(`\nNew config: ${newTsConfigStr}`);
  writeFileSync(tsConfigPath, newTsConfigStr);

  // Run ngcc.
  const ngccArgs = '--loglevel debug --properties es2015 module';
  console.log(`\nRunning ngcc (with args: ${ngccArgs})...`);
  exec(`yarn ivy-ngcc ${ngccArgs}`);

  // Done.
  console.log('\nReady to build with Ivy!');
  console.log('(To switch back to ViewEngine (with packages from npm), undo the changes in ' +
              `\`${tsConfigPath}\` and run \`yarn aio-use-npm && yarn example-use-npm\`.)`);
}
1253083
public function main()
    {
        $this->setup();
        while (!$this->eos()) {
            $p = $this->pos();
            $state = $this->stateName();

            $this->loadTransitions();
            list($nextPatternData, $nextPatternIndex, $nextPatternMatches) = $this->nextStartData();
            list($endIndex, $endMatches) = $this->nextEndData();

            if (($nextPatternIndex <= $endIndex || $endIndex === -1) && $nextPatternIndex !== -1) {
                // we're pushing a new state
                if ($p < $nextPatternIndex) {
                    $this->recordRange($p, $nextPatternIndex);
                }
                $newPos = $nextPatternIndex;
                $this->pos($newPos);
                $tok = $nextPatternData[0];
                if (isset($this->overrides[$tok])) {
                    // call override
                    $ret = call_user_func($this->overrides[$tok], $nextPatternMatches);
                    if ($ret === true) {
                        break;
                    }
                    if ($this->stateName() === $state && $this->pos() <= $newPos) {
                        throw new Exception('Override failed to either advance the pointer or change the state');
                    }
                } else {
                    // no override
                    $this->posShift(strlen($nextPatternMatches[0]));
                    $this->pushState($nextPatternData);
                    $this->record($nextPatternMatches[0]);
                    if ($nextPatternData[2] === null) {
                        // state was a full pattern, so pop now
                        $this->popState();
                    }
                }
            } elseif ($endIndex !== -1) {
                // we're at the end of a state, record what's left and pop it
                $to = $endIndex + strlen($endMatches[0]);
                $this->recordRange($this->pos(), $to);
                $this->pos($to);
                $this->popState();
            } else {
                // no more matches, consume the rest of the stirng and break
                $this->record($this->rest());
                $this->terminate();
                break;
            }
            if ($this->stateName() === $state && $this->pos() <= $p) {
                throw new Exception('Failed to advance pointer in state' . $this->stateName());
            }
        }

        // unterminated states will have left some tokens open, we need to
        // close these so there's just the root node on the stack
        assert(count($this->tokenTreeStack) >= 1);
        while (count($this->tokenTreeStack) > 1) {
            $this->popState();
        }

        return $this->tokenTreeStack[0];
    }
1288206
public static void main(final String[] args) throws Exception {
		// System.out.println(getSystemInfo().toString().replaceAll(",",
		// JK.NEW_LINE));
		System.out.println(HardWare.MAC);
		System.out.println(getMacAddress());
	}