function Accordion(container, oneAtATime) {
	/* ACCORDION object
		This ain't your great-uncle Maury's accordion.  It's basically a container for many "ribs" that each contain their own 
		information.  Accordion's container is usually (but not always) a DIV, as are all of its Ribs.
		
		Accordion [abstract]
		 _CLASS_parameters:
		    - allAccordions [Array] :: Array of all Accordion instances
		    - count [Integer] :: Running total of all Accordion instances

		 _INSTANCE_parameters:
			- container [String | Element] :: Accordion's container  ** REQUIRED **
			- oneAtATime [Boolean] :: Only one container can be opened at one time?/not
		_INSTANCE_methods:
			- addrib :: Add a Rib to this Accordion.  
			- getAllRibs :: Fetch this Accordion's array of all child Ribs
			- closeAllRibsExcept :: Collapse all Ribs of this Accordion except the one passed.
	*/		
		
	this.box = getEl(container);	// div to contain Accordion
	this.w = container.style.width;	// its width
	this.id = container.id;			// its 'id' 
	this.ribs = new Array();		// list of all of this accordion's ribs
	this.oneOnly = oneAtATime?true:false;		// can only have on rib open?
	Accordion.allAccordions[Accordion.allAccordions.length] = this;	// add this accordion the array of all Accordion instances
	Accordion.count = Accordion.allAccordions.length;
}
function accAddRib(w, initContent, sClass, eClass, initShrunk, sHandler, eHandler) {
	/*
	addrib :: Add a Rib to this Accordion.
		 ~ w [Integer | String] :: width... Optional; not even recommended, really.
	     ~ initContent [String | Element] :: Rib's initial contents. 
	     ~ sClass [String] :: Class of Rib element when collapsed
	     ~ eClass [String] :: Class of Rib element when expanded
	     ~ initShrunk [Boolean] :: Whether/not Rib's collapsed to begin with.  Default is True.
	     ~ sHandler [Function] :: Additional function run as Rib collapse begins
	     ~ eHandler [Function] :: Additional function run as Rib expansion begins
	     
	     RETURNS: reference ot new Rib instance
	*/
	var nurib = new Rib(this, w, initContent, sClass, eClass, initShrunk, sHandler, eHandler);
	this.ribs[this.ribs.length] = nurib;
	
	return nurib;
}
function accGetAllRibs() {	
	/* 
	accGetAllRibs :: Returns the reference to an array of all Rib instances of this Accordion 
	*/
	return this.ribs;
}
function accCloseAllRibsExcept(ribId) {
	/*
	accCloseAllRibsExcept :: Just like it says - close all Rib instances of this Accordion except the instance passed
		~ ribId [Rib] :: Rib reference that will NOT be closed
	*/
	var openRib = null;
	if (ribId.constructor == Rib) {	// assuming it's a reference to the Rib itself
		openRib = ribId;
	} else {	// could/should be an Integer then
		openRib = Rib.getRib(ribId + 0);
	}
	
	var i = this.ribs.length;
	while(i > 0) {
		i--;
		var thisRib = this.ribs[i];
		if (thisRib && thisRib != openRib) { thisRib.shrink();	}
	}
}		

// Accordian CLASS params
Accordion.allAccordions = new Array();	// array of all Accordion instances
Accordion.count = 0;	// number of existing Accordion instances

// Accordian instance functions
Accordion.prototype.addRib = accAddRib;	// add rib to this Accordion
Accordion.prototype.getAllRibs = accGetAllRibs;	// returns array of all of THIS Accordion's ribs
Accordion.prototype.closeAllRibsExcept = accCloseAllRibsExcept;	// close all ribs but target

function Rib(acc, w, initialContent, shrunkClass, expandedClass, initiallyShrunk, shrinkHandler, expandHandler) {
	/* RIB object
		A container for the contents that you want hidden / revealed by the Accordion.
		
		Rib [abstract]
		 _CLASS_parameters:
		    - AllRibs [Array] :: Array of all Rib instances
		    - count [Integer] :: Running total of all Rib instances
		 _CLASS_methods:
		    - getRib :: Return a reference to a Rib whose ID is provided
		    - onInstance :: Optional user-defined function which is run at a Rib object's instantiation
		    
		 _INSTANCE_parameters:
		    - acc [Accordion] :: Reference to parent Accordion  ** REQUIRED **
		    - w [String] :: CSS-unit width
		    - initialContent [String | Element] :: String or element representing Rib's initial contents
		    - shrunkClass [String] :: CSS class of Rib's style when collapsed
		    - expandClass [String] :: CSS class of Rib's style when expanded
		    - initiallyShrunk [Boolean] :: Specifies whether this Rib will be collapsed at first (DEFAULT is false)
		    - shrinkHandler [Function] :: User-defined function to call when Rib is collapsed
		    - expandHandler [Function] :: User-defined function to call when Rib is expanded
		_INSTANCE_methods:
			- shrink :: Collapse this Rib
			- expand :: Expand this Rib
			- toggle :: Toggle Rib to expand/collapse
			- append :: Add contents to Rib instance's container
	*/	
	this.acc = acc;								// this rib's accordion < REQUIRED
	this.id = Rib.ribCount;						// unique id for this rib
	this.parentEl = acc.box;					// this rib's accordion's container/div
	this.shrunk = initiallyShrunk?true:false;	// initially shrunk? or not?
	this.shrunkClass = shrunkClass;				// class when shrunk
	this.expandedClass = expandedClass;			// class when expanded
	this.initialClass = this.shrunk?shrunkClass:expandedClass;	// set initial class of rib to shrunk/expanded class
	this.ribW = w || acc.w || "100%";			// default width of rib
	this.box = createDiv(this.id, this.initialClass, acc.box);	// create div to contain rib (its "box")
	
	this.onExpand = expandHandler || null;		// optional function run on expand
	this.onShrink = shrinkHandler || null;		// optional function run on shrink
	
	this.initialContent = initialContent;		// initialContent of rib @ instance creation < STRING | ELEMENT
	
	// if it needs initial content, add it now
	if (this.initialContent && this.initialContent.constructor == String) {	// see if it's an String
		this.box.innerHTML = this.initialContent;
	} else if (this.initialContent) {
		this.box.appendChild(this.initialContent);	// otherwise, treat it as an Element
	}	

	this.initialHeight = this.box.style.height;	// initial height of rib
	
	Rib.allRibs[Rib.allRibs.length] = this;		// add rib to list of all Rib instances
	Rib.ribCount = Rib.allRibs.length;			// update running total of all Rib instances
	
	if (this.shrunk) {
		this.shrink();
	}
	
	// run additional steps, if defined
	if (Rib.onInstance) {
		Rib.onInstance(this);
	}
	
	this.toString = function() {
		return "[Object of type 'Rib' :: .id = " + this.id + "]";
	}
	
	return this;
}
function ribShrink() {
	if (this.shrunk)	// don't shrink if shrunk!
		return;
		
	if (this.onShrink) {	// run optional onShrink handler
		this.onShrink(this);	// ** probably need to set up a timer here ***
	}
	
	// need to animate the following, eventually
	this.box.className = this.shrunkClass;		// change its class to shrunken
	this.shrunk = true;							// flag shrunk to TRUE
}
function ribExpand() {
	if (!this.shrunk)	// don't expand if already have
		return;
		
	if (this.onExpand) {	// run optional expand handler
		this.onExpand();
	}
	
	this.box.className = this.expandedClass;
	this.shrunk = false;
	
	// see if only one rib can be expanded at a time
	if (this.acc.oneOnly) {
		this.acc.closeAllRibsExcept(this.id);
	}
	
}
function ribToggle() {
	if (this.shrunk)
		this.expand();
	else
		this.shrink();
}
function ribAppend(moreCon) {
	if (moreCon) {
		if (moreCon.constructor == String) {
			this.box.innerHTML += moreCon;
		} else {
			try { this.box.appendChild(moreCon); }
			catch (err) {}
		}
	}
}
function ribGetRibById(ribId) {
	if (ribId.constructor == Rib) { return ribId; }	// return it if it's already the Rib in question
	return Rib.allRibs[ribId + 0];	// don't assume an Integer was passed; convert to Integer as if it wasn't.
}

// Rib CLASS params
Rib.allRibs = new Array();	// array of all Rib instances
Rib.ribCount = 0;			// running total of Rib instances

// Rib CLASS funtions
Rib.getRib = ribGetRibById;	// get Rib instance by .id
Rib.onInstance = null;		// optional function run @ instantiation

// Rib instance functions
Rib.prototype.shrink = ribShrink;	// function called when shrunk
Rib.prototype.expand = ribExpand;	// function called when expanded
Rib.prototype.toggle = ribToggle;	// toggle betw. expanded/shrunk
Rib.prototype.append = ribAppend;	// add content to the rib


// UTILITY FUNCTIONS
function createDiv(divId, divClass, parentEl) {	
	// create a DIV w/ an id [divId, STRING], class [divClass, STRING], and parent element [parentEl, ELEMENT] 
	// immediately adds it to parentEl, if defined
	
	var d = newEl('div');	// create a new DIV
	d.id = divId;	// give it an ID
	
	if (divClass) {
		d.className = divClass;	// give it a class, if known
	}
	
	if (!parentEl) {	// if no parent element provided, parent is BODY
		document.body.appendChild(d);	
	}
	else {
		parentEl.appendChild(d);	// put it at the end of the parent element's nodes
	}
	
	return d;	// return reference to the new DIV
	
}


function getEl(el) {
	if (el.constructor == String) {
		return document.getElementById(el);	// if string, assuming it's an element's ID attrib
	} else {
		return el;	// assuming that el is already a reference to an element
	}
}

function newEl(elName) {
	return document.createElement(elName);
}

function newText(text) {
	return document.createTextNode(text);
}

function note(output) {
	var p = getEl('pad_out');

	p.innerHTML += output + "<br />\n";
	// p.scrollByLines(10);
}

