e['function3'] = function () {
	//all functions are private unless included in return statement
// 'abstract' method implementations (for api)
	function getInterface() {
		var out = "<ul>";
		out += "<li><h1>Matrices</h1></li>";
		// input #1 (onKeyPress need to calc height & width of matrix in validate input)
		out += "<li><span id='matrix1_size' style='float:right;'>" + getSizeHtml(4,3) + "</span><label for='matrix1'>Matrix A</label></li>";
		out += "<li class='input'><textarea id='matrix1' rows='8' cols='40'>";
		out += "2 3 -2\n";
		out += "-1 4 3\n";
		out += "0 -7 3\n";
		out += "1 1 0";
		out += "</textarea></li>";
		// input #2 (onKeyPress need to calc height & width of matrix in validate input)
		out += "<li><span id='matrix2_size' style='float:right;'>" + getSizeHtml(3,2) + "</span><label for='matrix2'>Matrix B</label></li>";
		out += "<li class='input'><textarea id='matrix2' rows='8' cols='40'>";
		out += "2 1\n";
		out += "-7 -4\n";
		out += "3 -2";
		out += "</textarea></li>";
		// submit button's
		out += "<li>&nbsp;</li>";
		out += "<li class='input'><input id='submit_add' onclick=\"e['function3'].getHTML(this, document.getElementById('returnValue'))\" type='submit' value='Add (A + B)'/></li>";
		out += "<li class='input'><input id='submit_sub' onclick=\"e['function3'].getHTML(this, document.getElementById('returnValue'))\" type='submit' value='Subtract (A - B)'/></li>";
		out += "<li class='input'><input id='submit_mul' onclick=\"e['function3'].getHTML(this, document.getElementById('returnValue'))\" type='submit' value='Multiply (A * B)'/></li>";

		out += "</ul>";
		return out;
	}

	function getHTML(caller, returnNode) {
		// grab input vals
		var matrixContainer1 = document.getElementById('matrix1');
		var matrixContainer2 = document.getElementById('matrix2');
		if (validateInput(matrixContainer1) && validateInput(matrixContainer2)) {
			var m1 = getMatrix(matrixContainer1);
			var m2 = getMatrix(matrixContainer2);
			var size1 = document.getElementById('matrix1_size');
			var size2 = document.getElementById('matrix2_size');

			var r1 = getRows(m1);
			var r2 = getRows(m2);
			var c1 = getCols(m1);
			var c2 = getCols(m2);

			//format for output and create html
			var out = "<ul>";
			out += "<li><h1>Results</h1></li>";
			var returnM;
			if (caller.id == 'submit_add' && size1.textContent == size2.textContent) {
				returnM = mAdd(m1, m2);
			} else if (caller.id == 'submit_sub' && size1.textContent == size2.textContent) {
				returnM = mSub(m1, m2);
			} else if (caller.id == 'submit_mul' && c1 == r2) {
				returnM = mMul(m1, m2);
			} else if (caller.id == 'submit_mul' && c1 == r1 == 1) {
				returnM = mMulScalar(m1[0][0], m2);
			} else if (caller.id == 'submit_mul' && c2 == r2 == 1) {
				returnM = mMulScalar(m2[0][0], m1);
			} else {
				out += "<li><label for='results'>" + caller.value + "</label></li>";
				out += "<li class='error'><span>Operation Not Defined</span></li>";
				returnNode.innerHTML = out + "</ul>";
				return false;
			}
			out += "<li><span id='results_size' style='float:right;'>" + getSizeHtml(getRows(returnM), getCols(returnM)) + "</span><label for='results'>" + caller.value + "</label></li>";
			out += "<li class='output'><textarea id='results' rows='8' disabled='disabled' cols='40'>" + getPrintMatrix(returnM) + "</textarea></li>";
			returnNode.innerHTML = out + "</ul>";
		}
	}

	function validateInput(matrixContainer) {
		var m1 = getMatrix(matrixContainer);
		document.getElementById(matrixContainer.id + '_size').textContent = getSizeHtml(getRows(m1), getCols(m1));
		// meh, return true i guess (it's a matrix after all; this isnt' a validate method, it just updates the display)
		return true;
	}

// Program & Presentation Functions
	function getMatrix(from) {
		from.value = from.value.trim();
		var m = from.value.split('\n');
		for (i = 0; i < m.length; i++) {
			m[i] = m[i].trim().split(' ');
			for (var j = 0; j < m[i].length; j++) { m[i][j] = parseFloat(m[i][j]); }
		}
		return m;
	}
	function getPrintMatrix(m) {
		var out = new String();
		if (!m) { return out; }
		for (i = 0; i < m.length; i++) {
			for (j = 0; j < m[i].length; j++) {
				if (typeof(m[i][j]) == 'number') { out += m[i][j].toFixed(3) + " "; }
			}
			out += '\n';
		}
		return out;
	}
	function getRows(m) {
		if (!m) { return 0; }
		return m.length;
	}
	function getCols(m) {
		if (!m) { return 0; }
		var maxCols;
		for (var i = 0; i < m.length; i++) {
			maxCols = (maxCols < m[i].length ? maxCols : m[i].length);
		}
		return maxCols;
	}

	function getSizeHtml(rows, cols) {
		return '[' + rows + ' x ' + cols + ']';
	}

// Math Functions
	function mAdd(a, b) {
		var m = new Array();
		for (var r = 0; r < getRows(a); r++) {
			m[r] = new Array();
			for (var c = 0; c < getCols(b); c++) {
				m[r][c] = a[r][c] + b[r][c];
			}
		}
		return m;
	}
	function mSub(a, b) {
		var m = new Array();
		for (var r = 0; r < getRows(a); r++) {
			m[r] = new Array();
			for (var c = 0; c < getCols(b); c++) {
				m[r][c] = a[r][c] - b[r][c];
			}
		}
		return m;
	}
	function mMul(a, b) {
		var m = new Array();
		for (var r = 0; r < getRows(a); r++) {
			m[r] = new Array();
			for (var c = 0; c < getCols(b); c++) {
				m[r][c] = 0;
				for (var r2 = 0; r2 < getCols(a); r2++) {
					m[r][c] += a[r][r2] * b[r2][c];
				}
			}
		}
		return m;
	}
	function mMulScalar(k, a) {
		for (var i = 0; i < getRows(a); i++) {
			for (var j = 0; j < getCols(a); j++) {
				a[i][j] = k * a[i][j];
			}
		}
		return a;
	}

// return public pointers to the private methods
	return {
		getInterface:getInterface,
		getHTML:getHTML,
		validateInput:validateInput,

		getMatrix:getMatrix,
		getPrintMatrix:getPrintMatrix,
		getRows:getRows,
		getCols:getCols,
		getSizeHtml:getSizeHtml
	}

}();

