diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..57872d0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/vendor/
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..8057da0
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,17 @@
+{
+    "name": "jaeger/querylist",
+    "description": "QueryList是基于phpQuery的无比强大的PHP采集工具",
+    "require": {
+        "PHP":">=5.3.0",
+        "jaeger/phpquery-single": "^0.9.5",
+        "jaeger/curlmulti":"^1.0",
+        "jaeger/http":"^0.1"
+    },
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Jaeger",
+            "email": "hj.q@qq.com"
+        }
+    ]
+}
diff --git a/extensions/vendors/CurlMulti.php b/extensions/vendors/CurlMulti.php
deleted file mode 100644
index ab75a3d..0000000
--- a/extensions/vendors/CurlMulti.php
+++ /dev/null
@@ -1,698 +0,0 @@
-<?php
-/**
- * Chrome	Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11
- * IE6		Mozilla/5.0 (Windows NT 6.1; rv:9.0.1) Gecko/20100101 Firefox/9.0.1
- * FF		Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0
- * 
- * more useragent:http://www.useragentstring.com/
- *
- * @author admin@phpdr.net
- *        
- */
-class CurlMulti {
-	// url
-	const TASK_ITEM_URL = 0x01;
-	// file
-	const TASK_ITEM_FILE = 0x02;
-	// arguments
-	const TASK_ITEM_ARGS = 0x03;
-	// operation, task level
-	const TASK_ITEM_OPT = 0x04;
-	// control options
-	const TASK_ITEM_CTL = 0x05;
-	// file pointer
-	const TASK_FP = 0x06;
-	// success callback
-	const TASK_PROCESS = 0x07;
-	// curl fail callback
-	const TASK_FAIL = 0x08;
-	// tryed times
-	const TASK_TRYED = 0x09;
-	// handler
-	const TASK_CH = 0x0A;
-	
-	// global max thread num
-	public $maxThread = 10;
-	// Max thread by task type.Task type is specified in $item['ctl'] in add().If task has no type,$this->maxThreadNoType is maxThread-sum(maxThreadType).If less than 0 $this->maxThreadNoType is set to 0.
-	public $maxThreadType = array ();
-	// retry time(s) when task failed
-	public $maxTry = 3;
-	// operation, class level curl opt
-	public $opt = array ();
-	// cache options,dirLevel values is less than 3
-	public $cache = array (
-			'enable' => false,
-			'enableDownload' => false,
-			'compress' => false,
-			'dir' => null,
-			'expire' => 86400,
-			'dirLevel' => 1 
-	);
-	// stack or queue
-	public $taskPoolType = 'stack';
-	// eliminate duplicate for taskpool, will delete previous task and add new one
-	public $taskOverride = false;
-	// task callback,add() should be called in callback, $cbTask[0] is callback, $cbTask[1] is param.
-	public $cbTask = null;
-	// status callback
-	public $cbInfo = null;
-	// user callback
-	public $cbUser = null;
-	// common fail callback, called if no one specified
-	public $cbFail = null;
-	
-	// is the loop running
-	protected $isRunning = false;
-	// max thread num no type
-	protected $maxThreadNoType = null;
-	// all added task was saved here first
-	protected $taskPool = array ();
-	// taskPool with high priority
-	protected $taskPoolAhead = array ();
-	// running task(s)
-	protected $taskRunning = array ();
-	// failed task need to retry
-	protected $taskFail = array ();
-	
-	// handle of multi-thread curl
-	private $mh = null;
-	// user error
-	private $userError = null;
-	// if __construct called
-	private $isConstructCalled = false;
-	// running info
-	private $info = array (
-			'all' => array (
-					// process start time
-					'startTime' => null,
-					// download start time
-					'startTimeDownload' => null,
-					// the real multi-thread num
-					'activeNum' => null,
-					// finished task in the queue
-					'queueNum' => null,
-					// byte
-					'downloadSize' => 0,
-					// finished task number,include failed task and cache
-					'finishNum' => 0,
-					// The number of cache used
-					'cacheNum' => 0,
-					// completely failed task number
-					'failNum' => 0,
-					// task num has added
-					'taskNum' => 0,
-					// task running num by type,
-					'taskRunningNumType' => array (),
-					// task ruuning num no type
-					'taskRunningNumNoType' => 0,
-					// $this->taskPool size
-					'taskPoolNum' => 0,
-					// $this->taskRunning size
-					'taskRunningNum' => 0,
-					// $this->taskFail size
-					'taskFailNum' => 0,
-					// finish percent
-					'finishPercent' => 0,
-					// time cost
-					'timeSpent' => 0,
-					// download time cost
-					'timeSpentDownload' => 0,
-					// curl task speed
-					'taskSpeedNoCache' => 0,
-					// network speed, bytes
-					'downloadSpeed' => 0 
-			),
-			'running' => array () 
-	);
-	function __construct() {
-		$this->isConstructCalled = true;
-		if (version_compare ( PHP_VERSION, '5.1.0' ) < 0) {
-			throw new CurlMulti_Exception ( 'PHP 5.1.0+ is needed' );
-		}
-	}
-	
-	/**
-	 * add a task to taskPool
-	 *
-	 * @param array $item
-	 *        	array('url'=>'',['file'=>'',['opt'=>array(),['args'=>array(),['ctl'=>array('type'=>'','ahead'=>false,'cache'=>array('enable'=>bool,'expire'=>0),'close'=>true))]]]])
-	 * @param mixed $process
-	 *        	success callback,for callback first param array('info'=>,'content'=>), second param $item[args]
-	 * @param mixed $fail
-	 *        	curl fail callback,for callback first param array('error'=>array(0=>code,1=>msg),'info'=>array),second param $item[args];
-	 * @throws CurlMulti_Exception
-	 * @return \frame\lib\CurlMulti
-	 */
-	function add(array $item, $process = null, $fail = null) {
-		// check
-		if (! is_array ( $item )) {
-			user_error ( 'item must be array, item is ' . gettype ( $item ), E_USER_WARNING );
-		} else {
-			$item ['url'] = trim ( $item ['url'] );
-			if (empty ( $item ['url'] )) {
-				user_error ( "url can't be empty, url=$item[url]", E_USER_WARNING );
-			} else {
-				// replace space with + to avoid some curl problems
-				$item ['url'] = str_replace ( ' ', '+', $item ['url'] );
-				// fix
-				if (empty ( $item ['file'] ))
-					$item ['file'] = null;
-				if (empty ( $item ['opt'] ))
-					$item ['opt'] = array ();
-				if (empty ( $item ['args'] ))
-					$item ['args'] = array ();
-				if (empty ( $item ['ctl'] )) {
-					$item ['ctl'] = array ();
-				}
-				if (! isset ( $item ['ctl'] ['cache'] ) || ! isset ( $item ['ctl'] ['cache'] ['enable'] )) {
-					$item ['ctl'] ['cache'] = array (
-							'enable' => false,
-							'expire' => 0 
-					);
-				}
-				if (! isset ( $item ['ctl'] ['ahead'] )) {
-					$item ['ctl'] ['ahead'] = false;
-				}
-				if (empty ( $process )) {
-					$process = null;
-				}
-				if (empty ( $fail )) {
-					$fail = null;
-				}
-				$task = array ();
-				$task [self::TASK_ITEM_URL] = $item ['url'];
-				$task [self::TASK_ITEM_FILE] = $item ['file'];
-				$task [self::TASK_ITEM_ARGS] = array (
-						$item ['args'] 
-				);
-				$task [self::TASK_ITEM_OPT] = $item ['opt'];
-				$task [self::TASK_ITEM_CTL] = $item ['ctl'];
-				$task [self::TASK_PROCESS] = $process;
-				$task [self::TASK_FAIL] = $fail;
-				$task [self::TASK_TRYED] = 0;
-				$task [self::TASK_CH] = null;
-				$this->addTaskPool ( $task );
-				$this->info ['all'] ['taskNum'] ++;
-			}
-		}
-		return $this;
-	}
-	
-	/**
-	 * add task to taskPool
-	 *
-	 * @param unknown $task        	
-	 */
-	private function addTaskPool($task) {
-		// uniq
-		if ($this->taskOverride) {
-			foreach ( array (
-					'taskPoolAhead',
-					'taskPool' 
-			) as $v ) {
-				foreach ( $this->$v as $k1 => $v1 ) {
-					if ($v1 [self::TASK_ITEM_URL] == $task [self::TASK_ITEM_URL]) {
-						$t = &$this->$v;
-						unset ( $t [$k1] );
-					}
-				}
-			}
-		}
-		// add
-		if (true == $task [self::TASK_ITEM_CTL] ['ahead']) {
-			$this->taskPoolAhead [] = $task;
-		} else {
-			if ($this->taskPoolType == 'queue') {
-				$this->taskPool [] = $task;
-			} elseif ($this->taskPoolType == 'stack') {
-				array_unshift ( $this->taskPool, $task );
-			} else {
-				throw new CurlMulti_Exception ( 'taskPoolType not found, taskPoolType=' . $this->taskPoolType );
-			}
-		}
-	}
-	
-	/**
-	 * Perform the actual task(s).
-	 */
-	function start() {
-		if ($this->isRunning) {
-			throw new CurlMulti_Exception ( __CLASS__ . ' is running !' );
-		}
-		if (false === $this->isConstructCalled) {
-			throw new CurlMulti_Exception ( __CLASS__ . ' __construct is not called' );
-		}
-		$this->mh = curl_multi_init ();
-		$this->info ['all'] ['startTime'] = time ();
-		$this->info ['all'] ['timeStartDownload'] = null;
-		$this->info ['all'] ['downloadSize'] = 0;
-		$this->info ['all'] ['finishNum'] = 0;
-		$this->info ['all'] ['cacheNum'] = 0;
-		$this->info ['all'] ['failNum'] = 0;
-		$this->info ['all'] ['taskNum'] = 0;
-		$this->info ['all'] ['taskRunningNumNoType'] = 0;
-		$this->setThreadData ();
-		$this->isRunning = true;
-		$this->addTask ();
-		do {
-			$this->exec ();
-			curl_multi_select ( $this->mh );
-			$this->callCbInfo ();
-			if (isset ( $this->cbUser )) {
-				call_user_func ( $this->cbUser );
-			}
-			while ( false != ($curlInfo = curl_multi_info_read ( $this->mh, $this->info ['all'] ['queueNum'] )) ) {
-				$ch = $curlInfo ['handle'];
-				$task = $this->taskRunning [( int ) $ch];
-				$info = curl_getinfo ( $ch );
-				$this->info ['all'] ['downloadSize'] += $info ['size_download'];
-				if (isset ( $task [self::TASK_FP] )) {
-					fclose ( $task [self::TASK_FP] );
-				}
-				if ($curlInfo ['result'] == CURLE_OK) {
-					$param = array ();
-					$param ['info'] = $info;
-					$param ['ext'] = array (
-							'ch' => $ch 
-					);
-					if (! isset ( $task [self::TASK_ITEM_FILE] )) {
-						$param ['content'] = curl_multi_getcontent ( $ch );
-					}
-				}
-				curl_multi_remove_handle ( $this->mh, $ch );
-				// must close first,other wise download may be not commpleted in process callback
-				if (! array_key_exists ( 'close', $task [self::TASK_ITEM_CTL] ) || $task [self::TASK_ITEM_CTL] ['close'] == true) {
-					curl_close ( $ch );
-				}
-				if ($curlInfo ['result'] == CURLE_OK) {
-					$this->process ( $task, $param, false );
-				}
-				// error handle
-				$callFail = false;
-				if ($curlInfo ['result'] !== CURLE_OK || isset ( $this->userError )) {
-					if ($task [self::TASK_TRYED] >= $this->maxTry) {
-						// user error
-						if (isset ( $this->userError )) {
-							$err = array (
-									'error' => $this->userError 
-							);
-						} else {
-							$err = array (
-									'error' => array (
-											$curlInfo ['result'],
-											curl_error ( $ch ) 
-									) 
-							);
-						}
-						$err ['info'] = $info;
-						if (isset ( $task [self::TASK_FAIL] ) || isset ( $this->cbFail )) {
-							array_unshift ( $task [self::TASK_ITEM_ARGS], $err );
-							$callFail = true;
-						} else {
-							echo "\nError " . implode ( ', ', $err ['error'] ) . ", url=$info[url]\n";
-						}
-						$this->info ['all'] ['failNum'] ++;
-					} else {
-						$task [self::TASK_TRYED] ++;
-						$task [self::TASK_ITEM_CTL] ['useCache'] = false;
-						$this->taskFail [] = $task;
-						$this->info ['all'] ['taskNum'] ++;
-					}
-					if (isset ( $this->userError )) {
-						unset ( $this->userError );
-					}
-				}
-				if ($callFail) {
-					if (isset ( $task [self::TASK_FAIL] )) {
-						call_user_func_array ( $task [self::TASK_FAIL], $task [self::TASK_ITEM_ARGS] );
-					} elseif (isset ( $this->cbFail )) {
-						call_user_func_array ( $this->cbFail, $task [self::TASK_ITEM_ARGS] );
-					}
-				}
-				unset ( $this->taskRunning [( int ) $ch] );
-				if (array_key_exists ( 'type', $task [self::TASK_ITEM_CTL] )) {
-					$this->info ['all'] ['taskRunningNumType'] [$task [self::TASK_ITEM_CTL] ['type']] --;
-				} else {
-					$this->info ['all'] ['taskRunningNumNoType'] --;
-				}
-				$this->addTask ();
-				$this->info ['all'] ['finishNum'] ++;
-				// if $this->info['all']['queueNum'] grow very fast there will be no efficiency lost,because outer $this->exec() won't be executed.
-				$this->exec ();
-				$this->callCbInfo ();
-				if (isset ( $this->cbUser )) {
-					call_user_func ( $this->cbUser );
-				}
-			}
-		} while ( $this->info ['all'] ['activeNum'] || $this->info ['all'] ['queueNum'] || ! empty ( $this->taskFail ) || ! empty ( $this->taskRunning ) || ! empty ( $this->taskPool ) );
-		$this->callCbInfo ( true );
-		curl_multi_close ( $this->mh );
-		unset ( $this->mh );
-		$this->isRunning = false;
-	}
-	
-	/**
-	 * call $this->cbInfo
-	 */
-	private function callCbInfo($force = false) {
-		static $lastTime;
-		if (! isset ( $lastTime )) {
-			$lastTime = time ();
-		}
-		$now = time ();
-		if (($force || $now - $lastTime > 0) && isset ( $this->cbInfo )) {
-			$lastTime = $now;
-			$this->info ['all'] ['taskPoolNum'] = count ( $this->taskPool );
-			$this->info ['all'] ['taskRunningNum'] = count ( $this->taskRunning );
-			$this->info ['all'] ['taskFailNum'] = count ( $this->taskFail );
-			if ($this->info ['all'] ['taskNum'] > 0) {
-				$this->info ['all'] ['finishPercent'] = round ( $this->info ['all'] ['finishNum'] / $this->info ['all'] ['taskNum'], 4 );
-			}
-			$this->info ['all'] ['timeSpent'] = time () - $this->info ['all'] ['startTime'];
-			if (isset ( $this->info ['all'] ['timeStartDownload'] )) {
-				$this->info ['all'] ['timeSpentDownload'] = time () - $this->info ['all'] ['timeStartDownload'];
-			}
-			if ($this->info ['all'] ['timeSpentDownload'] > 0) {
-				$this->info ['all'] ['taskSpeedNoCache'] = round ( ($this->info ['all'] ['finishNum'] - $this->info ['all'] ['cacheNum']) / $this->info ['all'] ['timeSpentDownload'], 2 );
-				$this->info ['all'] ['downloadSpeed'] = round ( $this->info ['all'] ['downloadSize'] / $this->info ['all'] ['timeSpentDownload'], 2 );
-			}
-			// running
-			$this->info ['running'] = array ();
-			foreach ( $this->taskRunning as $k => $v ) {
-				$this->info ['running'] [$k] = curl_getinfo ( $v [self::TASK_CH] );
-			}
-			call_user_func_array ( $this->cbInfo, array (
-					$this->info 
-			) );
-		}
-	}
-	
-	/**
-	 * set $this->maxThreadNoType, $this->info['all']['taskRunningNumType'], $this->info['all']['taskRunningNumNoType'] etc
-	 */
-	private function setThreadData() {
-		$this->maxThreadNoType = $this->maxThread - array_sum ( $this->maxThreadType );
-		if ($this->maxThreadNoType < 0) {
-			$this->maxThreadNoType = 0;
-		}
-		// unset none exitst type num
-		foreach ( $this->info ['all'] ['taskRunningNumType'] as $k => $v ) {
-			if ($v == 0 && ! array_key_exists ( $k, $this->maxThreadType )) {
-				unset ( $this->info ['all'] ['taskRunningNumType'] [$k] );
-			}
-		}
-		// init type num
-		foreach ( $this->maxThreadType as $k => $v ) {
-			if ($v == 0) {
-				user_error ( 'maxThreadType[' . $k . '] is 0, task of this type will never be added!', E_USER_WARNING );
-			}
-			if (! array_key_exists ( $k, $this->info ['all'] ['taskRunningNumType'] )) {
-				$this->info ['all'] ['taskRunningNumType'] [$k] = 0;
-			}
-		}
-	}
-	
-	/**
-	 * curl_multi_exec()
-	 */
-	private function exec() {
-		while ( curl_multi_exec ( $this->mh, $this->info ['all'] ['activeNum'] ) === CURLM_CALL_MULTI_PERFORM ) {
-		}
-	}
-	
-	/**
-	 * add a task to curl, keep $this->maxThread concurrent automatically
-	 */
-	private function addTask() {
-		$c = $this->maxThread - count ( $this->taskRunning );
-		while ( $c > 0 ) {
-			$task = array ();
-			// search failed first
-			if (! empty ( $this->taskFail )) {
-				$task = array_pop ( $this->taskFail );
-			} else {
-				// cbTask
-				if (0 < ($this->maxThread - count ( $this->taskPool )) and ! empty ( $this->cbTask )) {
-					if (! isset ( $this->cbTask [1] )) {
-						$this->cbTask [1] = array ();
-					}
-					call_user_func_array ( $this->cbTask [0], array (
-							$this->cbTask [1] 
-					) );
-				}
-				if (! empty ( $this->taskPoolAhead )) {
-					$task = array_pop ( $this->taskPoolAhead );
-				} elseif (! empty ( $this->taskPool )) {
-					if ($this->taskPoolType == 'stack') {
-						$task = array_pop ( $this->taskPool );
-					} elseif ($this->taskPoolType == 'queue') {
-						$task = array_shift ( $this->taskPool );
-					} else {
-						throw new CurlMulti_Exception ( 'taskPoolType not found, taskPoolType=' . $this->taskPoolType );
-					}
-				}
-			}
-			$noAdd = false;
-			$cache = null;
-			if (! empty ( $task )) {
-				if (true == $task [self::TASK_ITEM_CTL] ['cache'] ['enable'] || $this->cache ['enable']) {
-					$cache = $this->cache ( $task );
-					if (null !== $cache) {
-						if (isset ( $task [self::TASK_ITEM_FILE] )) {
-							file_put_contents ( $task [self::TASK_ITEM_FILE], $cache ['content'], LOCK_EX );
-							unset ( $cache ['content'] );
-						}
-						$this->process ( $task, $cache, true );
-						$this->info ['all'] ['cacheNum'] ++;
-						$this->info ['all'] ['finishNum'] ++;
-						$this->callCbInfo ();
-					}
-				}
-				if (! $cache) {
-					$this->setThreadData ();
-					if (array_key_exists ( 'type', $task [self::TASK_ITEM_CTL] ) && ! array_key_exists ( $task [self::TASK_ITEM_CTL] ['type'], $this->maxThreadType )) {
-						user_error ( 'task was set to notype because type was not set in $this->maxThreadType, type=' . $task [self::TASK_ITEM_CTL] ['type'], E_USER_WARNING );
-						unset ( $task [self::TASK_ITEM_CTL] ['type'] );
-					}
-					if (array_key_exists ( 'type', $task [self::TASK_ITEM_CTL] )) {
-						$maxThread = $this->maxThreadType [$task [self::TASK_ITEM_CTL] ['type']];
-						$isNoType = false;
-					} else {
-						$maxThread = $this->maxThreadNoType;
-						$isNoType = true;
-					}
-					if ($isNoType && $maxThread == 0) {
-						user_error ( 'task was disgarded because maxThreadNoType=0, url=' . $task [self::TASK_ITEM_URL], E_USER_WARNING );
-					}
-					if (($isNoType && $this->info ['all'] ['taskRunningNumNoType'] < $maxThread) || (! $isNoType && $this->info ['all'] ['taskRunningNumType'] [$task [self::TASK_ITEM_CTL] ['type']] < $maxThread)) {
-						$task [self::TASK_CH] = $this->curlInit ( $task [self::TASK_ITEM_URL] );
-						// is a download task?
-						if (isset ( $task [self::TASK_ITEM_FILE] )) {
-							// curl can create the last level directory
-							$dir = dirname ( $task [self::TASK_ITEM_FILE] );
-							if (! file_exists ( $dir ))
-								mkdir ( $dir, 0777 );
-							$task [self::TASK_FP] = fopen ( $task [self::TASK_ITEM_FILE], 'w' );
-							curl_setopt ( $task [self::TASK_CH], CURLOPT_FILE, $task [self::TASK_FP] );
-						}
-						// single task curl option
-						if (isset ( $task [self::TASK_ITEM_OPT] )) {
-							foreach ( $task [self::TASK_ITEM_OPT] as $k => $v ) {
-								curl_setopt ( $task [self::TASK_CH], $k, $v );
-							}
-						}
-						$this->taskRunning [( int ) $task [self::TASK_CH]] = $task;
-						if (! isset ( $this->info ['all'] ['timeStartDownload'] )) {
-							$this->info ['all'] ['timeStartDownload'] = time ();
-						}
-						if ($isNoType) {
-							$this->info ['all'] ['taskRunningNumNoType'] ++;
-						} else {
-							$this->info ['all'] ['taskRunningNumType'] [$task [self::TASK_ITEM_CTL] ['type']] ++;
-						}
-						curl_multi_add_handle ( $this->mh, $task [self::TASK_CH] );
-					} else {
-						// rotate task to pool
-						if ($task [self::TASK_TRYED] > 0) {
-							array_unshift ( $this->taskFail, $task );
-						} else {
-							array_unshift ( $this->taskPool, $task );
-						}
-						$noAdd = true;
-					}
-				}
-			}
-			if (! $cache || $noAdd) {
-				$c --;
-			}
-		}
-	}
-	
-	/**
-	 * do process
-	 *
-	 * @param unknown $task        	
-	 * @param unknown $r        	
-	 * @param unknown $isCache        	
-	 */
-	private function process($task, $r, $isCache) {
-		array_unshift ( $task [self::TASK_ITEM_ARGS], $r );
-		if (isset ( $task [self::TASK_PROCESS] )) {
-			$userRes = call_user_func_array ( $task [self::TASK_PROCESS], $task [self::TASK_ITEM_ARGS] );
-		}
-		if (! isset ( $userRes )) {
-			$userRes = true;
-		}
-		array_shift ( $task [self::TASK_ITEM_ARGS] );
-		// backoff
-		if (false === $userRes) {
-			if (false == $this->cache ['enable'] && false == $task [self::TASK_ITEM_CTL] ['cache'] ['enable']) {
-				$task [self::TASK_ITEM_CTL] ['cache'] = array (
-						'enable' => true,
-						'expire' => 3600 
-				);
-			}
-			$this->addTaskPool ( $task );
-		}
-		// write cache
-		if (false == $isCache && false == isset ( $this->userError ) && (true == $task [self::TASK_ITEM_CTL] ['cache'] ['enable']) || $this->cache ['enable']) {
-			$this->cache ( $task, $r );
-		}
-	}
-	
-	/**
-	 * set or get file cache
-	 *
-	 * @param string $url        	
-	 * @param mixed $content
-	 *        	array('info','content')
-	 * @return return array|null|boolean
-	 */
-	private function cache($task, $content = null) {
-		if (! isset ( $this->cache ['dir'] ))
-			throw new CurlMulti_Exception ( 'Cache dir is not defined' );
-		$url = $task [self::TASK_ITEM_URL];
-		$key = md5 ( $url );
-		$isDownload = isset ( $task [self::TASK_ITEM_FILE] );
-		$file = rtrim ( $this->cache ['dir'], '/' ) . '/';
-		if (isset ( $this->cache ['dirLevel'] ) && $this->cache ['dirLevel'] != 0) {
-			if ($this->cache ['dirLevel'] == 1) {
-				$file .= substr ( $key, 0, 3 ) . '/' . substr ( $key, 3 );
-			} elseif ($this->cache ['dirLevel'] == 2) {
-				$file .= substr ( $key, 0, 3 ) . '/' . substr ( $key, 3, 3 ) . '/' . substr ( $key, 6 );
-			} else {
-				throw new CurlMulti_Exception ( 'cache dirLevel is invalid, dirLevel=' . $this->cache ['dirLevel'] );
-			}
-		} else {
-			$file .= $key;
-		}
-		$r = null;
-		if (! isset ( $content )) {
-			if (file_exists ( $file )) {
-				if (true == $task [self::TASK_ITEM_CTL] ['cache'] ['enable']) {
-					$expire = $task [self::TASK_ITEM_CTL] ['cache'] ['expire'];
-				} else {
-					$expire = $this->cache ['expire'];
-				}
-				if (time () - filemtime ( $file ) < $expire) {
-					$r = file_get_contents ( $file );
-					if ($this->cache ['compress']) {
-						$r = gzuncompress ( $r );
-					}
-					$r = unserialize ( $r );
-					if ($isDownload) {
-						$r ['content'] = base64_decode ( $r ['content'] );
-					}
-				}
-			}
-		} else {
-			$r = false;
-			// check main cache directory
-			if (! is_dir ( $this->cache ['dir'] )) {
-				throw new CurlMulti_Exception ( "Cache dir doesn't exists" );
-			} else {
-				$dir = dirname ( $file );
-				// level 1 subdir
-				if (isset ( $this->cache ['dirLevel'] ) && $this->cache ['dirLevel'] > 1) {
-					$dir1 = dirname ( $dir );
-					if (! is_dir ( $dir1 ) && ! mkdir ( $dir1 )) {
-						throw new CurlMulti_Exception ( 'Create dir failed, dir=' . $dir1 );
-					}
-				}
-				if (! is_dir ( $dir ) && ! mkdir ( $dir )) {
-					throw new CurlMulti_Exception ( 'Create dir failed, dir=' . $dir );
-				}
-				if ($isDownload) {
-					$content ['content'] = base64_encode ( file_get_contents ( $task [self::TASK_ITEM_FILE] ) );
-				}
-				$content = serialize ( $content );
-				if ($this->cache ['compress']) {
-					$content = gzcompress ( $content );
-				}
-				if (file_put_contents ( $file, $content, LOCK_EX )) {
-					$r = true;
-				} else {
-					throw new CurlMulti_Exception ( 'Write cache file failed' );
-				}
-			}
-		}
-		return $r;
-	}
-	
-	/**
-	 * user error for current callback
-	 * not curl error
-	 * must be called in process callback
-	 *
-	 * @param unknown $msg        	
-	 */
-	function error($msg) {
-		$this->userError = array (
-				CURLE_OK,
-				$msg 
-		);
-	}
-	
-	/**
-	 * return a default $ch initialized with global opt
-	 *
-	 * @param unknown $url        	
-	 * @return resource
-	 */
-	function getch($url = null) {
-		return $this->curlInit ( $url );
-	}
-	
-	/**
-	 * get curl handle
-	 *
-	 * @param string $url        	
-	 * @return resource
-	 */
-	private function curlInit($url = null) {
-		$ch = curl_init ();
-		$opt = array ();
-		if (isset ( $url )) {
-			$opt [CURLOPT_URL] = $url;
-		}
-		$opt [CURLOPT_HEADER] = false;
-		$opt [CURLOPT_CONNECTTIMEOUT] = 10;
-		$opt [CURLOPT_TIMEOUT] = 30;
-		$opt [CURLOPT_AUTOREFERER] = true;
-		$opt [CURLOPT_USERAGENT] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11';
-		$opt [CURLOPT_RETURNTRANSFER] = true;
-		$opt [CURLOPT_FOLLOWLOCATION] = true;
-		$opt [CURLOPT_MAXREDIRS] = 10;
-		// user defined opt
-		if (! empty ( $this->opt )) {
-			foreach ( $this->opt as $k => $v ) {
-				$opt [$k] = $v;
-			}
-		}
-		curl_setopt_array ( $ch, $opt );
-		return $ch;
-	}
-}
-
-class CurlMulti_Exception extends Exception {
-}
\ No newline at end of file
diff --git a/extensions/vendors/Http.php b/extensions/vendors/Http.php
deleted file mode 100644
index 17dda2a..0000000
--- a/extensions/vendors/Http.php
+++ /dev/null
@@ -1,934 +0,0 @@
-<?php
-
-/**
- * 
- * @desc  HTTP 请求类, 支持 CURL 和 Socket, 默认使用 CURL , 当手动指定  
- *              useCurl 或者 curl 扩展没有安装时, 会使用 Socket
- *              目前支持 get 和 post 两种请求方式
- * 
- * @example 
- * 
-1. 基本 get 请求: 
-
-    $http = new Http();         // 实例化对象
-    $result =  $http->get('http://weibo.com/at/comment');
-    
-2. 基本 post 请求: 
-
-    $http = new Http();         // 实例化对象
-    $result = $http->post('http://someurl.com/post-new-article', array('title'=>$title, 'body'=>$body) );
-    
-3. 模拟登录 ( post 和 get 同时使用, 利用 cookie 存储状态 ) : 
-
-    $http = new Http();         // 实例化对象
-    $http->setCookiepath(substr(md5($username), 0, 10));        // 设置 cookie, 如果是多个用户请求的话
-    // 提交 post 数据
-    $loginData = $http->post('http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.3.19)', array('username'=>$username, 'loginPass'=>$password) );
-    $result =  $http->get('http://weibo.com/at/comment');
-    
-4. 利用 initialize 函数设置多个 config 信息
-
-    $httpConfig['method']     = 'GET';
-    $httpConfig['target']     = 'http://www.somedomain.com/index.html';
-    $httpConfig['referrer']   = 'http://www.somedomain.com';
-    $httpConfig['user_agent'] = 'My Crawler';
-    $httpConfig['timeout']    = '30';
-    $httpConfig['params']     = array('var1' => 'testvalue', 'var2' => 'somevalue');
-    
-    $http = new Http();
-    $http->initialize($httpConfig);
-    
-    $result = $http->result;
-
-5. 复杂的设置: 
-    
-    $http = new Http();
-    $http->useCurl(false);      // 不使用 curl
-    $http->setMethod('POST');       // 使用 POST method
-    
-    // 设置 POST 数据
-    $http->addParam('user_name' , 'yourusername');
-    $http->addParam('password'  , 'yourpassword');
-    
-    // Referrer
-    $http->setReferrer('https://yourproject.projectpath.com/login');
-    
-    // 开始执行请求
-    $http->execute('https://yourproject.projectpath.com/login/authenticate');
-    $result = $http->getResult();
-
-6. 获取开启了 basic auth 的请求
-    
-    $http = new Http();
-    
-    // Set HTTP basic authentication realms
-    $http->setAuth('yourusername', 'yourpassword');
-    
-    // 获取某个被保护的应用的 feed
-    $http->get('http://www.someblog.com/protected/feed.xml');
-    
-    $result = $http->result;
-
- * 
- * @from http://www.phpfour.com/lib/http
- * @since Version 0.1
- * @original author      Md Emran Hasan <phpfour@gmail.com>
- * @modify by       Charlie Jade
- */
-
-class Http
-{
-    /**  目标请求 @var string */
-    var $target;
-    
-    /**  目标 URL 的 host @var string */
-    var $host;
-    
-    /**  请求目标的端口 @var integer */
-    var $port;
-    
-    /** 请求目标的 path @var string */
-    var $path;
-    
-    /** 请求目标的 schema  @var string */
-    var $schema;
-    
-    /** 请求的 method (GET 或者 POST)  @var string */
-    var $method;
-    
-    /** 请求的数据  @var array */
-    var $params;
-    
-    /**  请求时候的 cookie 数据  @var array */
-    var $cookies;
-    
-    /**  请求返回的 cookie 数据 @var array  */
-    var $_cookies;
-    
-    /** 请求超时时间, 默认是 25 @var integer */
-    var $timeout;
-    
-    /** 是否使用 cURL , 默认为 TRUE @var boolean */
-    var $useCurl;
-    
-    /**   referrer 信息 @var string */
-    var $referrer;
-    
-    /** 请求客户端 User agent  @var string */
-    var $userAgent;
-    
-    /**  Contains the cookie path (to be used with cURL) @var string */
-    var $cookiePath;
-    
-    /**  是否使用 Cookie @var boolean  */
-    var $useCookie;
-    
-    /** 是否为下一次请求保存 Cookie @var boolean */
-    var $saveCookie;
-    
-    /** HTTP Basic Auth 用户名 (for authentication) @var string */
-    var $username;
-    
-    /** HTTP Basic Auth 密码 (for authentication) @var string */
-    var $password;
-    
-    /** 请求的结果集 @var string */
-    var $result;
-    
-    /** 最后一个请求的 headers 信息  @var array */
-    var $headers;
-    
-    /** Contains the last call's http status code @var string  */
-    var $status;
-    
-    /** 是否跟随 http redirect 跳转  @var boolean */
-    var $redirect;
-    
-    /** 最大 http redirect 调整数 @var integer */
-    var $maxRedirect;
-    
-    /** 当前请求有多少个 URL  @var integer */
-    var $curRedirect;
-    
-    /** 错误代码 @var string */
-    var $error;
-    
-    /** Store the next token  @var string */
-    var $nextToken;
-    
-    /** 是否存储 bug 信息 @var boolean  */
-    var $debug;
-    
-    /** Stores the debug messages  @var array @todo will keep debug messages */
-    var $debugMsg;
-    
-    /**  Constructor for initializing the class with default values. @return void   */
-    public function __construct()
-    {
-        // 先初始化
-        $this->clear();    
-    }
-    
-    /**
-     * 初始化配置信息
-     * Initialize preferences
-     * 
-     * This function will take an associative array of config values and 
-     * will initialize the class variables using them. 
-     * 
-     * Example use:
-     * 
-     * <pre>
-     * $httpConfig['method']     = 'GET';
-     * $httpConfig['target']     = 'http://www.somedomain.com/index.html';
-     * $httpConfig['referrer']   = 'http://www.somedomain.com';
-     * $httpConfig['user_agent'] = 'My Crawler';
-     * $httpConfig['timeout']    = '30';
-     * $httpConfig['params']     = array('var1' => 'testvalue', 'var2' => 'somevalue');
-     * 
-     * $http = new Http();
-     * $http->initialize($httpConfig);
-     * </pre>
-     *
-     * @param array Config values as associative array
-     * @return void
-     */    
-    public function initialize($config = array())
-    {
-        $this->clear();
-        foreach ($config as $key => $val)
-        {
-            if (isset($this->$key))
-            {
-                $method = 'set' . ucfirst(str_replace('_', '', $key));
-                
-                if (method_exists($this, $method))
-                {
-                    $this->$method($val);
-                }
-                else
-                {
-                    $this->$key = $val;
-                }            
-            }
-        }
-    }
-    
-    /**
-     * 初始化所有
-     * 
-     * Clears all the properties of the class and sets the object to
-     * the beginning state. Very handy if you are doing subsequent calls 
-     * with different data.
-     *
-     * @return void
-     */
-    public function clear()
-    {
-        // Set the request defaults
-        $this->host         = '';
-        $this->port         = 0;
-        $this->path         = '';
-        $this->target       = '';
-        $this->method       = 'GET';
-        $this->schema       = 'http';
-        $this->params       = array();
-        $this->headers      = array();
-        $this->cookies      = array();
-        $this->_cookies     = array();
-        
-        // Set the config details        
-        $this->debug        = FALSE;
-        $this->error        = '';
-        $this->status       = 0;
-        $this->timeout      = '25';
-        $this->useCurl      = TRUE;
-        $this->referrer     = '';
-        $this->username     = '';
-        $this->password     = '';
-        $this->redirect     = TRUE;
-        
-        // Set the cookie and agent defaults
-        $this->nextToken    = '';
-        $this->useCookie    = FALSE;
-        $this->saveCookie   = FALSE;
-        $this->maxRedirect  = 3;
-        $this->cookiePath   = 'cookie.txt';
-        $this->userAgent    = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7';
-    }
-    
-    /** 设置目标 @return void */
-    public function setTarget($url)
-    {
-        $this->target = $url;
-    }
-    
-    /** 设置 http 请求方法  @param string HTTP method to use (GET or POST)  @return void */
-    public function setMethod($method)
-    {
-         $this->method = $method;
-    }
-    
-    /** 设置 referrer URL @param string URL of referrer page @return void */
-    public function setReferrer($referrer)
-    {
-         $this->referrer = $referrer;
-    }
-    
-    /**  设置 User agent  @param string Full user agent string @return void */
-    public function setUseragent($agent)
-    {
-        $this->userAgent = $agent;
-    }
-    
-    /** 设置请求 timeout  @param integer Timeout delay in seconds @return void */
-    public function setTimeout($seconds)
-    {
-        $this->timeout = $seconds;
-    }
-    
-    /** 设置  cookie path (只支持cURL ) @param string File location of cookiejar @return void */
-    public function setCookiepath($path)
-    {
-        
-        $this->cookiePath = $path;
-        $this->useCookie(TRUE);
-        $this->saveCookie(TRUE);
-    }
-    
-    /** 设置请求参数 parameters @param array GET or POST 的请求数据 @return void  */
-    public function setParams($dataArray)
-    {
-        $this->params = array_merge($this->params, $dataArray);
-    }
-    
-    /** 设置 basic http auth 域验证 @param string 用户名  @param string 密码  @return void */
-    public function setAuth($username, $password)
-    {
-        $this->username = $username;
-        $this->password = $password;
-    }
-    
-    /** 设置最大跳转数 @param integer Maximum number of redirects @return void */
-    public function setMaxredirect($value)
-    {
-        $this->maxRedirect = $value;
-    }
-    
-    /** 添加多一个新的请求数据 @param string Name of the parameter @param string Value of the paramete  @return void  */
-    public function addParam($name, $value)
-    {
-        $this->params[$name] = $value;
-    }
-    
-    /** 添加 cookie 请求数据  @param string Name of cookie  @param string Value of cookie */
-    public function addCookie($name, $value)
-    {
-        $this->cookies[$name] = $value;
-    }
-    
-    /** 是否使用 curl, 默认 true, false 为使用 socket  */
-    public function useCurl($value = TRUE)
-    {
-        if (is_bool($value))
-        {
-        $this->useCurl = $value;
-        }   
-    }
-    
-    /** 是否使用 cookie , 默认为 false  @param boolean Whether to use cookies or not  @return void  */
-    public function useCookie($value = FALSE)
-    {
-        $this->useCookie = $value;
-    }
-    
-    /** 是否使用 cookie , 以供下一次请求使用 @param boolean Whether to save persistent cookies or not @return void  */
-    public function saveCookie($value = FALSE)
-    {
-        $this->saveCookie = $value;
-    }
-    
-    /** 是否跟随 302 跳转 @param boolean Whether to follow HTTP redirects or not  */
-    public function followRedirects($value = TRUE)
-    {
-        $this->redirect = $value;
-    }
-    
-    /** 获取结果集  @return string output of execution */
-    public function getResult()
-    {
-        return $this->result;
-    }
-    
-    /** 获取最后一个返回的 headers 数组 */
-    public function getHeaders()
-    {
-        return $this->headers;
-    }
-
-    /** 获取请求的状态码  */
-    public function getStatus()
-    {
-        return $this->status;
-    }
-        
-    /** 获取最后运行错误   */
-    public function getError()
-    {
-        return $this->error;
-    }
-    
-    /** 执行一条 http get 请求  */
-    public function get($url, $data=array()){
-        return $this->execute($url, '', 'GET', $data);
-    }
-    
-    /** 执行一条 http post 请求  */
-    public function post($url, $data=array()){
-        return $this->execute($url, '', 'POST', $data);
-    }
-    
-    /**
-     * 使用当前的配置, 发送一条 HTTP 请求  
-     * 
-     * @param string URL of the target page (optional)
-     * @param string URL of the referrer page (optional)
-     * @param string 请求方法 (GET or POST) (optional)
-     * @param array 请求数据, key 和 value 对应的数组 (optional)
-     * @return string 请求的结果集
-     */    
-    public function execute($target = '', $referrer = '', $method = '', $data = array())
-    {
-        // Populate the properties
-        $this->target = ($target) ? $target : $this->target;
-        $this->method = ($method) ? $method : $this->method;
-        
-        $this->referrer = ($referrer) ? $referrer : $this->referrer;
-        
-        // Add the new params
-        if (is_array($data) && count($data) > 0) 
-        {
-            $this->params = array_merge($this->params, $data);
-        }
-        
-        // Process data, if presented
-        if(is_array($this->params) && count($this->params) > 0)
-        {
-            // Get a blank slate
-            $tempString = array();
-            
-            // Convert data array into a query string (ie animal=dog&sport=baseball)
-            foreach ($this->params as $key => $value) 
-            {
-                if(strlen(trim($value))>0)
-                {
-                    $tempString[] = $key . "=" . urlencode($value);
-                }
-            }
-            
-            $queryString = join('&', $tempString);
-        }
-        
-        // 如果 cURL 没有安装就使用 fscokopen 执行请求
-        $this->useCurl = $this->useCurl && in_array('curl', get_loaded_extensions());
-        
-        // GET method configuration
-        if($this->method == 'GET')
-        {
-            if(isset($queryString))
-            {
-                $this->target = $this->target . "?" . $queryString;
-            }
-        }
-        
-        // Parse target URL
-        $urlParsed = parse_url($this->target);
-        
-        // Handle SSL connection request
-        if ($urlParsed['scheme'] == 'https')
-        {
-            $this->host = 'ssl://' . $urlParsed['host'];
-            $this->port = ($this->port != 0) ? $this->port : 443;
-        }
-        else
-        {
-            $this->host = $urlParsed['host'];
-            $this->port = ($this->port != 0) ? $this->port : 80;
-        }
-        
-        // Finalize the target path
-        $this->path   = (isset($urlParsed['path']) ? $urlParsed['path'] : '/') . (isset($urlParsed['query']) ? '?' . $urlParsed['query'] : '');
-        $this->schema = $urlParsed['scheme'];
-        
-        // Pass the requred cookies
-        $this->_passCookies();
-        
-        // Process cookies, if requested
-        if(is_array($this->cookies) && count($this->cookies) > 0)
-        {
-            // Get a blank slate
-            $tempString   = array();
-            
-            // Convert cookiesa array into a query string (ie animal=dog&sport=baseball)
-            foreach ($this->cookies as $key => $value) 
-            {
-                if(strlen(trim($value)) > 0)
-                {
-                    $tempString[] = $key . "=" . urlencode($value);
-                }
-            }
-            
-            $cookieString = join('&', $tempString);
-        }
-        
-        // Do we need to use cURL
-        if ($this->useCurl)
-        {
-            // Initialize PHP cURL handle
-            $ch = curl_init();
-    
-            // GET method configuration
-            if($this->method == 'GET')
-            {
-                curl_setopt ($ch, CURLOPT_HTTPGET, TRUE); 
-                curl_setopt ($ch, CURLOPT_POST, FALSE); 
-            }
-            // POST method configuration
-            else
-            {
-                if(isset($queryString))
-                {
-                    curl_setopt ($ch, CURLOPT_POSTFIELDS, $queryString);
-                }
-                
-                curl_setopt ($ch, CURLOPT_POST, TRUE); 
-                curl_setopt ($ch, CURLOPT_HTTPGET, FALSE); 
-            }
-            
-            // Basic Authentication configuration
-            if ($this->username && $this->password)
-            {
-                curl_setopt($ch, CURLOPT_USERPWD, $this->username . ':' . $this->password);
-            }
-            
-            // Custom cookie configuration
-            if($this->useCookie && isset($cookieString))
-            {
-                curl_setopt ($ch, CURLOPT_COOKIE, $cookieString);
-            }
-            
-            curl_setopt($ch, CURLOPT_HEADER,         array('Accept-Language: zh-cn','Connection: Keep-Alive','Cache-Control: no-cache')); 
-            curl_setopt($ch, CURLOPT_NOBODY,         FALSE);                // Return body
-
-            curl_setopt($ch, CURLOPT_COOKIEJAR,      $this->cookiePath);    // cookie 文件
-            curl_setopt($ch, CURLOPT_COOKIEFILE,      $this->cookiePath);    // cookie 文件
-
-            curl_setopt($ch, CURLOPT_TIMEOUT,        $this->timeout);       // Timeout
-            curl_setopt($ch, CURLOPT_USERAGENT,      $this->userAgent);     // Webbot name
-            curl_setopt($ch, CURLOPT_URL,            $this->target);        // Target site
-            curl_setopt($ch, CURLOPT_REFERER,        $this->referrer);      // Referer value
-            
-            curl_setopt($ch, CURLOPT_VERBOSE,        FALSE);                // Minimize logs
-            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);                // No certificate
-            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $this->redirect);      // Follow redirects
-            curl_setopt($ch, CURLOPT_MAXREDIRS,      $this->maxRedirect);   // Limit redirections to four
-            curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);                 // 是否以 string 格式返回
-            
-            // Get the target contents
-            $content = curl_exec($ch);
-            
-            // Get the request info 
-            $curl_info = curl_getinfo($ch);
-            $header_size = $curl_info["header_size"];
-
-            // 赋值结果集
-            $this->result = substr($content, $header_size);
-            
-            $reader = explode("\r\n\r\n", trim(substr($content, 0, $header_size))); 
-            $this->status = $curl_info['http_code'];
-            
-            // Parse the headers
-            $this->_parseHeaders( explode("\r\n\r\n", trim(substr($content, 0, $header_size))) );
-            
-            // Store the error (is any)
-            $this->_setError(curl_error($ch));
-            
-            // Close PHP cURL handle
-            curl_close($ch);
-        }
-        else
-        {
-            // Get a file pointer
-            $filePointer = fsockopen($this->host, $this->port, $errorNumber, $errorString, $this->timeout);
-       
-            // We have an error if pointer is not there
-            if (!$filePointer)
-            {
-                $this->_setError('Failed opening http socket connection: ' . $errorString . ' (' . $errorNumber . ')');
-                return FALSE;
-            }
-
-            // Set http headers with host, user-agent and content type
-            $requestHeader  = $this->method . " " . $this->path . "  HTTP/1.1\r\n";
-            $requestHeader .= "Host: " . $urlParsed['host'] . "\r\n";
-            $requestHeader .= "User-Agent: " . $this->userAgent . "\r\n";
-            $requestHeader .= "Content-Type: application/x-www-form-urlencoded\r\n";
-            
-            // Specify the custom cookies
-            if ($this->useCookie && $cookieString != '')
-            {
-                $requestHeader.= "Cookie: " . $cookieString . "\r\n";
-            }
-
-            // POST method configuration
-            if ($this->method == "POST")
-            {
-                $requestHeader.= "Content-Length: " . strlen($queryString) . "\r\n";
-            }
-            
-            // Specify the referrer
-            if ($this->referrer != '')
-            {
-                $requestHeader.= "Referer: " . $this->referrer . "\r\n";
-            }
-            
-            // Specify http authentication (basic)
-            if ($this->username && $this->password)
-            {
-                $requestHeader.= "Authorization: Basic " . base64_encode($this->username . ':' . $this->password) . "\r\n";
-            }
-       
-            $requestHeader.= "Connection: close\r\n\r\n";
-       
-            // POST method configuration
-            if ($this->method == "POST")
-            {
-                $requestHeader .= $queryString;
-            }           
-
-            // We're ready to launch
-            fwrite($filePointer, $requestHeader);
-       
-            // Clean the slate
-            $responseHeader = '';
-            $responseContent = '';
-
-            // 3...2...1...Launch !
-            do
-            {
-                $responseHeader .= fread($filePointer, 1);
-            }
-            while (!preg_match('/\\r\\n\\r\\n$/', $responseHeader));
-            
-            // Parse the headers
-            $this->_parseHeaders($responseHeader);
-            
-            // Do we have a 301/302 redirect ?
-            if (($this->status == '301' || $this->status == '302') && $this->redirect == TRUE)
-            {
-                if ($this->curRedirect < $this->maxRedirect)
-                {
-                    // Let's find out the new redirect URL
-                    $newUrlParsed = parse_url($this->headers['location']);
-                    
-                    if ($newUrlParsed['host'])
-                    {
-                        $newTarget = $this->headers['location'];    
-                    }
-                    else
-                    {
-                        $newTarget = $this->schema . '://' . $this->host . '/' . $this->headers['location'];
-                    }
-                    
-                    // Reset some of the properties
-                    $this->port   = 0;
-                    $this->status = 0;
-                    $this->params = array();
-                    $this->method = 'GET';
-                    $this->referrer = $this->target;
-                    
-                    // Increase the redirect counter
-                    $this->curRedirect++;
-                    
-                    // Let's go, go, go !
-                    $this->result = $this->execute($newTarget);
-                }
-                else
-                {
-                    $this->_setError('Too many redirects.');
-                    return FALSE;
-                }
-            }
-            else
-            {
-                // Nope...so lets get the rest of the contents (non-chunked)
-                if ($this->headers['transfer-encoding'] != 'chunked')
-                {
-                    while (!feof($filePointer))
-                    {
-                        $responseContent .= fgets($filePointer, 128);
-                    }
-                }
-                else
-                {
-                    // Get the contents (chunked)
-                    while ($chunkLength = hexdec(fgets($filePointer)))
-                    {
-                        $responseContentChunk = '';
-                        $readLength = 0;
-                       
-                        while ($readLength < $chunkLength)
-                        {
-                            $responseContentChunk .= fread($filePointer, $chunkLength - $readLength);
-                            $readLength = strlen($responseContentChunk);
-                        }
-
-                        $responseContent .= $responseContentChunk;
-                        fgets($filePointer);  
-                    }
-                }
-                
-                // Store the target contents
-                $this->result = chop($responseContent);
-            }
-        }
-        
-        // There it is! We have it!! Return to base !!!
-        return $this->result;
-    }
-    
-    /** 解析 header 信息*/
-    private function _parseHeaders($responseHeader)
-    {
-        // Break up the headers
-        $headers = $responseHeader;
-        
-        // Clear the header array
-        $this->_clearHeaders();
-        
-        // Get resposne status
-        if($this->status == 0)
-        {
-            // Oooops !
-            if(!eregi($match = "^http/[0-9]+\\.[0-9]+[ \t]+([0-9]+)[ \t]*(.*)\$", $headers[0], $matches))
-            {
-                $this->_setError('Unexpected HTTP response status');
-                return FALSE;
-            }
-            
-            // Gotcha!
-            $this->status = $matches[1];
-            array_shift($headers);
-        }
-        
-        // Prepare all the other headers
-        foreach ($headers as $header)
-        {
-            // Get name and value
-            $headerName  = strtolower($this->_tokenize($header, ':'));
-            $headerValue = trim(chop($this->_tokenize("\r\n")));
-            
-            // If its already there, then add as an array. Otherwise, just keep there
-            if(isset($this->headers[$headerName]))
-            {
-                if(gettype($this->headers[$headerName]) == "string")
-                {
-                    $this->headers[$headerName] = array($this->headers[$headerName]);
-                }
-                    
-                $this->headers[$headerName][] = $headerValue;
-            }
-            else
-            {
-                $this->headers[$headerName] = $headerValue;
-            }
-        }
-            
-        // Save cookies if asked 
-        if ($this->saveCookie && isset($this->headers['set-cookie']))
-        {
-            $this->_parseCookie();
-        }
-    }
-    
-    /** 去除所有 header 信息 */
-    private function _clearHeaders()
-    {
-        $this->headers = array();
-    }
-    
-    /** 解析 COOKIE */
-    private function _parseCookie()
-    {
-        // Get the cookie header as array
-        if(gettype($this->headers['set-cookie']) == "array")
-        {
-            $cookieHeaders = $this->headers['set-cookie'];
-        }
-        else
-        {
-            $cookieHeaders = array($this->headers['set-cookie']);
-        }
-
-        // Loop through the cookies
-        for ($cookie = 0; $cookie < count($cookieHeaders); $cookie++)
-        {
-            $cookieName  = trim($this->_tokenize($cookieHeaders[$cookie], "="));
-            $cookieValue = $this->_tokenize(";");
-            
-            $urlParsed   = parse_url($this->target);
-            
-            $domain      = $urlParsed['host'];
-            $secure      = '0';
-            
-            $path        = "/";
-            $expires     = "";
-            
-            while(($name = trim(urldecode($this->_tokenize("=")))) != "")
-            {
-                $value = urldecode($this->_tokenize(";"));
-                
-                switch($name)
-                {
-                    case "path"     : $path     = $value; break;
-                    case "domain"   : $domain   = $value; break;
-                    case "secure"   : $secure   = ($value != '') ? '1' : '0'; break;
-                }
-            }
-            
-            $this->_setCookie($cookieName, $cookieValue, $expires, $path , $domain, $secure);
-        }
-    }
-    
-    /** 设置 cookie , 为下一次请求做准备 */
-    private function _setCookie($name, $value, $expires = "" , $path = "/" , $domain = "" , $secure = 0)
-    {
-        if(strlen($name) == 0)
-        {
-            return($this->_setError("No valid cookie name was specified."));
-        }
-
-        if(strlen($path) == 0 || strcmp($path[0], "/"))
-        {
-            return($this->_setError("$path is not a valid path for setting cookie $name."));
-        }
-            
-        if($domain == "" || !strpos($domain, ".", $domain[0] == "." ? 1 : 0))
-        {
-            return($this->_setError("$domain is not a valid domain for setting cookie $name."));
-        }
-        
-        $domain = strtolower($domain);
-        
-        if(!strcmp($domain[0], "."))
-        {
-            $domain = substr($domain, 1);
-        }
-            
-        $name  = $this->_encodeCookie($name, true);
-        $value = $this->_encodeCookie($value, false);
-        
-        $secure = intval($secure);
-        
-        $this->_cookies[] = array( "name"      =>  $name,
-                                   "value"     =>  $value,
-                                   "domain"    =>  $domain,
-                                   "path"      =>  $path,
-                                   "expires"   =>  $expires,
-                                   "secure"    =>  $secure
-                                 );
-    }
-    
-    /** cookie  数据集编码  */
-    private function _encodeCookie($value, $name)
-    {
-        return($name ? str_replace("=", "%25", $value) : str_replace(";", "%3B", $value));
-    }
-    
-    /** 把正确的 cookie 传输给当前请求 */
-    private function _passCookies()
-    {
-        if (is_array($this->_cookies) && count($this->_cookies) > 0)
-        {
-            $urlParsed = parse_url($this->target);
-            $tempCookies = array();
-            
-            foreach($this->_cookies as $cookie)
-            {
-                if ($this->_domainMatch($urlParsed['host'], $cookie['domain']) && (0 === strpos($urlParsed['path'], $cookie['path']))
-                    && (empty($cookie['secure']) || $urlParsed['protocol'] == 'https')) 
-                {
-                    $tempCookies[$cookie['name']][strlen($cookie['path'])] = $cookie['value'];
-                }
-            }
-            
-            // cookies with longer paths go first
-            foreach ($tempCookies as $name => $values) 
-            {
-                krsort($values);
-                foreach ($values as $value) 
-                {
-                    $this->addCookie($name, $value);
-                }
-            }
-        }
-    }
-    
-    /** 匹配域名 */
-    private function _domainMatch($requestHost, $cookieDomain)
-    {
-        if ('.' != $cookieDomain{0}) 
-        {
-            return $requestHost == $cookieDomain;
-        } 
-        elseif (substr_count($cookieDomain, '.') < 2) 
-        {
-            return false;
-        } 
-        else 
-        {
-            return substr('.'. $requestHost, - strlen($cookieDomain)) == $cookieDomain;
-        }
-    }
-    
-    /** 给当前操作做记号用的 */
-    private function _tokenize($string, $separator = '')
-    {
-        if(!strcmp($separator, ''))
-        {
-            $separator = $string;
-            $string = $this->nextToken;
-        }
-        
-        for($character = 0; $character < strlen($separator); $character++)
-        {
-            if(gettype($position = strpos($string, $separator[$character])) == "integer")
-            {
-                $found = (isset($found) ? min($found, $position) : $position);
-            }
-        }
-        
-        if(isset($found))
-        {
-            $this->nextToken = substr($string, $found + 1);
-            return(substr($string, 0, $found));
-        }
-        else
-        {
-            $this->nextToken = '';
-            return($string);
-        }
-    }
-    
-    /** 设置错误信息 */
-    private function _setError($error)
-    {
-        if ($error != '')
-        {
-            $this->error = $error;
-            return $error;
-        }
-    }
-}
-
-?>
\ No newline at end of file
diff --git a/phpQuery/phpQuery.php b/phpQuery/phpQuery.php
deleted file mode 100644
index 708b7a3..0000000
--- a/phpQuery/phpQuery.php
+++ /dev/null
@@ -1,5702 +0,0 @@
-<?php
-/**
- * phpQuery is a server-side, chainable, CSS3 selector driven
- * Document Object Model (DOM) API based on jQuery JavaScript Library.
- *
- * @version 0.9.5
- * @link http://code.google.com/p/phpquery/
- * @link http://phpquery-library.blogspot.com/
- * @link http://jquery.com/
- * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
- * @license http://www.opensource.org/licenses/mit-license.php MIT License
- * @package phpQuery
- */
-
-// class names for instanceof
-// TODO move them as class constants into phpQuery
-define('DOMDOCUMENT', 'DOMDocument');
-define('DOMELEMENT', 'DOMElement');
-define('DOMNODELIST', 'DOMNodeList');
-define('DOMNODE', 'DOMNode');
-
-/**
- * DOMEvent class.
- *
- * Based on
- * @link http://developer.mozilla.org/En/DOM:event
- * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
- * @package phpQuery
- * @todo implement ArrayAccess ?
- */
-class DOMEvent {
-	/**
-	 * Returns a boolean indicating whether the event bubbles up through the DOM or not.
-	 *
-	 * @var unknown_type
-	 */
-	public $bubbles = true;
-	/**
-	 * Returns a boolean indicating whether the event is cancelable.
-	 *
-	 * @var unknown_type
-	 */
-	public $cancelable = true;
-	/**
-	 * Returns a reference to the currently registered target for the event.
-	 *
-	 * @var unknown_type
-	 */
-	public $currentTarget;
-	/**
-	 * Returns detail about the event, depending on the type of event.
-	 *
-	 * @var unknown_type
-	 * @link http://developer.mozilla.org/en/DOM/event.detail
-	 */
-	public $detail;	// ???
-	/**
-	 * Used to indicate which phase of the event flow is currently being evaluated.
-	 *
-	 * NOT IMPLEMENTED
-	 *
-	 * @var unknown_type
-	 * @link http://developer.mozilla.org/en/DOM/event.eventPhase
-	 */
-	public $eventPhase;	// ???
-	/**
-	 * The explicit original target of the event (Mozilla-specific).
-	 *
-	 * NOT IMPLEMENTED
-	 *
-	 * @var unknown_type
-	 */
-	public $explicitOriginalTarget; // moz only
-	/**
-	 * The original target of the event, before any retargetings (Mozilla-specific).
-	 *
-	 * NOT IMPLEMENTED
-	 *
-	 * @var unknown_type
-	 */
-	public $originalTarget;	// moz only
-	/**
-	 * Identifies a secondary target for the event.
-	 *
-	 * @var unknown_type
-	 */
-	public $relatedTarget;
-	/**
-	 * Returns a reference to the target to which the event was originally dispatched.
-	 *
-	 * @var unknown_type
-	 */
-	public $target;
-	/**
-	 * Returns the time that the event was created.
-	 *
-	 * @var unknown_type
-	 */
-	public $timeStamp;
-	/**
-	 * Returns the name of the event (case-insensitive).
-	 */
-	public $type;
-	public $runDefault = true;
-	public $data = null;
-	public function __construct($data) {
-		foreach($data as $k => $v) {
-			$this->$k = $v;
-		}
-		if (! $this->timeStamp)
-			$this->timeStamp = time();
-	}
-	/**
-	 * Cancels the event (if it is cancelable).
-	 *
-	 */
-	public function preventDefault() {
-		$this->runDefault = false;
-	}
-	/**
-	 * Stops the propagation of events further along in the DOM.
-	 *
-	 */
-	public function stopPropagation() {
-		$this->bubbles = false;
-	}
-}
-
-
-/**
- * DOMDocumentWrapper class simplifies work with DOMDocument.
- *
- * Know bug:
- * - in XHTML fragments, <br /> changes to <br clear="none" />
- *
- * @todo check XML catalogs compatibility
- * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
- * @package phpQuery
- */
-class DOMDocumentWrapper {
-	/**
-	 * @var DOMDocument
-	 */
-	public $document;
-	public $id;
-	/**
-	 * @todo Rewrite as method and quess if null.
-	 * @var unknown_type
-	 */
-	public $contentType = '';
-	public $xpath;
-	public $uuid = 0;
-	public $data = array();
-	public $dataNodes = array();
-	public $events = array();
-	public $eventsNodes = array();
-	public $eventsGlobal = array();
-	/**
-	 * @TODO iframes support http://code.google.com/p/phpquery/issues/detail?id=28
-	 * @var unknown_type
-	 */
-	public $frames = array();
-	/**
-	 * Document root, by default equals to document itself.
-	 * Used by documentFragments.
-	 *
-	 * @var DOMNode
-	 */
-	public $root;
-	public $isDocumentFragment;
-	public $isXML = false;
-	public $isXHTML = false;
-	public $isHTML = false;
-	public $charset;
-	public function __construct($markup = null, $contentType = null, $newDocumentID = null) {
-		if (isset($markup))
-			$this->load($markup, $contentType, $newDocumentID);
-		$this->id = $newDocumentID
-			? $newDocumentID
-			: md5(microtime());
-	}
-	public function load($markup, $contentType = null, $newDocumentID = null) {
-//		phpQuery::$documents[$id] = $this;
-		$this->contentType = strtolower($contentType);
-		if ($markup instanceof DOMDOCUMENT) {
-			$this->document = $markup;
-			$this->root = $this->document;
-			$this->charset = $this->document->encoding;
-			// TODO isDocumentFragment
-		} else {
-			$loaded = $this->loadMarkup($markup);
-		}
-		if ($loaded) {
-//			$this->document->formatOutput = true;
-			$this->document->preserveWhiteSpace = true;
-			$this->xpath = new DOMXPath($this->document);
-			$this->afterMarkupLoad();
-			return true;
-			// remember last loaded document
-//			return phpQuery::selectDocument($id);
-		}
-		return false;
-	}
-	protected function afterMarkupLoad() {
-		if ($this->isXHTML) {
-			$this->xpath->registerNamespace("html", "http://www.w3.org/1999/xhtml");
-		}
-	}
-	protected function loadMarkup($markup) {
-		$loaded = false;
-		if ($this->contentType) {
-			self::debug("Load markup for content type {$this->contentType}");
-			// content determined by contentType
-			list($contentType, $charset) = $this->contentTypeToArray($this->contentType);
-			switch($contentType) {
-				case 'text/html':
-					phpQuery::debug("Loading HTML, content type '{$this->contentType}'");
-					$loaded = $this->loadMarkupHTML($markup, $charset);
-				break;
-				case 'text/xml':
-				case 'application/xhtml+xml':
-					phpQuery::debug("Loading XML, content type '{$this->contentType}'");
-					$loaded = $this->loadMarkupXML($markup, $charset);
-				break;
-				default:
-					// for feeds or anything that sometimes doesn't use text/xml
-					if (strpos('xml', $this->contentType) !== false) {
-						phpQuery::debug("Loading XML, content type '{$this->contentType}'");
-						$loaded = $this->loadMarkupXML($markup, $charset);
-					} else
-						phpQuery::debug("Could not determine document type from content type '{$this->contentType}'");
-			}
-		} else {
-			// content type autodetection
-			if ($this->isXML($markup)) {
-				phpQuery::debug("Loading XML, isXML() == true");
-				$loaded = $this->loadMarkupXML($markup);
-				if (! $loaded && $this->isXHTML) {
-					phpQuery::debug('Loading as XML failed, trying to load as HTML, isXHTML == true');
-					$loaded = $this->loadMarkupHTML($markup);
-				}
-			} else {
-				phpQuery::debug("Loading HTML, isXML() == false");
-				$loaded = $this->loadMarkupHTML($markup);
-			}
-		}
-		return $loaded;
-	}
-	protected function loadMarkupReset() {
-		$this->isXML = $this->isXHTML = $this->isHTML = false;
-	}
-	protected function documentCreate($charset, $version = '1.0') {
-		if (! $version)
-			$version = '1.0';
-		$this->document = new DOMDocument($version, $charset);
-		$this->charset = $this->document->encoding;
-//		$this->document->encoding = $charset;
-		$this->document->formatOutput = true;
-		$this->document->preserveWhiteSpace = true;
-	}
-	protected function loadMarkupHTML($markup, $requestedCharset = null) {
-		if (phpQuery::$debug)
-			phpQuery::debug('Full markup load (HTML): '.substr($markup, 0, 250));
-		$this->loadMarkupReset();
-		$this->isHTML = true;
-		if (!isset($this->isDocumentFragment))
-			$this->isDocumentFragment = self::isDocumentFragmentHTML($markup);
-		$charset = null;
-		$documentCharset = $this->charsetFromHTML($markup);
-		$addDocumentCharset = false;
-		if ($documentCharset) {
-			$charset = $documentCharset;
-			$markup = $this->charsetFixHTML($markup);
-		} else if ($requestedCharset) {
-			$charset = $requestedCharset;
-		}
-		if (! $charset)
-			$charset = phpQuery::$defaultCharset;
-		// HTTP 1.1 says that the default charset is ISO-8859-1
-		// @see http://www.w3.org/International/O-HTTP-charset
-		if (! $documentCharset) {
-			$documentCharset = 'ISO-8859-1';
-			$addDocumentCharset = true;	
-		}
-		// Should be careful here, still need 'magic encoding detection' since lots of pages have other 'default encoding'
-		// Worse, some pages can have mixed encodings... we'll try not to worry about that
-		$requestedCharset = strtoupper($requestedCharset);
-		$documentCharset = strtoupper($documentCharset);
-		phpQuery::debug("DOC: $documentCharset REQ: $requestedCharset");
-		if ($requestedCharset && $documentCharset && $requestedCharset !== $documentCharset) {
-			phpQuery::debug("CHARSET CONVERT");
-			// Document Encoding Conversion
-			// http://code.google.com/p/phpquery/issues/detail?id=86
-			if (function_exists('mb_detect_encoding')) {
-				$possibleCharsets = array($documentCharset, $requestedCharset, 'AUTO');
-				$docEncoding = mb_detect_encoding($markup, implode(', ', $possibleCharsets));
-				if (! $docEncoding)
-					$docEncoding = $documentCharset; // ok trust the document
-				phpQuery::debug("DETECTED '$docEncoding'");
-				// Detected does not match what document says...
-				if ($docEncoding !== $documentCharset) {
-					// Tricky..
-				}
-				if ($docEncoding !== $requestedCharset) {
-					phpQuery::debug("CONVERT $docEncoding => $requestedCharset");
-					$markup = mb_convert_encoding($markup, $requestedCharset, $docEncoding);
-					$markup = $this->charsetAppendToHTML($markup, $requestedCharset);
-					$charset = $requestedCharset;
-				}
-			} else {
-				phpQuery::debug("TODO: charset conversion without mbstring...");
-			}
-		}
-		$return = false;
-		if ($this->isDocumentFragment) {
-			phpQuery::debug("Full markup load (HTML), DocumentFragment detected, using charset '$charset'");
-			$return = $this->documentFragmentLoadMarkup($this, $charset, $markup);
-		} else {
-			if ($addDocumentCharset) {
-				phpQuery::debug("Full markup load (HTML), appending charset: '$charset'");
-				$markup = $this->charsetAppendToHTML($markup, $charset);
-			}
-			phpQuery::debug("Full markup load (HTML), documentCreate('$charset')");
-			$this->documentCreate($charset);
-			$return = phpQuery::$debug === 2
-				? $this->document->loadHTML($markup)
-				: @$this->document->loadHTML($markup);
-			if ($return)
-				$this->root = $this->document;
-		}
-		if ($return && ! $this->contentType)
-			$this->contentType = 'text/html';
-		return $return;
-	}
-	protected function loadMarkupXML($markup, $requestedCharset = null) {
-		if (phpQuery::$debug)
-			phpQuery::debug('Full markup load (XML): '.substr($markup, 0, 250));
-		$this->loadMarkupReset();
-		$this->isXML = true;
-		// check agains XHTML in contentType or markup
-		$isContentTypeXHTML = $this->isXHTML();
-		$isMarkupXHTML = $this->isXHTML($markup);
-		if ($isContentTypeXHTML || $isMarkupXHTML) {
-			self::debug('Full markup load (XML), XHTML detected');
-			$this->isXHTML = true;
-		}
-		// determine document fragment
-		if (! isset($this->isDocumentFragment))
-			$this->isDocumentFragment = $this->isXHTML
-				? self::isDocumentFragmentXHTML($markup)
-				: self::isDocumentFragmentXML($markup);
-		// this charset will be used
-		$charset = null;
-		// charset from XML declaration @var string
-		$documentCharset = $this->charsetFromXML($markup);
-		if (! $documentCharset) {
-			if ($this->isXHTML) {
-				// this is XHTML, try to get charset from content-type meta header
-				$documentCharset = $this->charsetFromHTML($markup);
-				if ($documentCharset) {
-					phpQuery::debug("Full markup load (XML), appending XHTML charset '$documentCharset'");
-					$this->charsetAppendToXML($markup, $documentCharset);
-					$charset = $documentCharset;
-				}
-			}
-			if (! $documentCharset) {
-				// if still no document charset...
-				$charset = $requestedCharset;
-			}
-		} else if ($requestedCharset) {
-			$charset = $requestedCharset;
-		}
-		if (! $charset) {
-			$charset = phpQuery::$defaultCharset;
-		}
-		if ($requestedCharset && $documentCharset && $requestedCharset != $documentCharset) {
-			// TODO place for charset conversion
-//			$charset = $requestedCharset;
-		}
-		$return = false;
-		if ($this->isDocumentFragment) {
-			phpQuery::debug("Full markup load (XML), DocumentFragment detected, using charset '$charset'");
-			$return = $this->documentFragmentLoadMarkup($this, $charset, $markup);
-		} else {
-			// FIXME ???
-			if ($isContentTypeXHTML && ! $isMarkupXHTML)
-			if (! $documentCharset) {
-				phpQuery::debug("Full markup load (XML), appending charset '$charset'");
-				$markup = $this->charsetAppendToXML($markup, $charset);
-			}
-			// see http://pl2.php.net/manual/en/book.dom.php#78929
-			// LIBXML_DTDLOAD (>= PHP 5.1)
-			// does XML ctalogues works with LIBXML_NONET
-	//		$this->document->resolveExternals = true;
-			// TODO test LIBXML_COMPACT for performance improvement
-			// create document
-			$this->documentCreate($charset);
-			if (phpversion() < 5.1) {
-				$this->document->resolveExternals = true;
-				$return = phpQuery::$debug === 2
-					? $this->document->loadXML($markup)
-					: @$this->document->loadXML($markup);
-			} else {
-				/** @link http://pl2.php.net/manual/en/libxml.constants.php */
-				$libxmlStatic = phpQuery::$debug === 2
-					? LIBXML_DTDLOAD|LIBXML_DTDATTR|LIBXML_NONET
-					: LIBXML_DTDLOAD|LIBXML_DTDATTR|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOERROR;
-				$return = $this->document->loadXML($markup, $libxmlStatic);
-// 				if (! $return)
-// 					$return = $this->document->loadHTML($markup);
-			}
-			if ($return)
-				$this->root = $this->document;
-		}
-		if ($return) {
-			if (! $this->contentType) {
-				if ($this->isXHTML)
-					$this->contentType = 'application/xhtml+xml';
-				else
-					$this->contentType = 'text/xml';
-			}
-			return $return;
-		} else {
-			throw new Exception("Error loading XML markup");
-		}
-	}
-	protected function isXHTML($markup = null) {
-		if (! isset($markup)) {
-			return strpos($this->contentType, 'xhtml') !== false;
-		}
-		// XXX ok ?
-		return strpos($markup, "<!DOCTYPE html") !== false;
-//		return stripos($doctype, 'xhtml') !== false;
-//		$doctype = isset($dom->doctype) && is_object($dom->doctype)
-//			? $dom->doctype->publicId
-//			: self::$defaultDoctype;
-	}
-	protected function isXML($markup) {
-//		return strpos($markup, '<?xml') !== false && stripos($markup, 'xhtml') === false;
-		return strpos(substr($markup, 0, 100), '<'.'?xml') !== false;
-	}
-	protected function contentTypeToArray($contentType) {
-		$matches = explode(';', trim(strtolower($contentType)));
-		if (isset($matches[1])) {
-			$matches[1] = explode('=', $matches[1]);
-			// strip 'charset='
-			$matches[1] = isset($matches[1][1]) && trim($matches[1][1])
-				? $matches[1][1]
-				: $matches[1][0];
-		} else
-			$matches[1] = null;
-		return $matches;
-	}
-	/**
-	 *
-	 * @param $markup
-	 * @return array contentType, charset
-	 */
-	protected function contentTypeFromHTML($markup) {
-		$matches = array();
-		// find meta tag
-		preg_match('@<meta[^>]+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i',
-			$markup, $matches
-		);
-		if (! isset($matches[0]))
-			return array(null, null);
-		// get attr 'content'
-		preg_match('@content\\s*=\\s*(["|\'])(.+?)\\1@', $matches[0], $matches);
-		if (! isset($matches[0]))
-			return array(null, null);
-		return $this->contentTypeToArray($matches[2]);
-	}
-	protected function charsetFromHTML($markup) {
-		$contentType = $this->contentTypeFromHTML($markup);
-		return $contentType[1];
-	}
-	protected function charsetFromXML($markup) {
-		$matches;
-		// find declaration
-		preg_match('@<'.'?xml[^>]+encoding\\s*=\\s*(["|\'])(.*?)\\1@i',
-			$markup, $matches
-		);
-		return isset($matches[2])
-			? strtolower($matches[2])
-			: null;
-	}
-	/**
-	 * Repositions meta[type=charset] at the start of head. Bypasses DOMDocument bug.
-	 *
-	 * @link http://code.google.com/p/phpquery/issues/detail?id=80
-	 * @param $html
-	 */
-	protected function charsetFixHTML($markup) {
-		$matches = array();
-		// find meta tag
-		preg_match('@\s*<meta[^>]+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i',
-			$markup, $matches, PREG_OFFSET_CAPTURE
-		);
-		if (! isset($matches[0]))
-			return;
-		$metaContentType = $matches[0][0];
-		$markup = substr($markup, 0, $matches[0][1])
-			.substr($markup, $matches[0][1]+strlen($metaContentType));
-		$headStart = stripos($markup, '<head>');
-		$markup = substr($markup, 0, $headStart+6).$metaContentType
-			.substr($markup, $headStart+6);
-		return $markup;
-	}
-	protected function charsetAppendToHTML($html, $charset, $xhtml = false) {
-		// remove existing meta[type=content-type]
-		$html = preg_replace('@\s*<meta[^>]+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i', '', $html);
-		$meta = '<meta http-equiv="Content-Type" content="text/html;charset='
-			.$charset.'" '
-			.($xhtml ? '/' : '')
-			.'>';
-		if (strpos($html, '<head') === false) {
-			if (strpos($hltml, '<html') === false) {
-				return $meta.$html;
-			} else {
-				return preg_replace(
-					'@<html(.*?)(?(?<!\?)>)@s',
-					"<html\\1><head>{$meta}</head>",
-					$html
-				);
-			}
-		} else {
-			return preg_replace(
-				'@<head(.*?)(?(?<!\?)>)@s',
-				'<head\\1>'.$meta,
-				$html
-			);
-		}
-	}
-	protected function charsetAppendToXML($markup, $charset) {
-		$declaration = '<'.'?xml version="1.0" encoding="'.$charset.'"?'.'>';
-		return $declaration.$markup;
-	}
-	public static function isDocumentFragmentHTML($markup) {
-		return stripos($markup, '<html') === false && stripos($markup, '<!doctype') === false;
-	}
-	public static function isDocumentFragmentXML($markup) {
-		return stripos($markup, '<'.'?xml') === false;
-	}
-	public static function isDocumentFragmentXHTML($markup) {
-		return self::isDocumentFragmentHTML($markup);
-	}
-	public function importAttr($value) {
-		// TODO
-	}
-	/**
-	 *
-	 * @param $source
-	 * @param $target
-	 * @param $sourceCharset
-	 * @return array Array of imported nodes.
-	 */
-	public function import($source, $sourceCharset = null) {
-		// TODO charset conversions
-		$return = array();
-		if ($source instanceof DOMNODE && !($source instanceof DOMNODELIST))
-			$source = array($source);
-//		if (is_array($source)) {
-//			foreach($source as $node) {
-//				if (is_string($node)) {
-//					// string markup
-//					$fake = $this->documentFragmentCreate($node, $sourceCharset);
-//					if ($fake === false)
-//						throw new Exception("Error loading documentFragment markup");
-//					else
-//						$return = array_merge($return, 
-//							$this->import($fake->root->childNodes)
-//						);
-//				} else {
-//					$return[] = $this->document->importNode($node, true);
-//				}
-//			}
-//			return $return;
-//		} else {
-//			// string markup
-//			$fake = $this->documentFragmentCreate($source, $sourceCharset);
-//			if ($fake === false)
-//				throw new Exception("Error loading documentFragment markup");
-//			else
-//				return $this->import($fake->root->childNodes);
-//		}
-		if (is_array($source) || $source instanceof DOMNODELIST) {
-			// dom nodes
-			self::debug('Importing nodes to document');
-			foreach($source as $node)
-				$return[] = $this->document->importNode($node, true);
-		} else {
-			// string markup
-			$fake = $this->documentFragmentCreate($source, $sourceCharset);
-			if ($fake === false)
-				throw new Exception("Error loading documentFragment markup");
-			else
-				return $this->import($fake->root->childNodes);
-		}
-		return $return;
-	}
-	/**
-	 * Creates new document fragment.
-	 *
-	 * @param $source
-	 * @return DOMDocumentWrapper
-	 */
-	protected function documentFragmentCreate($source, $charset = null) {
-		$fake = new DOMDocumentWrapper();
-		$fake->contentType = $this->contentType;
-		$fake->isXML = $this->isXML;
-		$fake->isHTML = $this->isHTML;
-		$fake->isXHTML = $this->isXHTML;
-		$fake->root = $fake->document;
-		if (! $charset)
-			$charset = $this->charset;
-//	$fake->documentCreate($this->charset);
-		if ($source instanceof DOMNODE && !($source instanceof DOMNODELIST))
-			$source = array($source);
-		if (is_array($source) || $source instanceof DOMNODELIST) {
-			// dom nodes
-			// load fake document
-			if (! $this->documentFragmentLoadMarkup($fake, $charset))
-				return false;
-			$nodes = $fake->import($source);
-			foreach($nodes as $node)
-				$fake->root->appendChild($node);
-		} else {
-			// string markup
-			$this->documentFragmentLoadMarkup($fake, $charset, $source);
-		}
-		return $fake;
-	}
-	/**
-	 *
-	 * @param $document DOMDocumentWrapper
-	 * @param $markup
-	 * @return $document
-	 */
-	private function documentFragmentLoadMarkup($fragment, $charset, $markup = null) {
-		// TODO error handling
-		// TODO copy doctype
-		// tempolary turn off
-		$fragment->isDocumentFragment = false;
-		if ($fragment->isXML) {
-			if ($fragment->isXHTML) {
-				// add FAKE element to set default namespace
-				$fragment->loadMarkupXML('<?xml version="1.0" encoding="'.$charset.'"?>'
-					.'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" '
-					.'"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
-					.'<fake xmlns="http://www.w3.org/1999/xhtml">'.$markup.'</fake>');
-				$fragment->root = $fragment->document->firstChild->nextSibling;
-			} else {
-				$fragment->loadMarkupXML('<?xml version="1.0" encoding="'.$charset.'"?><fake>'.$markup.'</fake>');
-				$fragment->root = $fragment->document->firstChild;
-			}
-		} else {
-			$markup2 = phpQuery::$defaultDoctype.'<html><head><meta http-equiv="Content-Type" content="text/html;charset='
-				.$charset.'"></head>';
-			$noBody = strpos($markup, '<body') === false;
-			if ($noBody)
-				$markup2 .= '<body>';
-			$markup2 .= $markup;
-			if ($noBody)
-				$markup2 .= '</body>';
-			$markup2 .= '</html>';
-			$fragment->loadMarkupHTML($markup2);
-			// TODO resolv body tag merging issue
-			$fragment->root = $noBody
-				? $fragment->document->firstChild->nextSibling->firstChild->nextSibling
-				: $fragment->document->firstChild->nextSibling->firstChild->nextSibling;
-		}
-		if (! $fragment->root)
-			return false;
-		$fragment->isDocumentFragment = true;
-		return true;
-	}
-	protected function documentFragmentToMarkup($fragment) {
-		phpQuery::debug('documentFragmentToMarkup');
-		$tmp = $fragment->isDocumentFragment;
-		$fragment->isDocumentFragment = false;
-		$markup = $fragment->markup();
-		if ($fragment->isXML) {
-			$markup = substr($markup, 0, strrpos($markup, '</fake>'));
-			if ($fragment->isXHTML) {
-				$markup = substr($markup, strpos($markup, '<fake')+43);
-			} else {
-				$markup = substr($markup, strpos($markup, '<fake>')+6);
-			}
-		} else {
-				$markup = substr($markup, strpos($markup, '<body>')+6);
-				$markup = substr($markup, 0, strrpos($markup, '</body>'));
-		}
-		$fragment->isDocumentFragment = $tmp;
-		if (phpQuery::$debug)
-			phpQuery::debug('documentFragmentToMarkup: '.substr($markup, 0, 150));
-		return $markup;
-	}
-	/**
-	 * Return document markup, starting with optional $nodes as root.
-	 *
-	 * @param $nodes	DOMNode|DOMNodeList
-	 * @return string
-	 */
-	public function markup($nodes = null, $innerMarkup = false) {
-		if (isset($nodes) && count($nodes) == 1 && $nodes[0] instanceof DOMDOCUMENT)
-			$nodes = null;
-		if (isset($nodes)) {
-			$markup = '';
-			if (!is_array($nodes) && !($nodes instanceof DOMNODELIST) )
-				$nodes = array($nodes);
-			if ($this->isDocumentFragment && ! $innerMarkup)
-				foreach($nodes as $i => $node)
-					if ($node->isSameNode($this->root)) {
-					//	var_dump($node);
-						$nodes = array_slice($nodes, 0, $i)
-							+ phpQuery::DOMNodeListToArray($node->childNodes)
-							+ array_slice($nodes, $i+1);
-						}
-			if ($this->isXML && ! $innerMarkup) {
-				self::debug("Getting outerXML with charset '{$this->charset}'");
-				// we need outerXML, so we can benefit from
-				// $node param support in saveXML()
-				foreach($nodes as $node)
-					$markup .= $this->document->saveXML($node);
-			} else {
-				$loop = array();
-				if ($innerMarkup)
-					foreach($nodes as $node) {
-						if ($node->childNodes)
-							foreach($node->childNodes as $child)
-								$loop[] = $child;
-						else
-							$loop[] = $node;
-					}
-				else
-					$loop = $nodes;
-				self::debug("Getting markup, moving selected nodes (".count($loop).") to new DocumentFragment");
-				$fake = $this->documentFragmentCreate($loop);
-				$markup = $this->documentFragmentToMarkup($fake);
-			}
-			if ($this->isXHTML) {
-				self::debug("Fixing XHTML");
-				$markup = self::markupFixXHTML($markup);
-			}
-			self::debug("Markup: ".substr($markup, 0, 250));
-			return $markup;
-		} else {
-			if ($this->isDocumentFragment) {
-				// documentFragment, html only...
-				self::debug("Getting markup, DocumentFragment detected");
-//				return $this->markup(
-////					$this->document->getElementsByTagName('body')->item(0)
-//					$this->document->root, true
-//				);
-				$markup = $this->documentFragmentToMarkup($this);
-				// no need for markupFixXHTML, as it's done thought markup($nodes) method
-				return $markup;
-			} else {
-				self::debug("Getting markup (".($this->isXML?'XML':'HTML')."), final with charset '{$this->charset}'");
-				$markup = $this->isXML
-					? $this->document->saveXML()
-					: $this->document->saveHTML();
-				if ($this->isXHTML) {
-					self::debug("Fixing XHTML");
-					$markup = self::markupFixXHTML($markup);
-				}
-				self::debug("Markup: ".substr($markup, 0, 250));
-				return $markup;
-			}
-		}
-	}
-	protected static function markupFixXHTML($markup) {
-		$markup = self::expandEmptyTag('script', $markup);
-		$markup = self::expandEmptyTag('select', $markup);
-		$markup = self::expandEmptyTag('textarea', $markup);
-		return $markup;
-	}
-	public static function debug($text) {
-		phpQuery::debug($text);
-	}
-	/**
-	 * expandEmptyTag
-	 *
-	 * @param $tag
-	 * @param $xml
-	 * @return unknown_type
-	 * @author mjaque at ilkebenson dot com
-	 * @link http://php.net/manual/en/domdocument.savehtml.php#81256
-	 */
-	public static function expandEmptyTag($tag, $xml){
-        $indice = 0;
-        while ($indice< strlen($xml)){
-            $pos = strpos($xml, "<$tag ", $indice);
-            if ($pos){
-                $posCierre = strpos($xml, ">", $pos);
-                if ($xml[$posCierre-1] == "/"){
-                    $xml = substr_replace($xml, "></$tag>", $posCierre-1, 2);
-                }
-                $indice = $posCierre;
-            }
-            else break;
-        }
-        return $xml;
-	}
-}
-
-/**
- * Event handling class.
- *
- * @author Tobiasz Cudnik
- * @package phpQuery
- * @static
- */
-abstract class phpQueryEvents {
-	/**
-	 * Trigger a type of event on every matched element.
-	 *
-	 * @param DOMNode|phpQueryObject|string $document
-	 * @param unknown_type $type
-	 * @param unknown_type $data
-	 *
-	 * @TODO exclusive events (with !)
-	 * @TODO global events (test)
-	 * @TODO support more than event in $type (space-separated)
-	 */
-	public static function trigger($document, $type, $data = array(), $node = null) {
-		// trigger: function(type, data, elem, donative, extra) {
-		$documentID = phpQuery::getDocumentID($document);
-		$namespace = null;
-		if (strpos($type, '.') !== false)
-			list($name, $namespace) = explode('.', $type);
-		else
-			$name = $type;
-		if (! $node) {
-			if (self::issetGlobal($documentID, $type)) {
-				$pq = phpQuery::getDocument($documentID);
-				// TODO check add($pq->document)
-				$pq->find('*')->add($pq->document)
-					->trigger($type, $data);
-			}
-		} else {
-			if (isset($data[0]) && $data[0] instanceof DOMEvent) {
-				$event = $data[0];
-				$event->relatedTarget = $event->target;
-				$event->target = $node;
-				$data = array_slice($data, 1);
-			} else {
-				$event = new DOMEvent(array(
-					'type' => $type,
-					'target' => $node,
-					'timeStamp' => time(),
-				));
-			}
-			$i = 0;
-			while($node) {
-				// TODO whois
-				phpQuery::debug("Triggering ".($i?"bubbled ":'')."event '{$type}' on "
-					."node \n");//.phpQueryObject::whois($node)."\n");
-				$event->currentTarget = $node;
-				$eventNode = self::getNode($documentID, $node);
-				if (isset($eventNode->eventHandlers)) {
-					foreach($eventNode->eventHandlers as $eventType => $handlers) {
-						$eventNamespace = null;
-						if (strpos($type, '.') !== false)
-							list($eventName, $eventNamespace) = explode('.', $eventType);
-						else
-							$eventName = $eventType;
-						if ($name != $eventName)
-							continue;
-						if ($namespace && $eventNamespace && $namespace != $eventNamespace)
-							continue;
-						foreach($handlers as $handler) {
-							phpQuery::debug("Calling event handler\n");
-							$event->data = $handler['data']
-								? $handler['data']
-								: null;
-							$params = array_merge(array($event), $data);
-							$return = phpQuery::callbackRun($handler['callback'], $params);
-							if ($return === false) {
-								$event->bubbles = false;
-							}
-						}
-					}
-				}
-				// to bubble or not to bubble...
-				if (! $event->bubbles)
-					break;
-				$node = $node->parentNode;
-				$i++;
-			}
-		}
-	}
-	/**
-	 * Binds a handler to one or more events (like click) for each matched element.
-	 * Can also bind custom events.
-	 *
-	 * @param DOMNode|phpQueryObject|string $document
-	 * @param unknown_type $type
-	 * @param unknown_type $data Optional
-	 * @param unknown_type $callback
-	 *
-	 * @TODO support '!' (exclusive) events
-	 * @TODO support more than event in $type (space-separated)
-	 * @TODO support binding to global events
-	 */
-	public static function add($document, $node, $type, $data, $callback = null) {
-		phpQuery::debug("Binding '$type' event");
-		$documentID = phpQuery::getDocumentID($document);
-//		if (is_null($callback) && is_callable($data)) {
-//			$callback = $data;
-//			$data = null;
-//		}
-		$eventNode = self::getNode($documentID, $node);
-		if (! $eventNode)
-			$eventNode = self::setNode($documentID, $node);
-		if (!isset($eventNode->eventHandlers[$type]))
-			$eventNode->eventHandlers[$type] = array();
-		$eventNode->eventHandlers[$type][] = array(
-			'callback' => $callback,
-			'data' => $data,
-		);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param DOMNode|phpQueryObject|string $document
-	 * @param unknown_type $type
-	 * @param unknown_type $callback
-	 *
-	 * @TODO namespace events
-	 * @TODO support more than event in $type (space-separated)
-	 */
-	public static function remove($document, $node, $type = null, $callback = null) {
-		$documentID = phpQuery::getDocumentID($document);
-		$eventNode = self::getNode($documentID, $node);
-		if (is_object($eventNode) && isset($eventNode->eventHandlers[$type])) {
-			if ($callback) {
-				foreach($eventNode->eventHandlers[$type] as $k => $handler)
-					if ($handler['callback'] == $callback)
-						unset($eventNode->eventHandlers[$type][$k]);
-			} else {
-				unset($eventNode->eventHandlers[$type]);
-			}
-		}
-	}
-	protected static function getNode($documentID, $node) {
-		foreach(phpQuery::$documents[$documentID]->eventsNodes as $eventNode) {
-			if ($node->isSameNode($eventNode))
-				return $eventNode;
-		}
-	}
-	protected static function setNode($documentID, $node) {
-		phpQuery::$documents[$documentID]->eventsNodes[] = $node;
-		return phpQuery::$documents[$documentID]->eventsNodes[
-			count(phpQuery::$documents[$documentID]->eventsNodes)-1
-		];
-	}
-	protected static function issetGlobal($documentID, $type) {
-		return isset(phpQuery::$documents[$documentID])
-			? in_array($type, phpQuery::$documents[$documentID]->eventsGlobal)
-			: false;
-	}
-}
-
-
-interface ICallbackNamed {
-	function hasName();
-	function getName();
-}
-/**
- * Callback class introduces currying-like pattern.
- * 
- * Example:
- * function foo($param1, $param2, $param3) {
- *   var_dump($param1, $param2, $param3);
- * }
- * $fooCurried = new Callback('foo', 
- *   'param1 is now statically set', 
- *   new CallbackParam, new CallbackParam
- * );
- * phpQuery::callbackRun($fooCurried,
- * 	array('param2 value', 'param3 value'
- * );
- * 
- * Callback class is supported in all phpQuery methods which accepts callbacks. 
- *
- * @link http://code.google.com/p/phpquery/wiki/Callbacks#Param_Structures
- * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
- * 
- * @TODO??? return fake forwarding function created via create_function
- * @TODO honor paramStructure
- */
-class Callback
-	implements ICallbackNamed {
-	public $callback = null;
-	public $params = null;
-	protected $name;
-	public function __construct($callback, $param1 = null, $param2 = null, 
-			$param3 = null) {
-		$params = func_get_args();
-		$params = array_slice($params, 1);
-		if ($callback instanceof Callback) {
-			// TODO implement recurention
-		} else {
-			$this->callback = $callback;
-			$this->params = $params;
-		}
-	}
-	public function getName() {
-		return 'Callback: '.$this->name;
-	}
-	public function hasName() {
-		return isset($this->name) && $this->name;
-	}
-	public function setName($name) {
-		$this->name = $name;
-		return $this;
-	}
-	// TODO test me
-//	public function addParams() {
-//		$params = func_get_args();
-//		return new Callback($this->callback, $this->params+$params);
-//	}
-}
-/**
- * Shorthand for new Callback(create_function(...), ...);
- * 
- * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
- */
-class CallbackBody extends Callback {
-	public function __construct($paramList, $code, $param1 = null, $param2 = null, 
-			$param3 = null) {
-		$params = func_get_args();
-		$params = array_slice($params, 2);
-		$this->callback = create_function($paramList, $code);
-		$this->params = $params;
-	}
-}
-/**
- * Callback type which on execution returns reference passed during creation.
- * 
- * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
- */
-class CallbackReturnReference extends Callback
-	implements ICallbackNamed {
-	protected $reference;
-	public function __construct(&$reference, $name = null){
-		$this->reference =& $reference;
-		$this->callback = array($this, 'callback');
-	}
-	public function callback() {
-		return $this->reference;
-	}
-	public function getName() {
-		return 'Callback: '.$this->name;
-	}
-	public function hasName() {
-		return isset($this->name) && $this->name;
-	}
-}
-/**
- * Callback type which on execution returns value passed during creation.
- * 
- * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
- */
-class CallbackReturnValue extends Callback
-	implements ICallbackNamed {
-	protected $value;
-	protected $name;
-	public function __construct($value, $name = null){
-		$this->value =& $value;
-		$this->name = $name;
-		$this->callback = array($this, 'callback');
-	}
-	public function callback() {
-		return $this->value;
-	}
-	public function __toString() {
-		return $this->getName();
-	}
-	public function getName() {
-		return 'Callback: '.$this->name;
-	}
-	public function hasName() {
-		return isset($this->name) && $this->name;
-	}
-}
-/**
- * CallbackParameterToReference can be used when we don't really want a callback,
- * only parameter passed to it. CallbackParameterToReference takes first 
- * parameter's value and passes it to reference.
- *
- * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
- */
-class CallbackParameterToReference extends Callback {
-	/**
-	 * @param $reference
-	 * @TODO implement $paramIndex; 
-	 * param index choose which callback param will be passed to reference
-	 */
-	public function __construct(&$reference){
-		$this->callback =& $reference;
-	}
-}
-//class CallbackReference extends Callback {
-//	/**
-//	 *
-//	 * @param $reference
-//	 * @param $paramIndex
-//	 * @todo implement $paramIndex; param index choose which callback param will be passed to reference
-//	 */
-//	public function __construct(&$reference, $name = null){
-//		$this->callback =& $reference;
-//	}
-//}
-class CallbackParam {}
-
-/**
- * Class representing phpQuery objects.
- *
- * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
- * @package phpQuery
- * @method phpQueryObject clone() clone()
- * @method phpQueryObject empty() empty()
- * @method phpQueryObject next() next($selector = null)
- * @method phpQueryObject prev() prev($selector = null)
- * @property Int $length
- */
-class phpQueryObject
-	implements Iterator, Countable, ArrayAccess {
-	public $documentID = null;
-	/**
-	 * DOMDocument class.
-	 *
-	 * @var DOMDocument
-	 */
-	public $document = null;
-	public $charset = null;
-	/**
-	 *
-	 * @var DOMDocumentWrapper
-	 */
-	public $documentWrapper = null;
-	/**
-	 * XPath interface.
-	 *
-	 * @var DOMXPath
-	 */
-	public $xpath = null;
-	/**
-	 * Stack of selected elements.
-	 * @TODO refactor to ->nodes
-	 * @var array
-	 */
-	public $elements = array();
-	/**
-	 * @access private
-	 */
-	protected $elementsBackup = array();
-	/**
-	 * @access private
-	 */
-	protected $previous = null;
-	/**
-	 * @access private
-	 * @TODO deprecate
-	 */
-	protected $root = array();
-	/**
-	 * Indicated if doument is just a fragment (no <html> tag).
-	 *
-	 * Every document is realy a full document, so even documentFragments can
-	 * be queried against <html>, but getDocument(id)->htmlOuter() will return
-	 * only contents of <body>.
-	 *
-	 * @var bool
-	 */
-	public $documentFragment = true;
-	/**
-	 * Iterator interface helper
-	 * @access private
-	 */
-	protected $elementsInterator = array();
-	/**
-	 * Iterator interface helper
-	 * @access private
-	 */
-	protected $valid = false;
-	/**
-	 * Iterator interface helper
-	 * @access private
-	 */
-	protected $current = null;
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function __construct($documentID) {
-//		if ($documentID instanceof self)
-//			var_dump($documentID->getDocumentID());
-		$id = $documentID instanceof self
-			? $documentID->getDocumentID()
-			: $documentID;
-//		var_dump($id);
-		if (! isset(phpQuery::$documents[$id] )) {
-//			var_dump(phpQuery::$documents);
-			throw new Exception("Document with ID '{$id}' isn't loaded. Use phpQuery::newDocument(\$html) or phpQuery::newDocumentFile(\$file) first.");
-		}
-		$this->documentID = $id;
-		$this->documentWrapper =& phpQuery::$documents[$id];
-		$this->document =& $this->documentWrapper->document;
-		$this->xpath =& $this->documentWrapper->xpath;
-		$this->charset =& $this->documentWrapper->charset;
-		$this->documentFragment =& $this->documentWrapper->isDocumentFragment;
-		// TODO check $this->DOM->documentElement;
-//		$this->root = $this->document->documentElement;
-		$this->root =& $this->documentWrapper->root;
-//		$this->toRoot();
-		$this->elements = array($this->root);
-	}
-	/**
-	 *
-	 * @access private
-	 * @param $attr
-	 * @return unknown_type
-	 */
-	public function __get($attr) {
-		switch($attr) {
-			// FIXME doesnt work at all ?
-			case 'length':
-				return $this->size();
-			break;
-			default:
-				return $this->$attr;
-		}
-	}
-	/**
-	 * Saves actual object to $var by reference.
-	 * Useful when need to break chain.
-	 * @param phpQueryObject $var
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function toReference(&$var) {
-		return $var = $this;
-	}
-	public function documentFragment($state = null) {
-		if ($state) {
-			phpQuery::$documents[$this->getDocumentID()]['documentFragment'] = $state;
-			return $this;
-		}
-		return $this->documentFragment;
-	}
-	/**
-   * @access private
-   * @TODO documentWrapper
-	 */
-	protected function isRoot( $node) {
-//		return $node instanceof DOMDOCUMENT || $node->tagName == 'html';
-		return $node instanceof DOMDOCUMENT
-			|| ($node instanceof DOMELEMENT && $node->tagName == 'html')
-			|| $this->root->isSameNode($node);
-	}
-	/**
-   * @access private
-	 */
-	protected function stackIsRoot() {
-		return $this->size() == 1 && $this->isRoot($this->elements[0]);
-	}
-	/**
-	 * Enter description here...
-	 * NON JQUERY METHOD
-	 *
-	 * Watch out, it doesn't creates new instance, can be reverted with end().
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function toRoot() {
-		$this->elements = array($this->root);
-		return $this;
-//		return $this->newInstance(array($this->root));
-	}
-	/**
-	 * Saves object's DocumentID to $var by reference.
-	 * <code>
-	 * $myDocumentId;
-	 * phpQuery::newDocument('<div/>')
-	 *     ->getDocumentIDRef($myDocumentId)
-	 *     ->find('div')->...
-	 * </code>
-	 *
-	 * @param unknown_type $domId
-	 * @see phpQuery::newDocument
-	 * @see phpQuery::newDocumentFile
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function getDocumentIDRef(&$documentID) {
-		$documentID = $this->getDocumentID();
-		return $this;
-	}
-	/**
-	 * Returns object with stack set to document root.
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function getDocument() {
-		return phpQuery::getDocument($this->getDocumentID());
-	}
-	/**
-	 *
-	 * @return DOMDocument
-	 */
-	public function getDOMDocument() {
-		return $this->document;
-	}
-	/**
-	 * Get object's Document ID.
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function getDocumentID() {
-		return $this->documentID;
-	}
-	/**
-	 * Unloads whole document from memory.
-	 * CAUTION! None further operations will be possible on this document.
-	 * All objects refering to it will be useless.
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function unloadDocument() {
-		phpQuery::unloadDocuments($this->getDocumentID());
-	}
-	public function isHTML() {
-		return $this->documentWrapper->isHTML;
-	}
-	public function isXHTML() {
-		return $this->documentWrapper->isXHTML;
-	}
-	public function isXML() {
-		return $this->documentWrapper->isXML;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @link http://docs.jquery.com/Ajax/serialize
-	 * @return string
-	 */
-	public function serialize() {
-		return phpQuery::param($this->serializeArray());
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @link http://docs.jquery.com/Ajax/serializeArray
-	 * @return array
-	 */
-	public function serializeArray($submit = null) {
-		$source = $this->filter('form, input, select, textarea')
-			->find('input, select, textarea')
-			->andSelf()
-			->not('form');
-		$return = array();
-//		$source->dumpDie();
-		foreach($source as $input) {
-			$input = phpQuery::pq($input);
-			if ($input->is('[disabled]'))
-				continue;
-			if (!$input->is('[name]'))
-				continue;
-			if ($input->is('[type=checkbox]') && !$input->is('[checked]'))
-				continue;
-			// jquery diff
-			if ($submit && $input->is('[type=submit]')) {
-				if ($submit instanceof DOMELEMENT && ! $input->elements[0]->isSameNode($submit))
-					continue;
-				else if (is_string($submit) && $input->attr('name') != $submit)
-					continue;
-			}
-			$return[] = array(
-				'name' => $input->attr('name'),
-				'value' => $input->val(),
-			);
-		}
-		return $return;
-	}
-	/**
-	 * @access private
-	 */
-	protected function debug($in) {
-		if (! phpQuery::$debug )
-			return;
-		print('<pre>');
-		print_r($in);
-		// file debug
-//		file_put_contents(dirname(__FILE__).'/phpQuery.log', print_r($in, true)."\n", FILE_APPEND);
-		// quite handy debug trace
-//		if ( is_array($in))
-//			print_r(array_slice(debug_backtrace(), 3));
-		print("</pre>\n");
-	}
-	/**
-	 * @access private
-	 */
-	protected function isRegexp($pattern) {
-		return in_array(
-			$pattern[ mb_strlen($pattern)-1 ],
-			array('^','*','$')
-		);
-	}
-	/**
-	 * Determines if $char is really a char.
-	 *
-	 * @param string $char
-	 * @return bool
-	 * @todo rewrite me to charcode range ! ;)
-	 * @access private
-	 */
-	protected function isChar($char) {
-		return extension_loaded('mbstring') && phpQuery::$mbstringSupport
-			? mb_eregi('\w', $char)
-			: preg_match('@\w@', $char);
-	}
-	/**
-	 * @access private
-	 */
-	protected function parseSelector($query) {
-		// clean spaces
-		// TODO include this inside parsing ?
-		$query = trim(
-			preg_replace('@\s+@', ' ',
-				preg_replace('@\s*(>|\\+|~)\s*@', '\\1', $query)
-			)
-		);
-		$queries = array(array());
-		if (! $query)
-			return $queries;
-		$return =& $queries[0];
-		$specialChars = array('>',' ');
-//		$specialCharsMapping = array('/' => '>');
-		$specialCharsMapping = array();
-		$strlen = mb_strlen($query);
-		$classChars = array('.', '-');
-		$pseudoChars = array('-');
-		$tagChars = array('*', '|', '-');
-		// split multibyte string
-		// http://code.google.com/p/phpquery/issues/detail?id=76
-		$_query = array();
-		for ($i=0; $i<$strlen; $i++)
-			$_query[] = mb_substr($query, $i, 1);
-		$query = $_query;
-		// it works, but i dont like it...
-		$i = 0;
-		while( $i < $strlen) {
-			$c = $query[$i];
-			$tmp = '';
-			// TAG
-			if ($this->isChar($c) || in_array($c, $tagChars)) {
-				while(isset($query[$i])
-					&& ($this->isChar($query[$i]) || in_array($query[$i], $tagChars))) {
-					$tmp .= $query[$i];
-					$i++;
-				}
-				$return[] = $tmp;
-			// IDs
-			} else if ( $c == '#') {
-				$i++;
-				while( isset($query[$i]) && ($this->isChar($query[$i]) || $query[$i] == '-')) {
-					$tmp .= $query[$i];
-					$i++;
-				}
-				$return[] = '#'.$tmp;
-			// SPECIAL CHARS
-			} else if (in_array($c, $specialChars)) {
-				$return[] = $c;
-				$i++;
-			// MAPPED SPECIAL MULTICHARS
-//			} else if ( $c.$query[$i+1] == '//') {
-//				$return[] = ' ';
-//				$i = $i+2;
-			// MAPPED SPECIAL CHARS
-			} else if ( isset($specialCharsMapping[$c])) {
-				$return[] = $specialCharsMapping[$c];
-				$i++;
-			// COMMA
-			} else if ( $c == ',') {
-				$queries[] = array();
-				$return =& $queries[ count($queries)-1 ];
-				$i++;
-				while( isset($query[$i]) && $query[$i] == ' ')
-					$i++;
-			// CLASSES
-			} else if ($c == '.') {
-				while( isset($query[$i]) && ($this->isChar($query[$i]) || in_array($query[$i], $classChars))) {
-					$tmp .= $query[$i];
-					$i++;
-				}
-				$return[] = $tmp;
-			// ~ General Sibling Selector
-			} else if ($c == '~') {
-				$spaceAllowed = true;
-				$tmp .= $query[$i++];
-				while( isset($query[$i])
-					&& ($this->isChar($query[$i])
-						|| in_array($query[$i], $classChars)
-						|| $query[$i] == '*'
-						|| ($query[$i] == ' ' && $spaceAllowed)
-					)) {
-					if ($query[$i] != ' ')
-						$spaceAllowed = false;
-					$tmp .= $query[$i];
-					$i++;
-				}
-				$return[] = $tmp;
-			// + Adjacent sibling selectors
-			} else if ($c == '+') {
-				$spaceAllowed = true;
-				$tmp .= $query[$i++];
-				while( isset($query[$i])
-					&& ($this->isChar($query[$i])
-						|| in_array($query[$i], $classChars)
-						|| $query[$i] == '*'
-						|| ($spaceAllowed && $query[$i] == ' ')
-					)) {
-					if ($query[$i] != ' ')
-						$spaceAllowed = false;
-					$tmp .= $query[$i];
-					$i++;
-				}
-				$return[] = $tmp;
-			// ATTRS
-			} else if ($c == '[') {
-				$stack = 1;
-				$tmp .= $c;
-				while( isset($query[++$i])) {
-					$tmp .= $query[$i];
-					if ( $query[$i] == '[') {
-						$stack++;
-					} else if ( $query[$i] == ']') {
-						$stack--;
-						if (! $stack )
-							break;
-					}
-				}
-				$return[] = $tmp;
-				$i++;
-			// PSEUDO CLASSES
-			} else if ($c == ':') {
-				$stack = 1;
-				$tmp .= $query[$i++];
-				while( isset($query[$i]) && ($this->isChar($query[$i]) || in_array($query[$i], $pseudoChars))) {
-					$tmp .= $query[$i];
-					$i++;
-				}
-				// with arguments ?
-				if ( isset($query[$i]) && $query[$i] == '(') {
-					$tmp .= $query[$i];
-					$stack = 1;
-					while( isset($query[++$i])) {
-						$tmp .= $query[$i];
-						if ( $query[$i] == '(') {
-							$stack++;
-						} else if ( $query[$i] == ')') {
-							$stack--;
-							if (! $stack )
-								break;
-						}
-					}
-					$return[] = $tmp;
-					$i++;
-				} else {
-					$return[] = $tmp;
-				}
-			} else {
-				$i++;
-			}
-		}
-		foreach($queries as $k => $q) {
-			if (isset($q[0])) {
-				if (isset($q[0][0]) && $q[0][0] == ':')
-					array_unshift($queries[$k], '*');
-				if ($q[0] != '>')
-					array_unshift($queries[$k], ' ');
-			}
-		}
-		return $queries;
-	}
-	/**
-	 * Return matched DOM nodes.
-	 *
-	 * @param int $index
-	 * @return array|DOMElement Single DOMElement or array of DOMElement.
-	 */
-	public function get($index = null, $callback1 = null, $callback2 = null, $callback3 = null) {
-		$return = isset($index)
-			? (isset($this->elements[$index]) ? $this->elements[$index] : null)
-			: $this->elements;
-		// pass thou callbacks
-		$args = func_get_args();
-		$args = array_slice($args, 1);
-		foreach($args as $callback) {
-			if (is_array($return))
-				foreach($return as $k => $v)
-					$return[$k] = phpQuery::callbackRun($callback, array($v));
-			else
-				$return = phpQuery::callbackRun($callback, array($return));
-		}
-		return $return;
-	}
-	/**
-	 * Return matched DOM nodes.
-	 * jQuery difference.
-	 *
-	 * @param int $index
-	 * @return array|string Returns string if $index != null
-	 * @todo implement callbacks
-	 * @todo return only arrays ?
-	 * @todo maybe other name...
-	 */
-	public function getString($index = null, $callback1 = null, $callback2 = null, $callback3 = null) {
-		if ($index)
-			$return = $this->eq($index)->text();
-		else {
-			$return = array();
-			for($i = 0; $i < $this->size(); $i++) {
-				$return[] = $this->eq($i)->text();
-			}
-		}
-		// pass thou callbacks
-		$args = func_get_args();
-		$args = array_slice($args, 1);
-		foreach($args as $callback) {
-			$return = phpQuery::callbackRun($callback, array($return));
-		}
-		return $return;
-	}
-	/**
-	 * Return matched DOM nodes.
-	 * jQuery difference.
-	 *
-	 * @param int $index
-	 * @return array|string Returns string if $index != null
-	 * @todo implement callbacks
-	 * @todo return only arrays ?
-	 * @todo maybe other name...
-	 */
-	public function getStrings($index = null, $callback1 = null, $callback2 = null, $callback3 = null) {
-		if ($index)
-			$return = $this->eq($index)->text();
-		else {
-			$return = array();
-			for($i = 0; $i < $this->size(); $i++) {
-				$return[] = $this->eq($i)->text();
-			}
-			// pass thou callbacks
-			$args = func_get_args();
-			$args = array_slice($args, 1);
-		}
-		foreach($args as $callback) {
-			if (is_array($return))
-				foreach($return as $k => $v)
-					$return[$k] = phpQuery::callbackRun($callback, array($v));
-			else
-				$return = phpQuery::callbackRun($callback, array($return));
-		}
-		return $return;
-	}
-	/**
-	 * Returns new instance of actual class.
-	 *
-	 * @param array $newStack Optional. Will replace old stack with new and move old one to history.c
-	 */
-	public function newInstance($newStack = null) {
-		$class = get_class($this);
-		// support inheritance by passing old object to overloaded constructor
-		$new = $class != 'phpQuery'
-			? new $class($this, $this->getDocumentID())
-			: new phpQueryObject($this->getDocumentID());
-		$new->previous = $this;
-		if (is_null($newStack)) {
-			$new->elements = $this->elements;
-			if ($this->elementsBackup)
-				$this->elements = $this->elementsBackup;
-		} else if (is_string($newStack)) {
-			$new->elements = phpQuery::pq($newStack, $this->getDocumentID())->stack();
-		} else {
-			$new->elements = $newStack;
-		}
-		return $new;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * In the future, when PHP will support XLS 2.0, then we would do that this way:
-	 * contains(tokenize(@class, '\s'), "something")
-	 * @param unknown_type $class
-	 * @param unknown_type $node
-	 * @return boolean
-	 * @access private
-	 */
-	protected function matchClasses($class, $node) {
-		// multi-class
-		if ( mb_strpos($class, '.', 1)) {
-			$classes = explode('.', substr($class, 1));
-			$classesCount = count( $classes );
-			$nodeClasses = explode(' ', $node->getAttribute('class') );
-			$nodeClassesCount = count( $nodeClasses );
-			if ( $classesCount > $nodeClassesCount )
-				return false;
-			$diff = count(
-				array_diff(
-					$classes,
-					$nodeClasses
-				)
-			);
-			if (! $diff )
-				return true;
-		// single-class
-		} else {
-			return in_array(
-				// strip leading dot from class name
-				substr($class, 1),
-				// get classes for element as array
-				explode(' ', $node->getAttribute('class') )
-			);
-		}
-	}
-	/**
-	 * @access private
-	 */
-	protected function runQuery($XQuery, $selector = null, $compare = null) {
-		if ($compare && ! method_exists($this, $compare))
-			return false;
-		$stack = array();
-		if (! $this->elements)
-			$this->debug('Stack empty, skipping...');
-//		var_dump($this->elements[0]->nodeType);
-		// element, document
-		foreach($this->stack(array(1, 9, 13)) as $k => $stackNode) {
-			$detachAfter = false;
-			// to work on detached nodes we need temporary place them somewhere
-			// thats because context xpath queries sucks ;]
-			$testNode = $stackNode;
-			while ($testNode) {
-				if (! $testNode->parentNode && ! $this->isRoot($testNode)) {
-					$this->root->appendChild($testNode);
-					$detachAfter = $testNode;
-					break;
-				}
-				$testNode = isset($testNode->parentNode)
-					? $testNode->parentNode
-					: null;
-			}
-			// XXX tmp ?
-			$xpath = $this->documentWrapper->isXHTML
-				? $this->getNodeXpath($stackNode, 'html')
-				: $this->getNodeXpath($stackNode);
-			// FIXME pseudoclasses-only query, support XML
-			$query = $XQuery == '//' && $xpath == '/html[1]'
-				? '//*'
-				: $xpath.$XQuery;
-			$this->debug("XPATH: {$query}");
-			// run query, get elements
-			$nodes = $this->xpath->query($query);
-			$this->debug("QUERY FETCHED");
-			if (! $nodes->length )
-				$this->debug('Nothing found');
-			$debug = array();
-			foreach($nodes as $node) {
-				$matched = false;
-				if ( $compare) {
-					phpQuery::$debug ?
-						$this->debug("Found: ".$this->whois( $node ).", comparing with {$compare}()")
-						: null;
-					$phpQueryDebug = phpQuery::$debug;
-					phpQuery::$debug = false;
-					// TODO ??? use phpQuery::callbackRun()
-					if (call_user_func_array(array($this, $compare), array($selector, $node)))
-						$matched = true;
-					phpQuery::$debug = $phpQueryDebug;
-				} else {
-					$matched = true;
-				}
-				if ( $matched) {
-					if (phpQuery::$debug)
-						$debug[] = $this->whois( $node );
-					$stack[] = $node;
-				}
-			}
-			if (phpQuery::$debug) {
-				$this->debug("Matched ".count($debug).": ".implode(', ', $debug));
-			}
-			if ($detachAfter)
-				$this->root->removeChild($detachAfter);
-		}
-		$this->elements = $stack;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function find($selectors, $context = null, $noHistory = false) {
-		if (!$noHistory)
-			// backup last stack /for end()/
-			$this->elementsBackup = $this->elements;
-		// allow to define context
-		// TODO combine code below with phpQuery::pq() context guessing code
-		//   as generic function
-		if ($context) {
-			if (! is_array($context) && $context instanceof DOMELEMENT)
-				$this->elements = array($context);
-			else if (is_array($context)) {
-				$this->elements = array();
-				foreach ($context as $c)
-					if ($c instanceof DOMELEMENT)
-						$this->elements[] = $c;
-			} else if ( $context instanceof self )
-				$this->elements = $context->elements;
-		}
-		$queries = $this->parseSelector($selectors);
-		$this->debug(array('FIND', $selectors, $queries));
-		$XQuery = '';
-		// remember stack state because of multi-queries
-		$oldStack = $this->elements;
-		// here we will be keeping found elements
-		$stack = array();
-		foreach($queries as $selector) {
-			$this->elements = $oldStack;
-			$delimiterBefore = false;
-			foreach($selector as $s) {
-				// TAG
-				$isTag = extension_loaded('mbstring') && phpQuery::$mbstringSupport
-					? mb_ereg_match('^[\w|\||-]+$', $s) || $s == '*'
-					: preg_match('@^[\w|\||-]+$@', $s) || $s == '*';
-				if ($isTag) {
-					if ($this->isXML()) {
-						// namespace support
-						if (mb_strpos($s, '|') !== false) {
-							$ns = $tag = null;
-							list($ns, $tag) = explode('|', $s);
-							$XQuery .= "$ns:$tag";
-						} else if ($s == '*') {
-							$XQuery .= "*";
-						} else {
-							$XQuery .= "*[local-name()='$s']";
-						}
-					} else {
-						$XQuery .= $s;
-					}
-				// ID
-				} else if ($s[0] == '#') {
-					if ($delimiterBefore)
-						$XQuery .= '*';
-					$XQuery .= "[@id='".substr($s, 1)."']";
-				// ATTRIBUTES
-				} else if ($s[0] == '[') {
-					if ($delimiterBefore)
-						$XQuery .= '*';
-					// strip side brackets
-					$attr = trim($s, '][');
-					$execute = false;
-					// attr with specifed value
-					if (mb_strpos($s, '=')) {
-						$value = null;
-						list($attr, $value) = explode('=', $attr);
-						$value = trim($value, "'\"");
-						if ($this->isRegexp($attr)) {
-							// cut regexp character
-							$attr = substr($attr, 0, -1);
-							$execute = true;
-							$XQuery .= "[@{$attr}]";
-						} else {
-							$XQuery .= "[@{$attr}='{$value}']";
-						}
-					// attr without specified value
-					} else {
-						$XQuery .= "[@{$attr}]";
-					}
-					if ($execute) {
-						$this->runQuery($XQuery, $s, 'is');
-						$XQuery = '';
-						if (! $this->length())
-							break;
-					}
-				// CLASSES
-				} else if ($s[0] == '.') {
-					// TODO use return $this->find("./self::*[contains(concat(\" \",@class,\" \"), \" $class \")]");
-					// thx wizDom ;)
-					if ($delimiterBefore)
-						$XQuery .= '*';
-					$XQuery .= '[@class]';
-					$this->runQuery($XQuery, $s, 'matchClasses');
-					$XQuery = '';
-					if (! $this->length() )
-						break;
-				// ~ General Sibling Selector
-				} else if ($s[0] == '~') {
-					$this->runQuery($XQuery);
-					$XQuery = '';
-					$this->elements = $this
-						->siblings(
-							substr($s, 1)
-						)->elements;
-					if (! $this->length() )
-						break;
-				// + Adjacent sibling selectors
-				} else if ($s[0] == '+') {
-					// TODO /following-sibling::
-					$this->runQuery($XQuery);
-					$XQuery = '';
-					$subSelector = substr($s, 1);
-					$subElements = $this->elements;
-					$this->elements = array();
-					foreach($subElements as $node) {
-						// search first DOMElement sibling
-						$test = $node->nextSibling;
-						while($test && ! ($test instanceof DOMELEMENT))
-							$test = $test->nextSibling;
-						if ($test && $this->is($subSelector, $test))
-							$this->elements[] = $test;
-					}
-					if (! $this->length() )
-						break;
-				// PSEUDO CLASSES
-				} else if ($s[0] == ':') {
-					// TODO optimization for :first :last
-					if ($XQuery) {
-						$this->runQuery($XQuery);
-						$XQuery = '';
-					}
-					if (! $this->length())
-						break;
-					$this->pseudoClasses($s);
-					if (! $this->length())
-						break;
-				// DIRECT DESCENDANDS
-				} else if ($s == '>') {
-					$XQuery .= '/';
-					$delimiterBefore = 2;
-				// ALL DESCENDANDS
-				} else if ($s == ' ') {
-					$XQuery .= '//';
-					$delimiterBefore = 2;
-				// ERRORS
-				} else {
-					phpQuery::debug("Unrecognized token '$s'");
-				}
-				$delimiterBefore = $delimiterBefore === 2;
-			}
-			// run query if any
-			if ($XQuery && $XQuery != '//') {
-				$this->runQuery($XQuery);
-				$XQuery = '';
-			}
-			foreach($this->elements as $node)
-				if (! $this->elementsContainsNode($node, $stack))
-					$stack[] = $node;
-		}
-		$this->elements = $stack;
-		return $this->newInstance();
-	}
-	/**
-	 * @todo create API for classes with pseudoselectors
-	 * @access private
-	 */
-	protected function pseudoClasses($class) {
-		// TODO clean args parsing ?
-		$class = ltrim($class, ':');
-		$haveArgs = mb_strpos($class, '(');
-		if ($haveArgs !== false) {
-			$args = substr($class, $haveArgs+1, -1);
-			$class = substr($class, 0, $haveArgs);
-		}
-		switch($class) {
-			case 'even':
-			case 'odd':
-				$stack = array();
-				foreach($this->elements as $i => $node) {
-					if ($class == 'even' && ($i%2) == 0)
-						$stack[] = $node;
-					else if ( $class == 'odd' && $i % 2 )
-						$stack[] = $node;
-				}
-				$this->elements = $stack;
-				break;
-			case 'eq':
-				$k = intval($args);
-				$this->elements = isset( $this->elements[$k] )
-					? array( $this->elements[$k] )
-					: array();
-				break;
-			case 'gt':
-				$this->elements = array_slice($this->elements, $args+1);
-				break;
-			case 'lt':
-				$this->elements = array_slice($this->elements, 0, $args+1);
-				break;
-			case 'first':
-				if (isset($this->elements[0]))
-					$this->elements = array($this->elements[0]);
-				break;
-			case 'last':
-				if ($this->elements)
-					$this->elements = array($this->elements[count($this->elements)-1]);
-				break;
-			/*case 'parent':
-				$stack = array();
-				foreach($this->elements as $node) {
-					if ( $node->childNodes->length )
-						$stack[] = $node;
-				}
-				$this->elements = $stack;
-				break;*/
-			case 'contains':
-				$text = trim($args, "\"'");
-				$stack = array();
-				foreach($this->elements as $node) {
-					if (mb_stripos($node->textContent, $text) === false)
-						continue;
-					$stack[] = $node;
-				}
-				$this->elements = $stack;
-				break;
-			case 'not':
-				$selector = self::unQuote($args);
-				$this->elements = $this->not($selector)->stack();
-				break;
-			case 'slice':
-				// TODO jQuery difference ?
-				$args = explode(',',
-					str_replace(', ', ',', trim($args, "\"'"))
-				);
-				$start = $args[0];
-				$end = isset($args[1])
-					? $args[1]
-					: null;
-				if ($end > 0)
-					$end = $end-$start;
-				$this->elements = array_slice($this->elements, $start, $end);
-				break;
-			case 'has':
-				$selector = trim($args, "\"'");
-				$stack = array();
-				foreach($this->stack(1) as $el) {
-					if ($this->find($selector, $el, true)->length)
-						$stack[] = $el;
-				}
-				$this->elements = $stack;
-				break;
-			case 'submit':
-			case 'reset':
-				$this->elements = phpQuery::merge(
-					$this->map(array($this, 'is'),
-						"input[type=$class]", new CallbackParam()
-					),
-					$this->map(array($this, 'is'),
-						"button[type=$class]", new CallbackParam()
-					)
-				);
-			break;
-//				$stack = array();
-//				foreach($this->elements as $node)
-//					if ($node->is('input[type=submit]') || $node->is('button[type=submit]'))
-//						$stack[] = $el;
-//				$this->elements = $stack;
-			case 'input':
-				$this->elements = $this->map(
-					array($this, 'is'),
-					'input', new CallbackParam()
-				)->elements;
-			break;
-			case 'password':
-			case 'checkbox':
-			case 'radio':
-			case 'hidden':
-			case 'image':
-			case 'file':
-				$this->elements = $this->map(
-					array($this, 'is'),
-					"input[type=$class]", new CallbackParam()
-				)->elements;
-			break;
-			case 'parent':
-				$this->elements = $this->map(
-					create_function('$node', '
-						return $node instanceof DOMELEMENT && $node->childNodes->length
-							? $node : null;')
-				)->elements;
-			break;
-			case 'empty':
-				$this->elements = $this->map(
-					create_function('$node', '
-						return $node instanceof DOMELEMENT && $node->childNodes->length
-							? null : $node;')
-				)->elements;
-			break;
-			case 'disabled':
-			case 'selected':
-			case 'checked':
-				$this->elements = $this->map(
-					array($this, 'is'),
-					"[$class]", new CallbackParam()
-				)->elements;
-			break;
-			case 'enabled':
-				$this->elements = $this->map(
-					create_function('$node', '
-						return pq($node)->not(":disabled") ? $node : null;')
-				)->elements;
-			break;
-			case 'header':
-				$this->elements = $this->map(
-					create_function('$node',
-						'$isHeader = isset($node->tagName) && in_array($node->tagName, array(
-							"h1", "h2", "h3", "h4", "h5", "h6", "h7"
-						));
-						return $isHeader
-							? $node
-							: null;')
-				)->elements;
-//				$this->elements = $this->map(
-//					create_function('$node', '$node = pq($node);
-//						return $node->is("h1")
-//							|| $node->is("h2")
-//							|| $node->is("h3")
-//							|| $node->is("h4")
-//							|| $node->is("h5")
-//							|| $node->is("h6")
-//							|| $node->is("h7")
-//							? $node
-//							: null;')
-//				)->elements;
-			break;
-			case 'only-child':
-				$this->elements = $this->map(
-					create_function('$node',
-						'return pq($node)->siblings()->size() == 0 ? $node : null;')
-				)->elements;
-			break;
-			case 'first-child':
-				$this->elements = $this->map(
-					create_function('$node', 'return pq($node)->prevAll()->size() == 0 ? $node : null;')
-				)->elements;
-			break;
-			case 'last-child':
-				$this->elements = $this->map(
-					create_function('$node', 'return pq($node)->nextAll()->size() == 0 ? $node : null;')
-				)->elements;
-			break;
-			case 'nth-child':
-				$param = trim($args, "\"'");
-				if (! $param)
-					break;
-					// nth-child(n+b) to nth-child(1n+b)
-				if ($param{0} == 'n')
-					$param = '1'.$param;
-				// :nth-child(index/even/odd/equation)
-				if ($param == 'even' || $param == 'odd')
-					$mapped = $this->map(
-						create_function('$node, $param',
-							'$index = pq($node)->prevAll()->size()+1;
-							if ($param == "even" && ($index%2) == 0)
-								return $node;
-							else if ($param == "odd" && $index%2 == 1)
-								return $node;
-							else
-								return null;'),
-						new CallbackParam(), $param
-					);
-				else if (mb_strlen($param) > 1 && $param{1} == 'n')
-					// an+b
-					$mapped = $this->map(
-						create_function('$node, $param',
-							'$prevs = pq($node)->prevAll()->size();
-							$index = 1+$prevs;
-							$b = mb_strlen($param) > 3
-								? $param{3}
-								: 0;
-							$a = $param{0};
-							if ($b && $param{2} == "-")
-								$b = -$b;
-							if ($a > 0) {
-								return ($index-$b)%$a == 0
-									? $node
-									: null;
-								phpQuery::debug($a."*".floor($index/$a)."+$b-1 == ".($a*floor($index/$a)+$b-1)." ?= $prevs");
-								return $a*floor($index/$a)+$b-1 == $prevs
-										? $node
-										: null;
-							} else if ($a == 0)
-								return $index == $b
-										? $node
-										: null;
-							else
-								// negative value
-								return $index <= $b
-										? $node
-										: null;
-//							if (! $b)
-//								return $index%$a == 0
-//									? $node
-//									: null;
-//							else
-//								return ($index-$b)%$a == 0
-//									? $node
-//									: null;
-							'),
-						new CallbackParam(), $param
-					);
-				else
-					// index
-					$mapped = $this->map(
-						create_function('$node, $index',
-							'$prevs = pq($node)->prevAll()->size();
-							if ($prevs && $prevs == $index-1)
-								return $node;
-							else if (! $prevs && $index == 1)
-								return $node;
-							else
-								return null;'),
-						new CallbackParam(), $param
-					);
-				$this->elements = $mapped->elements;
-			break;
-			default:
-				$this->debug("Unknown pseudoclass '{$class}', skipping...");
-		}
-	}
-	/**
-	 * @access private
-	 */
-	protected function __pseudoClassParam($paramsString) {
-		// TODO;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function is($selector, $nodes = null) {
-		phpQuery::debug(array("Is:", $selector));
-		if (! $selector)
-			return false;
-		$oldStack = $this->elements;
-		$returnArray = false;
-		if ($nodes && is_array($nodes)) {
-			$this->elements = $nodes;
-		} else if ($nodes)
-			$this->elements = array($nodes);
-		$this->filter($selector, true);
-		$stack = $this->elements;
-		$this->elements = $oldStack;
-		if ($nodes)
-			return $stack ? $stack : null;
-		return (bool)count($stack);
-	}
-	/**
-	 * Enter description here...
-	 * jQuery difference.
-	 *
-	 * Callback:
-	 * - $index int
-	 * - $node DOMNode
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @link http://docs.jquery.com/Traversing/filter
-	 */
-	public function filterCallback($callback, $_skipHistory = false) {
-		if (! $_skipHistory) {
-			$this->elementsBackup = $this->elements;
-			$this->debug("Filtering by callback");
-		}
-		$newStack = array();
-		foreach($this->elements as $index => $node) {
-			$result = phpQuery::callbackRun($callback, array($index, $node));
-			if (is_null($result) || (! is_null($result) && $result))
-				$newStack[] = $node;
-		}
-		$this->elements = $newStack;
-		return $_skipHistory
-			? $this
-			: $this->newInstance();
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @link http://docs.jquery.com/Traversing/filter
-	 */
-	public function filter($selectors, $_skipHistory = false) {
-		if ($selectors instanceof Callback OR $selectors instanceof Closure)
-			return $this->filterCallback($selectors, $_skipHistory);
-		if (! $_skipHistory)
-			$this->elementsBackup = $this->elements;
-		$notSimpleSelector = array(' ', '>', '~', '+', '/');
-		if (! is_array($selectors))
-			$selectors = $this->parseSelector($selectors);
-		if (! $_skipHistory)
-			$this->debug(array("Filtering:", $selectors));
-		$finalStack = array();
-		foreach($selectors as $selector) {
-			$stack = array();
-			if (! $selector)
-				break;
-			// avoid first space or /
-			if (in_array($selector[0], $notSimpleSelector))
-				$selector = array_slice($selector, 1);
-			// PER NODE selector chunks
-			foreach($this->stack() as $node) {
-				$break = false;
-				foreach($selector as $s) {
-					if (!($node instanceof DOMELEMENT)) {
-						// all besides DOMElement
-						if ( $s[0] == '[') {
-							$attr = trim($s, '[]');
-							if ( mb_strpos($attr, '=')) {
-								list( $attr, $val ) = explode('=', $attr);
-								if ($attr == 'nodeType' && $node->nodeType != $val)
-									$break = true;
-							}
-						} else
-							$break = true;
-					} else {
-						// DOMElement only
-						// ID
-						if ( $s[0] == '#') {
-							if ( $node->getAttribute('id') != substr($s, 1) )
-								$break = true;
-						// CLASSES
-						} else if ( $s[0] == '.') {
-							if (! $this->matchClasses( $s, $node ) )
-								$break = true;
-						// ATTRS
-						} else if ( $s[0] == '[') {
-							// strip side brackets
-							$attr = trim($s, '[]');
-							if (mb_strpos($attr, '=')) {
-								list($attr, $val) = explode('=', $attr);
-								$val = self::unQuote($val);
-								if ($attr == 'nodeType') {
-									if ($val != $node->nodeType)
-										$break = true;
-								} else if ($this->isRegexp($attr)) {
-									$val = extension_loaded('mbstring') && phpQuery::$mbstringSupport
-										? quotemeta(trim($val, '"\''))
-										: preg_quote(trim($val, '"\''), '@');
-									// switch last character
-									switch( substr($attr, -1)) {
-										// quotemeta used insted of preg_quote
-										// http://code.google.com/p/phpquery/issues/detail?id=76
-										case '^':
-											$pattern = '^'.$val;
-											break;
-										case '*':
-											$pattern = '.*'.$val.'.*';
-											break;
-										case '$':
-											$pattern = '.*'.$val.'$';
-											break;
-									}
-									// cut last character
-									$attr = substr($attr, 0, -1);
-									$isMatch = extension_loaded('mbstring') && phpQuery::$mbstringSupport
-										? mb_ereg_match($pattern, $node->getAttribute($attr))
-										: preg_match("@{$pattern}@", $node->getAttribute($attr));
-									if (! $isMatch)
-										$break = true;
-								} else if ($node->getAttribute($attr) != $val)
-									$break = true;
-							} else if (! $node->hasAttribute($attr))
-								$break = true;
-						// PSEUDO CLASSES
-						} else if ( $s[0] == ':') {
-							// skip
-						// TAG
-						} else if (trim($s)) {
-							if ($s != '*') {
-								// TODO namespaces
-								if (isset($node->tagName)) {
-									if ($node->tagName != $s)
-										$break = true;
-								} else if ($s == 'html' && ! $this->isRoot($node))
-									$break = true;
-							}
-						// AVOID NON-SIMPLE SELECTORS
-						} else if (in_array($s, $notSimpleSelector)) {
-							$break = true;
-							$this->debug(array('Skipping non simple selector', $selector));
-						}
-					}
-					if ($break)
-						break;
-				}
-				// if element passed all chunks of selector - add it to new stack
-				if (! $break )
-					$stack[] = $node;
-			}
-			$tmpStack = $this->elements;
-			$this->elements = $stack;
-			// PER ALL NODES selector chunks
-			foreach($selector as $s)
-				// PSEUDO CLASSES
-				if ($s[0] == ':')
-					$this->pseudoClasses($s);
-			foreach($this->elements as $node)
-				// XXX it should be merged without duplicates
-				// but jQuery doesnt do that
-				$finalStack[] = $node;
-			$this->elements = $tmpStack;
-		}
-		$this->elements = $finalStack;
-		if ($_skipHistory) {
-			return $this;
-		} else {
-			$this->debug("Stack length after filter(): ".count($finalStack));
-			return $this->newInstance();
-		}
-	}
-	/**
-	 *
-	 * @param $value
-	 * @return unknown_type
-	 * @TODO implement in all methods using passed parameters
-	 */
-	protected static function unQuote($value) {
-		return $value[0] == '\'' || $value[0] == '"'
-			? substr($value, 1, -1)
-			: $value;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @link http://docs.jquery.com/Ajax/load
-	 * @return phpQuery|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @todo Support $selector
-	 */
-	public function load($url, $data = null, $callback = null) {
-		if ($data && ! is_array($data)) {
-			$callback = $data;
-			$data = null;
-		}
-		if (mb_strpos($url, ' ') !== false) {
-			$matches = null;
-			if (extension_loaded('mbstring') && phpQuery::$mbstringSupport)
-				mb_ereg('^([^ ]+) (.*)$', $url, $matches);
-			else
-				preg_match('^([^ ]+) (.*)$', $url, $matches);
-			$url = $matches[1];
-			$selector = $matches[2];
-			// FIXME this sucks, pass as callback param
-			$this->_loadSelector = $selector;
-		}
-		$ajax = array(
-			'url' => $url,
-			'type' => $data ? 'POST' : 'GET',
-			'data' => $data,
-			'complete' => $callback,
-			'success' => array($this, '__loadSuccess')
-		);
-		phpQuery::ajax($ajax);
-		return $this;
-	}
-	/**
-	 * @access private
-	 * @param $html
-	 * @return unknown_type
-	 */
-	public function __loadSuccess($html) {
-		if ($this->_loadSelector) {
-			$html = phpQuery::newDocument($html)->find($this->_loadSelector);
-			unset($this->_loadSelector);
-		}
-		foreach($this->stack(1) as $node) {
-			phpQuery::pq($node, $this->getDocumentID())
-				->markup($html);
-		}
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQuery|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @todo
-	 */
-	public function css() {
-		// TODO
-		return $this;
-	}
-	/**
-	 * @todo
-	 *
-	 */
-	public function show(){
-		// TODO
-		return $this;
-	}
-	/**
-	 * @todo
-	 *
-	 */
-	public function hide(){
-		// TODO
-		return $this;
-	}
-	/**
-	 * Trigger a type of event on every matched element.
-	 *
-	 * @param unknown_type $type
-	 * @param unknown_type $data
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @TODO support more than event in $type (space-separated)
-	 */
-	public function trigger($type, $data = array()) {
-		foreach($this->elements as $node)
-			phpQueryEvents::trigger($this->getDocumentID(), $type, $data, $node);
-		return $this;
-	}
-	/**
-	 * This particular method triggers all bound event handlers on an element (for a specific event type) WITHOUT executing the browsers default actions.
-	 *
-	 * @param unknown_type $type
-	 * @param unknown_type $data
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @TODO
-	 */
-	public function triggerHandler($type, $data = array()) {
-		// TODO;
-	}
-	/**
-	 * Binds a handler to one or more events (like click) for each matched element.
-	 * Can also bind custom events.
-	 *
-	 * @param unknown_type $type
-	 * @param unknown_type $data Optional
-	 * @param unknown_type $callback
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @TODO support '!' (exclusive) events
-	 * @TODO support more than event in $type (space-separated)
-	 */
-	public function bind($type, $data, $callback = null) {
-		// TODO check if $data is callable, not using is_callable
-		if (! isset($callback)) {
-			$callback = $data;
-			$data = null;
-		}
-		foreach($this->elements as $node)
-			phpQueryEvents::add($this->getDocumentID(), $node, $type, $data, $callback);
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param unknown_type $type
-	 * @param unknown_type $callback
-	 * @return unknown
-	 * @TODO namespace events
-	 * @TODO support more than event in $type (space-separated)
-	 */
-	public function unbind($type = null, $callback = null) {
-		foreach($this->elements as $node)
-			phpQueryEvents::remove($this->getDocumentID(), $node, $type, $callback);
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function change($callback = null) {
-		if ($callback)
-			return $this->bind('change', $callback);
-		return $this->trigger('change');
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function submit($callback = null) {
-		if ($callback)
-			return $this->bind('submit', $callback);
-		return $this->trigger('submit');
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function click($callback = null) {
-		if ($callback)
-			return $this->bind('click', $callback);
-		return $this->trigger('click');
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param String|phpQuery
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function wrapAllOld($wrapper) {
-		$wrapper = pq($wrapper)->_clone();
-		if (! $wrapper->length() || ! $this->length() )
-			return $this;
-		$wrapper->insertBefore($this->elements[0]);
-		$deepest = $wrapper->elements[0];
-		while($deepest->firstChild && $deepest->firstChild instanceof DOMELEMENT)
-			$deepest = $deepest->firstChild;
-		pq($deepest)->append($this);
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * TODO testme...
-	 * @param String|phpQuery
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function wrapAll($wrapper) {
-		if (! $this->length())
-			return $this;
-		return phpQuery::pq($wrapper, $this->getDocumentID())
-			->clone()
-			->insertBefore($this->get(0))
-			->map(array($this, '___wrapAllCallback'))
-			->append($this);
-	}
-  /**
-   *
-	 * @param $node
-	 * @return unknown_type
-	 * @access private
-   */
-	public function ___wrapAllCallback($node) {
-		$deepest = $node;
-		while($deepest->firstChild && $deepest->firstChild instanceof DOMELEMENT)
-			$deepest = $deepest->firstChild;
-		return $deepest;
-	}
-	/**
-	 * Enter description here...
-	 * NON JQUERY METHOD
-	 *
-	 * @param String|phpQuery
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function wrapAllPHP($codeBefore, $codeAfter) {
-		return $this
-			->slice(0, 1)
-				->beforePHP($codeBefore)
-			->end()
-			->slice(-1)
-				->afterPHP($codeAfter)
-			->end();
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param String|phpQuery
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function wrap($wrapper) {
-		foreach($this->stack() as $node)
-			phpQuery::pq($node, $this->getDocumentID())->wrapAll($wrapper);
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param String|phpQuery
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function wrapPHP($codeBefore, $codeAfter) {
-		foreach($this->stack() as $node)
-			phpQuery::pq($node, $this->getDocumentID())->wrapAllPHP($codeBefore, $codeAfter);
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param String|phpQuery
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function wrapInner($wrapper) {
-		foreach($this->stack() as $node)
-			phpQuery::pq($node, $this->getDocumentID())->contents()->wrapAll($wrapper);
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param String|phpQuery
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function wrapInnerPHP($codeBefore, $codeAfter) {
-		foreach($this->stack(1) as $node)
-			phpQuery::pq($node, $this->getDocumentID())->contents()
-				->wrapAllPHP($codeBefore, $codeAfter);
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @testme Support for text nodes
-	 */
-	public function contents() {
-		$stack = array();
-		foreach($this->stack(1) as $el) {
-			// FIXME (fixed) http://code.google.com/p/phpquery/issues/detail?id=56
-//			if (! isset($el->childNodes))
-//				continue;
-			foreach($el->childNodes as $node) {
-				$stack[] = $node;
-			}
-		}
-		return $this->newInstance($stack);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * jQuery difference.
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function contentsUnwrap() {
-		foreach($this->stack(1) as $node) {
-			if (! $node->parentNode )
-				continue;
-			$childNodes = array();
-			// any modification in DOM tree breaks childNodes iteration, so cache them first
-			foreach($node->childNodes as $chNode )
-				$childNodes[] = $chNode;
-			foreach($childNodes as $chNode )
-//				$node->parentNode->appendChild($chNode);
-				$node->parentNode->insertBefore($chNode, $node);
-			$node->parentNode->removeChild($node);
-		}
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * jQuery difference.
-	 */
-	public function switchWith($markup) {
-		$markup = pq($markup, $this->getDocumentID());
-		$content = null;
-		foreach($this->stack(1) as $node) {
-			pq($node)
-				->contents()->toReference($content)->end()
-				->replaceWith($markup->clone()->append($content));
-		}
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function eq($num) {
-		$oldStack = $this->elements;
-		$this->elementsBackup = $this->elements;
-		$this->elements = array();
-		if ( isset($oldStack[$num]) )
-			$this->elements[] = $oldStack[$num];
-		return $this->newInstance();
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function size() {
-		return count($this->elements);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @deprecated Use length as attribute
-	 */
-	public function length() {
-		return $this->size();
-	}
-	public function count() {
-		return $this->size();
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @todo $level
-	 */
-	public function end($level = 1) {
-//		$this->elements = array_pop( $this->history );
-//		return $this;
-//		$this->previous->DOM = $this->DOM;
-//		$this->previous->XPath = $this->XPath;
-		return $this->previous
-			? $this->previous
-			: $this;
-	}
-	/**
-	 * Enter description here...
-	 * Normal use ->clone() .
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @access private
-	 */
-	public function _clone() {
-		$newStack = array();
-		//pr(array('copy... ', $this->whois()));
-		//$this->dumpHistory('copy');
-		$this->elementsBackup = $this->elements;
-		foreach($this->elements as $node) {
-			$newStack[] = $node->cloneNode(true);
-		}
-		$this->elements = $newStack;
-		return $this->newInstance();
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function replaceWithPHP($code) {
-		return $this->replaceWith(phpQuery::php($code));
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param String|phpQuery $content
-	 * @link http://docs.jquery.com/Manipulation/replaceWith#content
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function replaceWith($content) {
-		return $this->after($content)->remove();
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param String $selector
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @todo this works ?
-	 */
-	public function replaceAll($selector) {
-		foreach(phpQuery::pq($selector, $this->getDocumentID()) as $node)
-			phpQuery::pq($node, $this->getDocumentID())
-				->after($this->_clone())
-				->remove();
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function remove($selector = null) {
-		$loop = $selector
-			? $this->filter($selector)->elements
-			: $this->elements;
-		foreach($loop as $node) {
-			if (! $node->parentNode )
-				continue;
-			if (isset($node->tagName))
-				$this->debug("Removing '{$node->tagName}'");
-			$node->parentNode->removeChild($node);
-			// Mutation event
-			$event = new DOMEvent(array(
-				'target' => $node,
-				'type' => 'DOMNodeRemoved'
-			));
-			phpQueryEvents::trigger($this->getDocumentID(),
-				$event->type, array($event), $node
-			);
-		}
-		return $this;
-	}
-	protected function markupEvents($newMarkup, $oldMarkup, $node) {
-		if ($node->tagName == 'textarea' && $newMarkup != $oldMarkup) {
-			$event = new DOMEvent(array(
-				'target' => $node,
-				'type' => 'change'
-			));
-			phpQueryEvents::trigger($this->getDocumentID(),
-				$event->type, array($event), $node
-			);
-		}
-	}
-	/**
-	 * jQuey difference
-	 *
-	 * @param $markup
-	 * @return unknown_type
-	 * @TODO trigger change event for textarea
-	 */
-	public function markup($markup = null, $callback1 = null, $callback2 = null, $callback3 = null) {
-		$args = func_get_args();
-		if ($this->documentWrapper->isXML)
-			return call_user_func_array(array($this, 'xml'), $args);
-		else
-			return call_user_func_array(array($this, 'html'), $args);
-	}
-	/**
-	 * jQuey difference
-	 *
-	 * @param $markup
-	 * @return unknown_type
-	 */
-	public function markupOuter($callback1 = null, $callback2 = null, $callback3 = null) {
-		$args = func_get_args();
-		if ($this->documentWrapper->isXML)
-			return call_user_func_array(array($this, 'xmlOuter'), $args);
-		else
-			return call_user_func_array(array($this, 'htmlOuter'), $args);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param unknown_type $html
-	 * @return string|phpQuery|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @TODO force html result
-	 */
-	public function html($html = null, $callback1 = null, $callback2 = null, $callback3 = null) {
-		if (isset($html)) {
-			// INSERT
-			$nodes = $this->documentWrapper->import($html);
-			$this->empty();
-			foreach($this->stack(1) as $alreadyAdded => $node) {
-				// for now, limit events for textarea
-				if (($this->isXHTML() || $this->isHTML()) && $node->tagName == 'textarea')
-					$oldHtml = pq($node, $this->getDocumentID())->markup();
-				foreach($nodes as $newNode) {
-					$node->appendChild($alreadyAdded
-						? $newNode->cloneNode(true)
-						: $newNode
-					);
-				}
-				// for now, limit events for textarea
-				if (($this->isXHTML() || $this->isHTML()) && $node->tagName == 'textarea')
-					$this->markupEvents($html, $oldHtml, $node);
-			}
-			return $this;
-		} else {
-			// FETCH
-			$return = $this->documentWrapper->markup($this->elements, true);
-			$args = func_get_args();
-			foreach(array_slice($args, 1) as $callback) {
-				$return = phpQuery::callbackRun($callback, array($return));
-			}
-			return $return;
-		}
-	}
-	/**
-	 * @TODO force xml result
-	 */
-	public function xml($xml = null, $callback1 = null, $callback2 = null, $callback3 = null) {
-		$args = func_get_args();
-		return call_user_func_array(array($this, 'html'), $args);
-	}
-	/**
-	 * Enter description here...
-	 * @TODO force html result
-	 *
-	 * @return String
-	 */
-	public function htmlOuter($callback1 = null, $callback2 = null, $callback3 = null) {
-		$markup = $this->documentWrapper->markup($this->elements);
-		// pass thou callbacks
-		$args = func_get_args();
-		foreach($args as $callback) {
-			$markup = phpQuery::callbackRun($callback, array($markup));
-		}
-		return $markup;
-	}
-	/**
-	 * @TODO force xml result
-	 */
-	public function xmlOuter($callback1 = null, $callback2 = null, $callback3 = null) {
-		$args = func_get_args();
-		return call_user_func_array(array($this, 'htmlOuter'), $args);
-	}
-	public function __toString() {
-		return $this->markupOuter();
-	}
-	/**
-	 * Just like html(), but returns markup with VALID (dangerous) PHP tags.
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @todo support returning markup with PHP tags when called without param
-	 */
-	public function php($code = null) {
-		return $this->markupPHP($code);
-	}
-	/**
-	 * Enter description here...
-	 * 
-	 * @param $code
-	 * @return unknown_type
-	 */
-	public function markupPHP($code = null) {
-		return isset($code)
-			? $this->markup(phpQuery::php($code))
-			: phpQuery::markupToPHP($this->markup());
-	}
-	/**
-	 * Enter description here...
-	 * 
-	 * @param $code
-	 * @return unknown_type
-	 */
-	public function markupOuterPHP() {
-		return phpQuery::markupToPHP($this->markupOuter());
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function children($selector = null) {
-		$stack = array();
-		foreach($this->stack(1) as $node) {
-//			foreach($node->getElementsByTagName('*') as $newNode) {
-			foreach($node->childNodes as $newNode) {
-				if ($newNode->nodeType != 1)
-					continue;
-				if ($selector && ! $this->is($selector, $newNode))
-					continue;
-				if ($this->elementsContainsNode($newNode, $stack))
-					continue;
-				$stack[] = $newNode;
-			}
-		}
-		$this->elementsBackup = $this->elements;
-		$this->elements = $stack;
-		return $this->newInstance();
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function ancestors($selector = null) {
-		return $this->children( $selector );
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function append( $content) {
-		return $this->insert($content, __FUNCTION__);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function appendPHP( $content) {
-		return $this->insert("<php><!-- {$content} --></php>", 'append');
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function appendTo( $seletor) {
-		return $this->insert($seletor, __FUNCTION__);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function prepend( $content) {
-		return $this->insert($content, __FUNCTION__);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @todo accept many arguments, which are joined, arrays maybe also
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function prependPHP( $content) {
-		return $this->insert("<php><!-- {$content} --></php>", 'prepend');
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function prependTo( $seletor) {
-		return $this->insert($seletor, __FUNCTION__);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function before($content) {
-		return $this->insert($content, __FUNCTION__);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function beforePHP( $content) {
-		return $this->insert("<php><!-- {$content} --></php>", 'before');
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param String|phpQuery
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function insertBefore( $seletor) {
-		return $this->insert($seletor, __FUNCTION__);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function after( $content) {
-		return $this->insert($content, __FUNCTION__);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function afterPHP( $content) {
-		return $this->insert("<php><!-- {$content} --></php>", 'after');
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function insertAfter( $seletor) {
-		return $this->insert($seletor, __FUNCTION__);
-	}
-	/**
-	 * Internal insert method. Don't use it.
-	 *
-	 * @param unknown_type $target
-	 * @param unknown_type $type
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @access private
-	 */
-	public function insert($target, $type) {
-		$this->debug("Inserting data with '{$type}'");
-		$to = false;
-		switch( $type) {
-			case 'appendTo':
-			case 'prependTo':
-			case 'insertBefore':
-			case 'insertAfter':
-				$to = true;
-		}
-		switch(gettype($target)) {
-			case 'string':
-				$insertFrom = $insertTo = array();
-				if ($to) {
-					// INSERT TO
-					$insertFrom = $this->elements;
-					if (phpQuery::isMarkup($target)) {
-						// $target is new markup, import it
-						$insertTo = $this->documentWrapper->import($target);
-					// insert into selected element
-					} else {
-						// $tagret is a selector
-						$thisStack = $this->elements;
-						$this->toRoot();
-						$insertTo = $this->find($target)->elements;
-						$this->elements = $thisStack;
-					}
-				} else {
-					// INSERT FROM
-					$insertTo = $this->elements;
-					$insertFrom = $this->documentWrapper->import($target);
-				}
-				break;
-			case 'object':
-				$insertFrom = $insertTo = array();
-				// phpQuery
-				if ($target instanceof self) {
-					if ($to) {
-						$insertTo = $target->elements;
-						if ($this->documentFragment && $this->stackIsRoot())
-							// get all body children
-//							$loop = $this->find('body > *')->elements;
-							// TODO test it, test it hard...
-//							$loop = $this->newInstance($this->root)->find('> *')->elements;
-							$loop = $this->root->childNodes;
-						else
-							$loop = $this->elements;
-						// import nodes if needed
-						$insertFrom = $this->getDocumentID() == $target->getDocumentID()
-							? $loop
-							: $target->documentWrapper->import($loop);
-					} else {
-						$insertTo = $this->elements;
-						if ( $target->documentFragment && $target->stackIsRoot() )
-							// get all body children
-//							$loop = $target->find('body > *')->elements;
-							$loop = $target->root->childNodes;
-						else
-							$loop = $target->elements;
-						// import nodes if needed
-						$insertFrom = $this->getDocumentID() == $target->getDocumentID()
-							? $loop
-							: $this->documentWrapper->import($loop);
-					}
-				// DOMNODE
-				} elseif ($target instanceof DOMNODE) {
-					// import node if needed
-//					if ( $target->ownerDocument != $this->DOM )
-//						$target = $this->DOM->importNode($target, true);
-					if ( $to) {
-						$insertTo = array($target);
-						if ($this->documentFragment && $this->stackIsRoot())
-							// get all body children
-							$loop = $this->root->childNodes;
-//							$loop = $this->find('body > *')->elements;
-						else
-							$loop = $this->elements;
-						foreach($loop as $fromNode)
-							// import nodes if needed
-							$insertFrom[] = ! $fromNode->ownerDocument->isSameNode($target->ownerDocument)
-								? $target->ownerDocument->importNode($fromNode, true)
-								: $fromNode;
-					} else {
-						// import node if needed
-						if (! $target->ownerDocument->isSameNode($this->document))
-							$target = $this->document->importNode($target, true);
-						$insertTo = $this->elements;
-						$insertFrom[] = $target;
-					}
-				}
-				break;
-		}
-		phpQuery::debug("From ".count($insertFrom)."; To ".count($insertTo)." nodes");
-		foreach($insertTo as $insertNumber => $toNode) {
-			// we need static relative elements in some cases
-			switch( $type) {
-				case 'prependTo':
-				case 'prepend':
-					$firstChild = $toNode->firstChild;
-					break;
-				case 'insertAfter':
-				case 'after':
-					$nextSibling = $toNode->nextSibling;
-					break;
-			}
-			foreach($insertFrom as $fromNode) {
-				// clone if inserted already before
-				$insert = $insertNumber
-					? $fromNode->cloneNode(true)
-					: $fromNode;
-				switch($type) {
-					case 'appendTo':
-					case 'append':
-//						$toNode->insertBefore(
-//							$fromNode,
-//							$toNode->lastChild->nextSibling
-//						);
-						$toNode->appendChild($insert);
-						$eventTarget = $insert;
-						break;
-					case 'prependTo':
-					case 'prepend':
-						$toNode->insertBefore(
-							$insert,
-							$firstChild
-						);
-						break;
-					case 'insertBefore':
-					case 'before':
-						if (! $toNode->parentNode)
-							throw new Exception("No parentNode, can't do {$type}()");
-						else
-							$toNode->parentNode->insertBefore(
-								$insert,
-								$toNode
-							);
-						break;
-					case 'insertAfter':
-					case 'after':
-						if (! $toNode->parentNode)
-							throw new Exception("No parentNode, can't do {$type}()");
-						else
-							$toNode->parentNode->insertBefore(
-								$insert,
-								$nextSibling
-							);
-						break;
-				}
-				// Mutation event
-				$event = new DOMEvent(array(
-					'target' => $insert,
-					'type' => 'DOMNodeInserted'
-				));
-				phpQueryEvents::trigger($this->getDocumentID(),
-					$event->type, array($event), $insert
-				);
-			}
-		}
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return Int
-	 */
-	public function index($subject) {
-		$index = -1;
-		$subject = $subject instanceof phpQueryObject
-			? $subject->elements[0]
-			: $subject;
-		foreach($this->newInstance() as $k => $node) {
-			if ($node->isSameNode($subject))
-				$index = $k;
-		}
-		return $index;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param unknown_type $start
-	 * @param unknown_type $end
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @testme
-	 */
-	public function slice($start, $end = null) {
-//		$last = count($this->elements)-1;
-//		$end = $end
-//			? min($end, $last)
-//			: $last;
-//		if ($start < 0)
-//			$start = $last+$start;
-//		if ($start > $last)
-//			return array();
-		if ($end > 0)
-			$end = $end-$start;
-		return $this->newInstance(
-			array_slice($this->elements, $start, $end)
-		);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function reverse() {
-		$this->elementsBackup = $this->elements;
-		$this->elements = array_reverse($this->elements);
-		return $this->newInstance();
-	}
-	/**
-	 * Return joined text content.
-	 * @return String
-	 */
-	public function text($text = null, $callback1 = null, $callback2 = null, $callback3 = null) {
-		if (isset($text))
-			return $this->html(htmlspecialchars($text));
-		$args = func_get_args();
-		$args = array_slice($args, 1);
-		$return = '';
-		foreach($this->elements as $node) {
-			$text = $node->textContent;
-			if (count($this->elements) > 1 && $text)
-				$text .= "\n";
-			foreach($args as $callback) {
-				$text = phpQuery::callbackRun($callback, array($text));
-			}
-			$return .= $text;
-		}
-		return $return;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function plugin($class, $file = null) {
-		phpQuery::plugin($class, $file);
-		return $this;
-	}
-	/**
-	 * Deprecated, use $pq->plugin() instead.
-	 *
-	 * @deprecated
-	 * @param $class
-	 * @param $file
-	 * @return unknown_type
-	 */
-	public static function extend($class, $file = null) {
-		return $this->plugin($class, $file);
-	}
-	/**
-	 *
-	 * @access private
-	 * @param $method
-	 * @param $args
-	 * @return unknown_type
-	 */
-	public function __call($method, $args) {
-		$aliasMethods = array('clone', 'empty');
-		if (isset(phpQuery::$extendMethods[$method])) {
-			array_unshift($args, $this);
-			return phpQuery::callbackRun(
-				phpQuery::$extendMethods[$method], $args
-			);
-		} else if (isset(phpQuery::$pluginsMethods[$method])) {
-			array_unshift($args, $this);
-			$class = phpQuery::$pluginsMethods[$method];
-			$realClass = "phpQueryObjectPlugin_$class";
-			$return = call_user_func_array(
-				array($realClass, $method),
-				$args
-			);
-			// XXX deprecate ?
-			return is_null($return)
-				? $this
-				: $return;
-		} else if (in_array($method, $aliasMethods)) {
-			return call_user_func_array(array($this, '_'.$method), $args);
-		} else
-			throw new Exception("Method '{$method}' doesnt exist");
-	}
-	/**
-	 * Safe rename of next().
-	 *
-	 * Use it ONLY when need to call next() on an iterated object (in same time).
-	 * Normaly there is no need to do such thing ;)
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @access private
-	 */
-	public function _next($selector = null) {
-		return $this->newInstance(
-			$this->getElementSiblings('nextSibling', $selector, true)
-		);
-	}
-	/**
-	 * Use prev() and next().
-	 *
-	 * @deprecated
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @access private
-	 */
-	public function _prev($selector = null) {
-		return $this->prev($selector);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function prev($selector = null) {
-		return $this->newInstance(
-			$this->getElementSiblings('previousSibling', $selector, true)
-		);
-	}
-	/**
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @todo
-	 */
-	public function prevAll($selector = null) {
-		return $this->newInstance(
-			$this->getElementSiblings('previousSibling', $selector)
-		);
-	}
-	/**
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @todo FIXME: returns source elements insted of next siblings
-	 */
-	public function nextAll($selector = null) {
-		return $this->newInstance(
-			$this->getElementSiblings('nextSibling', $selector)
-		);
-	}
-	/**
-	 * @access private
-	 */
-	protected function getElementSiblings($direction, $selector = null, $limitToOne = false) {
-		$stack = array();
-		$count = 0;
-		foreach($this->stack() as $node) {
-			$test = $node;
-			while( isset($test->{$direction}) && $test->{$direction}) {
-				$test = $test->{$direction};
-				if (! $test instanceof DOMELEMENT)
-					continue;
-				$stack[] = $test;
-				if ($limitToOne)
-					break;
-			}
-		}
-		if ($selector) {
-			$stackOld = $this->elements;
-			$this->elements = $stack;
-			$stack = $this->filter($selector, true)->stack();
-			$this->elements = $stackOld;
-		}
-		return $stack;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function siblings($selector = null) {
-		$stack = array();
-		$siblings = array_merge(
-			$this->getElementSiblings('previousSibling', $selector),
-			$this->getElementSiblings('nextSibling', $selector)
-		);
-		foreach($siblings as $node) {
-			if (! $this->elementsContainsNode($node, $stack))
-				$stack[] = $node;
-		}
-		return $this->newInstance($stack);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function not($selector = null) {
-		if (is_string($selector))
-			phpQuery::debug(array('not', $selector));
-		else
-			phpQuery::debug('not');
-		$stack = array();
-		if ($selector instanceof self || $selector instanceof DOMNODE) {
-			foreach($this->stack() as $node) {
-				if ($selector instanceof self) {
-					$matchFound = false;
-					foreach($selector->stack() as $notNode) {
-						if ($notNode->isSameNode($node))
-							$matchFound = true;
-					}
-					if (! $matchFound)
-						$stack[] = $node;
-				} else if ($selector instanceof DOMNODE) {
-					if (! $selector->isSameNode($node))
-						$stack[] = $node;
-				} else {
-					if (! $this->is($selector))
-						$stack[] = $node;
-				}
-			}
-		} else {
-			$orgStack = $this->stack();
-			$matched = $this->filter($selector, true)->stack();
-//			$matched = array();
-//			// simulate OR in filter() instead of AND 5y
-//			foreach($this->parseSelector($selector) as $s) {
-//				$matched = array_merge($matched,
-//					$this->filter(array($s))->stack()
-//				);
-//			}
-			foreach($orgStack as $node)
-				if (! $this->elementsContainsNode($node, $matched))
-					$stack[] = $node;
-		}
-		return $this->newInstance($stack);
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param string|phpQueryObject
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function add($selector = null) {
-		if (! $selector)
-			return $this;
-		$stack = array();
-		$this->elementsBackup = $this->elements;
-		$found = phpQuery::pq($selector, $this->getDocumentID());
-		$this->merge($found->elements);
-		return $this->newInstance();
-	}
-	/**
-	 * @access private
-	 */
-	protected function merge() {
-		foreach(func_get_args() as $nodes)
-			foreach($nodes as $newNode )
-				if (! $this->elementsContainsNode($newNode) )
-					$this->elements[] = $newNode;
-	}
-	/**
-	 * @access private
-	 * TODO refactor to stackContainsNode
-	 */
-	protected function elementsContainsNode($nodeToCheck, $elementsStack = null) {
-		$loop = ! is_null($elementsStack)
-			? $elementsStack
-			: $this->elements;
-		foreach($loop as $node) {
-			if ( $node->isSameNode( $nodeToCheck ) )
-				return true;
-		}
-		return false;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function parent($selector = null) {
-		$stack = array();
-		foreach($this->elements as $node )
-			if ( $node->parentNode && ! $this->elementsContainsNode($node->parentNode, $stack) )
-				$stack[] = $node->parentNode;
-		$this->elementsBackup = $this->elements;
-		$this->elements = $stack;
-		if ( $selector )
-			$this->filter($selector, true);
-		return $this->newInstance();
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function parents($selector = null) {
-		$stack = array();
-		if (! $this->elements )
-			$this->debug('parents() - stack empty');
-		foreach($this->elements as $node) {
-			$test = $node;
-			while( $test->parentNode) {
-				$test = $test->parentNode;
-				if ($this->isRoot($test))
-					break;
-				if (! $this->elementsContainsNode($test, $stack)) {
-					$stack[] = $test;
-					continue;
-				}
-			}
-		}
-		$this->elementsBackup = $this->elements;
-		$this->elements = $stack;
-		if ( $selector )
-			$this->filter($selector, true);
-		return $this->newInstance();
-	}
-	/**
-	 * Internal stack iterator.
-	 *
-	 * @access private
-	 */
-	public function stack($nodeTypes = null) {
-		if (!isset($nodeTypes))
-			return $this->elements;
-		if (!is_array($nodeTypes))
-			$nodeTypes = array($nodeTypes);
-		$return = array();
-		foreach($this->elements as $node) {
-			if (in_array($node->nodeType, $nodeTypes))
-				$return[] = $node;
-		}
-		return $return;
-	}
-	// TODO phpdoc; $oldAttr is result of hasAttribute, before any changes
-	protected function attrEvents($attr, $oldAttr, $oldValue, $node) {
-		// skip events for XML documents
-		if (! $this->isXHTML() && ! $this->isHTML())
-			return;
-		$event = null;
-		// identify
-		$isInputValue = $node->tagName == 'input'
-			&& (
-				in_array($node->getAttribute('type'),
-					array('text', 'password', 'hidden'))
-				|| !$node->getAttribute('type')
-				 );
-		$isRadio = $node->tagName == 'input'
-			&& $node->getAttribute('type') == 'radio';
-		$isCheckbox = $node->tagName == 'input'
-			&& $node->getAttribute('type') == 'checkbox';
-		$isOption = $node->tagName == 'option';
-		if ($isInputValue && $attr == 'value' && $oldValue != $node->getAttribute($attr)) {
-			$event = new DOMEvent(array(
-				'target' => $node,
-				'type' => 'change'
-			));
-		} else if (($isRadio || $isCheckbox) && $attr == 'checked' && (
-				// check
-				(! $oldAttr && $node->hasAttribute($attr))
-				// un-check
-				|| (! $node->hasAttribute($attr) && $oldAttr)
-			)) {
-			$event = new DOMEvent(array(
-				'target' => $node,
-				'type' => 'change'
-			));
-		} else if ($isOption && $node->parentNode && $attr == 'selected' && (
-				// select
-				(! $oldAttr && $node->hasAttribute($attr))
-				// un-select
-				|| (! $node->hasAttribute($attr) && $oldAttr)
-			)) {
-			$event = new DOMEvent(array(
-				'target' => $node->parentNode,
-				'type' => 'change'
-			));
-		}
-		if ($event) {
-			phpQueryEvents::trigger($this->getDocumentID(),
-				$event->type, array($event), $node
-			);
-		}
-	}
-	public function attr($attr = null, $value = null) {
-		foreach($this->stack(1) as $node) {
-			if (! is_null($value)) {
-				$loop = $attr == '*'
-					? $this->getNodeAttrs($node)
-					: array($attr);
-				foreach($loop as $a) {
-					$oldValue = $node->getAttribute($a);
-					$oldAttr = $node->hasAttribute($a);
-					// TODO raises an error when charset other than UTF-8
-					// while document's charset is also not UTF-8
-					@$node->setAttribute($a, $value);
-					$this->attrEvents($a, $oldAttr, $oldValue, $node);
-				}
-			} else if ($attr == '*') {
-				// jQuery difference
-				$return = array();
-				foreach($node->attributes as $n => $v)
-					$return[$n] = $v->value;
-				return $return;
-			} else
-				return $node->hasAttribute($attr)
-					? $node->getAttribute($attr)
-					: null;
-		}
-		return is_null($value)
-			? '' : $this;
-	}
-	/**
-	 * @access private
-	 */
-	protected function getNodeAttrs($node) {
-		$return = array();
-		foreach($node->attributes as $n => $o)
-			$return[] = $n;
-		return $return;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @todo check CDATA ???
-	 */
-	public function attrPHP($attr, $code) {
-		if (! is_null($code)) {
-			$value = '<'.'?php '.$code.' ?'.'>';
-			// TODO tempolary solution
-			// http://code.google.com/p/phpquery/issues/detail?id=17
-//			if (function_exists('mb_detect_encoding') && mb_detect_encoding($value) == 'ASCII')
-//				$value	= mb_convert_encoding($value, 'UTF-8', 'HTML-ENTITIES');
-		}
-		foreach($this->stack(1) as $node) {
-			if (! is_null($code)) {
-//				$attrNode = $this->DOM->createAttribute($attr);
-				$node->setAttribute($attr, $value);
-//				$attrNode->value = $value;
-//				$node->appendChild($attrNode);
-			} else if ( $attr == '*') {
-				// jQuery diff
-				$return = array();
-				foreach($node->attributes as $n => $v)
-					$return[$n] = $v->value;
-				return $return;
-			} else
-				return $node->getAttribute($attr);
-		}
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function removeAttr($attr) {
-		foreach($this->stack(1) as $node) {
-			$loop = $attr == '*'
-				? $this->getNodeAttrs($node)
-				: array($attr);
-			foreach($loop as $a) {
-				$oldValue = $node->getAttribute($a);
-				$node->removeAttribute($a);
-				$this->attrEvents($a, $oldValue, null, $node);
-			}
-		}
-		return $this;
-	}
-	/**
-	 * Return form element value.
-	 *
-	 * @return String Fields value.
-	 */
-	public function val($val = null) {
-		if (! isset($val)) {
-			if ($this->eq(0)->is('select')) {
-					$selected = $this->eq(0)->find('option[selected=selected]');
-					if ($selected->is('[value]'))
-						return $selected->attr('value');
-					else
-						return $selected->text();
-			} else if ($this->eq(0)->is('textarea'))
-					return $this->eq(0)->markup();
-				else
-					return $this->eq(0)->attr('value');
-		} else {
-			$_val = null;
-			foreach($this->stack(1) as $node) {
-				$node = pq($node, $this->getDocumentID());
-				if (is_array($val) && in_array($node->attr('type'), array('checkbox', 'radio'))) {
-					$isChecked = in_array($node->attr('value'), $val)
-							|| in_array($node->attr('name'), $val);
-					if ($isChecked)
-						$node->attr('checked', 'checked');
-					else
-						$node->removeAttr('checked');
-				} else if ($node->get(0)->tagName == 'select') {
-					if (! isset($_val)) {
-						$_val = array();
-						if (! is_array($val))
-							$_val = array((string)$val);
-						else
-							foreach($val as $v)
-								$_val[] = $v;
-					}
-					foreach($node['option']->stack(1) as $option) {
-						$option = pq($option, $this->getDocumentID());
-						$selected = false;
-						// XXX: workaround for string comparsion, see issue #96
-						// http://code.google.com/p/phpquery/issues/detail?id=96
-						$selected = is_null($option->attr('value'))
-							? in_array($option->markup(), $_val)
-							: in_array($option->attr('value'), $_val);
-//						$optionValue = $option->attr('value');
-//						$optionText = $option->text();
-//						$optionTextLenght = mb_strlen($optionText);
-//						foreach($_val as $v)
-//							if ($optionValue == $v)
-//								$selected = true;
-//							else if ($optionText == $v && $optionTextLenght == mb_strlen($v))
-//								$selected = true;
-						if ($selected)
-							$option->attr('selected', 'selected');
-						else
-							$option->removeAttr('selected');
-					}
-				} else if ($node->get(0)->tagName == 'textarea')
-					$node->markup($val);
-				else
-					$node->attr('value', $val);
-			}
-		}
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function andSelf() {
-		if ( $this->previous )
-			$this->elements = array_merge($this->elements, $this->previous->elements);
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function addClass( $className) {
-		if (! $className)
-			return $this;
-		foreach($this->stack(1) as $node) {
-			if (! $this->is(".$className", $node))
-				$node->setAttribute(
-					'class',
-					trim($node->getAttribute('class').' '.$className)
-				);
-		}
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function addClassPHP( $className) {
-		foreach($this->stack(1) as $node) {
-				$classes = $node->getAttribute('class');
-				$newValue = $classes
-					? $classes.' <'.'?php '.$className.' ?'.'>'
-					: '<'.'?php '.$className.' ?'.'>';
-				$node->setAttribute('class', $newValue);
-		}
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param	string	$className
-	 * @return	bool
-	 */
-	public function hasClass($className) {
-		foreach($this->stack(1) as $node) {
-			if ( $this->is(".$className", $node))
-				return true;
-		}
-		return false;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function removeClass($className) {
-		foreach($this->stack(1) as $node) {
-			$classes = explode( ' ', $node->getAttribute('class'));
-			if ( in_array($className, $classes)) {
-				$classes = array_diff($classes, array($className));
-				if ( $classes )
-					$node->setAttribute('class', implode(' ', $classes));
-				else
-					$node->removeAttribute('class');
-			}
-		}
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function toggleClass($className) {
-		foreach($this->stack(1) as $node) {
-			if ( $this->is( $node, '.'.$className ))
-				$this->removeClass($className);
-			else
-				$this->addClass($className);
-		}
-		return $this;
-	}
-	/**
-	 * Proper name without underscore (just ->empty()) also works.
-	 *
-	 * Removes all child nodes from the set of matched elements.
-	 *
-	 * Example:
-	 * pq("p")._empty()
-	 *
-	 * HTML:
-	 * <p>Hello, <span>Person</span> <a href="#">and person</a></p>
-	 *
-	 * Result:
-	 * [ <p></p> ]
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @access private
-	 */
-	public function _empty() {
-		foreach($this->stack(1) as $node) {
-			// thx to 'dave at dgx dot cz'
-			$node->nodeValue = '';
-		}
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param array|string $callback Expects $node as first param, $index as second
-	 * @param array $scope External variables passed to callback. Use compact('varName1', 'varName2'...) and extract($scope)
-	 * @param array $arg1 Will ba passed as third and futher args to callback.
-	 * @param array $arg2 Will ba passed as fourth and futher args to callback, and so on...
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function each($callback, $param1 = null, $param2 = null, $param3 = null) {
-		$paramStructure = null;
-		if (func_num_args() > 1) {
-			$paramStructure = func_get_args();
-			$paramStructure = array_slice($paramStructure, 1);
-		}
-		foreach($this->elements as $v)
-			phpQuery::callbackRun($callback, array($v), $paramStructure);
-		return $this;
-	}
-	/**
-	 * Run callback on actual object.
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function callback($callback, $param1 = null, $param2 = null, $param3 = null) {
-		$params = func_get_args();
-		$params[0] = $this;
-		phpQuery::callbackRun($callback, $params);
-		return $this;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @todo add $scope and $args as in each() ???
-	 */
-	public function map($callback, $param1 = null, $param2 = null, $param3 = null) {
-//		$stack = array();
-////		foreach($this->newInstance() as $node) {
-//		foreach($this->newInstance() as $node) {
-//			$result = call_user_func($callback, $node);
-//			if ($result)
-//				$stack[] = $result;
-//		}
-		$params = func_get_args();
-		array_unshift($params, $this->elements);
-		return $this->newInstance(
-			call_user_func_array(array('phpQuery', 'map'), $params)
-//			phpQuery::map($this->elements, $callback)
-		);
-	}
-	/**
-	 * Enter description here...
-	 * 
-	 * @param <type> $key
-	 * @param <type> $value
-	 */
-	public function data($key, $value = null) {
-		if (! isset($value)) {
-			// TODO? implement specific jQuery behavior od returning parent values
-			// is child which we look up doesn't exist
-			return phpQuery::data($this->get(0), $key, $value, $this->getDocumentID());
-		} else {
-			foreach($this as $node)
-				phpQuery::data($node, $key, $value, $this->getDocumentID());
-			return $this;
-		}
-	}
-	/**
-	 * Enter description here...
-	 * 
-	 * @param <type> $key
-	 */
-	public function removeData($key) {
-		foreach($this as $node)
-			phpQuery::removeData($node, $key, $this->getDocumentID());
-		return $this;
-	}
-	// INTERFACE IMPLEMENTATIONS
-
-	// ITERATOR INTERFACE
-	/**
-   * @access private
-	 */
-	public function rewind(){
-		$this->debug('iterating foreach');
-//		phpQuery::selectDocument($this->getDocumentID());
-		$this->elementsBackup = $this->elements;
-		$this->elementsInterator = $this->elements;
-		$this->valid = isset( $this->elements[0] )
-			? 1 : 0;
-// 		$this->elements = $this->valid
-// 			? array($this->elements[0])
-// 			: array();
-		$this->current = 0;
-	}
-	/**
-   * @access private
-	 */
-	public function current(){
-		return $this->elementsInterator[ $this->current ];
-	}
-	/**
-   * @access private
-	 */
-	public function key(){
-		return $this->current;
-	}
-	/**
-	 * Double-function method.
-	 *
-	 * First: main iterator interface method.
-	 * Second: Returning next sibling, alias for _next().
-	 *
-	 * Proper functionality is choosed automagicaly.
-	 *
-	 * @see phpQueryObject::_next()
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public function next($cssSelector = null){
-//		if ($cssSelector || $this->valid)
-//			return $this->_next($cssSelector);
-		$this->valid = isset( $this->elementsInterator[ $this->current+1 ] )
-			? true
-			: false;
-		if (! $this->valid && $this->elementsInterator) {
-			$this->elementsInterator = null;
-		} else if ($this->valid) {
-			$this->current++;
-		} else {
-			return $this->_next($cssSelector);
-		}
-	}
-	/**
-   * @access private
-	 */
-	public function valid(){
-		return $this->valid;
-	}
-	// ITERATOR INTERFACE END
-	// ARRAYACCESS INTERFACE
-	/**
-   * @access private
-	 */
-	public function offsetExists($offset) {
-		return $this->find($offset)->size() > 0;
-	}
-	/**
-   * @access private
-	 */
-	public function offsetGet($offset) {
-		return $this->find($offset);
-	}
-	/**
-   * @access private
-	 */
-	public function offsetSet($offset, $value) {
-//		$this->find($offset)->replaceWith($value);
-		$this->find($offset)->html($value);
-	}
-	/**
-   * @access private
-	 */
-	public function offsetUnset($offset) {
-		// empty
-		throw new Exception("Can't do unset, use array interface only for calling queries and replacing HTML.");
-	}
-	// ARRAYACCESS INTERFACE END
-	/**
-	 * Returns node's XPath.
-	 *
-	 * @param unknown_type $oneNode
-	 * @return string
-	 * @TODO use native getNodePath is avaible
-	 * @access private
-	 */
-	protected function getNodeXpath($oneNode = null, $namespace = null) {
-		$return = array();
-		$loop = $oneNode
-			? array($oneNode)
-			: $this->elements;
-//		if ($namespace)
-//			$namespace .= ':';
-		foreach($loop as $node) {
-			if ($node instanceof DOMDOCUMENT) {
-				$return[] = '';
-				continue;
-			}
-			$xpath = array();
-			while(! ($node instanceof DOMDOCUMENT)) {
-				$i = 1;
-				$sibling = $node;
-				while($sibling->previousSibling) {
-					$sibling = $sibling->previousSibling;
-					$isElement = $sibling instanceof DOMELEMENT;
-					if ($isElement && $sibling->tagName == $node->tagName)
-						$i++;
-				}
-				$xpath[] = $this->isXML()
-					? "*[local-name()='{$node->tagName}'][{$i}]"
-					: "{$node->tagName}[{$i}]";
-				$node = $node->parentNode;
-			}
-			$xpath = join('/', array_reverse($xpath));
-			$return[] = '/'.$xpath;
-		}
-		return $oneNode
-			? $return[0]
-			: $return;
-	}
-	// HELPERS
-	public function whois($oneNode = null) {
-		$return = array();
-		$loop = $oneNode
-			? array( $oneNode )
-			: $this->elements;
-		foreach($loop as $node) {
-			if (isset($node->tagName)) {
-				$tag = in_array($node->tagName, array('php', 'js'))
-					? strtoupper($node->tagName)
-					: $node->tagName;
-				$return[] = $tag
-					.($node->getAttribute('id')
-						? '#'.$node->getAttribute('id'):'')
-					.($node->getAttribute('class')
-						? '.'.join('.', split(' ', $node->getAttribute('class'))):'')
-					.($node->getAttribute('name')
-						? '[name="'.$node->getAttribute('name').'"]':'')
-					.($node->getAttribute('value') && strpos($node->getAttribute('value'), '<'.'?php') === false
-						? '[value="'.substr(str_replace("\n", '', $node->getAttribute('value')), 0, 15).'"]':'')
-					.($node->getAttribute('value') && strpos($node->getAttribute('value'), '<'.'?php') !== false
-						? '[value=PHP]':'')
-					.($node->getAttribute('selected')
-						? '[selected]':'')
-					.($node->getAttribute('checked')
-						? '[checked]':'')
-				;
-			} else if ($node instanceof DOMTEXT) {
-				if (trim($node->textContent))
-					$return[] = 'Text:'.substr(str_replace("\n", ' ', $node->textContent), 0, 15);
-			} else {
-
-			}
-		}
-		return $oneNode && isset($return[0])
-			? $return[0]
-			: $return;
-	}
-	/**
-	 * Dump htmlOuter and preserve chain. Usefull for debugging.
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 *
-	 */
-	public function dump() {
-		print 'DUMP #'.(phpQuery::$dumpCount++).' ';
-		$debug = phpQuery::$debug;
-		phpQuery::$debug = false;
-//		print __FILE__.':'.__LINE__."\n";
-		var_dump($this->htmlOuter());
-		return $this;
-	}
-	public function dumpWhois() {
-		print 'DUMP #'.(phpQuery::$dumpCount++).' ';
-		$debug = phpQuery::$debug;
-		phpQuery::$debug = false;
-//		print __FILE__.':'.__LINE__."\n";
-		var_dump('whois', $this->whois());
-		phpQuery::$debug = $debug;
-		return $this;
-	}
-	public function dumpLength() {
-		print 'DUMP #'.(phpQuery::$dumpCount++).' ';
-		$debug = phpQuery::$debug;
-		phpQuery::$debug = false;
-//		print __FILE__.':'.__LINE__."\n";
-		var_dump('length', $this->length());
-		phpQuery::$debug = $debug;
-		return $this;
-	}
-	public function dumpTree($html = true, $title = true) {
-		$output = $title
-			? 'DUMP #'.(phpQuery::$dumpCount++)." \n" : '';
-		$debug = phpQuery::$debug;
-		phpQuery::$debug = false;
-		foreach($this->stack() as $node)
-			$output .= $this->__dumpTree($node);
-		phpQuery::$debug = $debug;
-		print $html
-			? nl2br(str_replace(' ', '&nbsp;', $output))
-			: $output;
-		return $this;
-	}
-	private function __dumpTree($node, $intend = 0) {
-		$whois = $this->whois($node);
-		$return = '';
-		if ($whois)
-			$return .= str_repeat(' - ', $intend).$whois."\n";
-		if (isset($node->childNodes))
-			foreach($node->childNodes as $chNode)
-				$return .= $this->__dumpTree($chNode, $intend+1);
-		return $return;
-	}
-	/**
-	 * Dump htmlOuter and stop script execution. Usefull for debugging.
-	 *
-	 */
-	public function dumpDie() {
-		print __FILE__.':'.__LINE__;
-		var_dump($this->htmlOuter());
-		die();
-	}
-}
-
-
-// -- Multibyte Compatibility functions ---------------------------------------
-// http://svn.iphonewebdev.com/lace/lib/mb_compat.php
-
-/**
- *  mb_internal_encoding()
- *
- *  Included for mbstring pseudo-compatability.
- */
-if (!function_exists('mb_internal_encoding'))
-{
-	function mb_internal_encoding($enc) {return true; }
-}
-
-/**
- *  mb_regex_encoding()
- *
- *  Included for mbstring pseudo-compatability.
- */
-if (!function_exists('mb_regex_encoding'))
-{
-	function mb_regex_encoding($enc) {return true; }
-}
-
-/**
- *  mb_strlen()
- *
- *  Included for mbstring pseudo-compatability.
- */
-if (!function_exists('mb_strlen'))
-{
-	function mb_strlen($str)
-	{
-		return strlen($str);
-	}
-}
-
-/**
- *  mb_strpos()
- *
- *  Included for mbstring pseudo-compatability.
- */
-if (!function_exists('mb_strpos'))
-{
-	function mb_strpos($haystack, $needle, $offset=0)
-	{
-		return strpos($haystack, $needle, $offset);
-	}
-}
-/**
- *  mb_stripos()
- *
- *  Included for mbstring pseudo-compatability.
- */
-if (!function_exists('mb_stripos'))
-{
-	function mb_stripos($haystack, $needle, $offset=0)
-	{
-		return stripos($haystack, $needle, $offset);
-	}
-}
-
-/**
- *  mb_substr()
- *
- *  Included for mbstring pseudo-compatability.
- */
-if (!function_exists('mb_substr'))
-{
-	function mb_substr($str, $start, $length=0)
-	{
-		return substr($str, $start, $length);
-	}
-}
-
-/**
- *  mb_substr_count()
- *
- *  Included for mbstring pseudo-compatability.
- */
-if (!function_exists('mb_substr_count'))
-{
-	function mb_substr_count($haystack, $needle)
-	{
-		return substr_count($haystack, $needle);
-	}
-}
-
-
-/**
- * Static namespace for phpQuery functions.
- *
- * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
- * @package phpQuery
- */
-abstract class phpQuery {
-	/**
-	 * XXX: Workaround for mbstring problems 
-	 * 
-	 * @var bool
-	 */
-	public static $mbstringSupport = true;
-	public static $debug = false;
-	public static $documents = array();
-	public static $defaultDocumentID = null;
-//	public static $defaultDoctype = 'html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"';
-	/**
-	 * Applies only to HTML.
-	 *
-	 * @var unknown_type
-	 */
-	public static $defaultDoctype = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
-"http://www.w3.org/TR/html4/loose.dtd">';
-	public static $defaultCharset = 'UTF-8';
-	/**
-	 * Static namespace for plugins.
-	 *
-	 * @var object
-	 */
-	public static $plugins = array();
-	/**
-	 * List of loaded plugins.
-	 *
-	 * @var unknown_type
-	 */
-	public static $pluginsLoaded = array();
-	public static $pluginsMethods = array();
-	public static $pluginsStaticMethods = array();
-	public static $extendMethods = array();
-	/**
-	 * @TODO implement
-	 */
-	public static $extendStaticMethods = array();
-	/**
-	 * Hosts allowed for AJAX connections.
-	 * Dot '.' means $_SERVER['HTTP_HOST'] (if any).
-	 *
-	 * @var array
-	 */
-	public static $ajaxAllowedHosts = array(
-		'.'
-	);
-	/**
-	 * AJAX settings.
-	 *
-	 * @var array
-	 * XXX should it be static or not ?
-	 */
-	public static $ajaxSettings = array(
-		'url' => '',//TODO
-		'global' => true,
-		'type' => "GET",
-		'timeout' => null,
-		'contentType' => "application/x-www-form-urlencoded",
-		'processData' => true,
-//		'async' => true,
-		'data' => null,
-		'username' => null,
-		'password' => null,
-		'accepts' => array(
-			'xml' => "application/xml, text/xml",
-			'html' => "text/html",
-			'script' => "text/javascript, application/javascript",
-			'json' => "application/json, text/javascript",
-			'text' => "text/plain",
-			'_default' => "*/*"
-		)
-	);
-	public static $lastModified = null;
-	public static $active = 0;
-	public static $dumpCount = 0;
-	/**
-	 * Multi-purpose function.
-	 * Use pq() as shortcut.
-	 *
-	 * In below examples, $pq is any result of pq(); function.
-	 *
-	 * 1. Import markup into existing document (without any attaching):
-	 * - Import into selected document:
-	 *   pq('<div/>')				// DOESNT accept text nodes at beginning of input string !
-	 * - Import into document with ID from $pq->getDocumentID():
-	 *   pq('<div/>', $pq->getDocumentID())
-	 * - Import into same document as DOMNode belongs to:
-	 *   pq('<div/>', DOMNode)
-	 * - Import into document from phpQuery object:
-	 *   pq('<div/>', $pq)
-	 *
-	 * 2. Run query:
-	 * - Run query on last selected document:
-	 *   pq('div.myClass')
-	 * - Run query on document with ID from $pq->getDocumentID():
-	 *   pq('div.myClass', $pq->getDocumentID())
-	 * - Run query on same document as DOMNode belongs to and use node(s)as root for query:
-	 *   pq('div.myClass', DOMNode)
-	 * - Run query on document from phpQuery object
-	 *   and use object's stack as root node(s) for query:
-	 *   pq('div.myClass', $pq)
-	 *
-	 * @param string|DOMNode|DOMNodeList|array	$arg1	HTML markup, CSS Selector, DOMNode or array of DOMNodes
-	 * @param string|phpQueryObject|DOMNode	$context	DOM ID from $pq->getDocumentID(), phpQuery object (determines also query root) or DOMNode (determines also query root)
-	 *
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery|QueryTemplatesPhpQuery|false
-   * phpQuery object or false in case of error.
-	 */
-	public static function pq($arg1, $context = null) {
-		if ($arg1 instanceof DOMNODE && ! isset($context)) {
-			foreach(phpQuery::$documents as $documentWrapper) {
-				$compare = $arg1 instanceof DOMDocument
-					? $arg1 : $arg1->ownerDocument;
-				if ($documentWrapper->document->isSameNode($compare))
-					$context = $documentWrapper->id;
-			}
-		}
-		if (! $context) {
-			$domId = self::$defaultDocumentID;
-			if (! $domId)
-				throw new Exception("Can't use last created DOM, because there isn't any. Use phpQuery::newDocument() first.");
-//		} else if (is_object($context) && ($context instanceof PHPQUERY || is_subclass_of($context, 'phpQueryObject')))
-		} else if (is_object($context) && $context instanceof phpQueryObject)
-			$domId = $context->getDocumentID();
-		else if ($context instanceof DOMDOCUMENT) {
-			$domId = self::getDocumentID($context);
-			if (! $domId) {
-				//throw new Exception('Orphaned DOMDocument');
-				$domId = self::newDocument($context)->getDocumentID();
-			}
-		} else if ($context instanceof DOMNODE) {
-			$domId = self::getDocumentID($context);
-			if (! $domId) {
-				throw new Exception('Orphaned DOMNode');
-//				$domId = self::newDocument($context->ownerDocument);
-			}
-		} else
-			$domId = $context;
-		if ($arg1 instanceof phpQueryObject) {
-//		if (is_object($arg1) && (get_class($arg1) == 'phpQueryObject' || $arg1 instanceof PHPQUERY || is_subclass_of($arg1, 'phpQueryObject'))) {
-			/**
-			 * Return $arg1 or import $arg1 stack if document differs:
-			 * pq(pq('<div/>'))
-			 */
-			if ($arg1->getDocumentID() == $domId)
-				return $arg1;
-			$class = get_class($arg1);
-			// support inheritance by passing old object to overloaded constructor
-			$phpQuery = $class != 'phpQuery'
-				? new $class($arg1, $domId)
-				: new phpQueryObject($domId);
-			$phpQuery->elements = array();
-			foreach($arg1->elements as $node)
-				$phpQuery->elements[] = $phpQuery->document->importNode($node, true);
-			return $phpQuery;
-		} else if ($arg1 instanceof DOMNODE || (is_array($arg1) && isset($arg1[0]) && $arg1[0] instanceof DOMNODE)) {
-			/*
-			 * Wrap DOM nodes with phpQuery object, import into document when needed:
-			 * pq(array($domNode1, $domNode2))
-			 */
-			$phpQuery = new phpQueryObject($domId);
-			if (!($arg1 instanceof DOMNODELIST) && ! is_array($arg1))
-				$arg1 = array($arg1);
-			$phpQuery->elements = array();
-			foreach($arg1 as $node) {
-				$sameDocument = $node->ownerDocument instanceof DOMDOCUMENT
-					&& ! $node->ownerDocument->isSameNode($phpQuery->document);
-				$phpQuery->elements[] = $sameDocument
-					? $phpQuery->document->importNode($node, true)
-					: $node;
-			}
-			return $phpQuery;
-		} else if (self::isMarkup($arg1)) {
-			/**
-			 * Import HTML:
-			 * pq('<div/>')
-			 */
-			$phpQuery = new phpQueryObject($domId);
-			return $phpQuery->newInstance(
-				$phpQuery->documentWrapper->import($arg1)
-			);
-		} else {
-			/**
-			 * Run CSS query:
-			 * pq('div.myClass')
-			 */
-			$phpQuery = new phpQueryObject($domId);
-//			if ($context && ($context instanceof PHPQUERY || is_subclass_of($context, 'phpQueryObject')))
-			if ($context && $context instanceof phpQueryObject)
-				$phpQuery->elements = $context->elements;
-			else if ($context && $context instanceof DOMNODELIST) {
-				$phpQuery->elements = array();
-				foreach($context as $node)
-					$phpQuery->elements[] = $node;
-			} else if ($context && $context instanceof DOMNODE)
-				$phpQuery->elements = array($context);
-			return $phpQuery->find($arg1);
-		}
-	}
-	/**
-	 * Sets default document to $id. Document has to be loaded prior
-	 * to using this method.
-	 * $id can be retrived via getDocumentID() or getDocumentIDRef().
-	 *
-	 * @param unknown_type $id
-	 */
-	public static function selectDocument($id) {
-		$id = self::getDocumentID($id);
-		self::debug("Selecting document '$id' as default one");
-		self::$defaultDocumentID = self::getDocumentID($id);
-	}
-	/**
-	 * Returns document with id $id or last used as phpQueryObject.
-	 * $id can be retrived via getDocumentID() or getDocumentIDRef().
-	 * Chainable.
-	 *
-	 * @see phpQuery::selectDocument()
-	 * @param unknown_type $id
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public static function getDocument($id = null) {
-		if ($id)
-			phpQuery::selectDocument($id);
-		else
-			$id = phpQuery::$defaultDocumentID;
-		return new phpQueryObject($id);
-	}
-	/**
-	 * Creates new document from markup.
-	 * Chainable.
-	 *
-	 * @param unknown_type $markup
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public static function newDocument($markup = null, $contentType = null) {
-		if (! $markup)
-			$markup = '';
-		$documentID = phpQuery::createDocumentWrapper($markup, $contentType);
-		return new phpQueryObject($documentID);
-	}
-	/**
-	 * Creates new document from markup.
-	 * Chainable.
-	 *
-	 * @param unknown_type $markup
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public static function newDocumentHTML($markup = null, $charset = null) {
-		$contentType = $charset
-			? ";charset=$charset"
-			: '';
-		return self::newDocument($markup, "text/html{$contentType}");
-	}
-	/**
-	 * Creates new document from markup.
-	 * Chainable.
-	 *
-	 * @param unknown_type $markup
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public static function newDocumentXML($markup = null, $charset = null) {
-		$contentType = $charset
-			? ";charset=$charset"
-			: '';
-		return self::newDocument($markup, "text/xml{$contentType}");
-	}
-	/**
-	 * Creates new document from markup.
-	 * Chainable.
-	 *
-	 * @param unknown_type $markup
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public static function newDocumentXHTML($markup = null, $charset = null) {
-		$contentType = $charset
-			? ";charset=$charset"
-			: '';
-		return self::newDocument($markup, "application/xhtml+xml{$contentType}");
-	}
-	/**
-	 * Creates new document from markup.
-	 * Chainable.
-	 *
-	 * @param unknown_type $markup
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public static function newDocumentPHP($markup = null, $contentType = "text/html") {
-		// TODO pass charset to phpToMarkup if possible (use DOMDocumentWrapper function)
-		$markup = phpQuery::phpToMarkup($markup, self::$defaultCharset);
-		return self::newDocument($markup, $contentType);
-	}
-	public static function phpToMarkup($php, $charset = 'utf-8') {
-		$regexes = array(
-			'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)<'.'?php?(.*?)(?:\\?>)([^\']*)\'@s',
-			'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(")([^"]*)<'.'?php?(.*?)(?:\\?>)([^"]*)"@s',
-		);
-		foreach($regexes as $regex)
-			while (preg_match($regex, $php, $matches)) {
-				$php = preg_replace_callback(
-					$regex,
-//					create_function('$m, $charset = "'.$charset.'"',
-//						'return $m[1].$m[2]
-//							.htmlspecialchars("<"."?php".$m[4]."?".">", ENT_QUOTES|ENT_NOQUOTES, $charset)
-//							.$m[5].$m[2];'
-//					),
-					array('phpQuery', '_phpToMarkupCallback'),
-					$php
-				);
-			}
-		$regex = '@(^|>[^<]*)+?(<\?php(.*?)(\?>))@s';
-//preg_match_all($regex, $php, $matches);
-//var_dump($matches);
-		$php = preg_replace($regex, '\\1<php><!-- \\3 --></php>', $php);
-		return $php;
-	}
-	public static function _phpToMarkupCallback($php, $charset = 'utf-8') {
-		return $m[1].$m[2]
-			.htmlspecialchars("<"."?php".$m[4]."?".">", ENT_QUOTES|ENT_NOQUOTES, $charset)
-			.$m[5].$m[2];
-	}
-	public static function _markupToPHPCallback($m) {
-		return "<"."?php ".htmlspecialchars_decode($m[1])." ?".">";
-	}
-	/**
-	 * Converts document markup containing PHP code generated by phpQuery::php()
-	 * into valid (executable) PHP code syntax.
-	 *
-	 * @param string|phpQueryObject $content
-	 * @return string PHP code.
-	 */
-	public static function markupToPHP($content) {
-		if ($content instanceof phpQueryObject)
-			$content = $content->markupOuter();
-		/* <php>...</php> to <?php...? > */
-		$content = preg_replace_callback(
-			'@<php>\s*<!--(.*?)-->\s*</php>@s',
-//			create_function('$m',
-//				'return "<'.'?php ".htmlspecialchars_decode($m[1])." ?'.'>";'
-//			),
-			array('phpQuery', '_markupToPHPCallback'),
-			$content
-		);
-		/* <node attr='< ?php ? >'> extra space added to save highlighters */
-		$regexes = array(
-			'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)(?:&lt;|%3C)\\?(?:php)?(.*?)(?:\\?(?:&gt;|%3E))([^\']*)\'@s',
-			'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(")([^"]*)(?:&lt;|%3C)\\?(?:php)?(.*?)(?:\\?(?:&gt;|%3E))([^"]*)"@s',
-		);
-		foreach($regexes as $regex)
-			while (preg_match($regex, $content))
-				$content = preg_replace_callback(
-					$regex,
-					create_function('$m',
-						'return $m[1].$m[2].$m[3]."<?php "
-							.str_replace(
-								array("%20", "%3E", "%09", "&#10;", "&#9;", "%7B", "%24", "%7D", "%22", "%5B", "%5D"),
-								array(" ", ">", "	", "\n", "	", "{", "$", "}", \'"\', "[", "]"),
-								htmlspecialchars_decode($m[4])
-							)
-							." ?>".$m[5].$m[2];'
-					),
-					$content
-				);
-		return $content;
-	}
-	/**
-	 * Creates new document from file $file.
-	 * Chainable.
-	 *
-	 * @param string $file URLs allowed. See File wrapper page at php.net for more supported sources.
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public static function newDocumentFile($file, $contentType = null) {
-		$documentID = self::createDocumentWrapper(
-			file_get_contents($file), $contentType
-		);
-		return new phpQueryObject($documentID);
-	}
-	/**
-	 * Creates new document from markup.
-	 * Chainable.
-	 *
-	 * @param unknown_type $markup
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public static function newDocumentFileHTML($file, $charset = null) {
-		$contentType = $charset
-			? ";charset=$charset"
-			: '';
-		return self::newDocumentFile($file, "text/html{$contentType}");
-	}
-	/**
-	 * Creates new document from markup.
-	 * Chainable.
-	 *
-	 * @param unknown_type $markup
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public static function newDocumentFileXML($file, $charset = null) {
-		$contentType = $charset
-			? ";charset=$charset"
-			: '';
-		return self::newDocumentFile($file, "text/xml{$contentType}");
-	}
-	/**
-	 * Creates new document from markup.
-	 * Chainable.
-	 *
-	 * @param unknown_type $markup
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public static function newDocumentFileXHTML($file, $charset = null) {
-		$contentType = $charset
-			? ";charset=$charset"
-			: '';
-		return self::newDocumentFile($file, "application/xhtml+xml{$contentType}");
-	}
-	/**
-	 * Creates new document from markup.
-	 * Chainable.
-	 *
-	 * @param unknown_type $markup
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 */
-	public static function newDocumentFilePHP($file, $contentType = null) {
-		return self::newDocumentPHP(file_get_contents($file), $contentType);
-	}
-	/**
-	 * Reuses existing DOMDocument object.
-	 * Chainable.
-	 *
-	 * @param $document DOMDocument
-	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
-	 * @TODO support DOMDocument
-	 */
-	public static function loadDocument($document) {
-		// TODO
-		die('TODO loadDocument');
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param unknown_type $html
-	 * @param unknown_type $domId
-	 * @return unknown New DOM ID
-	 * @todo support PHP tags in input
-	 * @todo support passing DOMDocument object from self::loadDocument
-	 */
-	protected static function createDocumentWrapper($html, $contentType = null, $documentID = null) {
-		if (function_exists('domxml_open_mem'))
-			throw new Exception("Old PHP4 DOM XML extension detected. phpQuery won't work until this extension is enabled.");
-//		$id = $documentID
-//			? $documentID
-//			: md5(microtime());
-		$document = null;
-		if ($html instanceof DOMDOCUMENT) {
-			if (self::getDocumentID($html)) {
-				// document already exists in phpQuery::$documents, make a copy
-				$document = clone $html;
-			} else {
-				// new document, add it to phpQuery::$documents
-				$wrapper = new DOMDocumentWrapper($html, $contentType, $documentID);
-			}
-		} else {
-			$wrapper = new DOMDocumentWrapper($html, $contentType, $documentID);
-		}
-//		$wrapper->id = $id;
-		// bind document
-		phpQuery::$documents[$wrapper->id] = $wrapper;
-		// remember last loaded document
-		phpQuery::selectDocument($wrapper->id);
-		return $wrapper->id;
-	}
-	/**
-	 * Extend class namespace.
-	 *
-	 * @param string|array $target
-	 * @param array $source
-	 * @TODO support string $source
-	 * @return unknown_type
-	 */
-	public static function extend($target, $source) {
-		switch($target) {
-			case 'phpQueryObject':
-				$targetRef = &self::$extendMethods;
-				$targetRef2 = &self::$pluginsMethods;
-				break;
-			case 'phpQuery':
-				$targetRef = &self::$extendStaticMethods;
-				$targetRef2 = &self::$pluginsStaticMethods;
-				break;
-			default:
-				throw new Exception("Unsupported \$target type");
-		}
-		if (is_string($source))
-			$source = array($source => $source);
-		foreach($source as $method => $callback) {
-			if (isset($targetRef[$method])) {
-//				throw new Exception
-				self::debug("Duplicate method '{$method}', can\'t extend '{$target}'");
-				continue;
-			}
-			if (isset($targetRef2[$method])) {
-//				throw new Exception
-				self::debug("Duplicate method '{$method}' from plugin '{$targetRef2[$method]}',"
-					." can\'t extend '{$target}'");
-				continue;
-			}
-			$targetRef[$method] = $callback;
-		}
-		return true;
-	}
-	/**
-	 * Extend phpQuery with $class from $file.
-	 *
-	 * @param string $class Extending class name. Real class name can be prepended phpQuery_.
-	 * @param string $file Filename to include. Defaults to "{$class}.php".
-	 */
-	public static function plugin($class, $file = null) {
-		// TODO $class checked agains phpQuery_$class
-//		if (strpos($class, 'phpQuery') === 0)
-//			$class = substr($class, 8);
-		if (in_array($class, self::$pluginsLoaded))
-			return true;
-		if (! $file)
-			$file = $class.'.php';
-		$objectClassExists = class_exists('phpQueryObjectPlugin_'.$class);
-		$staticClassExists = class_exists('phpQueryPlugin_'.$class);
-		if (! $objectClassExists && ! $staticClassExists)
-			require_once($file);
-		self::$pluginsLoaded[] = $class;
-		// static methods
-		if (class_exists('phpQueryPlugin_'.$class)) {
-			$realClass = 'phpQueryPlugin_'.$class;
-			$vars = get_class_vars($realClass);
-			$loop = isset($vars['phpQueryMethods'])
-				&& ! is_null($vars['phpQueryMethods'])
-				? $vars['phpQueryMethods']
-				: get_class_methods($realClass);
-			foreach($loop as $method) {
-				if ($method == '__initialize')
-					continue;
-				if (! is_callable(array($realClass, $method)))
-					continue;
-				if (isset(self::$pluginsStaticMethods[$method])) {
-					throw new Exception("Duplicate method '{$method}' from plugin '{$c}' conflicts with same method from plugin '".self::$pluginsStaticMethods[$method]."'");
-					return;
-				}
-				self::$pluginsStaticMethods[$method] = $class;
-			}
-			if (method_exists($realClass, '__initialize'))
-				call_user_func_array(array($realClass, '__initialize'), array());
-		}
-		// object methods
-		if (class_exists('phpQueryObjectPlugin_'.$class)) {
-			$realClass = 'phpQueryObjectPlugin_'.$class;
-			$vars = get_class_vars($realClass);
-			$loop = isset($vars['phpQueryMethods'])
-				&& ! is_null($vars['phpQueryMethods'])
-				? $vars['phpQueryMethods']
-				: get_class_methods($realClass);
-			foreach($loop as $method) {
-				if (! is_callable(array($realClass, $method)))
-					continue;
-				if (isset(self::$pluginsMethods[$method])) {
-					throw new Exception("Duplicate method '{$method}' from plugin '{$c}' conflicts with same method from plugin '".self::$pluginsMethods[$method]."'");
-					continue;
-				}
-				self::$pluginsMethods[$method] = $class;
-			}
-		}
-		return true;
-	}
-	/**
-	 * Unloades all or specified document from memory.
-	 *
-	 * @param mixed $documentID @see phpQuery::getDocumentID() for supported types.
-	 */
-	public static function unloadDocuments($id = null) {
-		if (isset($id)) {
-			if ($id = self::getDocumentID($id))
-				unset(phpQuery::$documents[$id]);
-		} else {
-			foreach(phpQuery::$documents as $k => $v) {
-				unset(phpQuery::$documents[$k]);
-			}
-		}
-	}
-	/**
-	 * Parses phpQuery object or HTML result against PHP tags and makes them active.
-	 *
-	 * @param phpQuery|string $content
-	 * @deprecated
-	 * @return string
-	 */
-	public static function unsafePHPTags($content) {
-		return self::markupToPHP($content);
-	}
-	public static function DOMNodeListToArray($DOMNodeList) {
-		$array = array();
-		if (! $DOMNodeList)
-			return $array;
-		foreach($DOMNodeList as $node)
-			$array[] = $node;
-		return $array;
-	}
-	/**
-	 * Checks if $input is HTML string, which has to start with '<'.
-	 *
-	 * @deprecated
-	 * @param String $input
-	 * @return Bool
-	 * @todo still used ?
-	 */
-	public static function isMarkup($input) {
-		return ! is_array($input) && substr(trim($input), 0, 1) == '<';
-	}
-	public static function debug($text) {
-		if (self::$debug)
-			print var_dump($text);
-	}
-	/**
-	 * Make an AJAX request.
-	 *
-	 * @param array See $options http://docs.jquery.com/Ajax/jQuery.ajax#toptions
-	 * Additional options are:
-	 * 'document' - document for global events, @see phpQuery::getDocumentID()
-	 * 'referer' - implemented
-	 * 'requested_with' - TODO; not implemented (X-Requested-With)
-	 * @return Zend_Http_Client
-	 * @link http://docs.jquery.com/Ajax/jQuery.ajax
-	 *
-	 * @TODO $options['cache']
-	 * @TODO $options['processData']
-	 * @TODO $options['xhr']
-	 * @TODO $options['data'] as string
-	 * @TODO XHR interface
-	 */
-	public static function ajax($options = array(), $xhr = null) {
-		$options = array_merge(
-			self::$ajaxSettings, $options
-		);
-		$documentID = isset($options['document'])
-			? self::getDocumentID($options['document'])
-			: null;
-		if ($xhr) {
-			// reuse existing XHR object, but clean it up
-			$client = $xhr;
-//			$client->setParameterPost(null);
-//			$client->setParameterGet(null);
-			$client->setAuth(false);
-			$client->setHeaders("If-Modified-Since", null);
-			$client->setHeaders("Referer", null);
-			$client->resetParameters();
-		} else {
-			// create new XHR object
-			require_once('Zend/Http/Client.php');
-			$client = new Zend_Http_Client();
-			$client->setCookieJar();
-		}
-		if (isset($options['timeout']))
-			$client->setConfig(array(
-				'timeout'      => $options['timeout'],
-			));
-//			'maxredirects' => 0,
-		foreach(self::$ajaxAllowedHosts as $k => $host)
-			if ($host == '.' && isset($_SERVER['HTTP_HOST']))
-				self::$ajaxAllowedHosts[$k] = $_SERVER['HTTP_HOST'];
-		$host = parse_url($options['url'], PHP_URL_HOST);
-		if (! in_array($host, self::$ajaxAllowedHosts)) {
-			throw new Exception("Request not permitted, host '$host' not present in "
-				."phpQuery::\$ajaxAllowedHosts");
-		}
-		// JSONP
-		$jsre = "/=\\?(&|$)/";
-		if (isset($options['dataType']) && $options['dataType'] == 'jsonp') {
-			$jsonpCallbackParam = $options['jsonp']
-				? $options['jsonp'] : 'callback';
-			if (strtolower($options['type']) == 'get') {
-				if (! preg_match($jsre, $options['url'])) {
-					$sep = strpos($options['url'], '?')
-						? '&' : '?';
-					$options['url'] .= "$sep$jsonpCallbackParam=?";
-				}
-			} else if ($options['data']) {
-				$jsonp = false;
-				foreach($options['data'] as $n => $v) {
-					if ($v == '?')
-						$jsonp = true;
-				}
-				if (! $jsonp) {
-					$options['data'][$jsonpCallbackParam] = '?';
-				}
-			}
-			$options['dataType'] = 'json';
-		}
-		if (isset($options['dataType']) && $options['dataType'] == 'json') {
-			$jsonpCallback = 'json_'.md5(microtime());
-			$jsonpData = $jsonpUrl = false;
-			if ($options['data']) {
-				foreach($options['data'] as $n => $v) {
-					if ($v == '?')
-						$jsonpData = $n;
-				}
-			}
-			if (preg_match($jsre, $options['url']))
-				$jsonpUrl = true;
-			if ($jsonpData !== false || $jsonpUrl) {
-				// remember callback name for httpData()
-				$options['_jsonp'] = $jsonpCallback;
-				if ($jsonpData !== false)
-					$options['data'][$jsonpData] = $jsonpCallback;
-				if ($jsonpUrl)
-					$options['url'] = preg_replace($jsre, "=$jsonpCallback\\1", $options['url']);
-			}
-		}
-		$client->setUri($options['url']);
-		$client->setMethod(strtoupper($options['type']));
-		if (isset($options['referer']) && $options['referer'])
-			$client->setHeaders('Referer', $options['referer']);
-		$client->setHeaders(array(
-//			'content-type' => $options['contentType'],
-			'User-Agent' => 'Mozilla/5.0 (X11; U; Linux x86; en-US; rv:1.9.0.5) Gecko'
-				 .'/2008122010 Firefox/3.0.5',
-	 		// TODO custom charset
-			'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
-// 	 		'Connection' => 'keep-alive',
-// 			'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
-	 		'Accept-Language' => 'en-us,en;q=0.5',
-		));
-		if ($options['username'])
-			$client->setAuth($options['username'], $options['password']);
-		if (isset($options['ifModified']) && $options['ifModified'])
-			$client->setHeaders("If-Modified-Since",
-				self::$lastModified
-					? self::$lastModified
-					: "Thu, 01 Jan 1970 00:00:00 GMT"
-			);
-		$client->setHeaders("Accept",
-			isset($options['dataType'])
-			&& isset(self::$ajaxSettings['accepts'][ $options['dataType'] ])
-				? self::$ajaxSettings['accepts'][ $options['dataType'] ].", */*"
-				: self::$ajaxSettings['accepts']['_default']
-		);
-		// TODO $options['processData']
-		if ($options['data'] instanceof phpQueryObject) {
-			$serialized = $options['data']->serializeArray($options['data']);
-			$options['data'] = array();
-			foreach($serialized as $r)
-				$options['data'][ $r['name'] ] = $r['value'];
-		}
-		if (strtolower($options['type']) == 'get') {
-			$client->setParameterGet($options['data']);
-		} else if (strtolower($options['type']) == 'post') {
-			$client->setEncType($options['contentType']);
-			$client->setParameterPost($options['data']);
-		}
-		if (self::$active == 0 && $options['global'])
-			phpQueryEvents::trigger($documentID, 'ajaxStart');
-		self::$active++;
-		// beforeSend callback
-		if (isset($options['beforeSend']) && $options['beforeSend'])
-			phpQuery::callbackRun($options['beforeSend'], array($client));
-		// ajaxSend event
-		if ($options['global'])
-			phpQueryEvents::trigger($documentID, 'ajaxSend', array($client, $options));
-		if (phpQuery::$debug) {
-			self::debug("{$options['type']}: {$options['url']}\n");
-			self::debug("Options: <pre>".var_export($options, true)."</pre>\n");
-//			if ($client->getCookieJar())
-//				self::debug("Cookies: <pre>".var_export($client->getCookieJar()->getMatchingCookies($options['url']), true)."</pre>\n");
-		}
-		// request
-		$response = $client->request();
-		if (phpQuery::$debug) {
-			self::debug('Status: '.$response->getStatus().' / '.$response->getMessage());
-			self::debug($client->getLastRequest());
-			self::debug($response->getHeaders());
-		}
-		if ($response->isSuccessful()) {
-			// XXX tempolary
-			self::$lastModified = $response->getHeader('Last-Modified');
-			$data = self::httpData($response->getBody(), $options['dataType'], $options);
-			if (isset($options['success']) && $options['success'])
-				phpQuery::callbackRun($options['success'], array($data, $response->getStatus(), $options));
-			if ($options['global'])
-				phpQueryEvents::trigger($documentID, 'ajaxSuccess', array($client, $options));
-		} else {
-			if (isset($options['error']) && $options['error'])
-				phpQuery::callbackRun($options['error'], array($client, $response->getStatus(), $response->getMessage()));
-			if ($options['global'])
-				phpQueryEvents::trigger($documentID, 'ajaxError', array($client, /*$response->getStatus(),*/$response->getMessage(), $options));
-		}
-		if (isset($options['complete']) && $options['complete'])
-			phpQuery::callbackRun($options['complete'], array($client, $response->getStatus()));
-		if ($options['global'])
-			phpQueryEvents::trigger($documentID, 'ajaxComplete', array($client, $options));
-		if ($options['global'] && ! --self::$active)
-			phpQueryEvents::trigger($documentID, 'ajaxStop');
-		return $client;
-//		if (is_null($domId))
-//			$domId = self::$defaultDocumentID ? self::$defaultDocumentID : false;
-//		return new phpQueryAjaxResponse($response, $domId);
-	}
-	protected static function httpData($data, $type, $options) {
-		if (isset($options['dataFilter']) && $options['dataFilter'])
-			$data = self::callbackRun($options['dataFilter'], array($data, $type));
-		if (is_string($data)) {
-			if ($type == "json") {
-				if (isset($options['_jsonp']) && $options['_jsonp']) {
-					$data = preg_replace('/^\s*\w+\((.*)\)\s*$/s', '$1', $data);
-				}
-				$data = self::parseJSON($data);
-			}
-		}
-		return $data;
-	}
-	/**
-	 * Enter description here...
-	 *
-	 * @param array|phpQuery $data
-	 *
-	 */
-	public static function param($data) {
-		return http_build_query($data, null, '&');
-	}
-	public static function get($url, $data = null, $callback = null, $type = null) {
-		if (!is_array($data)) {
-			$callback = $data;
-			$data = null;
-		}
-		// TODO some array_values on this shit
-		return phpQuery::ajax(array(
-			'type' => 'GET',
-			'url' => $url,
-			'data' => $data,
-			'success' => $callback,
-			'dataType' => $type,
-		));
-	}
-	public static function post($url, $data = null, $callback = null, $type = null) {
-		if (!is_array($data)) {
-			$callback = $data;
-			$data = null;
-		}
-		return phpQuery::ajax(array(
-			'type' => 'POST',
-			'url' => $url,
-			'data' => $data,
-			'success' => $callback,
-			'dataType' => $type,
-		));
-	}
-	public static function getJSON($url, $data = null, $callback = null) {
-		if (!is_array($data)) {
-			$callback = $data;
-			$data = null;
-		}
-		// TODO some array_values on this shit
-		return phpQuery::ajax(array(
-			'type' => 'GET',
-			'url' => $url,
-			'data' => $data,
-			'success' => $callback,
-			'dataType' => 'json',
-		));
-	}
-	public static function ajaxSetup($options) {
-		self::$ajaxSettings = array_merge(
-			self::$ajaxSettings,
-			$options
-		);
-	}
-	public static function ajaxAllowHost($host1, $host2 = null, $host3 = null) {
-		$loop = is_array($host1)
-			? $host1
-			: func_get_args();
-		foreach($loop as $host) {
-			if ($host && ! in_array($host, phpQuery::$ajaxAllowedHosts)) {
-				phpQuery::$ajaxAllowedHosts[] = $host;
-			}
-		}
-	}
-	public static function ajaxAllowURL($url1, $url2 = null, $url3 = null) {
-		$loop = is_array($url1)
-			? $url1
-			: func_get_args();
-		foreach($loop as $url)
-			phpQuery::ajaxAllowHost(parse_url($url, PHP_URL_HOST));
-	}
-	/**
-	 * Returns JSON representation of $data.
-	 *
-	 * @static
-	 * @param mixed $data
-	 * @return string
-	 */
-	public static function toJSON($data) {
-		if (function_exists('json_encode'))
-			return json_encode($data);
-		require_once('Zend/Json/Encoder.php');
-		return Zend_Json_Encoder::encode($data);
-	}
-	/**
-	 * Parses JSON into proper PHP type.
-	 *
-	 * @static
-	 * @param string $json
-	 * @return mixed
-	 */
-	public static function parseJSON($json) {
-		if (function_exists('json_decode')) {
-			$return = json_decode(trim($json), true);
-			// json_decode and UTF8 issues
-			if (isset($return))
-				return $return;
-		}
-		require_once('Zend/Json/Decoder.php');
-		return Zend_Json_Decoder::decode($json);
-	}
-	/**
-	 * Returns source's document ID.
-	 *
-	 * @param $source DOMNode|phpQueryObject
-	 * @return string
-	 */
-	public static function getDocumentID($source) {
-		if ($source instanceof DOMDOCUMENT) {
-			foreach(phpQuery::$documents as $id => $document) {
-				if ($source->isSameNode($document->document))
-					return $id;
-			}
-		} else if ($source instanceof DOMNODE) {
-			foreach(phpQuery::$documents as $id => $document) {
-				if ($source->ownerDocument->isSameNode($document->document))
-					return $id;
-			}
-		} else if ($source instanceof phpQueryObject)
-			return $source->getDocumentID();
-		else if (is_string($source) && isset(phpQuery::$documents[$source]))
-			return $source;
-	}
-	/**
-	 * Get DOMDocument object related to $source.
-	 * Returns null if such document doesn't exist.
-	 *
-	 * @param $source DOMNode|phpQueryObject|string
-	 * @return string
-	 */
-	public static function getDOMDocument($source) {
-		if ($source instanceof DOMDOCUMENT)
-			return $source;
-		$source = self::getDocumentID($source);
-		return $source
-			? self::$documents[$id]['document']
-			: null;
-	}
-
-	// UTILITIES
-	// http://docs.jquery.com/Utilities
-
-	/**
-	 *
-	 * @return unknown_type
-	 * @link http://docs.jquery.com/Utilities/jQuery.makeArray
-	 */
-	public static function makeArray($obj) {
-		$array = array();
-		if (is_object($object) && $object instanceof DOMNODELIST) {
-			foreach($object as $value)
-				$array[] = $value;
-		} else if (is_object($object) && ! ($object instanceof Iterator)) {
-			foreach(get_object_vars($object) as $name => $value)
-				$array[0][$name] = $value;
-		} else {
-			foreach($object as $name => $value)
-				$array[0][$name] = $value;
-		}
-		return $array;
-	}
-	public static function inArray($value, $array) {
-		return in_array($value, $array);
-	}
-	/**
-	 *
-	 * @param $object
-	 * @param $callback
-	 * @return unknown_type
-	 * @link http://docs.jquery.com/Utilities/jQuery.each
-	 */
-	public static function each($object, $callback, $param1 = null, $param2 = null, $param3 = null) {
-		$paramStructure = null;
-		if (func_num_args() > 2) {
-			$paramStructure = func_get_args();
-			$paramStructure = array_slice($paramStructure, 2);
-		}
-		if (is_object($object) && ! ($object instanceof Iterator)) {
-			foreach(get_object_vars($object) as $name => $value)
-				phpQuery::callbackRun($callback, array($name, $value), $paramStructure);
-		} else {
-			foreach($object as $name => $value)
-				phpQuery::callbackRun($callback, array($name, $value), $paramStructure);
-		}
-	}
-	/**
-	 *
-	 * @link http://docs.jquery.com/Utilities/jQuery.map
-	 */
-	public static function map($array, $callback, $param1 = null, $param2 = null, $param3 = null) {
-		$result = array();
-		$paramStructure = null;
-		if (func_num_args() > 2) {
-			$paramStructure = func_get_args();
-			$paramStructure = array_slice($paramStructure, 2);
-		}
-		foreach($array as $v) {
-			$vv = phpQuery::callbackRun($callback, array($v), $paramStructure);
-//			$callbackArgs = $args;
-//			foreach($args as $i => $arg) {
-//				$callbackArgs[$i] = $arg instanceof CallbackParam
-//					? $v
-//					: $arg;
-//			}
-//			$vv = call_user_func_array($callback, $callbackArgs);
-			if (is_array($vv))  {
-				foreach($vv as $vvv)
-					$result[] = $vvv;
-			} else if ($vv !== null) {
-				$result[] = $vv;
-			}
-		}
-		return $result;
-	}
-	/**
-	 *
-	 * @param $callback Callback
-	 * @param $params
-	 * @param $paramStructure
-	 * @return unknown_type
-	 */
-	public static function callbackRun($callback, $params = array(), $paramStructure = null) {
-		if (! $callback)
-			return;
-		if ($callback instanceof CallbackParameterToReference) {
-			// TODO support ParamStructure to select which $param push to reference
-			if (isset($params[0]))
-				$callback->callback = $params[0];
-			return true;
-		}
-		if ($callback instanceof Callback) {
-			$paramStructure = $callback->params;
-			$callback = $callback->callback;
-		}
-		if (! $paramStructure)
-			return call_user_func_array($callback, $params);
-		$p = 0;
-		foreach($paramStructure as $i => $v) {
-			$paramStructure[$i] = $v instanceof CallbackParam
-				? $params[$p++]
-				: $v;
-		}
-		return call_user_func_array($callback, $paramStructure);
-	}
-	/**
-	 * Merge 2 phpQuery objects.
-	 * @param array $one
-	 * @param array $two
-	 * @protected
-	 * @todo node lists, phpQueryObject
-	 */
-	public static function merge($one, $two) {
-		$elements = $one->elements;
-		foreach($two->elements as $node) {
-			$exists = false;
-			foreach($elements as $node2) {
-				if ($node2->isSameNode($node))
-					$exists = true;
-			}
-			if (! $exists)
-				$elements[] = $node;
-		}
-		return $elements;
-//		$one = $one->newInstance();
-//		$one->elements = $elements;
-//		return $one;
-	}
-	/**
-	 *
-	 * @param $array
-	 * @param $callback
-	 * @param $invert
-	 * @return unknown_type
-	 * @link http://docs.jquery.com/Utilities/jQuery.grep
-	 */
-	public static function grep($array, $callback, $invert = false) {
-		$result = array();
-		foreach($array as $k => $v) {
-			$r = call_user_func_array($callback, array($v, $k));
-			if ($r === !(bool)$invert)
-				$result[] = $v;
-		}
-		return $result;
-	}
-	public static function unique($array) {
-		return array_unique($array);
-	}
-	/**
-	 *
-	 * @param $function
-	 * @return unknown_type
-	 * @TODO there are problems with non-static methods, second parameter pass it
-	 * 	but doesnt verify is method is really callable
-	 */
-	public static function isFunction($function) {
-		return is_callable($function);
-	}
-	public static function trim($str) {
-		return trim($str);
-	}
-	/* PLUGINS NAMESPACE */
-	/**
-	 *
-	 * @param $url
-	 * @param $callback
-	 * @param $param1
-	 * @param $param2
-	 * @param $param3
-	 * @return phpQueryObject
-	 */
-	public static function browserGet($url, $callback, $param1 = null, $param2 = null, $param3 = null) {
-		if (self::plugin('WebBrowser')) {
-			$params = func_get_args();
-			return self::callbackRun(array(self::$plugins, 'browserGet'), $params);
-		} else {
-			self::debug('WebBrowser plugin not available...');
-		}
-	}
-	/**
-	 *
-	 * @param $url
-	 * @param $data
-	 * @param $callback
-	 * @param $param1
-	 * @param $param2
-	 * @param $param3
-	 * @return phpQueryObject
-	 */
-	public static function browserPost($url, $data, $callback, $param1 = null, $param2 = null, $param3 = null) {
-		if (self::plugin('WebBrowser')) {
-			$params = func_get_args();
-			return self::callbackRun(array(self::$plugins, 'browserPost'), $params);
-		} else {
-			self::debug('WebBrowser plugin not available...');
-		}
-	}
-	/**
-	 *
-	 * @param $ajaxSettings
-	 * @param $callback
-	 * @param $param1
-	 * @param $param2
-	 * @param $param3
-	 * @return phpQueryObject
-	 */
-	public static function browser($ajaxSettings, $callback, $param1 = null, $param2 = null, $param3 = null) {
-		if (self::plugin('WebBrowser')) {
-			$params = func_get_args();
-			return self::callbackRun(array(self::$plugins, 'browser'), $params);
-		} else {
-			self::debug('WebBrowser plugin not available...');
-		}
-	}
-	/**
-	 *
-	 * @param $code
-	 * @return string
-	 */
-	public static function php($code) {
-		return self::code('php', $code);
-	}
-	/**
-	 *
-	 * @param $type
-	 * @param $code
-	 * @return string
-	 */
-	public static function code($type, $code) {
-		return "<$type><!-- ".trim($code)." --></$type>";
-	}
-
-	public static function __callStatic($method, $params) {
-		return call_user_func_array(
-			array(phpQuery::$plugins, $method),
-			$params
-		);
-	}
-	protected static function dataSetupNode($node, $documentID) {
-		// search are return if alredy exists
-		foreach(phpQuery::$documents[$documentID]->dataNodes as $dataNode) {
-			if ($node->isSameNode($dataNode))
-				return $dataNode;
-		}
-		// if doesn't, add it
-		phpQuery::$documents[$documentID]->dataNodes[] = $node;
-		return $node;
-	}
-	protected static function dataRemoveNode($node, $documentID) {
-		// search are return if alredy exists
-		foreach(phpQuery::$documents[$documentID]->dataNodes as $k => $dataNode) {
-			if ($node->isSameNode($dataNode)) {
-				unset(self::$documents[$documentID]->dataNodes[$k]);
-				unset(self::$documents[$documentID]->data[ $dataNode->dataID ]);
-			}
-		}
-	}
-	public static function data($node, $name, $data, $documentID = null) {
-		if (! $documentID)
-			// TODO check if this works
-			$documentID = self::getDocumentID($node);
-		$document = phpQuery::$documents[$documentID];
-		$node = self::dataSetupNode($node, $documentID);
-		if (! isset($node->dataID))
-			$node->dataID = ++phpQuery::$documents[$documentID]->uuid;
-		$id = $node->dataID;
-		if (! isset($document->data[$id]))
-			$document->data[$id] = array();
-		if (! is_null($data))
-			$document->data[$id][$name] = $data;
-		if ($name) {
-			if (isset($document->data[$id][$name]))
-				return $document->data[$id][$name];
-		} else
-			return $id;
-	}
-	public static function removeData($node, $name, $documentID) {
-		if (! $documentID)
-			// TODO check if this works
-			$documentID = self::getDocumentID($node);
-		$document = phpQuery::$documents[$documentID];
-		$node = self::dataSetupNode($node, $documentID);
-		$id = $node->dataID;
-		if ($name) {
-			if (isset($document->data[$id][$name]))
-				unset($document->data[$id][$name]);
-			$name = null;
-			foreach($document->data[$id] as $name)
-				break;
-			if (! $name)
-				self::removeData($node, $name, $documentID);
-		} else {
-			self::dataRemoveNode($node, $documentID);
-		}
-	}
-}
-/**
- * Plugins static namespace class.
- *
- * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
- * @package phpQuery
- * @todo move plugin methods here (as statics)
- */
-class phpQueryPlugins {
-	public function __call($method, $args) {
-		if (isset(phpQuery::$extendStaticMethods[$method])) {
-			$return = call_user_func_array(
-				phpQuery::$extendStaticMethods[$method],
-				$args
-			);
-		} else if (isset(phpQuery::$pluginsStaticMethods[$method])) {
-			$class = phpQuery::$pluginsStaticMethods[$method];
-			$realClass = "phpQueryPlugin_$class";
-			$return = call_user_func_array(
-				array($realClass, $method),
-				$args
-			);
-			return isset($return)
-				? $return
-				: $this;
-		} else
-			throw new Exception("Method '{$method}' doesnt exist");
-	}
-}
-/**
- * Shortcut to phpQuery::pq($arg1, $context)
- * Chainable.
- *
- * @see phpQuery::pq()
- * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery
- * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
- * @package phpQuery
- */
-function pq($arg1, $context = null) {
-	$args = func_get_args();
-	return call_user_func_array(
-		array('phpQuery', 'pq'),
-		$args
-	);
-}
-// add plugins dir and Zend framework to include path
-set_include_path(
-	get_include_path()
-		.PATH_SEPARATOR.dirname(__FILE__).'/phpQuery/'
-		.PATH_SEPARATOR.dirname(__FILE__).'/phpQuery/plugins/'
-);
-// why ? no __call nor __get for statics in php...
-// XXX __callStatic will be available in PHP 5.3
-phpQuery::$plugins = new phpQueryPlugins();
-// include bootstrap file (personal library config)
-if (file_exists(dirname(__FILE__).'/phpQuery/bootstrap.php'))
-	require_once dirname(__FILE__).'/phpQuery/bootstrap.php';
\ No newline at end of file