diff --git a/docroot/amfphp/core/amf/app/Actions.php b/docroot/amfphp/core/amf/app/Actions.php new file mode 100755 index 0000000..dc92526 --- /dev/null +++ b/docroot/amfphp/core/amf/app/Actions.php @@ -0,0 +1,240 @@ +targetURI; + + if (strpos($target, "http://") === false && strpos($target, "https://") === false) { // check for a http link which means web service + $lpos = strrpos($target, "."); + if ($lpos === false) { + //Check to see if this is in fact a RemotingMessage + $body = $amfbody->getValue(); + $handled = false; + + $messageType = $body[0]->_explicitType; + if($messageType == 'flex.messaging.messages.RemotingMessage') + { + $handled = true; + + //Fix for AMF0 mixed array bug in Flex 2 + if(isset($body[0]->body['length'])) + { + unset($body[0]->body['length']); + } + + $amfbody->setValue($body[0]->body); + $amfbody->setSpecialHandling("RemotingMessage"); + $amfbody->setMetadata("clientId", $body[0]->clientId); + $amfbody->setMetadata("messageId", $body[0]->messageId); + + $GLOBALS['amfphp']['lastMessageId'] = $body[0]->messageId; + + $methodname = $body[0]->operation; + $classAndPackage = $body[0]->source; + $lpos = strrpos($classAndPackage, "."); + if($lpos !== FALSE) + { + $classname = substr($classAndPackage, $lpos + 1); + } + else + { + $classname = $classAndPackage; + } + $uriclasspath = str_replace('.','/',$classAndPackage) . '.php'; + $classpath = $baseClassPath . $uriclasspath; + } + elseif($messageType == "flex.messaging.messages.CommandMessage") + { + if($body[0]->operation == 5) + { + $handled = true; + $amfbody->setSpecialHandling("Ping"); + $amfbody->setMetadata("clientId", $body[0]->clientId); + $amfbody->setMetadata("messageId", $body[0]->messageId); + $amfbody->noExec = true; + } + } + + if(!$handled) + { + $uriclasspath = "amfphp/Amf3Broker.php"; + $classpath = $baseClassPath . "amfphp/Amf3Broker.php"; + $classname = "Amf3Broker"; + $methodname = "handleMessage"; + } + } else { + $methodname = substr($target, $lpos + 1); + $trunced = substr($target, 0, $lpos); + $lpos = strrpos($trunced, "."); + if ($lpos === false) { + $classname = $trunced; + if ($classname == "PageAbleResult" && $methodname == 'getRecords') { + $val = $amfbody->getValue(); + $id = $val[0]; + $keys = explode("=", $id); + $currset = intval($keys[1]); + + $set = $_SESSION['amfphp_recordsets'][$currset]; + + $uriclasspath = $set['class']; + $classpath = $baseClassPath . $set['class']; + $methodname = $set['method']; + + $classname = substr(strrchr('/' . $set['class'], '/'), 1, -4); + + //Now set args for body + $amfbody->setValue(array_merge($set['args'], array($val[1], $val[2]))); + + //Tell amfbody that this is a dynamic paged resultset + $amfbody->setSpecialHandling('pageFetch'); + } + else if($classname == "PageAbleResult" && $methodname == 'release') + { + $amfbody->setSpecialHandling('pageRelease'); + $amfbody->noExec = true; + } + else { + $uriclasspath = $trunced . ".php"; + $classpath = $baseClassPath . $trunced . ".php"; + } + } else { + $classname = substr($trunced, $lpos + 1); + $classpath = $baseClassPath . str_replace(".", "/", $trunced) . ".php"; // removed to strip the basecp out of the equation here + $uriclasspath = str_replace(".", "/", $trunced) . ".php"; // removed to strip the basecp out of the equation here + } + } + } else { // This is a web service and is unsupported + trigger_error("Web services are not supported in this release", E_USER_ERROR); + } + + $amfbody->classPath = $classpath; + $amfbody->uriClassPath = $uriclasspath; + $amfbody->className = $classname; + $amfbody->methodName = $methodname; + + return true; +} + +/** + * ExecutionAction executes the required methods + */ +function executionAction (&$amfbody) +{ + $specialHandling = $amfbody->getSpecialHandling(); + + if (!$amfbody->isSpecialHandling() || $amfbody->isSpecialHandling(array('describeService', 'pageFetch', 'RemotingMessage'))) + { + $construct = &$amfbody->getClassConstruct(); + $method = $amfbody->methodName; + $args = $amfbody->getValue(); + + if($specialHandling == 'describeService') + { + include_once(AMFPHP_BASE . "util/DescribeService.php"); + $ds = new DescribeService(); + $results = $ds->describe($construct, $amfbody->className); + } + else if($specialHandling == 'pageFetch') + { + $args[count($args) - 2] = $args[count($args) - 2] - 1; + + $dataset = Executive::doMethodCall($amfbody, $construct, $method, $args); + $results = array("cursor" => $args[count($args) - 2] + 1, + "data" => $dataset); + $amfbody->setMetadata('type', '__DYNAMIC_PAGE__'); + } + else + { + /* + if(isset($construct->methodTable[$method]['pagesize'])) + { + //Check if counting method was overriden + if(isset($construct->methodTable[$method]['countMethod'])) + { + $counter = $construct->methodTable[$method]['countMethod']; + } + else + { + $counter = $method . '_count'; + } + + $dataset = Executive::doMethodCall($amfbody, $construct, $method, $args); // do the magic + $count = Executive::doMethodCall($amfbody, $construct, $counter, $args); + + //Include the wrapper + $results = array('class' => $amfbody->uriClassPath, + 'method' => $amfbody->methodName, + 'count' => $count, + "args" => $args, + "data" => $dataset); + $amfbody->setMetadata('type', '__DYNAMIC_PAGEABLE_RESULTSET__'); + $amfbody->setMetadata('pagesize', $construct->methodTable[$method]['pagesize']); + */ + //} + //else + //{ + //The usual + $time = microtime_float(); + $results = Executive::doMethodCall($amfbody, $construct, $method, $args); // do the magic + global $amfphp; + $amfphp['callTime'] += microtime_float() - $time; + //} + } + + if($results !== '__amfphp_error') + { + if($specialHandling == 'RemotingMessage') + { + + $wrapper = new AcknowledgeMessage($amfbody->getMetadata("messageId"), + $amfbody->getMetadata("clientId")); + $wrapper->body = $results; + $amfbody->setResults($wrapper); + } + else + { + $amfbody->setResults($results); + } + + $amfbody->responseURI = $amfbody->responseIndex . "/onResult"; + } + return false; + } + elseif($specialHandling == 'Ping') + { + $wrapper = new AcknowledgeMessage($amfbody->getMetadata("messageId"), + $amfbody->getMetadata("clientId")); + $amfbody->setResults($wrapper); + $amfbody->responseURI = $amfbody->responseIndex . "/onResult"; + } + else if($specialHandling == 'pageRelease') + { + //Ignore PageAbleResult.release + $amfbody->setResults(true); + $amfbody->setMetaData('type', 'boolean'); + $amfbody->responseURI = $amfbody->responseIndex . "/onResult"; + return false; + } + return true; +} +?> \ No newline at end of file diff --git a/docroot/amfphp/core/amf/app/Filters.php b/docroot/amfphp/core/amf/app/Filters.php new file mode 100755 index 0000000..9f58923 --- /dev/null +++ b/docroot/amfphp/core/amf/app/Filters.php @@ -0,0 +1,210 @@ +rawData); // deserialize the data + } + else + { + include_once(AMFPHP_BASE . "amf/io/AMFDeserializer.php"); + include_once(AMFPHP_BASE . "amf/io/AMFSerializer.php"); + $deserializer = new AMFDeserializer($amf->rawData); // deserialize the data + } + + $deserializer->deserialize($amf); // run the deserializer + + //Add some headers + $headers = $amf->_headerTable; + if(isset($headers) && is_array($headers)) + { + foreach($headers as $key => $value) + { + Headers::setHeader($value->name, $value->value); + } + } + + //Set as a describe service + $describeHeader = $amf->getHeader(AMFPHP_SERVICE_BROWSER_HEADER); + + if ($describeHeader !== false) { + if($GLOBALS['amfphp']['disableDescribeService']) + { + //Exit + trigger_error("Service description not allowed", E_USER_ERROR); + die(); + } + $bodyCopy = &$amf->getBodyAt(0); + $bodyCopy->setSpecialHandling('describeService'); + $bodyCopy->noExec = true; + } +} + +/** + * AuthenticationFilter looks at the credential headers, starts sessions, etc. + */ +function authenticationFilter (&$amf) { + $authHeader = $amf->getHeader(AMFPHP_CREDENTIALS_HEADER); + + if ($authHeader !== false && $authHeader->value !== AMFPHP_CLEARED_CREDENTIALS) { + //In PHP5, objects are always pass-by-ref, hence this branch + if(AMFPHP_PHP5) + { + $bodyCopy = clone($amf->getBodyAt(0)); + } + else + { + $bodyCopy = $amf->getBodyAt(0); + } + + $uri = $bodyCopy->targetURI; + $lpos = strrpos($uri, "."); + $cp = substr($uri, 0, $lpos + 1) . "_authenticate"; + $bodyCopy->targetURI = $cp; + $bodyCopy->setSpecialHandling('auth'); + $val = $authHeader->value; + $bodyCopy->setValue($val); + $amf->addBodyAt(0, $bodyCopy); + + //Make it so that the data will stop being transmitted + $clearHeader = array('name' => 'Credentials', 'mustUnderstand' => false, + 'data' => AMFPHP_CLEARED_CREDENTIALS); + $outHeader = new MessageHeader("RequestPersistentHeader", true, $clearHeader); + $amf->addOutgoingHeader($outHeader); + } + + $sessionName = @ini_get('session.name'); + if($sessionName == "" || $sessionName == NULL) + { + //Fix for godaddy not allowing ini_get + $sessionName = "PHPSESSID"; + } + session_start(); + $session_id = session_id(); + if(!strpos($_SERVER['QUERY_STRING'], $session_id) !== FALSE) + { + /** + Instead of trying to guess if using https, + just use AppendTogGatewayUrl instead + of ReplaceGatewayUrl + */ + if(strrpos($_SERVER['QUERY_STRING'], "?") !== FALSE) + { + $joint = "&"; + } + else + { + $joint = "?"; + } + $outHeader = new MessageHeader("AppendToGatewayUrl", false, $joint . $sessionName . "=" . $session_id); + $amf->addOutgoingHeader($outHeader); + } +} + +/** + * Executes each of the bodys + */ +function batchProcessFilter(&$amf) +{ + $bodycount = $amf->numBody(); + + for ($i = 0; $i < $bodycount; $i++) { + $bodyObj = &$amf->getBodyAt($i); + $actions = $GLOBALS['amfphp']['actions']; + foreach($actions as $key => $action) + { + $results = $action($bodyObj); + if($results === false) + { + break; + } + } + } + + $bodycount = $amf->numBody(); + + for ($i = 0; $i < $bodycount; $i++) { + $bodyObj = &$amf->getBodyAt($i); + if($bodyObj->getSpecialHandling() == 'auth' && $bodyObj->getResults() === NULL) + { + $amf->removeBodyAt($i); + break; + } + } +} + +/** + * Adds debugging information to outgoing packet + */ +function debugFilter (&$amf) { + //Add trace headers before outputting + if(!$GLOBALS['amfphp']['isFlashComm'] && !$GLOBALS['amfphp']['disableTrace']) + { + $headerresults = array(); // create a result array + $headerresults[0] = array(); // create a sub array in results (CF seems to do this, don't know why) + + if(count(NetDebug::getTraceStack()) != 0) + { + $ts = NetDebug::getTraceStack(); + $headerresults[0][] = new TraceHeader($ts); + } + if(Headers::getHeader("serviceBrowser") == true) + { + global $amfphp; + $amfphp['totalTime'] = microtime_float() - $amfphp['startTime']; + $headerresults[0][] = new ProfilingHeader(); + } + + //Get the last body in the stack + if(count($headerresults[0]) > 0) + { + $body = &$amf->getBodyAt($amf->numBody() - 1); + + $headers = new MessageBody(NULL, $body->responseIndex, NULL); // create a new amf body + $headers->responseURI = $body->responseIndex . "/onDebugEvents"; // set the response uri of this body + + $headers->setResults($headerresults); // set the results. + $amf->addBodyAt(0, $headers); + } + } +} + +/** + * Serializes the object + */ +function serializationFilter (&$amf) { + if($GLOBALS['amfphp']['native'] === true && function_exists('amf_decode')) + { + $serializer = new AMFBaseSerializer(); // Create a serailizer around the output stream + } + else + { + $serializer = new AMFSerializer(); // Create a serailizer around the output stream + } + $result = $serializer->serialize($amf); // serialize the data + $amf->outputStream = $result; +} +?> \ No newline at end of file diff --git a/docroot/amfphp/core/amf/app/Gateway.php b/docroot/amfphp/core/amf/app/Gateway.php new file mode 100755 index 0000000..ac6edf0 --- /dev/null +++ b/docroot/amfphp/core/amf/app/Gateway.php @@ -0,0 +1,410 @@ +exec = new Executive(); + $this->filters = array(); + $this->actions = array(); + $this->registerFilterChain(); + $this->registerActionChain(); + } + + /** + * Create the chain of filters + * Subclass gateway and overwrite to create a custom gateway + */ + function registerFilterChain() + { + //filters + $this->filters['deserial'] = 'deserializationFilter'; + $this->filters['auth'] = 'authenticationFilter'; + $this->filters['batch'] = 'batchProcessFilter'; + $this->filters['debug'] = 'debugFilter'; + $this->filters['serialize'] = 'serializationFilter'; + } + + /** + * Create the chain of actions + * Subclass gateway and overwrite to create a custom gateway + */ + function registerActionChain() + { + $this->actions['adapter'] = 'adapterAction'; + $this->actions['class'] = 'classLoaderAction'; + $this->actions['security'] = 'securityAction'; + $this->actions['exec'] = 'executionAction'; + } + + /** + * The service method runs the gateway application. It turns the gateway 'on'. You + * have to call the service method as the last line of the gateway script after all of the + * gateway configuration properties have been set. + * + * Right now the service method also includes a very primitive debugging mode that + * just dumps the raw amf input and output to files. This may change in later versions. + * The debugging implementation is NOT thread safe so be aware of file corruptions that + * may occur in concurrent environments. + */ + + function service() { + + //Set the parameters for the charset handler + CharsetHandler::setMethod($this->_charsetMethod); + CharsetHandler::setPhpCharset($this->_charsetPhp); + CharsetHandler::setSqlCharset($this->_charsetSql); + + //Attempt to call charset handler to catch any uninstalled extensions + $ch = new CharsetHandler('flashtophp'); + $ch->transliterate('?'); + + $ch2 = new CharsetHandler('sqltophp'); + $ch2->transliterate('?'); + + $GLOBALS['amfphp']['actions'] = $this->actions; + + if (!isset($GLOBALS['HTTP_RAW_POST_DATA'])){ + $GLOBALS['HTTP_RAW_POST_DATA'] = file_get_contents('php://input'); + } + + if(isset($GLOBALS["HTTP_RAW_POST_DATA"]) && $GLOBALS["HTTP_RAW_POST_DATA"] != "") + { + //Start NetDebug + NetDebug::initialize(); + + error_reporting($GLOBALS['amfphp']['errorLevel']); + + //Enable loose mode if requested + if($this->_looseMode) + { + ob_start(); + } + + $amf = new AMFObject($GLOBALS["HTTP_RAW_POST_DATA"]); // create the amf object + + if($this->incomingMessagesFolder != NULL) + { + $mt = microtime(); + $pieces = explode(' ', $mt); + file_put_contents($this->incomingMessagesFolder . + 'in.' . $pieces[1] . '.' . substr($pieces[0], 2) . ".amf", + $GLOBALS["HTTP_RAW_POST_DATA"]); + } + + foreach($this->filters as $key => $filter) + { + $filter($amf); // invoke the first filter in the chain + } + + $output = $amf->outputStream; // grab the output stream + + //Clear the current output buffer if requested + if($this->_looseMode) + { + ob_end_clean(); + } + + //Send content length header + //Thanks to Alec Horley for pointing out the necessity + //of this for FlashComm support + header(AMFPHP_CONTENT_TYPE); // define the proper header + + if(Headers::getHeader('serviceBrowser') == true) + { + //Add the total time header + $toAddPos = strpos($output, "\301\260\0\0\1\0\0\0"); + $time = (int) ((microtime_float() - $GLOBALS['amfphp']['startTime'])*1000); + $b = pack("d", $time); // pack the bytes + if (AMFPHP_BIG_ENDIAN) { // if we are a big-endian processor + $r = strrev($b); + } else { // add the bytes to the output + $r = $b; + } + $output = substr($output, 0, $toAddPos) . $r . substr($output, $toAddPos + 8); + } + + //Send expire header, apparently helps for SSL + //Thanks to Gary Rogers for that + //And also to Lucas Filippi from openAMF list + //And to Robert Reinhardt who appears to be the first who + //documented the bug + //Finally to Gary who appears to have find a solution which works even more reliably + $dateStr = date("D, j M Y ") . date("H:i:s", strtotime("-2 days")); + header("Expires: $dateStr GMT"); + header("Pragma: no-store"); + header("Cache-Control: no-store"); + + //else don't send any special headers at all + + if($this->outgoingMessagesFolder != NULL) + { + $mt = microtime(); + $pieces = explode(' ', $mt); + file_put_contents($this->outgoingMessagesFolder . + 'out.' . $pieces[1] . '.' . substr($pieces[0], 2) . ".amf", $output); + } + + $doCompress = false; + $outputCompression = @ini_get("zlib.output_compression"); + if(!$outputCompression) + { + if(strlen($output) > $this->_gzipCompressionThreshold && + extension_loaded("zlib") && + strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE && + $this->_enableGzipCompression) + { + $doCompress = true; + ob_start(); + ob_start('ob_gzhandler'); + } + else + { + header("Content-length: " . strlen($output)); + } + } + + print($output); // flush the binary data + + if($doCompress) + { + ob_end_flush(); + header("Content-length: " . ob_get_length()); + ob_end_flush(); + } + } + else + { + echo("
amfphp and this gateway are installed correctly. You may now connect " . + "to this gateway from Flash.
"); + + if(function_exists("amf_decode")) + { + echo("AMF C Extension is loaded " . + ($GLOBALS['amfphp']['native'] ? "and enabled." : "but disabled") . + "
"); + } + echo "Note: If you're reading an " . + "old tutorial, it will tell you that you should see a download ". + "window instead of this message. This confused people so this is " . + "the new behaviour starting from amfphp 1.2.
" . + "View the amfphp documentation
" . + ""; + echo "";
+		}
+	}
+	
+	/**
+	 * Setter for error handling
+	 * 
+	 * @param the error handling level
+	 */
+	function setErrorHandling($level)
+	{
+		$GLOBALS['amfphp']['errorLevel'] = $level;
+	}
+	
+	/**
+	 * Sets the base path for loading service methods.
+	 * 
+	 * Call this method to define the directory to look for service classes in.
+	 * Relative or full paths are acceptable
+	 * 
+	 * @param string $path The path the the service class directory
+	 */
+	function setClassPath($value) {
+		$path = realpath($value . '/') . '/';
+		$GLOBALS['amfphp']['classPath'] = $path;
+	}
+	
+	/**
+	 * Sets the base path for loading service methods.
+	 * 
+	 * Call this method to define the directory to look for service classes in.
+	 * Relative or full paths are acceptable
+	 * 
+	 * @param string $path The path the the service class directory
+	 */
+	function setClassMappingsPath($value) {
+		$path = realpath($value . '/') . '/';
+		$GLOBALS['amfphp']['customMappingsPath'] = $path;
+	}
+	
+	/**
+	 * Sets the loose mode. This will enable outbut buffering
+	 * And flushing and set error_reporting to 0. The point is if set to true, a few
+	 * of the usual NetConnection.BadVersion error should disappear
+	 * Like if you try to echo directly from your function, if you are issued a 
+	 * warning and such. Errors should still be logged to the error log though.
+	 *
+	 * @example In gateway.php, before $gateway->service(), use $gateway->setLooseMode(true) 
+	 * @param bool $mode Enable or disable loose mode
+	 */
+	function setLooseMode($paramLoose = true) {
+		$this->_looseMode = $paramLoose;
+	} 
+	
+	function enableGzipCompression($threshold = 30100)
+	{
+		$this->_enableGzipCompression = true;
+		$this->_gzipCompressionThreshold = $threshold;
+	}
+	
+	/**
+	 * Sets the charset handler. 
+	 * The charset handler handles reencoding from and to a specific charset
+	 * for PHP and SQL resources.
+	 *
+	 * @param $method The method used for reencoding, either "none", "iconv" or "runtime"
+	 * @param $php The internal encoding that is assumed for PHP (typically ISO-8859-1)
+	 * @param $sql The internal encoding that is assumed for SQL resources
+	 */
+	function setCharsetHandler($method = "none", $php, $sql) {
+		$this->_charsetMethod = $method;
+		$this->_charsetPhp = $php;
+		$this->_charsetSql = $sql;
+	} 
+	
+	/**
+	 * disableTrace will ignore any calls to NetDebug::trace
+	 * 
+	 * @param bool $bool Whether to disable tracing
+	 */
+	function disableDebug($value = true) {
+		$GLOBALS['amfphp']['disableDebug'] = $value;
+	} 
+	
+	/**
+	 * Disable native extension will disable the native C extension
+	 */
+	function disableNativeExtension()
+	{
+		$GLOBALS['amfphp']['native'] = false;
+	}
+	
+	/**
+	 * Log incoming messages to the specified folder
+	 */
+	function logIncomingMessages($folder = NULL)
+	{
+		$this->incomingMessagesFolder = realpath($folder) . '/';
+	}
+	
+	/**
+	 * Log outgoing messages to the specified folder
+	 */
+	function logOutgoingMessages($folder = NULL)
+	{
+		$this->outgoingMessagesFolder = realpath($folder) . '/';
+	}
+
+	/**
+	 * Dumps data to a file
+	 * 
+	 * @param string $filepath The location of the dump file
+	 * @param string $data The data to insert into the dump file
+	 */
+	function _saveRawDataToFile($filepath, $data) {
+		if (!$handle = fopen($filepath, 'w')) {
+			exit;
+		} 
+		if (!fwrite($handle, $data)) {
+			exit;
+		} 
+		fclose($handle);
+	}
+
+	/**
+	 * Appends data to a file
+	 * 
+	 * @param string $filepath The location of the dump file
+	 * @param string $data The data to append to the dump file
+	 */
+	function _appendRawDataToFile($filepath, $data) {
+		$handle = fopen($filepath, 'a');
+		fwrite($handle, $data);
+		fclose($handle);
+	}
+}
+
+?>
\ No newline at end of file
diff --git a/docroot/amfphp/core/amf/io/AMFBaseDeserializer.php b/docroot/amfphp/core/amf/io/AMFBaseDeserializer.php
new file mode 100755
index 0000000..53aabe6
--- /dev/null
+++ b/docroot/amfphp/core/amf/io/AMFBaseDeserializer.php
@@ -0,0 +1,400 @@
+isBigEndian = AMFPHP_BIG_ENDIAN;
+		$this->current_byte = 0;
+		$this->raw_data = $rd;  // store the stream in this object
+		$this->content_length = strlen($this->raw_data); // grab the total length of this stream
+		$this->charsetHandler = new CharsetHandler('flashtophp');
+		$this->storedStrings = array();
+		$this->storedObjects = array();
+		$this->storedDefinitions = array();
+		$this->native = $GLOBALS['amfphp']['native'] && function_exists('amf_decode');
+		$this->decodeFlags = (AMFPHP_BIG_ENDIAN*2) | 4;
+	} 
+
+	/**
+	 * deserialize invokes this class to transform the raw data into valid object
+	 * 
+	 * @param object $amfdata The object to put the deserialized data in
+	 */
+	function deserialize (&$amfdata) {
+		$time = microtime_float();
+		$this->amfdata = &$amfdata;
+		$this->readHeader(); // read the binary header
+		$this->readBody(); // read the binary body
+		if($this->decodeFlags & 1 == 1)
+		{
+			//AMF3 mode
+			$GLOBALS['amfphp']['encoding'] = "amf3";
+		}
+		global $amfphp;
+		$amfphp['decodeTime'] = microtime_float() - $time;
+	} 
+	/**
+	 * returns the built AMFObject from the deserialization operation
+	 * 
+	 * @return object The deserialized AMFObject
+	 */
+	function getAMFObject() {
+		return $this->amfdata;
+	} 
+	
+	/**
+	 * Decode callback is triggered when an object is encountered on decode
+	 */
+	function decodeCallback($event, $arg)
+	{
+		if($event == 1) //Object
+		{
+		   $type =$arg;
+		   return $this->mapClass($type);
+		}
+		else if($event == 2) //Object post decode
+		{
+		   $obj = $arg;
+		   if(method_exists($obj, 'init'))
+		   {
+		       $obj->init();
+		   }
+		   return $obj;
+		} 
+		else if($event == 3) //XML post-decode
+		{
+			return $arg;
+		}
+		else if($event == 4) //Serializable post-decode
+		{
+			if($type == 'flex.messaging.io.ArrayCollection' || $type == 'flex.messaging.io.ObjectProxy')
+			{
+			    return;
+			}
+			else
+			{
+			   trigger_error("Unable to read externalizable data type " . $type, E_USER_ERROR);
+			   return "error";
+			}
+		}
+		else if($event == 5) //ByteArray post decode
+		{
+			return new ByteArray($arg);
+		}
+	}
+
+	/**
+	 * readHeader converts that header section of the amf message into php obects.
+	 * Header information typically contains meta data about the message.
+	 */
+	function readHeader() {
+
+		$topByte = $this->readByte(); // ignore the first two bytes --  version or something
+		$secondByte = $this->readByte(); //0 for Flash,
+										 //1 for FlashComm                   
+		//Disable debug events for FlashComm
+		$GLOBALS['amfphp']['isFlashComm'] = $secondByte == 1;
+		
+		//If firstByte != 0, then the AMF data is corrupted, for example the transmission 
+		//
+		if(!($topByte == 0 || $topByte == 3))
+		{
+			trigger_error("Malformed AMF message, connection may have dropped");
+			exit();
+		}
+		$this->header_count = $this->readInt(); //  find the total number of header elements
+		while ($this->header_count--) { // loop over all of the header elements
+			$name = $this->readUTF();
+			$required = $this->readByte() == 1; // find the must understand flag
+			//$length   = $this->readLong(); // grab the length of  the header element
+			$this->current_byte += 4; // grab the length of the header element
+			if($this->native)
+			{
+			    $content = amf_decode($this->raw_data, $this->decodeFlags, $this->current_byte, array(& $this, "decodeCallback"));
+			}
+			else
+			{
+			    $type = $this->readByte();  // grab the type of the element
+			    $content = $this->readData($type); // turn the element into real data
+			}
+			
+			$this->amfdata->addHeader(new MessageHeader($name, $required, $content)); // save the name/value into the headers array
+		}
+
+	} 
+
+	/**
+	 * readBody converts the payload of the message into php objects.
+	 */
+	function readBody() {
+		$this->body_count = $this->readInt(); // find the total number  of body elements
+		while ($this->body_count--) { // loop over all of the body elements
+			
+			$this->amf0storedObjects = array();
+			$this->storedStrings = array();
+			$this->storedObjects = array();
+			$this->storedDefinitions = array();
+			
+			$target = $this->readUTF();
+			$response = $this->readUTF(); //    the response that the client understands
+			
+			//$length = $this->readLong(); // grab the length of    the body element
+			$this->current_byte += 4;
+			
+			if($this->native)
+			   $data = amf_decode($this->raw_data, $this->decodeFlags, $this->current_byte, array(& $this, "decodeCallback"));
+			else
+			{
+			   $type = $this->readByte();  // grab the type of the element
+			   $data = $this->readData($type); // turn the element into real data
+			}
+			
+			$this->amfdata->addBody(new MessageBody($target, $response, $data)); // add the body element to the body object
+			
+		} 
+	} 
+	
+	/********************************************************************************
+	 *                       This used to be in AmfInputStream
+	 ********************************************************************************
+
+	/**
+	 * readByte grabs the next byte from the data stream and returns it.
+	 * 
+	 * @return int The next byte converted into an integer
+	 */
+	function readByte() {
+		return ord($this->raw_data[$this->current_byte++]); // return the next byte
+	}
+
+	/**
+	 * readInt grabs the next 2 bytes and returns the next two bytes, shifted and combined
+	 * to produce the resulting integer
+	 * 
+	 * @return int The resulting integer from the next 2 bytes
+	 */
+	function readInt() {
+		return ((ord($this->raw_data[$this->current_byte++]) << 8) |
+			ord($this->raw_data[$this->current_byte++])); // read the next 2 bytes, shift and add
+	} 
+
+	/**
+	 * readUTF first grabs the next 2 bytes which represent the string length.
+	 * Then it grabs the next (len) bytes of the resulting string.
+	 * 
+	 * @return string The utf8 decoded string
+	 */
+	function readUTF() {
+		$length = $this->readInt(); // get the length of the string (1st 2 bytes)
+		//BUg fix:: if string is empty skip ahead
+		if($length == 0)
+		{
+			return "";
+		}
+		else
+		{
+			$val = substr($this->raw_data, $this->current_byte, $length); // grab the string
+			$this->current_byte += $length; // move the seek head to the end of the string
+			return $this->charsetHandler->transliterate($val); // return the string
+		}
+	} 
+	
+	/**
+	 * readLong grabs the next 4 bytes shifts and combines them to produce an integer
+	 * 
+	 * @return int The resulting integer from the next 4 bytes
+	 */
+	function readLong() {
+		return ((ord($this->raw_data[$this->current_byte++]) << 24) |
+			(ord($this->raw_data[$this->current_byte++]) << 16) |
+			(ord($this->raw_data[$this->current_byte++]) << 8) |
+			ord($this->raw_data[$this->current_byte++])); // read the next 4 bytes, shift and add
+	} 
+
+	/**
+	 * readDouble reads the floating point value from the bytes stream and properly orders
+	 * the bytes depending on the system architecture.
+	 * 
+	 * @return float The floating point value of the next 8 bytes
+	 */
+	function readDouble() {
+		$bytes = substr($this->raw_data, $this->current_byte, 8);
+		$this->current_byte += 8;
+		if ($this->isBigEndian) {
+			 $bytes = strrev($bytes);
+		} 
+		$zz = unpack("dflt", $bytes); // unpack the bytes
+		return $zz['flt']; // return the number from the associative array
+	} 
+
+	/**
+	 * readLongUTF first grabs the next 4 bytes which represent the string length.
+	 * Then it grabs the next (len) bytes of the resulting in the string
+	 * 
+	 * @return string The utf8 decoded string
+	 */
+	function readLongUTF() {
+		$length = $this->readLong(); // get the length of the string (1st 4 bytes)
+		$val = substr($this->raw_data, $this->current_byte, $length); // grab the string
+		$this->current_byte += $length; // move the seek head to the end of the string
+		return $this->charsetHandler->transliterate($val); // return the string
+	} 
+    
+    function mapClass($typeIdentifier)
+    {
+		//Check out if class exists
+		if($typeIdentifier == "")
+		{
+			return NULL;
+		}
+		$clazz = NULL;
+		$mappedClass = str_replace('.', '/', $typeIdentifier);
+		
+		if($typeIdentifier == "flex.messaging.messages.CommandMessage")
+		{
+			return new CommandMessage();
+		}
+		if($typeIdentifier == "flex.messaging.messages.RemotingMessage")
+		{
+			return new RemotingMessage();
+		}
+		
+		if(isset($GLOBALS['amfphp']['incomingClassMappings'][$typeIdentifier]))
+		{
+			$mappedClass = str_replace('.', '/', $GLOBALS['amfphp']['incomingClassMappings'][$typeIdentifier]);
+		}
+		
+		$include = FALSE;
+		if(file_exists($GLOBALS['amfphp']['customMappingsPath'] . $mappedClass . '.php'))
+		{
+			$include = $GLOBALS['amfphp']['customMappingsPath'] . $mappedClass . '.php';
+		}
+		elseif(file_exists($GLOBALS['amfphp']['customMappingsPath'] . $mappedClass . '.class.php'))
+		{
+			$include = $GLOBALS['amfphp']['customMappingsPath'] . $mappedClass . '.class.php';
+		}
+		
+		if($include !== FALSE)
+		{
+			include_once($include);
+			$lastPlace = strrpos('/' . $mappedClass, '/');
+			$classname = substr($mappedClass, $lastPlace);
+			if(class_exists($classname))
+			{
+				$clazz = new $classname;
+			}
+		}
+		
+		return $clazz; // return the object
+    }
+} 
+
+?>
\ No newline at end of file
diff --git a/docroot/amfphp/core/amf/io/AMFBaseSerializer.php b/docroot/amfphp/core/amf/io/AMFBaseSerializer.php
new file mode 100755
index 0000000..e404d51
--- /dev/null
+++ b/docroot/amfphp/core/amf/io/AMFBaseSerializer.php
@@ -0,0 +1,327 @@
+isBigEndian = AMFPHP_BIG_ENDIAN;
+		$this->outBuffer = ""; // the buffer
+		$this->charsetHandler = new CharsetHandler('phptoflash');
+		$this->rsCharsetHandler = new CharsetHandler('sqltoflash');
+		$this->resourceObjects = $GLOBALS['amfphp']['adapterMappings'];
+		$this->native = $GLOBALS['amfphp']['native'] && function_exists('amf_decode');
+		$this->encodeFlags = (AMFPHP_BIG_ENDIAN?2:0) | 
+							  ($GLOBALS['amfphp']['encoding'] == 'amf3' ? 1:0);
+	} 
+
+	/**
+	 * serialize is the run method of the class.  When serialize is called
+	 * the AMFObject passed in is read and converted into the amf binary
+	 * representing the PHP data represented.
+	 * 
+	 * @param object $d the AMFObject to serialize
+	 */
+	function serialize(&$amfout) {
+		$encodeCallback = array(&$this,"encodeCallback");
+		$this->writeInt(0); //  write the version ???
+		$count = $amfout->numOutgoingHeader();
+		$this->writeInt($count); // write header count
+		for ($i = 0; $i < $count; $i++) {
+			//write headers
+			$header = &$amfout->getOutgoingHeaderAt($i);
+			$this->writeUTF($header->name);
+			$this->writeByte(0);
+			$tempBuf = $this->outBuffer;
+			$this->outBuffer = "";
+			if($this->native)
+			    $this->outBuffer .= amf_encode($header->value,$this->encodeFlags, $encodeCallback);
+			else
+			    $this->writeData($header->value);
+			$tempBuf2 = $this->outBuffer;
+			$this->outBuffer = $tempBuf;
+			$this->writeLong(strlen($tempBuf2));
+			$this->outBuffer .= $tempBuf2;
+		} 
+		$count = $amfout->numBody();
+		$this->writeInt($count); // write the body  count
+		for ($i = 0; $i < $count; $i++) {
+			//write body
+			$this->amf0StoredObjects = array();
+			$this->storedStrings = array();
+			$this->storedObjects = array();
+			$this->encounteredStrings = 0;
+			$this->storedDefinitions = 0;
+			$body = &$amfout->getBodyAt($i);
+			$this->currentBody = & $body;
+			$this->writeUTF($body->responseURI); // write the responseURI header
+			$this->writeUTF($body->responseTarget); //  write null, haven't found another use for this
+			$tempBuf = $this->outBuffer;
+			$this->outBuffer = "";
+			
+			if($this->native)
+			    $this->outBuffer .= amf_encode($body->getResults(),$this->encodeFlags, $encodeCallback);
+			else
+			    $this->writeData($body->getResults());
+
+			$tempBuf2 = $this->outBuffer;
+			$this->outBuffer = $tempBuf;
+			$this->writeLong(strlen($tempBuf2));
+			$this->outBuffer .= $tempBuf2;
+		} 
+		
+		return $this->outBuffer;
+	} 
+	
+	function encodeCallback($value)
+	{
+		///print_r($value);
+		if(is_object($value))
+		{
+			$className = strtolower(get_class($value));
+			if(AMFPHP_PHP5 && $className == 'domdocument')
+			{
+				return array($this->cleanXml($value->saveXml()),1);
+			}
+			else if(array_key_exists($className, $GLOBALS['amfphp']['adapterMappings']))
+			{
+				$subtype = $GLOBALS['amfphp']['adapterMappings'][strtolower($className)];
+				
+				$classname = $subtype . "Adapter"; // full class name
+				$includeFile = include_once(AMFPHP_BASE . "shared/adapters/" . $classname . ".php"); // try to load the recordset library from the sql folder
+				if (!$includeFile) {
+					trigger_error("The recordset filter class " . $classname . " was not found", E_USER_ERROR);
+				} 
+				$recordSet = new $classname($value); // returns formatted recordset
+				return array(
+					array("__amf_recordset__" => 2,
+						 "rows" => $recordSet->rows,
+						 "columns" => $recordSet->columns),
+				5);
+			}
+			else if(AMFPHP_PHP5 == 0 && $className == 'domdocument')
+			{
+				return array($this->cleanXml($value->dump_mem()),1);
+			}
+			else if($className == 'simplexmlelement')
+			{
+				return array($this->cleanXml($value->asXML()),1);
+			}
+			elseif($className == 'bytearray' && $this->encodeFlags & 1 == 1)
+			{
+				return array($value->data, 7);
+			}
+			else
+			{
+				$className = $this->getClassName($value);
+				return array($value,3,$className);
+			}
+		}
+		else
+		{
+			//A resource
+			$type = get_resource_type($value);
+			list($type, $subtype) = $this->sanitizeType($type);
+			$classname = $subtype . "Adapter"; // full class name
+			$includeFile = include_once(AMFPHP_BASE . "shared/adapters/" . $classname . ".php"); // try to load the recordset library from the sql folder
+			if (!$includeFile) {
+				trigger_error("The recordset filter class " . $classname . " was not found", E_USER_ERROR);
+			} 
+			$recordSet = new $classname($value); // returns formatted recordset
+			return array(
+				array("__amf_recordset__" => 2,
+						 "rows" => $recordSet->rows,
+						 "columns" => $recordSet->columns), 
+				5);
+		}
+	}
+	
+	function cleanXml($d)
+	{
+		return preg_replace('/\>(\n|\r|\r\n| |\t)*\','><',trim($d));
+	}
+	
+	/**********************************************************************************
+	 *                      This code used to be in AMFOutputStream
+	 ********************************************************************************/
+
+	/**
+	 * writeByte writes a singe byte to the output stream
+	 * 0-255 range
+	 * 
+	 * @param int $b An int that can be converted to a byte
+	 */
+	function writeByte($b) {
+		$this->outBuffer .= pack("c", $b); // use pack with the c flag
+	} 
+
+	/**
+	 * writeInt takes an int and writes it as 2 bytes to the output stream
+	 * 0-65535 range
+	 * 
+	 * @param int $n An integer to convert to a 2 byte binary string
+	 */
+	function writeInt($n) {
+		$this->outBuffer .= pack("n", $n); // use pack with the n flag
+	} 
+
+	/**
+	 * writeLong takes an int, float or double and converts it to a 4 byte binary string and
+	 * adds it to the output buffer
+	 * 
+	 * @param long $l A long to convert to a 4 byte binary string
+	 */
+	function writeLong($l) {
+		$this->outBuffer .= pack("N", $l); // use pack with the N flag
+	} 
+
+	/**
+	 * writeUTF takes and input string, writes the length as an int and then
+	 * appends the string to the output buffer
+	 * 
+	 * @param string $s The string less than 65535 characters to add to the stream
+	 */
+	function writeUTF($s) {
+		$os = $this->charsetHandler->transliterate($s);
+		$this->writeInt(strlen($os)); // write the string length - max 65535
+		$this->outBuffer .= $os; // write the string chars
+	} 
+	
+	/**
+	 * writeBinary takes and input string, writes the length as an int and then
+	 * appends the string to the output buffer
+	 * 
+	 * @param string $s The string less than 65535 characters to add to the stream
+	 */
+	function writeBinary($s) {
+		$this->outBuffer .= $s; // write the string chars
+	} 
+
+	/**
+	 * writeLongUTF will write a string longer than 65535 characters.
+	 * It works exactly as writeUTF does except uses a long for the length
+	 * flag.
+	 * 
+	 * @param string $s A string to add to the byte stream
+	 */
+	function writeLongUTF($s) {
+		$os = $this->charsetHandler->transliterate($s);
+		$this->writeLong(strlen($os));
+		$this->outBuffer .= $os; // write the string chars
+	} 
+
+	/**
+	 * writeDouble takes a float as the input and writes it to the output stream.
+	 * Then if the system is big-endian, it reverses the bytes order because all
+	 * doubles passed via remoting are passed little-endian.
+	 * 
+	 * @param double $d The double to add to the output buffer
+	 */
+	function writeDouble($d) {
+		$b = pack("d", $d); // pack the bytes
+		if ($this->isBigEndian) { // if we are a big-endian processor
+			$r = strrev($b);
+		} else { // add the bytes to the output
+			$r = $b;
+		} 
+		
+		$this->outBuffer .= $r;
+	} 
+	
+	function sanitizeType($type)
+	{
+		$subtype = -1;
+		$type = strtolower($type);
+		if($type == NULL || trim($type) == "")
+		{
+			$type = -1;
+		}
+		
+		if(strpos($type, ' ') !== false)
+		{
+			$str = explode(' ', $type);
+			if(in_array($str[1], array("result", 'resultset', "recordset", "statement")))
+			{
+				$type = "__RECORDSET__";
+				$subtype = $str[0];
+			}
+		}
+		return array($type, $subtype);
+	} 
+	
+	function getClassName(&$d)
+	{
+		$classname = get_class($d);
+		if(strtolower($classname) == 'stdclass' && !isset($d->_explicitType) )
+		{
+			return "";
+		}
+		
+		if(isset($d->_explicitType))
+		{
+			$type = $d->_explicitType;
+			unset($d->_explicitType);
+			return $type;
+		}
+		
+		if(isset($GLOBALS['amfphp']['outgoingClassMappings'][strtolower($classname)]))
+		{
+			return $GLOBALS['amfphp']['outgoingClassMappings'][strtolower($classname)];
+		}
+		
+		if(class_exists("ReflectionClass")) //Another way of doing things, by Renaun Erickson
+		{
+		    $reflectionClass = new ReflectionClass( $classname );
+		    $fileName = $reflectionClass->getFileName();
+		   
+		    $basePath = $GLOBALS['amfphp']['customMappingsPath'];
+		    if( $basePath == "" )
+		        $basePath = getcwd();
+		
+		    // Handle OS filesystem differences
+		    if( DIRECTORY_SEPARATOR == "\\" && ( strpos( $basePath, DIRECTORY_SEPARATOR ) === false ) )
+		        $basePath = str_replace( "/", DIRECTORY_SEPARATOR, $basePath );
+		    
+		    if(strpos($fileName, $basePath) === FALSE)
+		    {
+		    	return $classname;
+		    }
+		    $fullClassName = substr( $fileName, strpos( $fileName, $basePath ) );
+		    $fullClassName = substr( $fullClassName, strlen( $basePath ) );
+		    $fullClassName = substr( $fullClassName, 0, strlen( $fullClassName ) - 4 );
+		    $fullClassName = str_replace( DIRECTORY_SEPARATOR, '.', $fullClassName );
+		
+		    return $fullClassName;
+		}
+		return $classname;
+	}
+}
+?>
\ No newline at end of file
diff --git a/docroot/amfphp/core/amf/io/AMFDeserializer.php b/docroot/amfphp/core/amf/io/AMFDeserializer.php
new file mode 100755
index 0000000..2acaa0c
--- /dev/null
+++ b/docroot/amfphp/core/amf/io/AMFDeserializer.php
@@ -0,0 +1,644 @@
+amf0storedObjects[] = & $ret;
+		$key = $this->readUTF(); // grab the key
+		for ($type = $this->readByte(); $type != 9; $type = $this->readByte()) {
+			$val = $this->readData($type); // grab the value
+			$ret[$key] = $val; // save the name/value pair in the array
+			$key = $this->readUTF(); // get the next name
+		}
+		return $ret; // return the array
+	} 
+	
+	/**
+	 * readMixedObject reads the name/value properties of the amf message and converts
+	 * numeric looking keys to numeric keys
+	 * 
+	 * @return array The php array with the object data
+	 */
+	function readMixedObject() {
+		$ret = array(); // init the array
+		$this->amf0storedObjects[] = & $ret;
+		$key = $this->readUTF(); // grab the key
+		for ($type = $this->readByte(); $type != 9; $type = $this->readByte()) {
+			$val = $this->readData($type); // grab the value
+			if(is_numeric($key))
+			{
+				$key = (float) $key;
+			}
+			$ret[$key] = $val; // save the name/value pair in the array
+			$key = $this->readUTF(); // get the next name
+		}
+		return $ret; // return the array
+	} 
+
+	/**
+	 * readArray turns an all numeric keyed actionscript array into a php array.
+	 * 
+	 * @return array The php array
+	 */
+	function readArray() {
+		$ret = array(); // init the array object
+		$this->amf0storedObjects[] = & $ret;
+		$length = $this->readLong(); // get the length  of the array
+		for ($i = 0; $i < $length; $i++) { // loop over all of the elements in the data
+			$type = $this->readByte();  // grab the type for each element
+			$ret[] = $this->readData($type); // grab each element
+		} 
+		return $ret; // return the data
+		
+	} 
+
+	/**
+	 * readMixedArray turns an array with numeric and string indexes into a php array
+	 * 
+	 * @return array The php array with mixed indexes
+	 */
+	function readMixedArray() {
+		//$length   = $this->readLong(); // get the length  property set by flash
+		$this->current_byte += 4;
+		return $this->readMixedObject(); // return the body of mixed array
+	} 
+
+	/**
+	 * readCustomClass reads the amf content associated with a class instance which was registered
+	 * with Object.registerClass.  In order to preserve the class name an additional property is assigned
+	 * to the object "_explicitType".  This property will be overwritten if it existed within the class already.
+	 * 
+	 * @return object The php representation of the object
+	 */
+	function readCustomClass() {
+		$typeIdentifier = str_replace('..', '', $this->readUTF());
+		$obj = $this->mapClass($typeIdentifier);
+		$isObject = true;
+		if($obj == NULL)
+		{
+			$obj = array();
+			$isObject = false;
+		}
+		$this->amf0storedObjects[] = & $obj;
+		$key = $this->readUTF(); // grab the key
+		for ($type = $this->readByte(); $type != 9; $type = $this->readByte()) {
+			$val = $this->readData($type); // grab the value
+			if($isObject)
+			{
+				$obj->$key = $val; // save the name/value pair in the array
+			}
+			else
+			{
+				$obj[$key] = $val; // save the name/value pair in the array
+			}
+			$key = $this->readUTF(); // get the next name
+		}
+		if(!$isObject)
+		{
+			$obj['_explicitType'] = $typeIdentifier;
+		}
+		return $obj; // return the array
+	} 
+
+	/**
+	 * readDate reads a date from the amf message and returns the time in ms.
+	 * This method is still under development.
+	 * 
+	 * @return long The date in ms.
+	 */
+	function readDate() {
+		$ms = $this->readDouble();  // date in milliseconds from 01/01/1970
+		$int = $this->readInt(); // nasty way to get timezone
+		if ($int > 720) {
+			$int = - (65536 - $int);
+		} 
+		$int *= -60;
+		//$int *= 1000;
+		//$min = $int % 60;
+		//$timezone = "GMT " . - $hr . ":" . abs($min);
+		// end nastiness
+		
+		//We store the last timezone found in date fields in the request
+		//FOr most purposes, it's expected that the timezones
+		//don't change from one date object to the other (they change per client though)
+		DateWrapper::setTimezone($int);
+		return $ms; 
+	}
+
+	/**
+	 * readReference replaces the old readFlushedSO. It treats where there
+	 * are references to other objects. Currently it does not resolve the
+	 * object as this would involve a serious amount of overhead, unless
+	 * you have a genius idea
+	 * 
+	 * @return String 
+	 */
+	function readReference() {
+		$reference = $this->readInt();
+		return $this->amf0storedObjects[$reference];
+	} 
+	
+	function readAny()
+	{
+	     if($this->native)
+	         return amfphp_decode($this->raw_data, $this->decodeFlags, $this->current_byte, array(& $this, "decodeCallback"));
+	     else
+	     {
+	 		$type = $this->readByte();  // grab the type of the element
+	 		return $this->readData($type); // turn the element into real data
+	     }
+	}
+
+	/**
+	 * readData is the main switch for mapping a type code to an actual
+	 * implementation for deciphering it.
+	 * 
+	 * @param mixed $type The $type integer
+	 * @return mixed The php version of the data in the message block
+	 */
+	function readData($type) {
+		switch ($type) {
+			case 0: // number
+				$data = $this->readDouble();
+				break;
+			case 1: // boolean
+				$data = $this->readByte() == 1;
+				break;
+			case 2: // string
+				$data = $this->readUTF();
+				break;
+			case 3: // object Object
+				$data = $this->readObject();
+				break;
+			case 5: // null
+				$data = null;
+				break;
+			case 6: // undefined
+				$data = null;
+				break;
+			case 7: // Circular references are returned here
+				$data = $this->readReference();
+				break;
+			case 8: // mixed array with numeric and string keys
+				$data = $this->readMixedArray();
+				break;
+			case 10: // array
+				$data = $this->readArray();
+				break;
+			case 11: // date
+				$data = $this->readDate();
+				break;
+			case 12: // string, strlen(string) > 2^16
+				$data = $this->readLongUTF();
+				break;
+			case 13: // mainly internal AS objects
+				$data = null;
+				break;
+			case 15: // XML
+				$data = $this->readLongUTF();
+				break;
+			case 16: // Custom Class
+				$data = $this->readCustomClass();
+				break;
+			case 17: //AMF3-specific
+				$GLOBALS['amfphp']['encoding'] = "amf3";
+				$data = $this->readAmf3Data();
+				break;
+			default: // unknown case
+				trigger_error("Found unhandled type with code: $type");
+				exit();
+				break;
+		} 
+		return $data;
+	} 
+	
+	/********************************************************************************
+	 *                       This is the AMF3 specific stuff
+	 ********************************************************************************/
+	function readAmf3Data()
+	{
+		$type = $this->readByte();
+		switch($type)
+		{
+			case 0x00 : return null; //undefined
+			case 0x01 : return null; //null
+			case 0x02 : return false; //boolean false
+			case 0x03 : return true;  //boolean true
+			case 0x04 : return $this->readAmf3Int();
+			case 0x05 : return $this->readDouble();
+			case 0x06 : return $this->readAmf3String();
+			case 0x07 : return $this->readAmf3XmlString();
+			case 0x08 : return $this->readAmf3Date();
+			case 0x09 : return $this->readAmf3Array();
+			case 0x0A : return $this->readAmf3Object();
+			case 0x0B : return $this->readAmf3XmlString();
+			case 0x0C : return $this->readAmf3ByteArray();
+			default: trigger_error("undefined Amf3 type encountered: " . $type, E_USER_ERROR);
+		}
+	}
+	
+	/// 
+	/// Handle decoding of the variable-length representation
+	/// which gives seven bits of value per serialized byte by using the high-order bit 
+	/// of each byte as a continuation flag.
+	///  
+	/// 
+ * @author      Brett Stimmerman 
+ * @copyright   2005 Michal Migurski
+ * @license     http://www.opensource.org/licenses/bsd-license.php
+ * @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198
+ *
+ * Note: this is a stripped version of JSON.php to remove pear dependencies and
+ * encoding capability
+ */
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_SLICE',   1);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_STR',  2);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_ARR',  3);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_OBJ',  4);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_CMT', 5);
+
+/**
+ * Behavior switch for Services_JSON::decode()
+ */
+define('SERVICES_JSON_LOOSE_TYPE', 16);
+
+/**
+ * Behavior switch for Services_JSON::decode()
+ */
+define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
+
+class Services_JSON
+{
+	function Services_JSON($use = 0)
+	{
+		$this->use = $use;
+	}
+
+	function utf162utf8($utf16)
+	{
+		// oh please oh please oh please oh please oh please
+		if(function_exists('mb_convert_encoding'))
+			return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
+		
+		$bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
+
+		switch(true) {
+			case ((0x7F & $bytes) == $bytes):
+				// this case should never be reached, because we are in ASCII range
+				// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+				return chr(0x7F & $bytes);
+
+			case (0x07FF & $bytes) == $bytes:
+				// return a 2-byte UTF-8 character
+				// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+				return chr(0xC0 | (($bytes >> 6) & 0x1F))
+					 . chr(0x80 | ($bytes & 0x3F));
+
+			case (0xFFFF & $bytes) == $bytes:
+				// return a 3-byte UTF-8 character
+				// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+				return chr(0xE0 | (($bytes >> 12) & 0x0F))
+					 . chr(0x80 | (($bytes >> 6) & 0x3F))
+					 . chr(0x80 | ($bytes & 0x3F));
+		}
+
+		// ignoring UTF-32 for now, sorry
+		return '';
+	}        
+
+	function utf82utf16($utf8)
+	{
+		// oh please oh please oh please oh please oh please
+		if(function_exists('mb_convert_encoding'))
+			return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
+		
+		switch(strlen($utf8)) {
+			case 1:
+				// this case should never be reached, because we are in ASCII range
+				// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+				return $ut8;
+
+			case 2:
+				// return a UTF-16 character from a 2-byte UTF-8 char
+				// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+				return chr(0x07 & (ord($utf8{0}) >> 2))
+					 . chr((0xC0 & (ord($utf8{0}) << 6))
+						 | (0x3F & ord($utf8{1})));
+				
+			case 3:
+				// return a UTF-16 character from a 3-byte UTF-8 char
+				// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+				return chr((0xF0 & (ord($utf8{0}) << 4))
+						 | (0x0F & (ord($utf8{1}) >> 2)))
+					 . chr((0xC0 & (ord($utf8{1}) << 6))
+						 | (0x7F & ord($utf8{2})));
+		}
+
+		// ignoring UTF-32 for now, sorry
+		return '';
+	}        
+	
+	function name_value($name, $value)
+	{
+		$encoded_value = $this->encode($value);
+	
+		return $this->encode(strval($name)) . ':' . $encoded_value;
+	}        
+
+	function reduce_string($str)
+	{
+		$str = preg_replace(array(
+		
+				// eliminate single line comments in '// ...' form
+				'#^\s*//(.+)$#m',
+	
+				// eliminate multi-line comments in '/* ... */' form, at start of string
+				'#^\s*/\*(.+)\*/#Us',
+	
+				// eliminate multi-line comments in '/* ... */' form, at end of string
+				'#/\*(.+)\*/\s*$#Us'
+	
+			), '', $str);
+		
+		// eliminate extraneous space
+		return trim($str);
+	}
+	
+   /**
+    * encodes an arbitrary variable into JSON format
+    *
+    * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
+    *                           see argument 1 to Services_JSON() above for array-parsing behavior.
+    *                           if var is a strng, note that encode() always expects it
+    *                           to be in ASCII or UTF-8 format!
+    *
+    * @return   mixed   JSON string representation of input var or an error if a problem occurs
+    * @access   public
+    */
+    function encode($var)
+    {
+        switch (gettype($var)) {
+            case 'boolean':
+                return $var ? 'true' : 'false';
+
+            case 'NULL':
+                return 'null';
+
+            case 'integer':
+                return (int) $var;
+
+            case 'double':
+            case 'float':
+                return (float) $var;
+
+            case 'string':
+                // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
+                $ascii = '';
+                $strlen_var = strlen($var);
+
+               /*
+                * Iterate over every character in the string,
+                * escaping with a slash or encoding to UTF-8 where necessary
+                */
+                for ($c = 0; $c < $strlen_var; ++$c) {
+
+                    $ord_var_c = ord($var{$c});
+
+                    switch (true) {
+                        case $ord_var_c == 0x08:
+                            $ascii .= '\b';
+                            break;
+                        case $ord_var_c == 0x09:
+                            $ascii .= '\t';
+                            break;
+                        case $ord_var_c == 0x0A:
+                            $ascii .= '\n';
+                            break;
+                        case $ord_var_c == 0x0C:
+                            $ascii .= '\f';
+                            break;
+                        case $ord_var_c == 0x0D:
+                            $ascii .= '\r';
+                            break;
+
+                        case $ord_var_c == 0x22:
+                        case $ord_var_c == 0x2F:
+                        case $ord_var_c == 0x5C:
+                            // double quote, slash, slosh
+                            $ascii .= '\\'.$var{$c};
+                            break;
+
+                        case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
+                            // characters U-00000000 - U-0000007F (same as ASCII)
+                            $ascii .= $var{$c};
+                            break;
+
+                        case (($ord_var_c & 0xE0) == 0xC0):
+                            // characters U-00000080 - U-000007FF, mask 110XXXXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
+                            $c += 1;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+
+                        case (($ord_var_c & 0xF0) == 0xE0):
+                            // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}));
+                            $c += 2;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+
+                        case (($ord_var_c & 0xF8) == 0xF0):
+                            // characters U-00010000 - U-001FFFFF, mask 11110XXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}),
+                                         ord($var{$c + 3}));
+                            $c += 3;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+
+                        case (($ord_var_c & 0xFC) == 0xF8):
+                            // characters U-00200000 - U-03FFFFFF, mask 111110XX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}),
+                                         ord($var{$c + 3}),
+                                         ord($var{$c + 4}));
+                            $c += 4;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+
+                        case (($ord_var_c & 0xFE) == 0xFC):
+                            // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}),
+                                         ord($var{$c + 3}),
+                                         ord($var{$c + 4}),
+                                         ord($var{$c + 5}));
+                            $c += 5;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+                    }
+                }
+
+                return '"'.$ascii.'"';
+
+            case 'array':
+               /*
+                * As per JSON spec if any array key is not an integer
+                * we must treat the the whole array as an object. We
+                * also try to catch a sparsely populated associative
+                * array with numeric keys here because some JS engines
+                * will create an array with empty indexes up to
+                * max_index which can cause memory issues and because
+                * the keys, which may be relevant, will be remapped
+                * otherwise.
+                *
+                * As per the ECMA and JSON specification an object may
+                * have any string as a property. Unfortunately due to
+                * a hole in the ECMA specification if the key is a
+                * ECMA reserved word or starts with a digit the
+                * parameter is only accessible using ECMAScript's
+                * bracket notation.
+                */
+
+                // treat as a JSON object
+                if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
+                    $properties = array_map(array($this, 'name_value'),
+                                            array_keys($var),
+                                            array_values($var));
+
+                    return '{' . join(',', $properties) . '}';
+                }
+
+                // treat it like a regular array
+                $elements = array_map(array($this, 'encode'), $var);
+
+                return '[' . join(',', $elements) . ']';
+
+            case 'object':
+                $vars = get_object_vars($var);
+
+                $properties = array_map(array($this, 'name_value'),
+                                        array_keys($vars),
+                                        array_values($vars));
+
+                return '{' . join(',', $properties) . '}';
+            case 'resource':
+				return null;
+            default:
+                return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
+                    ? 'null'
+                    : trigger_error(gettype($var)." can not be encoded as JSON string", E_USER_ERROR);
+        }
+    }
+    
+	function sanitizeType($type)
+	{
+		$subtype = -1;
+		$type = strtolower($type);
+		if($type == NULL || trim($type) == "")
+		{
+			$type = -1;
+		}
+		
+		if(strpos($type, ' ') !== false)
+		{
+			$str = explode(' ', $type);
+			if(in_array($str[1], array("result", 'resultset', "recordset", "statement")))
+			{
+				$type = "__RECORDSET__";
+				$subtype = $str[0];
+			}
+		}
+		return array($type, $subtype);
+	} 
+
+	function decode($str)
+	{
+		$str = $this->reduce_string($str);
+	
+		switch (strtolower($str)) {
+			case 'true':
+				return true;
+
+			case 'false':
+				return false;
+			
+			case 'null':
+				return null;
+			
+			default:
+				if (is_numeric($str)) {
+					// Lookie-loo, it's a number
+
+					// Return float or int, as appropriate
+					return ((float)$str == (integer)$str)
+						? (integer)$str
+						: (float)$str;
+					
+				} 
+				elseif (preg_match('/^("|\').*(\1)$/s', $str,   $m) && $m[1] == $m[2]) {
+					// STRINGS RETURNED IN UTF-8 FORMAT
+					$delim = substr($str, 0, 1);
+					$chrs = substr($str, 1, -1);
+					$utf8 = '';
+					$strlen_chrs = strlen($chrs);
+					
+					for ($c = 0; $c < $strlen_chrs; ++$c) {
+					
+						$substr_chrs_c_2 = substr($chrs, $c, 2);
+						$ord_chrs_c = ord($chrs{$c});
+						
+						switch (true) {
+							case $substr_chrs_c_2 == '\b':
+								$utf8 .= chr(0x08);
+								++$c;
+								break;
+							case $substr_chrs_c_2 == '\t':
+								$utf8 .= chr(0x09);
+								++$c;
+								break;
+							case $substr_chrs_c_2 == '\n':
+								$utf8 .= chr(0x0A);
+								++$c;
+								break;
+							case $substr_chrs_c_2 == '\f':
+								$utf8 .= chr(0x0C);
+								++$c;
+								break;
+							case $substr_chrs_c_2 == '\r':
+								$utf8 .= chr(0x0D);
+								++$c;
+								break;
+
+							case $substr_chrs_c_2 == '\\"':
+							case $substr_chrs_c_2 == '\\\'':
+							case $substr_chrs_c_2 == '\\\\':
+							case $substr_chrs_c_2 == '\\/':
+								if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
+								   ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
+									$utf8 .= $chrs{++$c};
+								}
+								break;
+								
+							case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
+								// single, escaped unicode character
+								$utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
+									   . chr(hexdec(substr($chrs, ($c + 4), 2)));
+								$utf8 .= $this->utf162utf8($utf16);
+								$c += 5;
+								break;
+		
+							case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
+								$utf8 .= $chrs{$c};
+								break;
+		
+							case ($ord_chrs_c & 0xE0) == 0xC0:
+								// characters U-00000080 - U-000007FF, mask 110XXXXX
+								//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+								$utf8 .= substr($chrs, $c, 2);
+								++$c;
+								break;
+	
+							case ($ord_chrs_c & 0xF0) == 0xE0:
+								// characters U-00000800 - U-0000FFFF, mask 1110XXXX
+								// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+								$utf8 .= substr($chrs, $c, 3);
+								$c += 2;
+								break;
+	
+							case ($ord_chrs_c & 0xF8) == 0xF0:
+								// characters U-00010000 - U-001FFFFF, mask 11110XXX
+								// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+								$utf8 .= substr($chrs, $c, 4);
+								$c += 3;
+								break;
+	
+							case ($ord_chrs_c & 0xFC) == 0xF8:
+								// characters U-00200000 - U-03FFFFFF, mask 111110XX
+								// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+								$utf8 .= substr($chrs, $c, 5);
+								$c += 4;
+								break;
+	
+							case ($ord_chrs_c & 0xFE) == 0xFC:
+								// characters U-04000000 - U-7FFFFFFF, mask 1111110X
+								// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+								$utf8 .= substr($chrs, $c, 6);
+								$c += 5;
+								break;
+
+						}
+
+					}
+					
+					return $utf8;
+				
+				} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
+					// array, or object notation
+
+					if ($str{0} == '[') {
+						$stk = array(SERVICES_JSON_IN_ARR);
+						$arr = array();
+					} else {
+						if ($this->use & SERVICES_JSON_LOOSE_TYPE ) {
+							$stk = array(SERVICES_JSON_IN_OBJ);
+							$obj = array();
+						} else {
+							$stk = array(SERVICES_JSON_IN_OBJ);
+							$obj = new stdClass();
+						}
+					}
+					
+					array_push($stk, array('what'  => SERVICES_JSON_SLICE,
+										   'where' => 0,
+										   'delim' => false));
+
+					$chrs = substr($str, 1, -1);
+					$chrs = $this->reduce_string($chrs);
+					
+					if ($chrs == '') {
+						if (reset($stk) == SERVICES_JSON_IN_ARR) {
+							return $arr;
+
+						} else {
+							return $obj;
+
+						}
+					}
+
+					//print("\nparsing {$chrs}\n");
+					
+					$strlen_chrs = strlen($chrs);
+					
+					for ($c = 0; $c <= $strlen_chrs; ++$c) {
+					
+						$top = end($stk);
+						$substr_chrs_c_2 = substr($chrs, $c, 2);
+					
+						if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
+							// found a comma that is not inside a string, array, etc.,
+							// OR we've reached the end of the character list
+							$slice = substr($chrs, $top['where'], ($c - $top['where']));
+							array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
+							//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+							if (reset($stk) == SERVICES_JSON_IN_ARR) {
+								// we are in an array, so just push an element onto the stack
+								array_push($arr, $this->decode($slice));
+
+							} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
+								// we are in an object, so figure
+								// out the property name and set an
+								// element in an associative array,
+								// for now
+								if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+									// "name":value pair
+									$key = $this->decode($parts[1]);
+									$val = $this->decode($parts[2]);
+
+									if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+										$obj[$key] = $val;
+									} else {
+										$obj->$key = $val;
+									}
+								} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+									// name:value pair, where name is unquoted
+									$key = $parts[1];
+									$val = $this->decode($parts[2]);
+
+									if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+										$obj[$key] = $val;
+									} else {
+										$obj->$key = $val;
+									}
+								}
+
+							}
+
+						} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
+							// found a quote, and we are not inside a string
+							array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
+							//print("Found start of string at {$c}\n");
+
+						} elseif (($chrs{$c} == $top['delim']) &&
+								 ($top['what'] == SERVICES_JSON_IN_STR) &&
+								 (($chrs{$c - 1} != '\\') ||
+								 ($chrs{$c - 1} == '\\' && $chrs{$c - 2} == '\\'))) {
+							// found a quote, we're in a string, and it's not escaped
+							array_pop($stk);
+							//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
+
+						} elseif (($chrs{$c} == '[') &&
+								 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+							// found a left-bracket, and we are in an array, object, or slice
+							array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
+							//print("Found start of array at {$c}\n");
+
+						} elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
+							// found a right-bracket, and we're in an array
+							array_pop($stk);
+							//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+						} elseif (($chrs{$c} == '{') &&
+								 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+							// found a left-brace, and we are in an array, object, or slice
+							array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
+							//print("Found start of object at {$c}\n");
+
+						} elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
+							// found a right-brace, and we're in an object
+							array_pop($stk);
+							//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+						} elseif (($substr_chrs_c_2 == '/*') &&
+								 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+							// found a comment start, and we are in an array, object, or slice
+							array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
+							$c++;
+							//print("Found start of comment at {$c}\n");
+
+						} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
+							// found a comment end, and we're in one now
+							array_pop($stk);
+							$c++;
+							
+							for ($i = $top['where']; $i <= $c; ++$i)
+								$chrs = substr_replace($chrs, ' ', $i, 1);
+							
+							//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+						}
+					
+					}
+					
+
+					
+					if (reset($stk) == SERVICES_JSON_IN_ARR) {
+						return $arr;
+
+					} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
+						return $obj;
+
+					}
+				
+				}
+		}
+	}
+}
+?>
\ No newline at end of file
diff --git a/docroot/amfphp/core/shared/util/MessageBody.php b/docroot/amfphp/core/shared/util/MessageBody.php
new file mode 100755
index 0000000..90edc59
--- /dev/null
+++ b/docroot/amfphp/core/shared/util/MessageBody.php
@@ -0,0 +1,143 @@
+responseIndex = $responseIndex;
+		$this->targetURI = $targetURI;
+		$this->responseURI = $this->responseIndex . "/onStatus"; // default to the onstatus method
+		$this->setValue($value);
+	}
+	
+	/**
+	 * setter for the results from the process execution
+	 * 
+	 * @param mixed $results The returned results from the process execution
+	 */
+	function setResults ($result) {
+		$this->_results = $result;
+	} 
+
+	/**
+	 * getter for the result of the process execution
+	 * 
+	 * @return mixed The results
+	 */
+	function &getResults () {
+		return $this->_results;
+	} 
+
+	/**
+	 * setter for the class construct
+	 * 
+	 * @param object $classConstruct The instance of the service class
+	 */
+	function setClassConstruct (&$classConstruct) {
+		$this->_classConstruct = &$classConstruct;
+	} 
+
+	/**
+	 * getter for the class construct
+	 * 
+	 * @return object The class instance
+	 */
+	function &getClassConstruct () {
+		return $this->_classConstruct;
+	} 
+	
+	/**
+	 * setter for the value property
+	 * 
+	 * @param mixed $value The value of the body object
+	 */
+	function setValue ($value) {
+		$this->_value = $value;
+	} 
+
+	/**
+	 * getter for the value property
+	 * 
+	 * @return mixed The value property
+	 */
+	function &getValue () {
+		return $this->_value;
+	} 
+	
+	/**
+	 * Set special handling type for this body
+	 */
+	function setSpecialHandling($type)
+	{
+		$this->_specialHandling = $type;
+	}
+	
+	/**
+	 * Get special handling type for this body
+	 */
+	function getSpecialHandling()
+	{
+		return $this->_specialHandling;
+	}
+
+	/**
+	 * Check if this body is handled special against an array of special cases
+	 */
+	function isSpecialHandling($against = NULL)
+	{
+		if($against !== NULL)
+		{
+			return in_array($this->_specialHandling, $against);
+		}
+		else
+		{
+			return ($this->_specialHandling != NULL);
+		}
+	}
+	
+	function setMetaData($key, $val)
+	{
+		$this->_metaData[$key] = $val;
+	}
+	
+	function getMetaData($key)
+	{
+		if(isset($this->_metaData[$key]))
+		{
+			return $this->_metaData[$key];
+		}
+		else
+		{
+			return NULL;
+		}
+	}
+} 
+
+?>
diff --git a/docroot/amfphp/core/shared/util/MessageHeader.php b/docroot/amfphp/core/shared/util/MessageHeader.php
new file mode 100755
index 0000000..43bcee3
--- /dev/null
+++ b/docroot/amfphp/core/shared/util/MessageHeader.php
@@ -0,0 +1,49 @@
+name = $name;
+		$this->required = $required;
+		$this->value = $value;
+	} 
+} 
+
+?>
\ No newline at end of file
diff --git a/docroot/amfphp/core/shared/util/MethodTable.php b/docroot/amfphp/core/shared/util/MethodTable.php
new file mode 100755
index 0000000..a52dc02
--- /dev/null
+++ b/docroot/amfphp/core/shared/util/MethodTable.php
@@ -0,0 +1,552 @@
+methodTable = MethodTable::create($this);
+ * @author Christophe Herreman
+ * @since 05/01/2005
+ * @version $id$
+ * 
+ * Special contributions by Allessandro Crugnola and Ted Milker
+ */
+
+if (!defined('T_ML_COMMENT')) {
+   define('T_ML_COMMENT', T_COMMENT);
+} else {
+   define('T_DOC_COMMENT', T_ML_COMMENT);
+}
+
+function strrstr($haystack, $needle)
+{
+	return substr($haystack, 0, strpos($haystack.$needle,$needle));
+}
+
+function strstrafter($haystack, $needle)
+{
+	return substr(strstr($haystack, $needle), strlen($needle));
+}
+
+class MethodTable
+{
+	/**
+	 * Constructor.
+	 *
+	 * Since this class should only be accessed through the static create() method
+	 * this constructor should be made private. Unfortunately, this is not possible
+	 * in PHP4.
+	 *
+	 * @access private
+	 */
+	function MethodTable(){
+	}
+
+
+	/**
+	 * Creates the methodTable for a passed class.
+	 *
+	 * @static
+	 * @access public
+	 * @param $className(String) The name of the service class.
+	 *        May also simply be __FILE__
+	 * @param $servicePath(String) The location of the classes (optional)
+	 */
+	function create($className, $servicePath = NULL, &$classComment){
+		
+		$methodTable = array();
+		if(file_exists($className))
+		{
+			//The new __FILE__ way of doing things was used
+			$sourcePath = $className;
+			$className = str_replace("\\", '/', $className);
+			$className = substr($className, strrpos($className, '/') + 1);
+			$className = str_replace('.php', '', $className);
+		}
+		else
+		{
+			$className = str_replace('.php', '', $className);
+			$fullPath = str_replace('.', '/', $className);
+			$className = $fullPath;
+			if(strpos($fullPath, '/') !== FALSE)
+			{
+				$className = substr(strrchr($fullPath, '/'), 1);
+			}
+			
+			if($servicePath == NULL)
+			{
+				if(isset($GLOBALS['amfphp']['classPath']))
+				{
+					$servicePath = $GLOBALS['amfphp']['classPath'];
+				}
+				else
+				{
+					$servicePath = "../services/";
+				}
+			}
+			$sourcePath = $servicePath . $fullPath . ".php";
+		}
+		
+		if(!file_exists($sourcePath))
+		{
+			trigger_error("The MethodTable class could not find {" . 
+				$sourcePath . "}", 
+				E_USER_ERROR);
+		}
+		
+		if(class_exists('ReflectionClass'))
+		{
+			//PHP5
+			$classMethods = MethodTable::getClassMethodsReflection($sourcePath, $className, $classComment);
+		}
+		else
+		{
+			//PHP4
+			
+			$classMethods = MethodTable::getClassMethodsTokenizer($sourcePath, $className, $classComment);
+		}
+		
+		foreach ($classMethods as $key => $value) {
+			if($value['name'][0] == '_' || $value['name'] == 'beforeFilter')
+			{
+				continue;
+			}
+			$methodSignature = $value['args'];
+			$methodName = $value['name'];
+			$methodComment = $value['comment'];
+			
+			$description = MethodTable::getMethodDescription($methodComment) . " " . MethodTable::getMethodCommentAttribute($methodComment, "desc");
+			$description = trim($description);
+			$access = MethodTable::getMethodCommentAttributeFirstWord($methodComment, "access");
+			$roles = MethodTable::getMethodCommentAttributeFirstWord($methodComment, "roles");
+			$instance = MethodTable::getMethodCommentAttributeFirstWord($methodComment, "instance");
+			$returns = MethodTable::getMethodCommentAttributeFirstLine($methodComment, "returns");
+			$pagesize = MethodTable::getMethodCommentAttributeFirstWord($methodComment, "pagesize");
+			$params = MethodTable::getMethodCommentArguments($methodComment);
+						
+			//description, arguments, access, [roles, [instance, [returns, [pagesize]]]]
+			$methodTable[$methodName] = array();
+			//$methodTable[$methodName]["signature"] = $methodSignature; //debug purposes
+			$methodTable[$methodName]["description"] = ($description == "") ? "No description given." : $description;
+			$methodTable[$methodName]["arguments"] = MethodTable::getMethodArguments($methodSignature, $params);
+			$methodTable[$methodName]["access"] = ($access == "") ? "private" : $access;
+			
+			if($roles != "") $methodTable[$methodName]["roles"] = $roles;
+			if($instance != "") $methodTable[$methodName]["instance"] = $instance;
+			if($returns != "") $methodTable[$methodName]["returns"] = $returns;
+			if($pagesize != "") $methodTable[$methodName]["pagesize"] = $pagesize;
+		}
+		
+		$classComment = trim(str_replace("\r\n", "\n", MethodTable::getMethodDescription($classComment)));
+		
+		return $methodTable;
+	}
+	
+	function getClassMethodsReflection($sourcePath, $className, & $classComment)
+	{
+		//Include the class in question
+		$dir = dirname($sourcePath);
+		if(!is_dir($dir))
+		{
+			return array();
+		}
+		
+		chdir($dir);
+		
+		if(!file_exists($sourcePath))
+		{
+			return array();
+		}
+		
+		//HACK: eAccelerator
+		//Check if eAccelator is installed
+		if( extension_loaded( "eAccelerator" ))
+		{
+			//Touch the file so the results of getDocComment will be accurate
+			touch($sourcePath);
+		}
+		
+		$included = include_once($sourcePath);
+		if($included === FALSE)
+		{
+			return array();
+		}
+		
+		//Verify that the class exists
+		if(!class_exists($className))
+		{
+			return array();
+		}
+		
+		$methodTable = array();
+		
+		$class = new ReflectionClass($className);
+		
+		$classComment = $class->getDocComment();
+		$methods = $class->getMethods();
+		
+		
+		foreach($methods as $reflectionMethod){
+			
+			if($reflectionMethod->isPublic() && $method->name[0] != '_' && $method->name != 'beforeFilter')
+			{
+				if($reflectionMethod->isConstructor())
+				{
+					$classComment .= $reflectionMethod->getDocComment();
+				}
+				else
+				{
+					$reflectionParameter = $reflectionMethod->getParameters();
+					
+					$methodTableEntry = array();			
+					$parameters = array();
+					
+					foreach($reflectionParameter as $parameter){
+						$parameters[] = $parameter->getName();
+					}
+					
+					$methodTableEntry['args'] = '(' . implode(', ', $parameters);
+					$methodTableEntry['name'] = $reflectionMethod->name;
+					$methodTableEntry['comment'] = $reflectionMethod->getDocComment();
+					
+					$methodTable[] = $methodTableEntry;
+				}
+			}
+		}
+		
+		return $methodTable;
+	}
+	
+	function getClassMethodsTokenizer($sourcePath, $className, & $classComment)
+	{
+		$source = file_get_contents($sourcePath);
+		$tokens = token_get_all($source);
+		
+		$waitingForOpenParenthesis = false;
+		$waitingForFunction = false;
+		$waitingForClassName = false;
+		$bufferingArgs = false;
+		$argBuffer = "";
+		$lastFunction = "";
+		$lastFunctionComment = "";
+		$lastComment = "";
+		$classMethods = array();
+		$realClassName = "";
+
+		$openBraces = -10000;
+
+		$waitingForEndEncapsedString = false;
+		foreach($tokens as $token)
+		{
+		   if (is_string($token)) {
+				if($token == '{')
+				{
+					$openBraces++;
+				}
+				if($token == '}')
+				{
+					if($waitingForEndEncapsedString)
+					{
+						$waitingForEndEncapsedString = false;
+					}
+					else
+					{
+						$lastComment = '';
+						$openBraces--;
+						
+						if($openBraces == 0)
+						{
+							//break;
+						}
+					}
+				}
+				elseif($waitingForOpenParenthesis && $token == '(')
+				{
+					$bufferingArgs = true;
+					$argBuffer = "";
+					$waitingForOpenParenthesis = false;
+				}
+				elseif($bufferingArgs)
+				{
+					if($token != ')')
+					{
+						$argBuffer .= $token;
+					}
+					else
+					{
+						if($lastFunction != $realClassName && $lastFunction != "__construct")
+						{
+							$classMethods[] = array("name" => $lastFunction,
+											   "comment" => $lastFunctionComment,
+											   "args" => $argBuffer);
+						}
+						else
+						{
+							$classComment .= "\n\n" . $lastComment;
+						}
+						
+						$bufferingArgs = false;
+						$argBuffer = "";
+						$lastFunction = "";
+						$lastFunctionComment = "";
+					}
+					
+				}
+		   } else {
+			   // token array
+			   list($id, $text) = $token;
+				
+				if($bufferingArgs)
+				{
+					$argBuffer .= $text;                    
+				}
+			   switch ($id) 
+			   {
+					
+				   case T_COMMENT:
+				   case T_ML_COMMENT: // we've defined this
+				   case T_DOC_COMMENT: // and this
+				   // no action on comments
+						$lastComment = $text;
+						break;
+				   case T_FUNCTION:
+						if($openBraces >= 1)
+						{
+							$waitingForFunction = true;
+						}
+						break;
+					case T_STRING:
+						if($waitingForFunction)
+						{
+							$waitingForFunction = false;
+							$waitingForOpenParenthesis = true;
+							$lastFunction = $text;
+							$lastFunctionComment = $lastComment;
+							$lastComment = "";              
+						}
+						if($waitingForClassName)
+						{
+							$waitingForClassName = false;
+							if(strpos(strtolower($className), strtolower($text)) !== FALSE)
+							{
+								//Not the class we were looking for
+								$classComment = $lastComment;
+								$realClassName = $text;
+							}
+						}
+						break;
+					case T_CLASS:
+						$openBraces = 0;
+						$waitingForClassName = true;
+						break;
+					case T_CURLY_OPEN:
+					case T_DOLLAR_OPEN_CURLY_BRACES:
+						$waitingForEndEncapsedString = true;
+						break;
+				}
+			}
+		}
+		return $classMethods;
+	}
+	
+	/**
+	 * 
+	 */
+	function getMethodCommentArguments($comment)
+	{
+		$pieces = explode('@param', $comment);
+		$args = array();
+		if(is_array($pieces) && count($pieces) > 1)
+		{
+			for($i = 0; $i < count($pieces) - 1; $i++)
+			{
+				$ps = strrstr($pieces[$i + 1], '@');
+				$ps = strrstr($ps, '*/');
+				$args[] = MethodTable::cleanComment($ps);
+			}
+		}
+		return $args;
+	}
+	
+	
+	/**
+	 * Returns the description from the comment.
+	 * The description is(are) the first line(s) in the comment.
+	 *
+	 * @static
+	 * @private
+	 * @param $comment(String) The method's comment.
+	 */
+	function getMethodDescription($comment){
+		$comment = MethodTable::cleanComment(strrstr($comment, "@"));
+		return trim($comment);
+	}
+	
+	
+	/**
+	 * Returns the value of a comment attribute.
+	 *
+	 * @static
+	 * @private
+	 * @param $comment(String) The method's comment.
+	 * @param $attribute(String) The name of the attribute to get its value from.
+	 */
+	function getMethodCommentAttribute($comment, $attribute){
+		$pieces = strstrafter($comment, '@' . $attribute);
+		if($pieces !== FALSE)
+		{
+			$pieces = strrstr($pieces, '@');
+			$pieces = strrstr($pieces, '*/');
+			return MethodTable::cleanComment($pieces);
+		}
+		return "";
+	}
+	
+	/**
+	 * Returns the value of a comment attribute.
+	 *
+	 * @static
+	 * @private
+	 * @param $comment(String) The method's comment.
+	 * @param $attribute(String) The name of the attribute to get its value from.
+	 */
+	function getMethodCommentAttributeFirstLine($comment, $attribute){
+		$pieces = strstrafter($comment, '@' . $attribute);
+		if($pieces !== FALSE)
+		{
+			$pieces = strrstr($pieces, '@');
+			$pieces = strrstr($pieces, "*");
+			$pieces = strrstr($pieces, "/");
+			$pieces = strrstr($pieces, "-");
+			$pieces = strrstr($pieces, "\n");
+			$pieces = strrstr($pieces, "\r");
+			$pieces = strrstr($pieces, '*/');
+			return MethodTable::cleanComment($pieces);
+		}
+		return "";
+	}
+	
+	function getMethodCommentAttributeFirstWord($comment, $attribute){
+		$pieces = strstrafter($comment, '@' . $attribute);
+		if($pieces !== FALSE)
+		{
+			$val = MethodTable::cleanComment($pieces);
+			return trim(strrstr($val, ' '));
+		}
+		return "";
+	}
+	
+	/**
+	 * Returns an array with the arguments of a method.
+	 *
+	 * @static
+	 * @access private
+	 * @param $methodSignature (String)The method's signatureg;
+	 */
+	function getMethodArguments($methodSignature, $commentParams){
+		if(strlen($methodSignature) < 2){
+			//no arguments, return an empty array
+			$result = array();
+		}else{
+			//clean the arguments before returning them
+			$result = MethodTable::cleanArguments(explode(",", $methodSignature), $commentParams);
+		}
+		
+		return $result;
+	}
+	
+	
+	/**
+	 * Cleans the arguments array.
+	 * This method removes all whitespaces and the leading "$" sign from each argument
+	 * in the array.
+	 *
+	 * @static
+	 * @access private
+	 * @param $args(Array) The "dirty" array with arguments.
+	 */
+	function cleanArguments($args, $commentParams){
+		$result = array();
+		
+		foreach($args as $index => $arg){
+			$arg = strrstr(str_replace('(', '', $arg), '=');
+			if(!isset($commentParams[$index]))
+			{
+				$result[] = trim($arg);
+			}
+			else
+			{
+				$start = trim($arg);
+				$end = trim(str_replace('$', '', $commentParams[$index]));
+				//echo($start);
+				//echo($end);
+				if($end != "" && $start != "" && strpos(strtolower($end), strtolower($start)) === 0)
+				{
+					$end = substr($end, strlen($start));
+				}
+				$result[] = $start . ' - ' . trim($end);
+			}
+		}
+		
+		return $result;
+	}
+	
+	
+	/**
+	 * Cleans the comment string by removing all comment start and end characters.
+	 *
+	 * @static
+	 * @private
+	 * @param $comment(String) The method's comment.
+	 */
+	function cleanComment($comment){
+		$comment = str_replace("/**", "", $comment);
+		$comment = str_replace("*/", "", $comment);
+		$comment = str_replace("*", "", $comment);
+		$comment = str_replace("\r", "", trim($comment));
+		$comment = eregi_replace("\n[ \t]+", "\n", trim($comment));
+		$comment = str_replace("\n", "\\n", trim($comment));
+		$comment = eregi_replace("[\t ]+", " ", trim($comment));
+		
+		$comment = str_replace("\"", "\\\"", $comment);
+		return $comment;
+	}
+
+	/**
+	 *
+	 */
+	function showCode($methodTable){
+		
+
+		foreach($methodTable as $methodName=>$methodProps){
+			$result .= "\n\t\"" . $methodName . "\" => array(";
+			
+			foreach($methodProps as $key=>$value){
+				$result .= "\n\t\t\"" . $key . "\" => ";
+
+				if($key=="arguments"){
+					$result .= "array(";
+					for($i=0; $imethodTable = array(" . $result;
+		$result .= "\n);";
+			
+		return $result;
+	}
+}
+?>
\ No newline at end of file
diff --git a/docroot/amfphp/core/shared/util/NetDebug.php b/docroot/amfphp/core/shared/util/NetDebug.php
new file mode 100755
index 0000000..f03f43c
--- /dev/null
+++ b/docroot/amfphp/core/shared/util/NetDebug.php
@@ -0,0 +1,52 @@
+
\ No newline at end of file
diff --git a/docroot/amfphp/core/shared/util/functions.php b/docroot/amfphp/core/shared/util/functions.php
new file mode 100755
index 0000000..5fefdf8
--- /dev/null
+++ b/docroot/amfphp/core/shared/util/functions.php
@@ -0,0 +1,44 @@
+
\ No newline at end of file
diff --git a/docroot/amfphp/core/xmlrpc/app/Actions.php b/docroot/amfphp/core/xmlrpc/app/Actions.php
new file mode 100755
index 0000000..7bfecd0
--- /dev/null
+++ b/docroot/amfphp/core/xmlrpc/app/Actions.php
@@ -0,0 +1,104 @@
+getValue();
+	
+	//Get the method that is being called
+	$description = xmlrpc_parse_method_descriptions($data);
+	$target = $description['methodName'];
+	
+	$baseClassPath = $GLOBALS['amfphp']['classPath'];
+	
+	$lpos = strrpos($target, '.');
+	
+	$methodname = substr($target, $lpos + 1);
+	$trunced = substr($target, 0, $lpos);
+	$lpos = strrpos($trunced, ".");
+	if ($lpos === false) {
+		$classname = $trunced;
+		$uriclasspath = $trunced . ".php";
+		$classpath = $baseClassPath . $trunced . ".php";
+	} else {
+		$classname = substr($trunced, $lpos + 1);
+		$classpath = $baseClassPath . str_replace(".", "/", $trunced) . ".php"; // removed to strip the basecp out of the equation here
+		$uriclasspath = str_replace(".", "/", $trunced) . ".php"; // removed to strip the basecp out of the equation here
+	} 
+	
+	$body->methodName = $methodname;
+	$body->className = $classname;
+	$body->classPath = $classpath;
+	$body->uriClassPath = $uriclasspath;
+	$body->packageClassMethodName = $description['methodName'];
+}
+
+function executionAction(& $body)
+{
+	$classConstruct = $body->getClassConstruct();
+	$methodName = $body->methodName;
+	$className = $body->className;
+	
+	$xmlrpc_server = xmlrpc_server_create();
+	
+	$lambdaFunc = 'return adapterMap(call_user_func_array (array(&$userData[0], $userData[1]), $args));';
+	$func = create_function('$a,$args,$userData', $lambdaFunc);
+
+	xmlrpc_server_register_method($xmlrpc_server,
+		$body->packageClassMethodName,
+		$func);
+	
+	$request_xml = $body->getValue();
+	$args = array($xmlrpc_server, $request_xml, array(&$classConstruct, $methodName));
+	$nullObj = NULL;
+	$response = Executive::doMethodCall($body, $nullObj, 'xmlrpc_server_call_method', $args);
+	//$response = xmlrpc_server_call_method();
+	
+	if($response !== "__amfphp_error")
+	{
+		$body->setResults($response);
+	}
+	else
+	{
+		return false;
+	}
+}
+
+/**
+ * Debug action
+ */
+function debugAction(& $body)
+{
+	if(count(NetDebug::getTraceStack()) != 0)
+	{
+		$previousResults = $body->getResults();
+		$debugInfo = NetDebug::getTraceStack();
+		$debugString = "";
+		$body->setResults($debugString . "\n" . $previousResults);
+	}
+}
+
+/**
+ * This won't ever be called unless there is an error
+ */
+function serializationAction(& $body)
+{
+	$request_xml = $body->getValue();
+	$toSerialize = $body->getResults();
+	
+	$lambdaFunc = 'return $userData;';
+	$func = create_function('$a,$b,$userData', $lambdaFunc);
+	
+	$xmlrpc_server = xmlrpc_server_create();
+	
+	$request_xml = $body->getValue();
+	
+	xmlrpc_server_register_method($xmlrpc_server,
+		$body->packageClassMethodName,
+		$func);
+
+	$response = xmlrpc_server_call_method($xmlrpc_server, $request_xml, $toSerialize);
+	
+	$body->setResults($response);
+}
+
+?>
\ No newline at end of file
diff --git a/docroot/amfphp/core/xmlrpc/app/Gateway.php b/docroot/amfphp/core/xmlrpc/app/Gateway.php
new file mode 100755
index 0000000..9698304
--- /dev/null
+++ b/docroot/amfphp/core/xmlrpc/app/Gateway.php
@@ -0,0 +1,34 @@
+setValue($GLOBALS["HTTP_RAW_POST_DATA"]);
+		return $body;
+	}
+	
+	/**
+	 * Create the chain of actions
+	 */
+	function registerActionChain()
+	{
+		$this->actions['deserialization'] = 'deserializationAction';
+		$this->actions['classLoader'] = 'classLoaderAction';
+		$this->actions['security'] = 'securityAction';
+		$this->actions['exec'] = 'executionAction';
+		$this->actions['debug'] = 'debugAction';
+	}
+}
+?>
\ No newline at end of file