// CjM Client-Side JavaScript (client.js)

//alert ('client.js linked'); // enable this line to quickly test whether or not this script is linked to the current page.
function CjM_Multimedia() { // signature
// properties (ioCjM)
	this.type = "CjM";
	this.author = "CjM"; 
	this.version = "20100210";
	this.script = "client.js";
	this.call = "act(this,event);"; // standard "call" code, placed within any event of client-side markup.
	this.actors = []; // this is the list of objects considered to be actors.
// methods (ioCjM)
	this.test = function(s) {
		alert(s);
	}
	this.actor = function(o) { // object
		this.actors.push(o);
	} // this makes a given object aware of user-instigated "act" signals.
	this.act = function(o,e) { // object, event // aka. act(this,event); // goes in markup tags like this: <a href=# onMouseDown="act(this,event);">Click me!</a>
		for (var i = 0; i < gActors.length; i++) {
			this.actors[i].act(o,e); // passes this,event to the act() method of any object listed as an actor.
		};
	} // basically, this sends an "act" signal to every listed actor, along with originating object reference and event reference, that the user has performed an act.
	return this;
} // client-side code interface
gCjM = new CjM_Multimedia();

// * SOME HOW GET THIS CODE TO WORK WITHIN AN OBJECT * //
// Actors (CjM)
gActors = []; // when an object is listed as an actor, it recieves act(this,event) pairs from user interactivity.
function actor(o) { // object
	gActors.push(o);
}; // lists an object as an actor (essentially, letting it recieve the "act(this,event);" message)
// custom classes can be built-in to list their objects automatically, using this actor() function within it's object constructor.

function act(o,e) { // this, event
//alert(gActors[0].type); //alert(o.name+'...'+e.type);
// b/c all markup nodes are standardized by this format: onEvent="act(this,event)"
//	alert(count(gActors));
//	alert(is(gActors,'array'));
	for (var i = 0; i < gActors.length; i++) {
		gActors[i].act(o,e); // passes this,event to the act() method of any object listed as an actor.
	};
}; // "act" is a global function that catches and routes nodes and events to the local objects listed as actors.
// "actors" must have an "act()" method/event defined in their class to recieve these events.
// this is done to fork one call across multiple scripts.

// CjM_Logic
// Elements
function is(o,y) { // object, type
// "is" dependencies on built-in javascript functions:  typeof(), isFinite().
	if ((o!=null) && (y!=null)) {
		switch (y) { // the order of the "is" matters! ;)
		// basic
			case 'boolean' : return (typeof(o) == 'boolean'); break;
			case 'integer' : // ...
			case 'number' : return (typeof(o) == 'number' && isFinite(o)); break;
			case 'string' : return (typeof(o) == 'string'); break;
			case 'undefined' : return (typeof(o) == 'undefined'); break;
//			case 'null' : return (typeof(o) == 'object' && !o); break;
			case 'function' : return (typeof(o) == 'function');	break; // function
			case 'array' : return (is(o,'object') && o.constructor == Array); break; // array
			case 'object' :	return ((o && typeof(o) == 'object') || is(o,'function')); break; // object
		// advanced
			case 'path' : return (is(o,'string')); break;
			default: // if y=null
//				var a = new Array('boolean','number','string','undefined','null','function','object','array');
//				if (is(o,'array')) { return 'array'; };
				var a = new Array('boolean','number','string','undefined','function','array','object'); // this code tells what types to look for (the order matters)
				var i; for (i in a) { if (is(o,a[i])) { return a[i]; };	}; // this code determines what it is.
				break;
		};	
	};	
};

function are(a,y) { // array, types
	if (is(a,'array')) {
		switch (y) { // multiple checks
			case 'strings' : var z = 'string'; break;
			case 'integer' : case 'integers' : 
			case 'numbers': var z = 'number'; break;
		};
		for (var i=0; i < a.length; i++) {
			if (is(a[i],z) != 1) { return 0; };	


		}; return 1;
	};
}; // "are" is an "is" for identifying multiple objects in an array.

function has(o,v) { // object, value
	switch (is(o)) {
		case 'array' : // whether this array has the value, as an element.
			for(var i=0; i < o.length; i++) {
				if (o[i] == v) return true;
			}; return false;
		break;
		case 'string' : // whether this string has the value, as a substring.
//			var m = new RegExp(o); // * why use JavaScript's RegExp Object to match strings?  i don't know.
			return (v == o.match(v)); // return (v == o.match(m));
		break;
	};
};

function count(o,y) { // object, symbol
	if (is(o,'array') || is(o,'string')) { return o.length; };
};

function digits(n) { // number-with-digits
	var s = '';
	if (is(n,'number')) { s = '' + n; }; // if number, converts number-to-string.
	return count(s);
}; // digits, returns the number of digits within a number.

function zeros(n,z) { // number-to-pad-with-, how-many-zeros
	var s = '';
	if (is(n,'integer') && is(z,'integer')) {
		s = '' + n;
		for (var i=1; i<=z; i++) {
			if (i > count(s)) { s = '0' + s; };
		};
	};
	return s;
}; // zeros, takes a number and prefixes a fill with zeros.

function hash(o,p,v) { // string-or-array, split-item-character, associative-value-character
	if (is(o,'string')) { 
		var a = o.split(p); 
		var r = [];
		for (i=0; i < a.length; i++) {
			var j = a[i].split(v); // this splits the name/value key by given seperator
			r.push(j[0]); // * this makes the name key.
			r[j[0]] = j[1]; // * this associates the value.
		};
		return r;
	}; // ex. o.split("&");
}

function get(aTagOrId) { // returns an HTML element object, by given tag or id string.
	var r = document.getElementById(aTagOrId); 
	if (r != null) { return r; };
	var r = document.getElementsByTagName(aTagOrId); 
	if (r != null) { 
		if (r[0] != null) { 
			if (r.length == 1) { // if single element within a collection, ..
				return r[0]; // .. then return only the single element, not the wrapper collection object.
			} else { // otherwise, there are multiple element objects, ..
				return r; // .. so return the entire collection object.
	};	};	};
	return null;
};

function set(aTagOrId,aPropertyOrAttribute,aValue,aStyleOrNot) {
	var o = get(aTagOrId);
	if (o) {
		switch (aStyleOrNot) {
			default: case 'style' : 
				if (navigator.userAgent && navigator.userAgent.indexOf("MSIE") >= 0) {
					o.style.setAttribute(aPropertyOrAttribute, aValue);
				} else {
					o.style.setProperty(aPropertyOrAttribute, aValue, null);
				};
			break; 
			case 'markup' : 
				switch (aPropertyOrAttribute) {
					case 'src' :
						o.src = aValue;
					break;
				};
			break;
		};
	};
	return o;
}; // set a markup or style attribute

// Arrays
function dupe(a) { // array-to-duplicate
// duplicates a given array, resulting in a new array with no references to the original array.
	if (is(a,'array')) {
		var d = new Array(); var i;
		for (i=0; i<a.length; i++) {
			d.push(a[i]);
		}; return d;
	}; return 0;
};

// * NORMALIZE DOESN'T WORK YET * //
function normalize(a) { // array-to-normalize
	if (is(a,'array')) {
//		alert(a);
		var f = false; // flag
		var nl = [];
		for (var i = 0; i >= count(a); i++) {
			if (is(o[i],'array')) { // add embeded array contents to end.
				for (var j = 0; j >= count(o[i]); j++) {
					nl.push(o[i][j]);
				};
				f = true;
			} else {
				nl.push(o[i]);
			};
		};
		if (f) { var nl = normalize(nl); }; // recurse
		return nl;
	};
}; // "normalizes" a set of given arrays, resulting in a new single 1-D array.

// Strings
function fix(p,s,q,m) { // prefix, string, postfix, mode
// dependencies, custom duplicate().
	switch (is(s)) {
		case 'string' : // single
			if (is(p,'string')) { s = p + s; }; // prefix
			if (is(q,'string')) { s = s + q; }; // postfix
			//return s;
			break;
		case 'array' : // multiple
			if (m != 'overwrite') { var s = dupe(s); };
			for (i=0; i<s.length; i++) {
				s[i] = fix(p,s[i],q); // recurse
			}; 
			//return a;
			break;
	}; return s;
};
function prefix(s,p) { return fix(p,s,0); };
function postfix(s,q) { return fix(0,s,q); };

function fit(n,h) { // division-name, height
	if ((h == null) && (h != 0)) { // then determine maximum height, then automatically fit!
		var height = 0;
		var divisions = document.getElementsByTagName("div");
//		for (var division in divisions) { // loops per division name (* doesn't work cross-browser *)
		for (var i=0; i < divisions.length; i++) { // * works cross-browser for IE, Firefox & Safari despite variations.
			division = divisions[i]; // 	
//			division = get(division); // gets the actual division object
			if (division) { // if not null, then ...
//				alert(division.offsetHeight);
				if (division.offsetHeight > height) { // if division height is greater than current height ..
					height = division.offsetHeight; // then update the current height.
		};	};	}; // booya!
		if (height != 0) { return fit(n,height); }; // fit the given-name-of-division's height * recurse
	};
	if ((get(n)) && (h != null)) { get(n).style.height = h + 'px'; return h; };
} // use "fit" to resize divisions to "fit" with each other automatically.

// function place() // * put code here * //

function place(n,v,h) { //,z) { // division-name, vertical(top), horizontal(left)
//function place(n,b,l,r,t) { // division-name, bottom, left, right, top
	d = get(n); // get the division
	if (d) { //
		if (v) { d.style['top'] = v + "px"; }; // set left
		if (h) { d.style['left'] = h + "px"; }; // set top
//		if (x) { d.style['left'] = x + "px"; }; // set left
//		if (y) { d.style['top'] = y + "px"; }; // set top
//		if (z) { d.style[''] = z; }; // set z
//		if (b) { d.style['bottom'] = b; }; // set bottom
//		if (l) { d.style['bottom'] = l; }; // set left
//		if (r) { d.style['bottom'] = r; }; // set right
//		if (t) { d.style['bottom'] = t; }; // set top
	};
} // use to "place" a division somewhere on the page.

function replace(s,o,n) { // string, old-string, new-string
	if (are([s,o],'strings')) {
		return s.replace(o,n);
	};
}; // "replace" essentially replaces the first instance of the old-pattern found within a string with the new-pattern.
// this custom "replace" function shares the name with a <String>.replace() method, so luckily it doesn't overlap.


// Visibility
function visible(a,v) { // object/array, visibility
	if ((v == 'hidden')||(v == 'visible')) { // ensure argument values are valid
		if (!is(a,'array')) { a = new Array(a); }; // make a single-element into an array.
		if (is(a,'array')) { // only process arrays (multiple-element style).
			for (i=0; i<a.length; i++) { 
				get(a[i]).style.visibility = v;
	};	};	};
};

function hide(o) { 
	var o = get(o);
	if (o) {
		o.visibility = 'hidden';
		o.style.display = 'none';
	};
}; // hide via CSS display

function show(o) { 
	o = get(o);
	if (o) {
		o.style.display = 'block'; 
		o.visibility = 'visible';
	};
}; // show via CSS display

function showhide(s,h) { // array-of-strings-of-elements-to-show, array-of-strings-of-elements-to-hide
	var c = count(h); // count of element in array
	for(var i=0; i < c; i++) { // hide all elements
		hide(h[i]);
	};
	var c = count(s); // count of element in array
	for(var i=0; i < c; i++) { // hide all elements
		show(s[i]);
	};
}; // show given element, and hide given elements

// Style (to control CSS Styles)
function style (aTagOrId, aStyleOrClassCSS, aStyleValue) { // element, style, value
	var vElementHTML = get(aTagOrId);
	if ((vElementHTML) && !(aStyleValue)) { // change CSS via HTML "class" attribute
		if (vElementHTML.className) { // sets the class="" propert;
			vElementHTML.className = aStyleOrClassCSS;
			return vElementHTML.className;
		};
	};
	if ((vElementHTML) && (aStyleValue)) { // change CSS styles via JavaScript/DOM <element>.style property interface.
		vElementHTML.style[aStyleOrClassCSS] = aStyleValue;
		return vElementHTML.style[aStyleOrClassCSS];
	};
	return null;
};
function stylize (aTagOrId, aStyleOrClassCSS) { return style(aTagOrId, aStyleOrClassCSS, aStyleValue); }; // syn.

function collapse(aTagOrId) { return style(aTagOrId,'display','none'); }; // use CSS style "display: none" to collapse DIV elements.
function uncollapse(aTagOrId) { return style(aTagOrId,'display','block'); }; // use CSS style "display: block" to uncollapse DIV elements.


// MATH //
function greatest(a) { // array-of-numbers
	if (is(a,'array')) { // * of numbers
		var c = count(a); // count of element in array
		for(var i=0; i < c; i++) {
			if (i == 0) { 
				var n = a[i]; 
			} else { 
				if (is(a[i],'number')) {
					if (a[i] > n) { n = a[i]; }; // greatest number variable
				};
			};
		};
		return n;
	};
}; // returns the greatest number in an array of numbers

function least(a) { // array-of-numbers
	if (is(a,'array')) { // * of numbers
		var c = count(a); // count of element in array
		for(var i=0; i < c; i++) {
			if (i == 0) { 
				var n = a[i]; 
			} else { 
				if (is(a[i],'number')) {
					if (a[i] < n) { n = a[i]; }; // greatest number variable
				};
			};
		};
		return n;
	};
}; // returns the greatest number in an array of numbers

// ELEMENTS //

function size(e) { // element(s)
	if (is(e,'string')) {
//		alert(e);
	};
};

// Input (via GET Method, aka. "Query-String")

function QueryString() { // object reads input via GET Method, aka "Query-String" on URL.
	// properties [raw, string, array, hash]
	// methods
	this.read = function (aName) { //
		if (aName == null) { // build the data
			this.raw = window.location.search; // The JavaScript Location Object has the URL QueryString.
		//if (this.raw.length < 1) { this.raw = null; };
		// capture string
			if (this.raw.length > 1) { 
				this.string = '';
				this.string = this.raw.substring(1,this.raw.length);
			}; // removes the question mark "?" leaving just the string.
		// build array
			if (this.string != '') { 
				this.array = new Array(); // array, store the name=value pairs
				for (var i=0; i < this.string.split("&").length; i++) { // first, split into name=value pairs.
					this.array[i] = this.string.split("&")[i];
				};
				this.hash = new Array(); // hash, store name/value pairs, values referenced by name.
				for (var i=0; i < this.array.length; i++) { // last, split the name=value pairs into a hash.
					this.hash[i] = this.array[i].split("=")[0]; // name
					this.hash[this.hash[i]] = this.array[i].split("=")[1]; // value
				};
				return this.hash;
			};
		} else { // return the value
			if (is(aName,'string') || is(aName,'number')) {
				if (this.hash == null) { this.read(); };
				return unescape(this.hash[aName]); // "unescape()" the encoded string, and return the value.
			};
		};
	};
	this.write = function (aName,aValue) {
		// this.read(aName);
		// escape();
	};
};

function read(e) { // element
	switch (e) {
		// Input elements.
		case 'QueryString' : // reads the query string
			var qs = new QueryString();
			return qs.read();
		break;
	};
};


// Trys to add a URL and it's name to the bookmarks/favorites list of your current browser.
function bookmark(u,n) { // url, name
	if (window.sidebar) { window.sidebar.addpanel(n,u,""); return 1; }; // Mozilla Firefox
	if (document.all) { window.external.AddFavorite(u,n); return 1; }; // Internet Explorer
	return 0;
}; // 
function favorite(u,n) { return bookmark(u,n); }; // alias, to bookmark
//

function visit(u,w) { // url, window
	switch(w) {
		case 'new' : window.open(u); break;
		default: //
			window.location = u;
	};
}; // visit sends the user experience to another URL.

function listen(o,e,m,b) { // object, event, method, bubble-or-capture
// make W3C psuedo-functionality by anonymous function to the object, if appropriate
// make the element listen to given event
	if (is(o,'string')) { o = get(o); };
	if (o.attachEvent) { o.attachEvent(e,m); return true; }; // IE
	if (o.addEventListener) { o.addEventListner(e,m,false); return true; }; // W3C // ex. document.getElementById( "myThing" ).addEventListener( "click", myFunction );
	return false;
}; // this function adds an event listener to given object, essentially commanding the object to listen for a specific event.

function test () {
//	alert('global test called for Client-Side JavaScript (client.js)');
};

// re-direction code, for 
//if (1) {
//	window.location = "/";
//	alert(window.self);
//};

/*
// class, via prototype (this definitely works)
function MyClass(MyArgument) {
    this.MyProperty = MyArgument;
}
MyClass.prototype.MyProperty;
// methods
MyClass.prototype.MyMethod = function() {
    return this.MyProperty;
}
// instance
var p = new Pet("Maxi");
alert(p.getName());
*/

// Memory //
function load(y,p,w,h) { // type, path, width, height
	switch (y) {
		case 'image' : // single
			if (is(w,'integer') && is(h,'integer')) { 
				var m = new Image(w,h);
			} else {
				var m = new Image();
			};
			if (is(p,'string')) { m.src = p; };
			//if (is(p,'path')) { m.src = p; };
		break;
		case 'images' : // multiple
//			if (is(p,'array')) {
//				if (is(w,'integer') && is(h,'integer')) { var m = new Image(w,h); };
//				for (var i = 0; i < p.length; i++) {
//					m.src = p[i];
//				};
//			};
		break;
	};
}
// load('images',[],100,100);
//

function getWindowHeight() {
	var windowHeight=0;
	if (typeof(window.innerHeight)=='number') {
		windowHeight=window.innerHeight;
	} else {
		if (document.documentElement&&document.documentElement.clientHeight) {
			windowHeight=document.documentElement.clientHeight;
		} else {
			if (document.body&&document.body.clientHeight) {
				windowHeight=document.body.clientHeight;
			}
		}
	}
	return windowHeight;
}

function url(o,f) { // object, format
	switch (o) { // <protocol>//<host>[:<port>]/<pathname>[<hash>][<search>] 
	// properties (Location)
//		case 'domain' : break;
		case 'host' : return location.host; break;
		case 'hostname' : return location.hostname; break;
		case 'href' : return location.href; break;
		case 'pathname' : return location.pathname; break;
		case 'port' : return location.port; break;
		case 'protocol' : return location.protocol; break;
		case 'search' : case 'querystring' : return location.search; break;
		case 'query' : return (url('search').replace(/^\?/g,'')); break; // * /^\?/g, removes the ? character.
	// methods (Location)
		case 'reload' : location.reload(); break;
		case 'replace' : location.replace(); break;
		default : return location; break;
	};
} // returns the current url, or requested portion.

function link(k) {
//	alert(k);
}

function adjust(e,r) { // element, to-relative-array-of-element-names-to-determine-midder-height
	// adjust #midder to the content <div> w/ the greatest height //
	switch (e) {
		case 'footer' : // adjusts the footer to the absolute bottom
			var a = document.getElementsByTagName('div');
			var v = 0;
			for (var n in a) { // parse names in elements
				o = get(n); // get object by element name
				if (o) { var h = o.offsetHeight; }; // 
				if (h) { if (v < h) { v = h; }; }; // 
			};
			v = v + get('header').offsetHeight; // midder + header = footer "top"
			place('footer',v); // vertical
		case 'midder' : 
			var h = 0; // height-to-calculate
			for (var i = 0; i < count(r); i++) {; 
				var o = get(r[i]);
//				if (o != null) { if (h < o.offsetHeight) { h = o.offsetHeight; };	}; // greatest height method (flawed)
				if (o != null) { if (o.offsetHeight) { h = h + o.offsetHeight; }; }; // given height method (better, but be careful what #elements exist!)
			};
			if (get('midder')) { if (get('midder').offsetHeight) { if (h > get('midder').offsetHeight) { set('midder').style.height = (h + 'px'); }; }; };
		break;
	};
//	set('footer','top',((get('content').offsetHeight + get('footer').offsetHeight)) + 'px');
}; // adjusts the "midder" shell of the layout

function activate(e) {
	switch (e) {
		case 'objects' : 
			var objects = document.getElementsByTagName("object"); 
		    for (var i = 0; i < objects.length; i++) 
		    { 
		      objects[i].outerHTML = objects[i].outerHTML; 
		    } ;
		break;
	};
}; // "activates" all embeded objects to get around annoying Microsoft "click to activate" crap.

function validate(o,m,r) { // object, method, require-array
	switch (m) {
		case 'email' : case 'e-mail' : case 'email address' : case 'e-mail address' :
			var validemail=/^\w+[\+\.\w-]*@([\w-]+\.)*\w+[\w-]*\.([a-z]{2,4}|\d+)$/i; // regular-expression to check against
			return validemail.test(o);
		break;
		case 'form' :
			if (is(r,'array')) {
/*
	for (var i = 0; i < q.length; i++){
		var e = o.elements[q[i]];
		if (e) {
			switch(e.type){
			case "select-one": if (o.selectedIndex == -1 || o.options[o.selectedIndex].text == "") {}; break;
			case "select-multiple": if (o.selectedIndex == -1) {}; break;
			case "text": case "textarea": if (o.value == "" || o.value == null) {}; break;
			default: break;
			};
			if (o.type == undefined){
				var blnchecked = false;
				for (var j = 0; j < o.length; j++){
					if (o[j].checked) { blnchecked = true; };
				};
				if (!blnchecked) {};
			};
		};
	};
*/
			};
		break;
	};
}; // 

// IMAGES //
function opacity() {
	if (is(o,'string')) { o = get(o); };
	if (is(o,'object')) { // single
		// changes opacity for different browsers
		o.opacity = (v / 100); // (?) browser
		o.MozOpacity = (v / 100); // 
		o.KhtmlOpacity = (v / 100); //
		o.filter - "alpha(opacity=" + v + ")"; // 
	};
}; // sets the level of opacity for given image-object, cross-browser.

function fade(o,v,e,t) { // element, opacity(-begin-value-percentage), opacity-end-value-percentage, time-in-milliseconds
	// set speed for each frame to animate
	var speed = Math.round(t / 100);
	var timer = 0;
	// behave with multiple calls over time
	if ((is(e,'integer')) && (is(t,'integer'))) {
		if (v > e) {
			for (i = v; i >= e; i--) { // fade-out
				setTimeout("opacity(" + i + ",'" + o.id + "')",(timer * speed));
				timer++;
			};
		} else if (v < e) {
			for (i = v; i <= e; i++) { // fade-in
				setTimeout("opacity(" + i + ",'" + o.id + "')",(timer * speed));
				timer++;
			};
		};
	};
}; // fade, fades in-or-out and image by changing it's opacity over time.

function transparency() {
}; // inverse-opacity (?)

function blend() {
}; // (?)

// OTHER //
function check(m,o) { // method, object
	return validate(o,m); //
}; //

// Event-Handling & Binding Settings //
//function event(e) { // * reserved 
//	alert('just testing event ... ' + e);
/*	if (!e) var e = window.event; // * cross-browser * access event
	if (e.keyCode) { code = e.keyCode; } else { if (e.which) { code = e.which; }; }; // * cross-browser * detects key
	// e.type // * cross-browser * check type of event
	var t; if (!e) { var e = window.event; } else { if (e.target) {	t = e.target; } else { if (e.srcElement) { t = e.srcElement; }; }; }; if (t.nodeType == 3) { t = t.parentNode; }; // defeat Safari bug // * cross-browser * target event
*/
//} // detects event properties and values, then generates and returns a cross-platform custom generic "event" object.

// Device Detection (I/O) //

// character-to-code "constants" //
var cSpace = 32;
var cBackspace = 8;
var cReturn = 13; var cEnter = 13; // syn.

// "CjM_Scribe" * tracks the character patterns being transcribed by the user //
var scribe = new Object;
scribe.fill = ['character','word','line','sentence','paragraph'];
//scribe.fill['character'] = ''; // tracks keyboard characters
scribe.fill['word'] = ''; // tracks keyboard word
scribe.fill['line'] = ''; // tracks keyboard line
//scribe.fill['sentence'] = ''; // tracks keyboard sentence
//scribe.fill['paragraph'] = ''; // tracks keyboard paragraph

// keyboard & keys //
function keys(e) {
	var key = new Object; // generic object
	
	// detect event //
	// if (!e) { var e = window.event; }; // * cross browser * access event
	var e = window.event; // * cross browser * access event
	key.event = e;

	// establish current key code & character //
	key.code = '';
	if (e.keyCode) { 
		key.code = e.keyCode; 
	} else { 
		if (e.which) { 
			key.code = e.which; 
		};
	};
	key.character = String.fromCharCode(key.code);

	// special keys (1 means pressed, 0 means not pressed)
	key.enter = 0; if (key.code == cEnter) { key.enter = 1; }; //
	// special keys (un-convential detection)
	key.alt = e.altKey;
	key.shift = e.shiftKey;
	key.ctrl = e.ctrlKey;

//	alert('Character was ' + key.character);
	// scribe //
	scribe.character = key.character;
	if ((key.code == 32)) { // "space" resets the word.
		scribe.word = scribe.fill['word']; scribe.fill['word'] = ''; return key; 
	}; //
	if (key.code == 8) { // "backspace" erases the previous character from the fill word.
//		alert('backspace! ' + key.event.type); 
		return key;
	}; //
	if ((key.code == 13)) { // "return" resets the line.
		scribe.line = scribe.fill['line']; scribe.fill['line'] = ''; return key; 
	}; // 
	if ((key.event.type == 'keypress')) { 
		scribe.fill['word'] = scribe.fill['word'] + key.character; // add character to the word
	};
	//
	return key;
} // detects key properties and values, then generates and returns a cross-platform custom generic "key" object.

function key(n,e,m) { // name-or-number, event-to-listen, method-to-execute
	var key = new Object;
	key.event = window.event; ; // * cross-platform * access current event object.
	// establish key code
	key.code = ''; 
	if (key.event.keyCode) { 
		key.code = key.event.keyCode; 
	} else { 
		if (key.event.which) { 
			key.code = key.event.which; 
		};
	};
	// establish key character
	key.character = String.fromCharCode(key.code); // * best method for detecting actual key characer
	// translate named characters
	switch (n) { // first check names * doesn't work yet ???
		case 'enter' : case 'return' : n = 13; break;
		case 'space' : n = 32; break;
		case 'backspace' : n = 8; break;
		case 'tab' : n = 9; break;
		case 'shift' : n = 16; break;
		case 'ctrl' : n = 17; break;
		case 'alt' : n = 18; break;
		case 'pause' : case 'break' : n = 19; break;
		case 'caps' : case 'capslock' : case 'caps lock' : n = 20; break;
		case 'escape' : n = 27; break;
		case 'pageup' : case 'page up' : n = 33; break;
		case 'pagedown' : case 'page down' : n = 34; break;
		case 'end' : n = 35; break;
		case 'home' : n = 36; break;
		case 'left' : case 'leftarrow' : case 'left arrow' : n = 37; break;
		case 'right' : case 'rightarrow' : case 'right arrow' : n = 39; break;
		case 'down' : case 'downarrow' : case 'down arrow' : n = 40; break;
		case 'insert' : n = 45; break;
		case 'delete' : n = 46; break;
		case 'left window key' : n = 91; break;
		case 'right window key' : n = 92; break;
		case 'select key' : n = 93; break;
		case 'numpad 0' : n = 96; break;
		case 'numpad 1' : n = 97; break;
		case 'numpad 2' : n = 98; break;
		case 'numpad 3' : n = 99; break;
		case 'numpad 4' : n = 100; break;
		case 'numpad 5' : n = 101; break;
		case 'numpad 6' : n = 102; break;
		case 'numpad 7' : n = 103; break;
		case 'numpad 8' : n = 104; break;
		case 'numpad 9' : n = 105; break;
		case 'multiply' : n = 106; break;
		case 'add' : n = 107; break;
		case 'subtract' : case 'minus' : n = 108; break;
		case 'decimal point' : n = 109; break;
		case 'divide' : n = 111; break;
		case 'f1' : case 'F1' : n = 112; break;
		case 'f2' : case 'F2' : n = 113; break;
		case 'f3' : case 'F3' : n = 114; break;
		case 'f4' : case 'F4' : n = 115; break;
		case 'f5' : case 'F5' : n = 116; break;
		case 'f6' : case 'F6' : n = 117; break;
		case 'f7' : case 'F7' : n = 118; break;
		case 'f8' : case 'F8' : n = 119; break;
		case 'f9' : case 'F9' : n = 120; break;
		case 'f10' : case 'F10' : n = 121; break;
		case 'f11' : case 'F11' : n = 122; break;
		case 'f12' : case 'F12' : n = 123; break;
		case 'num lock' : n = 144; break;
		case 'scroll lock' : n = 145; break;
		case 'semi-colon' : case ';' : n = 186; break;
		case 'equals' : case 'equal sign' : case '=' : n = 187; break;
		case 'comma' : case ',' : n = 188; break;
		case 'dash' : n = 189; break;
		case 'period' : case '.' : n = 190; break;
		case 'forward slash' : case '/' : n = 191; break;
		case 'grave accent' : n = 192; break;
		case 'open bracket' : break;
		case 'back slash' : break;
		case 'close bracket' : break;
		case 'single quote' : break;
	};
	// decide whether the event matches the given event.
	if (e) { if (e != key.event.type) { return false; }; };
	// decide whether a key character is pressed
	if ((is(n,'string')) || (is(n,'integer'))) {
		if ((key.character == n) || (key.code == n)) { // * case-sensitive *
			return true;
		} else { 
			return false; 
	};	};
	return key;
} // returns a key object, when the keys show the key being pressed.

function mouse(e) {
/*	// detect which button has been clicked
	// Please note that these properties don’t always work on a click event. To safely detect a mouse button you have to use the mousedown or mouseup events.
		//
		
		// detect a right click ...
	var rightclick;
	if (!e) var e = window.event;
	if (e.which) rightclick = (e.which == 3);
	else if (e.button) rightclick = (e.button == 2);
	alert('Rightclick: ' + rightclick); // true or false
		// detect mouse coordinates ...
	var posx = 0;
	var posy = 0;
	if (!e) var e = window.event;
	if (e.pageX || e.pageY) 	{
		posx = e.pageX;
		posy = e.pageY;
	}
	else if (e.clientX || e.clientY) 	{
		posx = e.clientX + document.body.scrollLeft
			+ document.documentElement.scrollLeft;
		posy = e.clientY + document.body.scrollTop
			+ document.documentElement.scrollTop;
	}
	// posx and posy contain the mouse position relative to the document
	// Do something with this information
*/	
} // detects mouse properties and values, then generates and returns a cross-platform custom generic "mouse" object.


function handle(e,o,a) { // event-object, element-object (aka. HTML element), action (aka. JavaScript function-or-method)
	if (!o) { // handle event
		if (!e) { return window.event }; // ensures cross-platform access to the event object is being handled.
		e.cancelBubble = true; if (e.stopPropagation) { e.stopPropagation(); }; // disables event-bubbling, cross-platform.
		if (e.keyCode) { k = e.keyCode; } else { if (e.which) { k = e.which; }; }; // reads keyboard input (?)
		return e; // * thanks, quirksmode.org
	};
	if (o) { // if (is(o,'element')) // register event to handle, via "traditional-method"
		switch (e) { // traditional-method // * thank you quirksmode.org
			case 'onclick' : o.onclick = a; if (o.captureEvents) { o.captureEvents(Event.CLICK); }; break;
		};
	};
} // handles the event object, makes sure all browsers cross-platform can access and react to it.

function bind(o,e,m) { // object, event-handler-indicator-string, method/function(the-name-itself-not-as-a-string)
	if (is(o,'string')) { var o = get(o); }; // link to the markup object
	if (is(e,'string')) { switch (e) { // begin "bind single event"
	// cross-browser compatible events
		// mouse
		case 'click' : case 'onclick' : o.onclick = m; if (o.captureEvents) { o.captureEvents(Event.CLICK); }; break;
		case 'dbleclick' : case 'ondbleclick' : o.ondbleclick = m; if (o.captureEvents) { o.captureEvents(Event.DBLECLICK); }; break;
		case 'mousedown' : case 'onmousedown' : o.onmousedown = m; if (o.captureEvents) { o.captureEvents(Event.MOUSEDOWN); }; break;
		case 'mouseup' : case 'onmouseup' : o.onmouseup = m; if (o.captureEvents) { o.captureEvents(Event.MOUSEUP); }; break;
		case 'mousemove' : case 'onmousemove' : o.onmousemove = m; if (o.captureEvents) { o.captureEvents(Event.MOUSEMOVE); }; break;
		// keyboard
		case 'keyup' : case 'onkeyup' : o.onkeyup = m; if (o.captureEvents) { o.captureEvents(Event.KEYUP); }; break;
		case 'keydown' : case 'onkeydown' : o.onkeydown = m; if (o.captureEvents) { o.captureEvents(Event.KEYDOWN); }; break;
		// forms
		case 'reset' : case 'onreset' : o.onreset = m; if (o.captureEvents) { o.captureEvents(Event.RESET); }; break;
		case 'select' : case 'onselect' : o.onselect = m; if (o.captureEvents) { o.captureEvents(Event.SELECT); }; break;
		case 'submit' : case 'onsubmit' : o.onsubmit = m; if (o.captureEvents) { o.captureEvents(Event.SUBMIT); }; break;
	// buggy events * relatively inconsistent cross-browser
		case 'focus' : case 'onfocus' : o.onfocus = m; if (o.captureEvents) { o.captureEvents(Event.FOCUS); }; break;
		case 'blur' : case 'onblur' : o.onblur = m; if (o.captureEvents) { o.captureEvents(Event.BLUR); }; break;
		case 'change' : case 'onchange' : o.onchange = m; if (o.captureEvents) { o.captureEvents(Event.CHANGE); }; break;
		case 'mouseout' : case 'onmouseout' : o.onmouseout = m; if (o.captureEvents) { o.captureEvents(Event.MOUSEOUT); }; break;
		case 'mouseover' : case 'onmouseover' : o.onmouseover = m; if (o.captureEvents) { o.captureEvents(Event.MOUSEOVER); }; break;
		case 'keypress' : case 'onkeypress' : o.onkeypress = m; if (o.captureEvents) { o.captureEvents(Event.KEYPRESS); }; break;
	}; }; // end "bind single event"
//	if (is(e,'associative-array')) { // begin "bind multiple events (via associative-array)"
//	}; // end "bind multiple events (via linear associative-array)"
} // binds a given function/method to a given object's given event, and when appropriate tells the browser to capture the events.

// function capture(e,b) { // event, boolean }; // method for "capturing" events * outside-in
// function bubble(e,b) { // event, boolean }; // method for "bubbling" events * inside-out

function events () {
	e = window.event; // access current event object
	return e;
}
// keyboard
document.onkeypress = events;
document.onkeydown = events;
document.onkeyup = events;
// mouse
document.onclick = events;
document.ondblclick = events;
document.onmousedown = events;
document.onmouseup = events;
document.onmouseover = events;
document.onmousemove = events;
document.onmouseout = events;
// page/window/frame
document.onload = events;
document.onunload = events;
document.onabort = events;
document.onerror = events;
document.onresize = events;
document.onscroll = events;
// forms
document.onselect = events;
document.onchange = events;
document.onsubmit = events;
document.onreset = events;
document.onfocus = events;
document.onblur = events;
//

// URLS //
// <protocol>//<host>[:<port>]/<pathname>[<hash>][<search>]

function redirect(url,secure) { //
/*	s = '';
	s = s + 'hash: ' + window.location.hash + '\n';
	s = s + 'host: ' + window.location.host + '\n';
	s = s + 'hostname: ' + window.location.hostname + '\n';
	s = s + 'href: ' + window.location.href + '\n';
	s = s + 'pathname: ' + window.location.pathname + '\n';
	s = s + 'port: ' + window.location.port + '\n';
	s = s + 'protocol: ' + window.location.protocol + '\n';
	s = s + 'search: ' + window.location.search + '\n';
	alert(s);
*/
	var hash = window.location.hash;
	var host = window.location.host;
	var hostname = window.location.hostname;
	var href = new String(window.location.href);
	var pathname = window.location.pathname;
	var port = window.location.port;
	var protocol = window.location.protocol;
	var search = window.location.search;
//
	switch (secure) {
		case 'secure' : case 1 : 
			href = href.replace("http:","https:");
		break;
		case 'insecure' : // case 0 : 
			href = href.replace("https:","http:");
		break;
	};
	window.location = url; // url;
//	window.location.reload(url); // url
//	window.location.replace(url); // url
}; // client-side re-direction via JavaScript 
function goto(url,secure) { redirect(url,secure); }; // alias "redirect"
function navigate(url,secure) { redirect(url,secure); }; // alias "redirect"

function site() { // * standard "site" function called onLoad
// standard calls to shell //
//	adjust('midder',['left','middle','right']); // adjusts layout height to greatest height ...
//	activate('objects'); // activate objects (* to get rid of the 'click-to-activate') ...
};

// DOESN'T WORK (maybe it's a security issue) //
//function imagine(n,f) { // image, file
//	get(n).src = f; 
//	alert(f);
//	str = get(n).src;
//	alert(str);
//	str = str.replace(/\:/g,"|"); // replace all colons with bars (|)
//	str = str.replace(/\|/,":"); // return first bar back to a colon (:)
//	alert(str);
//	get('item_image').src = str;
//};

// Objects //

/*
// (memory.js)

function Memory() {
	this.load = function(y,a,s) { // as-type, array-of-file-names, source-path
	switch (y) {
		case 'image' : case 'images' : // images
			if (document.images) { // * detect image-compatibility
				var c = a.length;
				for (var i=0; i < c; i++) {
					m = new Image(); // new Image(100,25); // width, height
					m.src= s + a[i]; // source = source-path + file-name
				}; // load images
			};
		break;
	};
}
//gCjM = new Memory();
//gCjM.load('images',['test1.jpg','test2.jpg'],'/test');
 */

/*
// (keyboard.js)
function keyboard(e) {
	var unicode = e.keyCode ? e.keyCode : e.charCode;
	var actualkey = String.fromCharCode(unicode);
	var specialkey = e.altKey;
	var specialkey = e.ctrlKey;
	var specialkey = e.shiftKey;
//	alert(unicode);
//	alert(actualkey);
//	alert(e.type);
}
function keyboard_press() { keyboard(event); }
function keyboard_down() { keyboard(event); }
function keyboard_up() { keyboard(event); }
//
document.onkeypress = keyboard_press;	//('press');	// invokes JavaScript code when a key is pressed 
document.onkeydown = keyboard_down;		//('down');	// invokes JavaScript code when a key is held down (but not yet released) 
document.onkeyup = keyboard_up;			//('up');	// invokes JavaScript code when a key is has been released after being pressed. 

*/

/*
// CjM_Book

function CjM_Book(p,c) { // pages, chapters
// properties (CjM_Book)
	this.chapters; //if (is(c,'array')) { this.chapters = c; } else { this.chapters = []; };
	this.pages; //if (is(p,'array')) { this.pages = p; } else { this.pages = []; };
	this.outline;
	this.chapter = '';
	this.page = '';
	this.mark = 0;
	this.book = this;
// methods (CjM_Book)
	this.bind = function (p,c) { // pages, chapter
		// establish outline (an array of chapters)
		if (!is(this.outline,'array') && is(this.chapters,'array')) {
			this.outline = this.chapters;
			// establish chapters (fill outline of chapters w/ arrays for pages)
			var c = count(this.chapters);
			for (var i = 0; i < c; i++) {
				this.outline[this.chapters[i]] = [];
			};
		};
		// establish pages, in already established chapters
		if (is(p,'array') && is(c,'string')) { this.outline[c] = p; }; // assign pages to chapters
	}
	this.turn = function (p,c) { // page, chapter
		// hide all pages
		n = count(this.pages)
		for (var i = 0; i < n; i++) {
			hide(this.pages[i]);
		}
		// hide all chapters
		n = count(this.chapters);
		for (var i = 0; i < n; i++) {
			hide(this.chapters[i]);
		}
		// mark given page
		if (is(p,'integer')) {
			var n = count(this.pages);
			if ((p >=0) && (p < n)) { this.mark = p; };
			if (this.mark >= n) { this.mark = 0; }; // cycle to first page
			if (this.mark < 0) { this.mark = n - 1; }; // cycle to last page
			if ((this.mark < n) && (this.mark >= 0)) { this.page = this.pages[this.mark]; };
		};
		if (is(p,'string')) { this.page = p; };
		// find and show chapter of given page
		n = count(this.chapters);
		for (var i = 0; i < n; i++) {
			m = count(this.outline[i]);
			for (var j = 0; j < m; j++) {
				if (this.outline[this.outline[i]][j] == this.page) { // find chapter by page
					this.chapter = this.outline[i];
					if (is(this.chapter,'string')) { show(this.chapter); };
				};
			};
		};
		//
//		alert(this.page);
		if (is(this.page,'string')) { show(this.page); };
//		alert(this.chapter + " " + this.page);
	}
	this.prev = function () { this.mark = this.mark - 1; this.turn(this.mark); }
	this.next = function () { this.mark = this.mark + 1; this.turn(this.mark); }
// events (CjM_Book)
	this.act = function (o,e) {
		switch (o.id) {
			case 'CjM_Book_next' : this.next(); break;
			case 'CjM_Book_prev' : this.prev(); break;
		};
		this.behave(o,e); // before, or after (?)
	}
	this.behave = function (o,e) {} // override this behave function to insert custom behavior
	actor(this);
	return this;
}
 */

/*
	function CjM_Console () {
	// properties (CjM_Console)
		this.type = "CjM_Console";
		this.rule; this.rules = []; // override
	// methods (CjM_Console)
		this.validate = function(f) {} // form // override
	// events (CjM_Console)
		this.act = function(o,e) {} // object, event // override
	// links (CjM_Console)
		actor(this);
	}
	vConsole = new CjM_Console(); // instantiate
// modify //
	vConsole.validate = function(f,a) { // form, action
		switch (a) {
			case 'Insert' : // validate insertions
				for(var i = 0; i < this.rules.length; i++) {
					this.rule = this.rules[i] + " " + this.rules[this.rules[i]];
					alert(this.rule);
//					if(eval(this.rule) == false) { return false };
				}; return true; // valid

			break;
		};
		return true;
	}
	vConsole.act = function(o,e) { // object, event
		if (this.validate(o.form,o.value)) { } else { return false; }; //o.form.submit(); };
	}
	function act(o,e) { // object, event
		e = handle(e);
		alert(o.name + " : " + e.type + " : " + o.value);
	};

*/

/*

//alert('hello, this is a form script');
function CjM_Form (f) { // client-side form object, object to control the current client-side form
// properties (CjM_Form)
	this.author = 'CjM';
	this.type = 'CjM_Form';
	this.version = '20060113';
	this.require = ['global.js'];
	this.rules; // = []; // an array to hold all the rules that the program requires to validate this form
	if (f != 0) { this.form = f; } else { this.form = 0; }; // form, this should become a reference to the actual form object itself.
//	this.form = f;
	this.command = ''; // the current command given to this object
// methods (CjM_Form)
	this.rule = function(p,c,v) { // rule (?): property|method-return, comparision, value
	};
	this.validate = function (f,r) { // form, rules
//		f['story'].value = escape(f['story'].value);
		return true;
	};
	this.confirm = function (b,f) { // boolean, form
		if (b) {
			return true;
		} else {
			return false;
		};
	};
	this.submit = function (f) { // form
		if (is(this.form,'string')) { this.form = get(this.form); };
		if (this.validate(this.form,this.rules)) { // 1st, validate
			if (this.confirm(this.form)) { // 2nd, confirm
				this.form.submit(); // 3rd, submit
			} else { // error, not confirmed
			};
		} else { // error, invalid
		};
	};
// events (CjM_Form)
	this.act = function (o,e) { // form-control-object(aka. button), event
	// * please override this event-method, to customize the behavior of this form.
		// if global.js then ...
//		this.form = o.form; // argue the control w/ a reference to the form (aka. the button), not the form.
//		this.command = o.value; // the command is held in the value of the calling button.
//		switch (this.command) {
//			case 'check' : break;
//			case 'confirm' : break;
//		};
//		this.validate(this.form,this.rules);
	};
// links (CjM_Form)
	actor(this); // essential, to run with the "actors" (er, "gActors") list
	return this;
}

*/

/*

// CjM Gallery (gallery.js)
function CjM_Gallery(g) { // gallery-name
	// properties (CjM_Gallery)
	this.author = 'CjM'; this.version = '2007062401';
	this.type = 'CjM_Gallery'; 
	// methods (CjM_Gallery)
	this.hang = function () {
		alert('hang');
	}; // hang generates the markup pictures for hanging the pictures
	// evnets (CjM_Gallery)
	return this;
}

 */

/*
// CjM JavaScript / Slide Show (slideshow.js)

function CjM_SlideShow(a) { // array
// properties (CjM_SlideShow)
	this.type = "CjM_SlideShow"; this.requires = 'client.js';
	this.slides = a; // //if (is(a,'array')) { this.slides = a; }; // array-of-strings, names-ids of the slide layers.
	this.slide; // string, name of current slide.
	this.point = 0; // number, which slide the show is pointing at currently.
// methods (CjM_SlideShow)
	this.shows = function (n) { // name-or-number
		var c = count(this.slides);
		if (is(n,'integer')) { // by point
			this.point = n; // adjust point by given number

			if (n >= c) { this.point = 0; }; // cycle to front
			if (n < 0) { this.point = c; }; // cycle to back
			this.slide = this.slides[this.point]; 
		};
		// hide all slides
		for (var i = 0; i < c; i++) {
			hide(this.slides[i]);
		};
		// show given slide
		if (is(this.slide,'string')) {
			show(this.slide);
		};
	}
	this.prev = function() { 
		this.point = this.point - 1; 
		this.shows(this.point); 
	}
	this.next = function() { 
		this.point = this.point + 1; 
		this.shows(this.point); 
	}
// events (CjM_SlideShow)
	this.act = function (o,e) {
		switch(o.id) {
			case 'CjM_SlideShow_next' : this.next(); break;
			case 'CjM_SlideShow_prev' : this.next(); break;
		};
	}
	return this;
}


 */
function fill(f,a) { // form-name, data-associative-array
	f = document.forms[f]; // get form
	for (var n in a) { // name
		var v = a[n]; // value
		f.elements[n].value = v;
	};
}


/*
// CjM_Slideshow

function CjM_Slideshow(a,n) { // name-of-projector-image-and-object, |OR|#string, path-on-file-system-to-image-files.
	// notes //
	// * CRITICAL * #timeouts make callbacks to elements defined off the root of the DOM Document object ([scope-page] myVariable.myMethod) and not within custom objects themselves ([scope-object] this.myMethod), so it's necessary to synchronize the (3) names of the variable's-name, this-object's-name, and the image-tag's-name-attribute.

	// arguments (defaults)
	if (!a) { }; // #string of file-system-path-of-images |OR| #array of DOM-image-objects.
	if (!n) { var n = 'slideshow_projector'; }; // default
	// properties
	this.name = n; // #string, unique name of this slideshow and projector image required to make #timeout features work. 
		// *** synchronize the varible's name, the image-tag's name, and this-object's name to work ***
		// ex.) CjM_Slideshow = new CjM_Slideshow(); this.name = "CjM_Slideshow"; && <img name="CjM_Slideshow" ...
	this.type = 'CjM_Slideshow'; this.version = '20090310'; this.author = 'CjM'; // signature.
	this.autostart = 1; // #boolean, whether or not to automatically start the slideshow on load.
	this.automatic = 1; // #boolean, whether or not the slides show automatically.
	this.interval = 3000; // #integer, slide-display interval, in millisecconds.
	this.timer; // #object, variable for the required #timeout object with callback generated to make it run.
	this.callback; // #string, the callback-string generated for the #timeout object.
	this.directive = 'random'; // #string, the directive for how the slideshow plays in each timer's callback interval.
	this.point = 0; // #integer, number that points to the current slide of this slideshow (default zero).
	if (is(a,'string')) { this.directory = a; }; // #string, path to the source-directory on the file-system holding the images.
	this.image = n; // #string, references the "name" attribute of the image object to play the slides.
	this.projector = document[this.image]; // #string-to-#image-object, reference to the existing DOM image object of the given image "name" attribute of the markup (<img name="slideshow" src="...).
	this.paths; 
	// #array, slideshow-array of 1st) image-paths on the file-system, and then image-objects created from these paths.
	if (is(a,'array')) { this.slides = a; } else { this.slides = new Array(); };
	this.total; // #integer, representing the total count of images in the slideshow array.
//	this.random = 0; // #boolean, whether or not the slides display randomly.
	this.range = 0; // #integer, the range of numbers from which to display randomly.
	// methods
	this.slides = function (a) { // array-of-path-strings
	// make slides (the advantages of creating image objects is to load them into memory).
		if ((is(a,'string')) || (is(a,'array'))) { this.slides = a; };
		this.total = this.slides.length; // counts the total image-objects in the array.
		for (var j = 0; j < this.total; j++) {
			if (is(this.slides[j],'string')) {
				var i = new Image(); // make an new DOM image object.
				i.src = this.slides[j]; // set source-path attribute to preload image data into memory.
				this.slides[j] = i; // replace the image-path with the image-object into the slideshow's slides array.
			};
		};
	}; // generates slides by given path
	this.slide = function (d,a,b) { // directive, argument-a, argument-b
		switch (d) {
			case 'next' : // next slide
				this.point = (this.point + 1) % this.total;
				this.slide(this.point);
			break;
			case 'prev' : case 'previous' : // previous slide
				this.point = (this.point - 1) % this.total;
				this.slide(this.point);
			break;
			case 'random' : // random slide
				if (!a) { a = 0; }; // first element, represented by zero.
				if (!b) { b = (this.images.length - 1); }; // total count of the array, minus 1.
				this.range = a - b + 1;
				this.point = Math.floor(Math.random() * this.range) + a;
				this.slide(this.point);
			break;
			//
			default : // * given integer .. switch the image.
				if (this.automatic) { // then, set the timer to automatically run this slideshow.
//					this.callback = "get('" + this.name + "').slide('" + this.directive + "')"; // * SOMEDAY *
					this.callback = this.name + ".slide('" + this.directive + "')"; // * (3x) synch'd name
					this.timer = setTimeout(this.callback,this.interval); // 
//					alert('slide');
				};
				if (this.projector) {
					this.projector = document[this.image]; // * update the projector reference * //
					this.projector.src = this.slides[this.point].src;  // switches the projector-image's source attribute to the current slide-image's source attribute, effectively showing the current slide.
				};
			break;
		};
	};
	this.start = function (d) { this.automatic = 1; this.directive = d; this.slide(); };
		this.play = function (d) { this.start(d); };
	this.stop = function () { this.automatic = 0; };
	// events
	// links
	// actions
	this.slides(); // * essential * must call "slides" to setup the slideshow.
	if (this.autostart) { this.play(); }
}
//var slideshow = new CjM_Slideshow(); // * synch slideshow's variable name, object's name and img-tag's name.
*/

function values (a,p,v) { // array-of-object-names, property-name, new-values-array
	if ((is(a,'array')) && (is(p,'string'))) { // get
		var r = new Array();
		for (var i=0; i < a.length; i++) {
			var o = get(a[i]);
			r.push(o[p]);
		};
		return r;
	};
}

function sum(a) {
	if (is(a,'array')) {
		var r = 0;
		for (var i = 0; i < a.length; i++) {
			if (is(a[i],'number')) { 
				r = r + a[i]; // add
			};
		};
		return r;
	};
} // returns the sum of any the numbers in the given array

function maximum(a) {
	if (is(a,'array')) {
		var r = 0;
		for (var i = 0; i < a.length; i++) {
			var n = a[i];
			if (is(n,'number')) { 
				if (n > r) {
					r = n;
				};
			};
		};
		return r;
	};
} // returns the maximum value of any numbers in the given array

function preload () { // accepts infinite arguments, like preload("image1.gif","image2.gif","image3.gif","image4.gif");
	var a = new Array(); // images
	for (x = 0; x < preload.arguments.length; x++) {
		a[x] = new Image();
		a[x].src = preload.arguments[x];
	};
} // preloads images of given image-paths into memory, client-side.

function swap (o,n) { // old-image-string, new-image-string
	get(o).src = n; // swaps the old image-path-string with the new image-path-string.
}

