@Override
	protected int processRecord (int recordCounter, byte[] recordData, short recordAttributes, int recordUniqueID) 
		{
		// local vars
		int processResult = SUCCESS ;
		int relations = 0 ;
		
		String nodeTitle = null;
		int titleLength = 0 ;
		
		String nodeNote = null;
		int noteLength = 0 ;
		
		String nodeMisc = null;
		int miscLength = 0 ;
		
		NodeImpl node = null;
		Integer wrappedLevel = null ;
							
		// if it's not the first record ...
		if (recordCounter > 0) {

			// it's a data-containing node
			
			// determine the node's level in the outline
			
			// if it's the first node
			if (recordCounter == 1) {
				
				// nodeLevel is just 0
				nodeLevel = 0 ;
				
				} // end if we're the first node
			
			// else it's not the first node
			else {
				// node's level was set by previous record
				nodeLevel = nextNodeLevel ;
				
				} // end else we're not the first node
			
			// determine the node level of the next node
			
			// grab current node's relations flags
			relations = BitsAndBytes.unsignedShort(recordData, PDB_SP_RECORD_RELATIONS, BitsAndBytes.HI_TO_LO) ;
			
			// note whether there's a sibling coming up
			siblingAhead = ((relations & PDB_SP_RECORD_HAS_SIBLING) != 0) ;
			
			// if current node has a child ...
			if ((relations & PDB_SP_RECORD_HAS_CHILD) != 0) {
				
				// that child is the next node
				// children live one level deeper
				nextNodeLevel = nodeLevel + 1 ;
					
				// if there's a sibling ahead
				if (siblingAhead) {
					
					// siblings live at the same level 
					// push that onto the stack
					wrappedLevel = new Integer(nodeLevel) ;
					siblingAheadLevels.push(wrappedLevel);
					
					} // end if there's a sibling ahead
				
				} // end if current node has a child
				
			// else if current node has no child, but does have a sibling
			else if (siblingAhead) {
				
				// that sibling is the next node
				// siblings live at the same level
				nextNodeLevel = nodeLevel ;
				
				} // end else if current node has a sibling
				
			// else current node has no siblings or children
			// if there are more nodes, then next node is some kind of forebear
			// we can find out if there are more nodes by checking the size of the stack
			// if it's empty, there are no more nodes
			else if (! siblingAheadLevels.empty()){
				
				// the stack's NOT empty
				//there's a next node, and it is a forebear
				// pop its level off of the stack
				wrappedLevel =  (Integer) siblingAheadLevels.pop() ;
				nextNodeLevel = wrappedLevel.intValue() ;
				wrappedLevel = null ; // avoid memory leaks
				
				} // end else current node has no siblings or children and stack's not empty
			
			// else there are no more nodes
			else {
				// let's free the stack to avoid memory leaks
				siblingAheadLevels = null ;
				
				} // end else there are no more nodes
			
			// phew
			
			// if there's node text ...
			// (Shadow Plan calls a node's text its title)
			titleLength =  BitsAndBytes.unsignedShort(recordData, PDB_SP_RECORD_TITLE_LENGTH, BitsAndBytes.HI_TO_LO) ;
			if (titleLength > 0) {
				
				// grab the node text as a string
				nodeTitle = new String(recordData, PDB_SP_RECORD_FOOTER, titleLength) ;

				// create a free-standing node with the proper contents
				node = new NodeImpl(null, nodeTitle);
	
				// set node attributes
				// TBD
	
				// add the node to the outline
				ourContentHandler.addNodeToOutline(node, nodeLevel) ;
				
				} // end if there's node text
		
		
			// if the node has a note ...
			noteLength =  (int) BitsAndBytes.unsignedInt(recordData, PDB_SP_RECORD_NOTE_LENGTH, BitsAndBytes.HI_TO_LO) ;
			if (noteLength > 0) {
				
				// grab the note text as a string
				nodeNote = new String(recordData, 
					PDB_SP_RECORD_FOOTER + titleLength+1, noteLength) ;

				// create a free-standing node with the proper contents
				node = new NodeImpl(null, nodeNote);
	
				// set node attributes
				// TBD
	
				// create a free-standing node with the proper contents
				node = new NodeImpl(null, SHADOW_PLAN_NOTE_START_MARKUP + nodeNote + SHADOW_PLAN_NOTE_STOP_MARKUP);
				
				// set node attributes
				// it's a Shadow Plan note node
				// TBD
				// for now, we encase in XMLian markup, as seen above
				
				// add the note to the outline as a child of the current node
				ourContentHandler.addNodeToOutline(node, nodeLevel + 1) ;
				
				} // end if the node has a note
			
			
			// if the node has misc stuff ...
			miscLength =  BitsAndBytes.unsignedShort(recordData, PDB_SP_RECORD_MISC_LENGTH, BitsAndBytes.HI_TO_LO) ;
			if (miscLength > 0) {
				
				// grab the misc text as a string
				nodeNote = new String(recordData, 
					PDB_SP_RECORD_FOOTER + titleLength+noteLength + 2, miscLength) ;

				// create a free-standing node with the proper contents
				node = new NodeImpl(null, nodeNote);
	
				// set node attributes
				// TBD
	
				// create a free-standing node with the proper contents
				node = new NodeImpl(null, SHADOW_PLAN_MISC_START_MARKUP + nodeNote + SHADOW_PLAN_MISC_STOP_MARKUP);
				
				// set node attributes
				// it's a Shadow Plan misc stuff node
				// TBD
				// for now, we encase in XMLian markup, as seen above
				
				// add the misc info to the outline as a child of the current node
				ourContentHandler.addNodeToOutline(node, nodeLevel + 1) ;
				
				} // end if the node has misc stuff
			
			} // end if it's not the first record

					
		// else it's the first record
		else {
			// the first record is special
			// it contains meta data RE the outline
			
			// more possibly TBD
			
			// reset nodeLevel stuff for upcoming convolutions
			nodeLevel = 0;
			nextNodeLevel = 0 ;
			siblingAhead = false ;
			siblingAheadLevels = new Stack();
					
			} // end else it's the first record
		
		// return a result
		// TBD make this real
		// TBD while doing so, get a try/catch in here
		
		return processResult ;
			
		} // end protected method processRecord