[Mapbender-commits] r6243 - in trunk/mapbender/http: extensions extensions/jsTree.v.1.0rc extensions/jsTree.v.1.0rc/_demo extensions/jsTree.v.1.0rc/_demo/_inc extensions/jsTree.v.1.0rc/_docs extensions/jsTree.v.1.0rc/_docs/syntax extensions/jsTree.v.1.0rc/_lib extensions/jsTree.v.1.0rc/themes extensions/jsTree.v.1.0rc/themes/default plugins

svn_mapbender at osgeo.org svn_mapbender at osgeo.org
Wed Jun 2 11:20:18 EDT 2010


Author: christoph
Date: 2010-06-02 11:20:17 -0400 (Wed, 02 Jun 2010)
New Revision: 6243

Added:
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_dump.sql
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/__mysql_errors.log
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/class._database.php
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/class._database_i.php
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/class.tree.php
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_install.txt
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/config.php
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/file.png
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/folder.png
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/index.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/root.png
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/server.php
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/!style.css
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_drive.png
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_html_data.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_json_data.json
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_search_data.json
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_search_result.json
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_xml_flat.xml
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_xml_nest.xml
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/checkbox.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/contextmenu.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/cookies.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/core.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/crrm.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/dnd.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/hotkeys.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/html_data.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/index.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/json_data.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/languages.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/search.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/sort.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/!script.js
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/!style.css
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/clipboard.swf
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/help.png
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/magnifier.png
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/page_white_code.png
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/page_white_copy.png
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/printer.png
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/wrapping.png
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/themes.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/types.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/ui.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/xml_data.html
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_lib/
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_lib/jquery.cookie.js
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_lib/jquery.hotkeys.js
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/_lib/jquery.js
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/jquery.jstree.js
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/jquery.jstree.min.js
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/d.png
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/dot_for_ie.gif
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/style.css
   trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/throbber.gif
Modified:
   trunk/mapbender/http/plugins/mb_metadata_edit.js
   trunk/mapbender/http/plugins/mb_metadata_layer.js
   trunk/mapbender/http/plugins/mb_metadata_layerTree.js
   trunk/mapbender/http/plugins/mb_metadata_select.js
   trunk/mapbender/http/plugins/mb_metadata_server.php
   trunk/mapbender/http/plugins/mb_metadata_submit.js
Log:
layer searchable in wms metadata editor, with new jstree 1.0

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_dump.sql
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_dump.sql	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_dump.sql	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,20 @@
+CREATE TABLE IF NOT EXISTS `tree` (
+  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+  `parent_id` bigint(20) unsigned NOT NULL,
+  `position` bigint(20) unsigned NOT NULL,
+  `left` bigint(20) unsigned NOT NULL,
+  `right` bigint(20) unsigned NOT NULL,
+  `level` bigint(20) unsigned NOT NULL,
+  `title` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
+  `type` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=13 ;
+
+INSERT INTO `tree` (`id`, `parent_id`, `position`, `left`, `right`, `level`, `title`, `type`) VALUES
+(1, 0, 2, 1, 14, 0, 'ROOT', ''),
+(2, 1, 0, 2, 11, 1, 'C:', 'drive'),
+(3, 2, 0, 3, 6, 2, '_demo', 'folder'),
+(4, 3, 0, 4, 5, 3, 'index.html', 'default'),
+(5, 2, 1, 7, 10, 2, '_docs', 'folder'),
+(6, 1, 1, 12, 13, 1, 'D:', 'drive'),
+(12, 5, 0, 8, 9, 3, 'zmei.html', 'default');

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/class._database.php
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/class._database.php	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/class._database.php	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,146 @@
+<?php
+class _database {
+	private $link		= false;
+	private $result		= false;
+	private $row		= false;
+
+	public $settings	= array(
+			"servername"=> "localhost",
+			"serverport"=> "3306",
+			"username"	=> false,
+			"password"	=> false,
+			"database"	=> false,
+			"persist"	=> false,
+			"dieonerror"=> false,
+			"showerror"	=> false,
+			"error_file"=> true
+		);
+
+	function __construct() {
+		global $db_config;
+		$this->settings = array_merge($this->settings, $db_config);
+		if($this->settings["error_file"] === true) $this->settings["error_file"] = dirname(__FILE__)."/__mysql_errors.log";
+	}
+
+	function connect() {
+		if (!$this->link) {
+			$this->link = ($this->settings["persist"]) ? 
+				mysql_pconnect(
+					$this->settings["servername"].":".$this->settings["serverport"], 
+					$this->settings["username"], 
+					$this->settings["password"]
+				) : 
+				mysql_connect(
+					$this->settings["servername"].":".$this->settings["serverport"], 
+					$this->settings["username"], 
+					$this->settings["password"]
+				) or $this->error();
+		}
+		if (!mysql_select_db($this->settings["database"], $this->link)) $this->error();
+		if($this->link) mysql_query("SET NAMES 'utf8'");
+		return ($this->link) ? true : false;
+	}
+
+	function query($sql) {
+		if (!$this->link && !$this->connect()) $this->error();
+		if (!($this->result = mysql_query($sql, $this->link))) $this->error($sql);
+		return ($this->result) ? true : false;
+	}
+	
+	function nextr() {
+		if(!$this->result) {
+			$this->error("No query pending");
+			return false;
+		}
+		unset($this->row);
+		$this->row = mysql_fetch_array($this->result, MYSQL_BOTH);
+		return ($this->row) ? true : false ;
+	}
+
+	function get_row($mode = "both") {
+		if(!$this->row) return false;
+
+		$return = array();
+		switch($mode) {
+			case "assoc":
+				foreach($this->row as $k => $v) {
+					if(!is_int($k)) $return[$k] = $v;
+				}
+				break;
+			case "num":
+				foreach($this->row as $k => $v) {
+					if(is_int($k)) $return[$k] = $v;
+				}
+				break;
+			default:
+				$return = $this->row;
+				break;
+		}
+		return $return;
+	}
+
+	function get_all($mode = "both", $key = false) {
+		if(!$this->result) {
+			$this->error("No query pending");
+			return false;
+		}
+		$return = array();
+		while($this->nextr()) {
+			if($key !== false) $return[$this->f($key)] = $this->get_row($mode);
+			else $return[] = $this->get_row($mode);
+		}
+		return $return;
+	}
+
+	function f($index) {
+		return stripslashes($this->row[$index]);
+	}
+
+	function go_to($row) {
+		if(!$this->result) {
+			$this->error("No query pending");
+			return false;
+		}
+		if(!mysql_data_seek($this->result, $row)) $this->error();
+	}
+
+	function nf() {
+		if ($numb = mysql_num_rows($this->result) === false) $this->error();
+		return mysql_num_rows($this->result);
+	}
+	function af() {
+		return mysql_affected_rows();
+	}
+	function error($string="") {
+		$error = mysql_error();
+		if($this->settings["show_error"]) echo $error;
+		if($this->settings["error_file"] !== false) {
+			$handle = @fopen($this->settings["error_file"], "a+");
+			if($handle) {
+				@fwrite($handle, "[".date("Y-m-d H:i:s")."] ".$string." <".$error.">\n");
+				@fclose($handle);
+			}
+		}
+		if($this->settings["dieonerror"]) {
+			if(isset($this->result)) mysql_free_result($this->result);
+			mysql_close($this->link);
+			die();
+		}
+	}
+	function insert_id() {
+		if(!$this->link) return false;
+		return mysql_insert_id();
+	}
+	function escape($string){
+		if(!$this->link) return addslashes($string);
+		return mysql_real_escape_string($string);
+	}
+
+	function destroy(){
+		if (isset($this->result)) mysql_free_result($this->result);
+		if (isset($this->link)) mysql_close($this->link);
+	}
+
+
+}
+?>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/class._database_i.php
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/class._database_i.php	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/class._database_i.php	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,152 @@
+<?php
+class _database {
+	private $data		= false;
+	private $result		= false;
+	private $row		= false;
+
+	public $settings	= array(
+			"servername"=> "localhost",
+			"serverport"=> "3306",
+			"username"	=> false,
+			"password"	=> false,
+			"database"	=> false,
+			"persist"	=> false,
+			"dieonerror"=> false,
+			"showerror"	=> false,
+			"error_file"=> true
+		);
+
+	function __construct() {
+		global $db_config;
+		$this->settings = array_merge($this->settings, $db_config);
+		if($this->settings["error_file"] === true) $this->settings["error_file"] = dirname(__FILE__)."/__mysql_errors.log";
+	}
+
+	function connect() {
+		$this->data = new mysqli(
+			$this->settings["servername"], 
+			$this->settings["username"], 
+			$this->settings["password"], 
+			$this->settings["database"],
+			$this->settings["serverport"]
+		);
+
+		if(mysqli_connect_errno()) { 
+			$this->error("Connection error: ".mysqli_connect_error() ); 
+			return false; 
+		}
+		if(!$this->data->set_charset("utf8")) {
+			$this->error("Error loading character set utf8");
+			return false;
+		}
+		return true;
+	}
+
+	function query($sql) {
+		if(!$this->data && !$this->connect()) {
+			$this->error("Could node connect for query: ".$sql);
+			return false;
+		}
+		//echo $sql."<br />:";
+		if(!($this->result = $this->data->query($sql))) $this->error($sql);
+		return ($this->result) ? true : false;
+	}
+	
+	function nextr(){
+		if(!$this->result) {
+			$this->error("No query pending");
+			return false;
+		}
+		unset($this->row);
+		$this->row = $this->result->fetch_array(MYSQL_BOTH);
+		return ($this->row) ? true : false ;
+	}
+
+	function get_row($mode = "both") {
+		if(!$this->row) return false;
+
+		$return = array();
+		switch($mode) {
+			case "assoc":
+				foreach($this->row as $k => $v) {
+					if(!is_int($k)) $return[$k] = $v;
+				}
+				break;
+			case "num":
+				foreach($this->row as $k => $v) {
+					if(is_int($k)) $return[$k] = $v;
+				}
+				break;
+			default:
+				$return = $this->row;
+				break;
+		}
+		return $return;
+	}
+
+	function get_all($mode = "both", $key = false) {
+		if(!$this->result) {
+			$this->error("No query pending");
+			return false;
+		}
+		$return = array();
+		while($this->nextr()) {
+			if($key !== false) $return[$this->f($key)] = $this->get_row($mode);
+			else $return[] = $this->get_row($mode);
+		}
+		return $return;
+	}
+
+	function f($index) {
+		return stripslashes($this->row[$index]);
+	}
+
+	function go_to($row) {
+		if(!$this->result) {
+			$this->error("No query pending");
+			return false;
+		}
+		if(!$this->data->data_seek($row)) $this->error();
+	}
+
+	function nf() {
+		if (!$this->result) {
+			$this->error("nf: no result set");
+			return false;
+		}
+		return $this->result->num_rows;
+	}
+	function af() {
+		return $this->data->affected_rows;
+	}
+	function error($string = "") {
+		$error = $this->data->error;
+		if($this->settings["show_error"]) echo $error;
+		if($this->settings["error_file"] !== false) {
+			$handle = @fopen($this->settings["error_file"], "a+");
+			if($handle) {
+				@fwrite($handle, "[".date("Y-m-d H:i:s")."] ".$string." <".$error.">\n");
+				@fclose($handle);
+			}
+		}
+		if($this->settings["dieonerror"]) {
+			if(isset($this->result)) $this->result->free();
+			@$this->data->close();
+			die();
+		}
+	}
+	function insert_id() {
+		return $this->data->insert_id;
+	}
+	function escape($string) {
+		if(!$this->data) return addslashes($string);
+		return $this->data->escape_string($string);
+	}
+
+	function destroy() {
+		if(isset($this->result)) $this->result->free();
+		if($this->data) $this->data->close();
+	}
+
+
+}
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/class.tree.php
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/class.tree.php	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_inc/class.tree.php	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,569 @@
+<?php
+class _tree_struct {
+	// Structure table and fields
+	protected $table	= "";
+	protected $fields	= array(
+			"id"		=> false,
+			"parent_id"	=> false,
+			"position"	=> false,
+			"left"		=> false,
+			"right"		=> false,
+			"level"		=> false
+		);
+
+	// Constructor
+	function __construct($table = "tree", $fields = array()) {
+		$this->table = $table;
+		if(!count($fields)) {
+			foreach($this->fields as $k => &$v) { $v = $k; }
+		}
+		else {
+			foreach($fields as $key => $field) {
+				switch($key) {
+					case "id":
+					case "parent_id":
+					case "position":
+					case "left":
+					case "right":
+					case "level":
+						$this->fields[$key] = $field;
+						break;
+				}
+			}
+		}
+		// Database
+		$this->db = new _database;
+	}
+
+	function _get_node($id) {
+		$this->db->query("SELECT `".implode("` , `", $this->fields)."` FROM `".$this->table."` WHERE `".$this->fields["id"]."` = ".(int) $id);
+		$this->db->nextr();
+		return $this->db->nf() === 0 ? false : $this->db->get_row("assoc");
+	}
+	function _get_children($id, $recursive = false) {
+		$children = array();
+		if($recursive) {
+			$node = $this->_get_node($id);
+			$this->db->query("SELECT `".implode("` , `", $this->fields)."` FROM `".$this->table."` WHERE `".$this->fields["left"]."` >= ".(int) $node[$this->fields["left"]]." AND `".$this->fields["right"]."` <= ".(int) $node[$this->fields["right"]]." ORDER BY `".$this->fields["left"]."` ASC");
+		}
+		else {
+			$this->db->query("SELECT `".implode("` , `", $this->fields)."` FROM `".$this->table."` WHERE `".$this->fields["parent_id"]."` = ".(int) $id." ORDER BY `".$this->fields["position"]."` ASC");
+		}
+		while($this->db->nextr()) $children[$this->db->f($this->fields["id"])] = $this->db->get_row("assoc");
+		return $children;
+	}
+	function _get_path($id) {
+		$node = $this->_get_node($id);
+		$path = array();
+		if(!$node === false) return false;
+		$this->db->query("SELECT `".implode("` , `", $this->fields)."` FROM `".$this->table."` WHERE `".$this->fields["left"]."` <= ".(int) $node[$this->fields["left"]]." AND `".$this->fields["right"]."` >= ".(int) $node[$this->fields["right"]]);
+		while($this->db->nextr()) $path[$this->db->f($this->fields["id"])] = $this->db->get_row("assoc");
+		return $path;
+	}
+
+	function _create($parent, $position) {
+		return $this->_move(0, $parent, $position);
+	}
+	function _remove($id) {
+		$data = $this->_get_node($id);
+		$lft = (int)$data[$this->fields["left"]];
+		$rgt = (int)$data[$this->fields["right"]];
+		$dif = $rgt - $lft + 1;
+
+		// deleting node and its children
+		$this->db->query("" . 
+			"DELETE FROM `".$this->table."` " . 
+			"WHERE `".$this->fields["left"]."` >= ".$lft." AND `".$this->fields["right"]."` <= ".$rgt
+		);
+		// shift left indexes of nodes right of the node
+		$this->db->query("".
+			"UPDATE `".$this->table."` " . 
+				"SET `".$this->fields["left"]."` = `".$this->fields["left"]."` - ".$dif." " . 
+			"WHERE `".$this->fields["left"]."` > ".$rgt
+		);
+		// shift right indexes of nodes right of the node and the node's parents
+		$this->db->query("" . 
+			"UPDATE `".$this->table."` " . 
+				"SET `".$this->fields["right"]."` = `".$this->fields["right"]."` - ".$dif." " . 
+			"WHERE `".$this->fields["right"]."` > ".$lft
+		);
+
+		$pid = (int)$data[$this->fields["parent_id"]];
+		$pos = (int)$data[$this->fields["position"]];
+
+		// Update position of siblings below the deleted node
+		$this->db->query("" . 
+			"UPDATE `".$this->table."` " . 
+				"SET `".$this->fields["position"]."` = `".$this->fields["position"]."` - 1 " . 
+			"WHERE `".$this->fields["parent_id"]."` = ".$pid." AND `".$this->fields["position"]."` > ".$pos
+		);
+		return true;
+	}
+	function _move($id, $ref_id, $position = 0, $is_copy = false) {
+		$sql		= array();						// Queries executed at the end
+		$node		= $this->_get_node($id);		// Node data
+		$nchildren	= $this->_get_children($id);	// Node children
+		$ref_node	= $this->_get_node($ref_id);	// Ref node data
+		$rchildren	= $this->_get_children($ref_id);// Ref node children
+
+		$ndif = 2;
+		$node_ids = array(-1);
+		if($node !== false) {
+			$node_ids = array_keys($this->_get_children($id, true));
+			// TODO: should be !$is_copy && , but if copied to self - screws some right indexes
+			if(in_array($ref_id, $node_ids)) return false;
+			$ndif = $node[$this->fields["right"]] - $node[$this->fields["left"]] + 1;
+		}
+		if($position >= count($rchildren)) {
+			$position = count($rchildren);
+		}
+
+		// Not creating or copying - old parent is cleaned
+		if($node !== false && $is_copy == false) {
+			$sql[] = "" . 
+				"UPDATE `".$this->table."` " . 
+					"SET `".$this->fields["position"]."` = `".$this->fields["position"]."` - 1 " . 
+				"WHERE " . 
+					"`".$this->fields["parent_id"]."` = ".$node[$this->fields["parent_id"]]." AND " . 
+					"`".$this->fields["position"]."` > ".$node[$this->fields["position"]];
+			$sql[] = "" . 
+				"UPDATE `".$this->table."` " . 
+					"SET `".$this->fields["left"]."` = `".$this->fields["left"]."` - ".$ndif." " . 
+				"WHERE `".$this->fields["left"]."` > ".$node[$this->fields["right"]];
+			$sql[] = "" . 
+				"UPDATE `".$this->table."` " . 
+					"SET `".$this->fields["right"]."` = `".$this->fields["right"]."` - ".$ndif." " . 
+				"WHERE " . 
+					"`".$this->fields["right"]."` > ".$node[$this->fields["left"]]." AND " . 
+					"`".$this->fields["id"]."` NOT IN (".implode(",", $node_ids).") ";
+		}
+		// Preparing new parent
+		$sql[] = "" . 
+			"UPDATE `".$this->table."` " . 
+				"SET `".$this->fields["position"]."` = `".$this->fields["position"]."` + 1 " . 
+			"WHERE " . 
+				"`".$this->fields["parent_id"]."` = ".$ref_id." AND " . 
+				"`".$this->fields["position"]."` >= ".$position." " . 
+				( $is_copy ? "" : " AND `".$this->fields["id"]."` NOT IN (".implode(",", $node_ids).") ");
+
+		$ref_ind = $ref_id === 0 ? (int)$rchildren[count($rchildren) - 1][$this->fields["right"]] + 1 : (int)$ref_node[$this->fields["right"]];
+		$ref_ind = max($ref_ind, 1);
+
+		$self = ($node !== false && !$is_copy && (int)$node[$this->fields["parent_id"]] == $ref_id && $position > $node[$this->fields["position"]]) ? 1 : 0;
+		foreach($rchildren as $k => $v) {
+			if($v[$this->fields["position"]] - $self == $position) {
+				$ref_ind = (int)$v[$this->fields["left"]];
+				break;
+			}
+		}
+		if($node !== false && !$is_copy && $node[$this->fields["left"]] < $ref_ind) {
+			$ref_ind -= $ndif;
+		}
+
+		$sql[] = "" . 
+			"UPDATE `".$this->table."` " . 
+				"SET `".$this->fields["left"]."` = `".$this->fields["left"]."` + ".$ndif." " . 
+			"WHERE " . 
+				"`".$this->fields["left"]."` >= ".$ref_ind." " . 
+				( $is_copy ? "" : " AND `".$this->fields["id"]."` NOT IN (".implode(",", $node_ids).") ");
+		$sql[] = "" . 
+			"UPDATE `".$this->table."` " . 
+				"SET `".$this->fields["right"]."` = `".$this->fields["right"]."` + ".$ndif." " . 
+			"WHERE " . 
+				"`".$this->fields["right"]."` >= ".$ref_ind." " . 
+				( $is_copy ? "" : " AND `".$this->fields["id"]."` NOT IN (".implode(",", $node_ids).") ");
+
+		$ldif = $ref_id == 0 ? 0 : $ref_node[$this->fields["level"]] + 1;
+		$idif = $ref_ind;
+		if($node !== false) {
+			$ldif = $node[$this->fields["level"]] - ($ref_node[$this->fields["level"]] + 1);
+			$idif = $node[$this->fields["left"]] - $ref_ind;
+			if($is_copy) {
+				$sql[] = "" . 
+					"INSERT INTO `".$this->table."` (" . 
+						"`".$this->fields["parent_id"]."`, " . 
+						"`".$this->fields["position"]."`, " . 
+						"`".$this->fields["left"]."`, " . 
+						"`".$this->fields["right"]."`, " . 
+						"`".$this->fields["level"]."`" . 
+					") " . 
+						"SELECT " . 
+							"".$ref_id.", " . 
+							"`".$this->fields["position"]."`, " . 
+							"`".$this->fields["left"]."` - (".($idif + ($node[$this->fields["left"]] >= $ref_ind ? $ndif : 0))."), " . 
+							"`".$this->fields["right"]."` - (".($idif + ($node[$this->fields["left"]] >= $ref_ind ? $ndif : 0))."), " . 
+							"`".$this->fields["level"]."` - (".$ldif.") " . 
+						"FROM `".$this->table."` " . 
+						"WHERE " . 
+							"`".$this->fields["id"]."` IN (".implode(",", $node_ids).") " . 
+						"ORDER BY `".$this->fields["level"]."` ASC";
+			}
+			else {
+				$sql[] = "" . 
+					"UPDATE `".$this->table."` SET " . 
+						"`".$this->fields["parent_id"]."` = ".$ref_id.", " . 
+						"`".$this->fields["position"]."` = ".$position." " . 
+					"WHERE " . 
+						"`".$this->fields["id"]."` = ".$id;
+				$sql[] = "" . 
+					"UPDATE `".$this->table."` SET " . 
+						"`".$this->fields["left"]."` = `".$this->fields["left"]."` - (".$idif."), " . 
+						"`".$this->fields["right"]."` = `".$this->fields["right"]."` - (".$idif."), " . 
+						"`".$this->fields["level"]."` = `".$this->fields["level"]."` - (".$ldif.") " . 
+					"WHERE " . 
+						"`".$this->fields["id"]."` IN (".implode(",", $node_ids).") ";
+			}
+		}
+		else {
+			$sql[] = "" . 
+				"INSERT INTO `".$this->table."` (" . 
+					"`".$this->fields["parent_id"]."`, " . 
+					"`".$this->fields["position"]."`, " . 
+					"`".$this->fields["left"]."`, " . 
+					"`".$this->fields["right"]."`, " . 
+					"`".$this->fields["level"]."` " . 
+					") " . 
+				"VALUES (" . 
+					$ref_id.", " . 
+					$position.", " . 
+					$idif.", " . 
+					($idif + 1).", " . 
+					$ldif. 
+				")";
+		}
+		foreach($sql as $q) { $this->db->query($q); }
+		$ind = $this->db->insert_id();
+		if($is_copy) $this->_fix_copy($ind, $position);
+		return $node === false || $is_copy ? $ind : true;
+	}
+	function _fix_copy($id, $position) {
+		$node = $this->_get_node($id);
+		$children = $this->_get_children($id, true);
+
+		$map = array();
+		for($i = $node[$this->fields["left"]] + 1; $i < $node[$this->fields["right"]]; $i++) {
+			$map[$i] = $id;
+		}
+		foreach($children as $cid => $child) {
+			if((int)$cid == (int)$id) {
+				$this->db->query("UPDATE `".$this->table."` SET `".$this->fields["position"]."` = ".$position." WHERE `".$this->fields["id"]."` = ".$cid);
+				continue;
+			}
+			$this->db->query("UPDATE `".$this->table."` SET `".$this->fields["parent_id"]."` = ".$map[(int)$child[$this->fields["left"]]]." WHERE `".$this->fields["id"]."` = ".$cid);
+			for($i = $child[$this->fields["left"]] + 1; $i < $child[$this->fields["right"]]; $i++) {
+				$map[$i] = $cid;
+			}
+		}
+	}
+
+	function _reconstruct() {
+		$this->db->query("" . 
+			"CREATE TEMPORARY TABLE `temp_tree` (" . 
+				"`".$this->fields["id"]."` INTEGER NOT NULL, " . 
+				"`".$this->fields["parent_id"]."` INTEGER NOT NULL, " . 
+				"`". $this->fields["position"]."` INTEGER NOT NULL" . 
+			") type=HEAP"
+		);
+		$this->db->query("" . 
+			"INSERT INTO `temp_tree` " . 
+				"SELECT " . 
+					"`".$this->fields["id"]."`, " . 
+					"`".$this->fields["parent_id"]."`, " . 
+					"`".$this->fields["position"]."` " . 
+				"FROM `".$this->table."`"
+		);
+
+		$this->db->query("" . 
+			"CREATE TEMPORARY TABLE `temp_stack` (" . 
+				"`".$this->fields["id"]."` INTEGER NOT NULL, " . 
+				"`".$this->fields["left"]."` INTEGER, " . 
+				"`".$this->fields["right"]."` INTEGER, " . 
+				"`".$this->fields["level"]."` INTEGER, " . 
+				"`stack_top` INTEGER NOT NULL, " . 
+				"`".$this->fields["parent_id"]."` INTEGER, " . 
+				"`".$this->fields["position"]."` INTEGER " . 
+			") type=HEAP"
+		);
+		$counter = 2;
+		$this->db->query("SELECT COUNT(*) FROM temp_tree");
+		$this->db->nextr();
+		$maxcounter = (int) $this->db->f(0) * 2;
+		$currenttop = 1;
+		$this->db->query("" . 
+			"INSERT INTO `temp_stack` " . 
+				"SELECT " . 
+					"`".$this->fields["id"]."`, " . 
+					"1, " . 
+					"NULL, " . 
+					"0, " . 
+					"1, " . 
+					"`".$this->fields["parent_id"]."`, " . 
+					"`".$this->fields["position"]."` " . 
+				"FROM `temp_tree` " . 
+				"WHERE `".$this->fields["parent_id"]."` = 0"
+		);
+		$this->db->query("DELETE FROM `temp_tree` WHERE `".$this->fields["parent_id"]."` = 0");
+
+		while ($counter <= $maxcounter) {
+			$this->db->query("" . 
+				"SELECT " . 
+					"`temp_tree`.`".$this->fields["id"]."` AS tempmin, " . 
+					"`temp_tree`.`".$this->fields["parent_id"]."` AS pid, " . 
+					"`temp_tree`.`".$this->fields["position"]."` AS lid " . 
+				"FROM `temp_stack`, `temp_tree` " . 
+				"WHERE " . 
+					"`temp_stack`.`".$this->fields["id"]."` = `temp_tree`.`".$this->fields["parent_id"]."` AND " . 
+					"`temp_stack`.`stack_top` = ".$currenttop." " . 
+				"ORDER BY `temp_tree`.`".$this->fields["position"]."` ASC LIMIT 1"
+			);
+
+			if ($this->db->nextr()) {
+				$tmp = $this->db->f("tempmin");
+
+				$q = "INSERT INTO temp_stack (stack_top, `".$this->fields["id"]."`, `".$this->fields["left"]."`, `".$this->fields["right"]."`, `".$this->fields["level"]."`, `".$this->fields["parent_id"]."`, `".$this->fields["position"]."`) VALUES(".($currenttop + 1).", ".$tmp.", ".$counter.", NULL, ".$currenttop.", ".$this->db->f("pid").", ".$this->db->f("lid").")";
+				$this->db->query($q);
+				$this->db->query("DELETE FROM `temp_tree` WHERE `".$this->fields["id"]."` = ".$tmp);
+				$counter++;
+				$currenttop++;
+			}
+			else {
+				$this->db->query("" . 
+					"UPDATE temp_stack SET " . 
+						"`".$this->fields["right"]."` = ".$counter.", " . 
+						"`stack_top` = -`stack_top` " . 
+					"WHERE `stack_top` = ".$currenttop
+				);
+				$counter++;
+				$currenttop--;
+			}
+		}
+
+		$temp_fields = $this->fields;
+		unset($temp_fields["parent_id"]);
+		unset($temp_fields["position"]);
+		unset($temp_fields["left"]);
+		unset($temp_fields["right"]);
+		unset($temp_fields["level"]);
+		if(count($temp_fields) > 1) {
+			$this->db->query("" . 
+				"CREATE TEMPORARY TABLE `temp_tree2` " . 
+					"SELECT `".implode("`, `", $temp_fields)."` FROM `".$this->table."` "
+			);
+		}
+		$this->db->query("TRUNCATE TABLE `".$this->table."`");
+		$this->db->query("" . 
+			"INSERT INTO ".$this->table." (" . 
+					"`".$this->fields["id"]."`, " . 
+					"`".$this->fields["parent_id"]."`, " . 
+					"`".$this->fields["position"]."`, " . 
+					"`".$this->fields["left"]."`, " . 
+					"`".$this->fields["right"]."`, " . 
+					"`".$this->fields["level"]."` " . 
+				") " . 
+				"SELECT " . 
+					"`".$this->fields["id"]."`, " . 
+					"`".$this->fields["parent_id"]."`, " . 
+					"`".$this->fields["position"]."`, " . 
+					"`".$this->fields["left"]."`, " . 
+					"`".$this->fields["right"]."`, " . 
+					"`".$this->fields["level"]."` " . 
+				"FROM temp_stack " . 
+				"ORDER BY `".$this->fields["id"]."`"
+		);
+		if(count($temp_fields) > 1) {
+			$sql = "" . 
+				"UPDATE `".$this->table."` v, `temp_tree2` SET v.`".$this->fields["id"]."` = v.`".$this->fields["id"]."` ";
+			foreach($temp_fields as $k => $v) {
+				if($k == "id") continue;
+				$sql .= ", v.`".$v."` = `temp_tree2`.`".$v."` ";
+			}
+			$sql .= " WHERE v.`".$this->fields["id"]."` = `temp_tree2`.`".$this->fields["id"]."` ";
+			$this->db->query($sql);
+		}
+	}
+
+	function _analyze() {
+		$report = array();
+
+		$this->db->query("" . 
+			"SELECT " . 
+				"`".$this->fields["left"]."` FROM `".$this->table."` s " . 
+			"WHERE " . 
+				"`".$this->fields["parent_id"]."` = 0 "
+		);
+		$this->db->nextr();
+		if($this->db->nf() == 0) {
+			$report[] = "[FAIL]\tNo root node.";
+		}
+		else {
+			$report[] = ($this->db->nf() > 1) ? "[FAIL]\tMore than one root node." : "[OK]\tJust one root node.";
+		}
+		$report[] = ($this->db->f(0) != 1) ? "[FAIL]\tRoot node's left index is not 1." : "[OK]\tRoot node's left index is 1.";
+
+		$this->db->query("" . 
+			"SELECT " . 
+				"COUNT(*) FROM `".$this->table."` s " . 
+			"WHERE " . 
+				"`".$this->fields["parent_id"]."` != 0 AND " . 
+				"(SELECT COUNT(*) FROM `".$this->table."` WHERE `".$this->fields["id"]."` = s.`".$this->fields["parent_id"]."`) = 0 ");
+		$this->db->nextr();
+		$report[] = ($this->db->f(0) > 0) ? "[FAIL]\tMissing parents." : "[OK]\tNo missing parents.";
+
+		$this->db->query("SELECT MAX(`".$this->fields["right"]."`) FROM `".$this->table."`");
+		$this->db->nextr();
+		$n = $this->db->f(0);
+		$this->db->query("SELECT COUNT(*) FROM `".$this->table."`");
+		$this->db->nextr();
+		$c = $this->db->f(0);
+		$report[] = ($n/2 != $c) ? "[FAIL]\tRight index does not match node count." : "[OK]\tRight index matches count.";
+
+		$this->db->query("" . 
+			"SELECT COUNT(`".$this->fields["id"]."`) FROM `".$this->table."` s " . 
+			"WHERE " . 
+				"(SELECT COUNT(*) FROM `".$this->table."` WHERE " . 
+					"`".$this->fields["right"]."` < s.`".$this->fields["right"]."` AND " . 
+					"`".$this->fields["left"]."` > s.`".$this->fields["left"]."` AND " . 
+					"`".$this->fields["level"]."` = s.`".$this->fields["level"]."` + 1" . 
+				") != " .
+				"(SELECT COUNT(*) FROM `".$this->table."` WHERE " . 
+					"`".$this->fields["parent_id"]."` = s.`".$this->fields["id"]."`" . 
+				") "
+			);
+		$this->db->nextr();
+		$report[] = ($this->db->f(0) > 0) ? "[FAIL]\tAdjacency and nested set do not match." : "[OK]\tNS and AJ match";
+
+		return implode("<br />",$report);
+	}
+
+	function _dump($output = false) {
+		$nodes = array();
+		$this->db->query("SELECT * FROM ".$this->table." ORDER BY `".$this->fields["left"]."`");
+		while($this->db->nextr()) $nodes[] = $this->db->get_row("assoc");
+		if($output) {
+			echo "<pre>";
+			foreach($nodes as $node) {
+				echo str_repeat("&#160;",(int)$node[$this->fields["level"]] * 2);
+				echo $node[$this->fields["id"]]." (".$node[$this->fields["left"]].",".$node[$this->fields["right"]].",".$node[$this->fields["level"]].",".$node[$this->fields["parent_id"]].",".$node[$this->fields["position"]].")<br />";
+			}
+			echo str_repeat("-",40);
+			echo "</pre>";
+		}
+		return $nodes;
+	}
+	function _drop() {
+		$this->db->query("TRUNCATE TABLE `".$this->table."`");
+	}
+}
+
+class json_tree extends _tree_struct { 
+	function __construct($table = "tree", $fields = array(), $add_fields = array("title" => "title", "type" => "type")) {
+		parent::__construct($table, $fields);
+		$this->fields = array_merge($this->fields, $add_fields);
+		$this->add_fields = $add_fields;
+	}
+
+	function create_node($data) {
+		$id = parent::_create((int)$data[$this->fields["id"]], (int)$data[$this->fields["position"]]);
+		if($id) {
+			$data["id"] = $id;
+			$this->set_data($data);
+			return  "{ \"status\" : 1, \"id\" : ".(int)$id." }";
+		}
+		return "{ \"status\" : 0 }";
+	}
+	function set_data($data) {
+		if(count($this->add_fields) == 0) { return "{ \"status\" : 1 }"; }
+		$s = "UPDATE `".$this->table."` SET `".$this->fields["id"]."` = `".$this->fields["id"]."` "; 
+		foreach($this->add_fields as $k => $v) {
+			if(isset($data[$k]))	$s .= ", `".$this->fields[$v]."` = \"".$this->db->escape($data[$k])."\" ";
+			else					$s .= ", `".$this->fields[$v]."` = `".$this->fields[$v]."` ";
+		}
+		$s .= "WHERE `".$this->fields["id"]."` = ".(int)$data["id"];
+		$this->db->query($s);
+		return "{ \"status\" : 1 }";
+	}
+	function rename_node($data) { return $this->set_data($data); }
+
+	function move_node($data) { 
+		return "{ \"status\" : ".parent::_move((int)$data["id"], (int)$data["ref"], (int)$data["position"], (int)$data["copy"])." }";
+	}
+	function remove_node($data) {
+		$id = parent::_remove((int)$data["id"]);
+		return "{ \"status\" : 1 }";
+	}
+	function get_children($data) {
+		$tmp = $this->_get_children((int)$data["id"]);
+		if((int)$data["id"] === 1 && count($tmp) === 0) {
+			$this->_create_default();
+			$tmp = $this->_get_children((int)$data["id"]);
+		}
+		$result = array();
+		foreach($tmp as $k => $v) {
+			$result[] = array(
+				"attr" => array("id" => "node_".$k, "rel" => $v[$this->fields["type"]]),
+				"data" => $v[$this->fields["title"]],
+				"state" => ($v[$this->fields["right"]] - $v[$this->fields["left"]] > 1) ? "closed" : ""
+			);
+		}
+		return json_encode($result);
+	}
+	function search($data) {
+		$this->db->query("SELECT `".$this->fields["left"]."`, `".$this->fields["right"]."` FROM `".$this->table."` WHERE `".$this->fields["title"]."` LIKE '%".$this->db->escape($data["search_str"])."%'");
+		if($this->db->nf() === 0) return "[]";
+		$q = "SELECT DISTINCT `".$this->fields["id"]."` FROM `".$this->table."` WHERE 0 ";
+		while($this->db->nextr()) {
+			$q .= " OR (`".$this->fields["left"]."` < ".(int)$this->db->f(0)." AND `".$this->fields["right"]."` > ".(int)$this->db->f(1).") ";
+		}
+		$result = array();
+		$this->db->query($q);
+		while($this->db->nextr()) { $result[] = "#node_".$this->db->f(0); }
+		return json_encode($result);
+	}
+
+	function _create_default() {
+		$this->_drop();
+		$this->create_node(array(
+			"id" => 0,
+			"position" => 0,
+			"title" => "ROOT"
+		));
+		$this->create_node(array(
+			"id" => 1,
+			"position" => 0,
+			"title" => "C:",
+			"type" => "drive"
+		));
+		$this->create_node(array(
+			"id" => 1,
+			"position" => 1,
+			"title" => "D:",
+			"type" => "drive"
+		));
+		$this->create_node(array(
+			"id" => 2,
+			"position" => 0,
+			"title" => "_demo",
+			"type" => "folder"
+		));
+		$this->create_node(array(
+			"id" => 2,
+			"position" => 1,
+			"title" => "_docs",
+			"type" => "folder"
+		));
+		$this->create_node(array(
+			"id" => 4,
+			"position" => 0,
+			"title" => "index.html",
+			"type" => "default"
+		));
+		$this->create_node(array(
+			"id" => 5,
+			"position" => 1,
+			"title" => "doc.html",
+			"type" => "default"
+		));
+	}
+}
+
+?>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_install.txt
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_install.txt	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/_install.txt	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,6 @@
+1) Create a database and a user with all privileges for this database.
+2) Edit the config.php file and update the configuration for the database at the top of the file
+3) Import the _dump.sql in your newly created database
+4) You are ready to go
+
+*) PLEASE NOTE THAT THE PHP TREE CLASS HAS NOT BEEN THOROUGHLY TESTED
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/config.php
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/config.php	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/config.php	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,14 @@
+<?php
+// Database config & class
+$db_config = array(
+	"servername"=> "localhost",
+	"username"	=> "root",
+	"password"	=> "",
+	"database"	=> "jstree"
+);
+if(extension_loaded("mysqli")) require_once("_inc/class._database_i.php"); 
+else require_once("_inc/class._database.php"); 
+
+// Tree class
+require_once("_inc/class.tree.php"); 
+?>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/file.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/file.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/folder.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/folder.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/index.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/index.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/index.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,253 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - full featured demo</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.min.js"></script>
+
+	<style type="text/css">
+	html, body { margin:0; padding:0; }
+	body, td, th, pre, code, select, option, input, textarea { font-family:verdana,arial,sans-serif; font-size:10px; }
+	.demo, .demo input, .jstree-dnd-helper, #vakata-contextmenu { font-size:10px; font-family:Verdana; }
+	#container { width:780px; margin:10px auto; overflow:hidden; position:relative; }
+	#demo { width:auto; height:400px; overflow:auto; border:1px solid gray; }
+
+	#menu { height:30px; overflow:auto; }
+	#text { margin-top:1px; }
+
+	#alog { font-size:9px !important; margin:5px; border:1px solid silver; }
+	</style>
+</head>
+<body>
+<div id="container">
+
+<div id="menu">
+<input type="button" id="add_folder" value="add folder" style="display:block; float:left;"/>
+<input type="button" id="add_default" value="add file" style="display:block; float:left;"/>
+<input type="button" id="rename" value="rename" style="display:block; float:left;"/>
+<input type="button" id="remove" value="remove" style="display:block; float:left;"/>
+<input type="button" id="cut" value="cut" style="display:block; float:left;"/>
+<input type="button" id="copy" value="copy" style="display:block; float:left;"/>
+<input type="button" id="paste" value="paste" style="display:block; float:left;"/>
+<input type="button" id="clear_search" value="clear" style="display:block; float:right;"/>
+<input type="button" id="search" value="search" style="display:block; float:right;"/>
+<input type="text" id="text" value="" style="display:block; float:right;" />
+</div>
+
+<!-- the tree container (notice NOT an UL node) -->
+<div id="demo" class="demo"></div>
+<!-- JavaScript neccessary for the tree -->
+<script type="text/javascript">
+$(function () {
+	// Settings up the tree - using $(selector).jstree(options);
+	// All those configuration options are documented in the _docs folder
+	$("#demo")
+		.jstree({ 
+			// the list of plugins to include
+			"plugins" : [ "themes", "json_data", "ui", "crrm", "cookies", "dnd", "search", "types", "hotkeys", "contextmenu" ],
+			// Plugin configuration
+
+			// I usually configure the plugin that handles the data first - in this case JSON as it is most common
+			"json_data" : { 
+				// I chose an ajax enabled tree - again - as this is most common, and maybe a bit more complex
+				// All the options are the same as jQuery's except for `data` which CAN (not should) be a function
+				"ajax" : {
+					// the URL to fetch the data
+					"url" : "./server.php",
+					// this function is executed in the instance's scope (this refers to the tree instance)
+					// the parameter is the node being loaded (may be -1, 0, or undefined when loading the root nodes)
+					"data" : function (n) { 
+						// the result is fed to the AJAX request `data` option
+						return { 
+							"operation" : "get_children", 
+							"id" : n.attr ? n.attr("id").replace("node_","") : 1 
+						}; 
+					}
+				}
+			},
+			// Configuring the search plugin
+			"search" : {
+				// As this has been a common question - async search
+				// Same as above - the `ajax` config option is actually jQuery's object (only `data` can be a function)
+				"ajax" : {
+					"url" : "./server.php",
+					// You get the search string as a parameter
+					"data" : function (str) {
+						return { 
+							"operation" : "search", 
+							"search_str" : str 
+						}; 
+					}
+				}
+			},
+			// Using types - most of the time this is an overkill
+			// Still meny people use them - here is how
+			"types" : {
+				// I set both options to -2, as I do not need depth and children count checking
+				// Those two checks may slow jstree a lot, so use only when needed
+				"max_depth" : -2,
+				"max_children" : -2,
+				// I want only `drive` nodes to be root nodes 
+				// This will prevent moving or creating any other type as a root node
+				"valid_children" : [ "drive" ],
+				"types" : {
+					// The default type
+					"default" : {
+						// I want this type to have no children (so only leaf nodes)
+						// In my case - those are files
+						"valid_children" : "none",
+						// If we specify an icon for the default type it WILL OVERRIDE the theme icons
+						"icon" : {
+							"image" : "./file.png"
+						}
+					},
+					// The `folder` type
+					"folder" : {
+						// can have files and other folders inside of it, but NOT `drive` nodes
+						"valid_children" : [ "default", "folder" ],
+						"icon" : {
+							"image" : "./folder.png"
+						}
+					},
+					// The `drive` nodes 
+					"drive" : {
+						// can have files and folders inside, but NOT other `drive` nodes
+						"valid_children" : [ "default", "folder" ],
+						"icon" : {
+							"image" : "./root.png"
+						},
+						// those options prevent the functions with the same name to be used on the `drive` type nodes
+						// internally the `before` event is used
+						"start_drag" : false,
+						"move_node" : false,
+						"delete_node" : false,
+						"remove" : false
+					}
+				}
+			},
+			// For UI & core - the nodes to initially select and open will be overwritten by the cookie plugin
+
+			// the UI plugin - it handles selecting/deselecting/hovering nodes
+			"ui" : {
+				// this makes the node with ID node_4 selected onload
+				"initially_select" : [ "node_4" ]
+			},
+			// the core plugin - not many options here
+			"core" : { 
+				// just open those two nodes up
+				// as this is an AJAX enabled tree, both will be downloaded from the server
+				"initially_open" : [ "node_2" , "node_3" ] 
+			}
+		})
+		.bind("create.jstree", function (e, data) {
+			$.post(
+				"./server.php", 
+				{ 
+					"operation" : "create_node", 
+					"id" : data.rslt.parent.attr("id").replace("node_",""), 
+					"position" : data.rslt.position,
+					"title" : data.rslt.name,
+					"type" : data.rslt.obj.attr("rel")
+				}, 
+				function (r) {
+					if(r.status) {
+						$(data.rslt.obj).attr("id", "node_" + r.id);
+					}
+					else {
+						$.jstree.rollback(data.rlbk);
+					}
+				}
+			);
+		})
+		.bind("remove.jstree", function (e, data) {
+			$.post(
+				"./server.php", 
+				{ 
+					"operation" : "remove_node", 
+					"id" : data.rslt.obj.attr("id").replace("node_","")
+				}, 
+				function (r) {
+					if(!r.status) {
+						$.jstree.rollback(data.rlbk);
+					}
+				}
+			);
+		})
+		.bind("rename.jstree", function (e, data) {
+			$.post(
+				"./server.php", 
+				{ 
+					"operation" : "rename_node", 
+					"id" : data.rslt.obj.attr("id").replace("node_",""),
+					"title" : data.rslt.new_name,
+				}, 
+				function (r) {
+					if(!r.status) {
+						$.jstree.rollback(data.rlbk);
+					}
+				}
+			);
+		})
+		.bind("move_node.jstree", function (e, data) {
+			$.post(
+				"./server.php", 
+				{ 
+					"operation" : "move_node", 
+					"id" : data.rslt.o.attr("id").replace("node_",""), 
+					"ref" : data.rslt.np.attr("id").replace("node_",""), 
+					"position" : data.rslt.cp,
+					"title" : data.rslt.name,
+					"copy" : data.rslt.cy ? 1 : 0
+				}, 
+				function (r) {
+					if(!r.status) {
+						$.jstree.rollback(data.rlbk);
+					}
+					else {
+						$(data.rslt.oc).attr("id", "node_" + r.id);
+						if(data.rslt.cy && oc.children("UL").length) {
+							data.inst.refresh(data.rslt.oc);
+						}
+					}
+					$("#analyze").click();
+				}
+			);
+		});
+});
+</script>
+<script type="text/javascript">
+$(function () { 
+	$("#menu input").click(function () {
+		switch(this.id) {
+			case "add_default":
+			case "add_folder":
+				$("#demo").jstree("create", null, "last", { "attr" : { "rel" : this.id.toString().replace("add_", "") } });
+				break;
+			case "search":
+				$("#demo").jstree("search", document.getElementById("text").value);
+				break;
+			case "text": break;
+			default:
+				$("#demo").jstree(this.id);
+				break;
+		}
+	});
+});
+</script>
+
+<div style="position:absolute; right:10px; top:40px; width:220px; border:1px solid silver; min-height:160px;">
+	<input type="button" style='display:block; width:170px; height:24px; margin:5px auto;' value="reconstruct" onclick="$.get('./server.php?reconstruct', function () { $('#demo').jstree('refresh',-1); });" />
+	<input type="button" style='display:block; width:170px; height:24px; margin:5px auto;' id="analyze" value="analyze" onclick="$('#alog').load('./server.php?analyze');" />
+	<input type="button" style='display:block; width:170px; height:24px; margin:5px auto;' value="refresh" onclick="$('#demo').jstree('refresh',-1);" />
+	<div id='alog'></div>
+</div>
+
+</div>
+
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/root.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/root.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/server.php
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/server.php	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_demo/server.php	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,69 @@
+<?php
+require_once("config.php");
+$jstree = new json_tree();
+
+//$jstree->_create_default();
+//die();
+
+if(isset($_GET["reconstruct"])) {
+	$jstree->_reconstruct();
+	die();
+}
+if(isset($_GET["analyze"])) {
+	echo $jstree->_analyze();
+	die();
+}
+
+if($_REQUEST["operation"] && strpos("_", $_REQUEST["operation"]) !== 0 && method_exists($jstree, $_REQUEST["operation"])) {
+	header("HTTP/1.0 200 OK");
+	header('Content-type: text/json; charset=utf-8');
+	header("Cache-Control: no-cache, must-revalidate");
+	header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
+	header("Pragma: no-cache");
+	echo $jstree->{$_REQUEST["operation"]}($_REQUEST);
+	die();
+}
+header("HTTP/1.0 404 Not Found"); 
+?>
+
+<?php
+/*
+$jstree->_drop();
+$jstree->create_node(array("id"=>0,"position"=>0));
+$jstree->create_node(array("id"=>1,"position"=>0));
+$jstree->create_node(array("id"=>1,"position"=>0));
+$jstree->create_node(array("id"=>3,"position"=>0,"name"=>"Pesho"));
+$jstree->move(3,2,0,true);
+$jstree->_dump(true);
+$jstree->_reconstruct();
+echo $jstree->_analyze();
+die();
+
+$tree = new _tree_struct;
+$tree->drop();
+$tree->create(0, 0);
+$tree->create(0, 0);
+$tree->create(1, 0);
+$tree->create(0, 3);
+$tree->create(2, 3);
+$tree->create(2, 0);
+$tree->dump(true);
+$tree->move(6,4,0);
+$tree->move(1,0,0);
+$tree->move(3,2,99,true);
+$tree->move(7,1,0,true);
+$tree->move(1,7,0);
+$tree->move(1,0,1,true);
+$tree->move(2, 0, 0, true);
+$tree->move(13, 12, 2, true);
+$tree->dump(true);
+$tree->move(15, 16, 2, true);
+$tree->dump(true);
+$tree->move(4, 0, 0);
+$tree->dump(true);
+$tree->move(4, 0, 2);
+$tree->dump(true);
+echo $tree->analyze();
+$tree->drop();
+*/
+?>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/!style.css
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/!style.css	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/!style.css	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,37 @@
+html, body { margin:0; padding:0; }
+body, td, th, pre, code, select, option, input, textarea { font-family:"lucida grande",tahoma,verdana,arial,sans-serif; font-size:10pt; }
+h1 { margin:0; padding:0.2em 0 0.5em 0; font-size:14pt; font-family:Georgia; /*text-shadow:1px 1px 2px gray;*/ border-bottom:2px solid; margin-bottom:0.5em; text-align:center;  }
+h2 { margin:0.5em 0 0.5em 0; padding:0.5em 0 0.5em 20px; font-size:12pt; font-family:Georgia; color:white; background:silver; text-shadow:1px 1px 2px gray; clear:both; -moz-border-radius:5px; }
+h3 { margin:0; padding:0.5em 0 0.5em 0; font-size:11.5pt; font-family:Georgia; color:gray; clear:both; }
+p { padding:0em 0 0.5em 0; margin:0; line-height:1.8em; }
+p.meta { font-size:9pt; color:gray; margin-top:-5px; }
+.arguments .tp, p code { color:green; padding:0 4px; font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; font-weight: normal !important; font-style: normal !important; font-size:13px; }
+#description, .panel { margin:0 20px; }
+#container { width:800px; margin:10px auto; overflow:hidden; }
+.demo { width:255px; float:left; margin:0; border:1px solid gray; background:white; overflow:auto; }
+.code { width:490px; float:right; margin:0 0 10px 0; border:1px solid gray; font-size:12px; }
+pre { display:block; }
+.code_f { border:1px solid gray; margin-bottom:1em; }
+.syntaxhighlighter { margin:0 0 0 0 !important; padding:0 !important; line-height:18px; }
+
+.log { padding:4px; border:1px solid gray; margin-bottom:1em; }
+.button { display:block; margin-bottom:0.5em; }
+.arguments { margin:0em 1em; padding:0; list-style-type:none; }
+.arguments .tp { padding:0 0 0 0; float:left; width:70px;  }
+.arguments strong { display:block; }
+
+.api h3 { margin-left:-10px; color:black; font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; font-weight: normal !important; font-size:14px; margin-top:2em; border-top:1px solid; width:780px; }
+.api .arguments li strong {  color:black; font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; font-weight: normal !important; font-size:13px; }
+
+.configuration h3 { margin-left:-10px; color:black; font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; font-weight: normal !important; font-size:14px; margin-top:2em; border-top:1px solid; width:780px; }
+.note { background:#ffffee; padding:10px 20px; border:1px solid #333; -moz-border-radius:5px; border-radius:5px; -webkit-border-radius:5px; margin-bottom:15px; text-align:center; font-weight:bold; }
+
+ul.columns { list-style-type:none; width:700px; margin:5px auto 15px auto; padding:0; overflow:hidden; }
+ul.columns li { float:left; margin:0; padding:0 0 0 0px; line-height:18px; width:345px; }
+ul.plugins li { width:220px; text-align:left; padding:5px 0; }
+ul.plugins li a { text-decoration:none; color:#3B5998; }
+ul.plugins li a:hover { text-decoration:underline; }
+ul.plugins li p { text-align:left; font-size:9px; color:#333; margin:0 5px 0 0; }
+
+.demo, .demo input, .jstree-dnd-helper, #vakata-contextmenu { font-size:10px; font-family:Verdana; }
+

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_drive.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_drive.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_html_data.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_html_data.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_html_data.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,2 @@
+<li class="jstree-closed"><a href="#">Node 1</a></li>
+<li><a href="#">Node 2</a></li>

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_json_data.json
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_json_data.json	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_json_data.json	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,4 @@
+[
+	{ "data" : "A node", "children" : [ { "data" : "Only child", "state" : "closed" } ], "state" : "open" },
+	"Ajax node"
+]
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_search_data.json
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_search_data.json	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_search_data.json	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,6 @@
+[
+	"Ajax node 1",
+	"Ajax node 2",
+	"TARGET",
+	"Ajax node 4"
+]
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_search_result.json
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_search_result.json	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_search_result.json	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1 @@
+[ "#root_node" ]
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_xml_flat.xml
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_xml_flat.xml	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_xml_flat.xml	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,12 @@
+<root>
+	<item parent_id="0" id="node_1" state="closed">
+		<content>
+			<name><![CDATA[Node 1]]></name>
+		</content>
+	</item>
+	<item parent_id="0" id="node_2">
+		<content>
+			<name><![CDATA[Node 2]]></name>
+		</content>
+	</item>
+</root>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_xml_nest.xml
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_xml_nest.xml	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/_xml_nest.xml	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<root>
+	<item id="pxml_1">
+		<content><name><![CDATA[Root node 1]]></name></content>
+		<item id="pxml_2">
+			<content><name><![CDATA[Child node 1]]></name></content>
+		</item>
+		<item id="pxml_3">
+			<content><name><![CDATA[Child node 2]]></name></content>
+		</item>
+		<item id="pxml_4">
+			<content><name><![CDATA[Some other child node]]></name></content>
+		</item>
+	</item>
+	<item id="pxml_5">
+		<content><name ><![CDATA[Root node 2]]></name></content>
+	</item>
+</root>

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/checkbox.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/checkbox.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/checkbox.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,148 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - checkbox documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - checkbox plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>checkbox</code> plugin makes multiselection possible using three-state checkboxes. The checkbox plugin requires the <a href="ui.html">UI plugin</a>.</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+<p>No configuration possible</p>
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+<h3>Using the checkbox plugin - all you need to do is include it in the list of active plugins.</h3>
+<div id="demo1" class="demo">
+	<ul>
+		<li id="phtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="phtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="phtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="phtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo1").jstree({ 
+		"plugins" : [ "themes", "html_data", "ui", "checkbox" ]
+	});
+});
+</script>
+
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+<p>The checkbox plugin maps UI's <a href="ui.html#get_selected">get_selected function</a> to its own <a href="#get_checked">get_checked function</a> and overwrites the <a href="ui.html#reselect">UI reselect function</a>. It also disables the <code>select_node</code>, <code>deselect_node</code> and <code>deselect_all</code> functions.
+
+<h3 id="_prepare_checkboxes">._prepare_checkboxes ( node )</h3>
+<p>Inserts the checkbox icons on the node. Used internally.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+</ul>
+
+<h3 id="_repair_state">._repair_state ( node )</h3>
+<p>Repairs the checkbox state inside the node. Used internally.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+</ul>
+
+<h3 id="change_state">.change_state ( node , uncheck )</h3>
+<p>Changes the state of a node. Used mostly internally - you'd be better off using the <code>check_node</code> and <code>uncheck_node</code> functions. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+	<li>
+		<code class="tp">boolean</code> <strong>uncheck</strong>
+		<p>If set to <code>true</code> the node is unchecked, if set to <code>false</code> the node is checked, otherwise - the state is toggled.</p>
+	</li>
+</ul>
+
+<h3 id="check_node">.check_node ( node )</h3>
+<p>Checks a node.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+</ul>
+
+<h3 id="uncheck_node">.uncheck_node ( node )</h3>
+<p>Unchecks a node.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+</ul>
+
+<h3 id="check_all">.check_all ( )</h3>
+<p>Checks all nodes.</p>
+
+<h3 id="uncheck_all">.uncheck_all ( )</h3>
+<p>Unchecks all nodes.</p>
+
+<h3 id="is_checked">.is_checked ( node )</h3>
+<p>Checks if a node is checked. Returns boolean.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+</ul>
+
+<div style="height:1px; visibility:hidden; overflow:hidden;"><span id="get_unchecked">&#160;</span></div>
+<h3 id="get_checked">.get_checked ( context ), .get_unchecked ( context )</h3>
+<p>Both functions return jQuery collections.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>context</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree. If specified only nodes inside the specified context are returned, otherwise the whole tree is searched.</p>
+	</li>
+</ul>
+
+<div style="height:1px; visibility:hidden; overflow:hidden;"><span id="hide_checkboxes">&#160;</span></div>
+<h3 id="show_checkboxes">.show_checkboxes ( ), .get_unchecked ( )</h3>
+<p>Show or hide the checkbox icons.</p>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/contextmenu.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/contextmenu.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/contextmenu.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,114 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - contextmenu documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - contextmenu plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>contextmenu</code> plugin enables a contextual menu to be shown, when the user right-clicks a node (or when triggered programatically by the developer).</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+<h3>show_at_node</h3>
+<p class="meta">Boolean. Default is <code>true</code>.</p>
+<p>Whether to show the context menu just below the node, or at the clicked point exactly.</p>
+
+<h3>items</h3>
+<p>Expects an object or a function, which should return an object. If a function is used it fired in the tree's context and receives one argument - the node that was right clicked. The object format is:</p>
+<div style="border:1px solid gray">
+<pre class="brush:js">
+{
+// Some key
+"rename" : {
+	// The item label
+	"label"				: "Rename",
+	// The function to execute upon a click
+	"action"			: function (obj) { this.rename(obj); },
+	// All below are optional 
+	"separator_before"	: false,	// Insert a separator before the item
+	"separator_after"	: true,		// Insert a separator after the item
+	// false or string - if does not contain `/` - used as classname
+	"icon"				: false,
+	"submenu"			: { 
+		/* Collection of objects (the same structure) */
+	}
+}
+/* MORE ENTRIES ... */
+}
+</pre>
+</div>
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+
+<h3>Using the contextmenu</h3>
+<div id="demo1" class="demo">
+	<ul>
+		<li id="phtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="phtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="phtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="phtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo1").jstree({ 
+		"plugins" : [ "themes", "html_data", "ui", "crrm", "contextmenu" ]
+	});
+});
+</script>
+
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+
+<h3 id="show_contextmenu">.show_contextmenu ( node , x, y )</h3>
+<p>Shows the contextmenu next to a node. Triggered automatically when right-clicking a node.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+	<li>
+		<code class="tp">number</code> <strong>x</strong>
+		<p>The X-coordinate to show the menu at - may be overwritten by <code>show_at_node</code>. If you omit this the menu is shown aligned with the left of the node.</p>
+	</li>
+	<li>
+		<code class="tp">number</code> <strong>y</strong>
+		<p>The Y-coordinate to show the menu at - may be overwritten by <code>show_at_node</code>. If you omit this the menu is shown just below the node.</p>
+	</li>
+</ul>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/cookies.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/cookies.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/cookies.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,96 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - cookies documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - cookies plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>cookies</code> enables jstree to save the state of the tree across sessions. What this does is save the opened and selected nodes in a cookie, and reopen &amp; reselect them the next time the user loads the tree. Depends on the <a href="http://plugins.jquery.com/project/cookie">jQuery.cookie</a> plugin.</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+
+<h3>save_opened</h3>
+<p class="meta">A string (or <code>false</code>). Default is <code>"jstree_open"</code>.</p>
+<p>The name of the cookie to save opened nodes in. If set to <code>false</code> - opened nodes won't be saved.</p>
+
+<h3>save_selected</h3>
+<p class="meta">A string (or <code>false</code>). Default is <code>"jstree_select"</code>.</p>
+<p>The name of the cookie to save selected nodes in. If set to <code>false</code> - selected nodes won't be saved.</p>
+
+<h3>auto_save</h3>
+<p class="meta">A Boolean. Default is <code>true</code>.</p>
+<p>If set to <code>true</code> jstree will automatically update the cookies every time a change in the state occurs.</p>
+
+<h3>cookie_options</h3>
+<p class="meta">An object. Default is <code>{}</code>.</p>
+<p>The options accepted by the <a href="http://plugins.jquery.com/project/cookie">jQuery.cookie</a> plugin.</p>
+
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+<p>Check your data plugin documentation (<a href="html_data.html">html_data</a>, <a href="xml_data.html">xml_data</a>, <a href="json_data.html">json_data</a>) or take a close look at these examples for information on how to specify multilanguage nodes.</p>
+
+<h3>Using the cookies plugin</h3>
+<p>Go ahead and make changes to the tree and then <a href="javascript:document.location.reload();">refresh this page</a>.</p>
+<div id="demo1" class="demo">
+	<ul>
+		<li id="phtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="phtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="phtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="phtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo1").jstree({ 
+		"plugins" : [ "themes", "html_data", "ui", "cookies" ]
+	});
+});
+</script>
+
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+
+<h3 id="save_cookie">.save_cookie ( event )</h3>
+<p>Save the current state.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">string</code> <strong>event</strong>
+		<p>Used internally with the <code>auto_save</code> option. Do not set this manually.</p>
+	</li>
+</ul>
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/core.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/core.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/core.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,599 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree Testing</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - Core</h1>
+<h2>Description</h2>
+<div id="description">
+<h3>Including the files</h3>
+<p>First of all, as jsTree is a jQuery component, you need to include jQuery itself. jsTree v.1.0 requires jQuery version 1.4.2</p>
+
+<div class="code_f"><pre class="brush:xml;">
+&lt;script type="text/javascript" src="_lib/jquery.js"&gt;&lt;/script&gt;
+</pre></div>
+
+<p>Then you need to include jsTree:</p>
+
+<div class="code_f"><pre class="brush:xml;">
+&lt;script type="text/javascript" src="jquery.jstree.js"&gt;&lt;/script&gt;
+</pre></div>
+
+<p>Or you could use the minified version:</p>
+
+<div class="code_f"><pre class="brush:xml;">
+&lt;script type="text/javascript" src="jquery.jstree.min.js"&gt;&lt/script&gt;
+</pre></div>
+
+<p>You may change the path to whatever you like, but it is recommended not to rename <code>jquery.tree.js</code> or <code>jquery.tree.min.js</code> as the filenames may be used for path autodetection (for example in the <code>themes</code> plugin, but if you really need to rename the file most plugins will give you the option to set the path manually).</p>
+
+<p>Additionally some plugins have dependencies - plugins that detect a dependency is missing will throw an error.</p>
+
+<h3>Creating and configuring an instance</h3>
+<p>You can create a tree in the following manner:</p>
+
+<div class="code_f"><pre class="brush:js;">
+jQuery("some-selector-to-container-node-here").jstree([ config_object ]);
+</pre></div>
+
+<p>In the optional config object you specify all the options that you want to set. Each plugin will describe its configuration and defaults. In the <a href="#configuration">configuration section</a> below you will find the options defined by the core. Each plugin's options (even the core) are set in their own subobject, which is named after the plugin. For example all of the core's options are set in the <code>core</code> key of the config object:</p>
+<div class="code_f"><pre class="brush:js;">
+jQuery("some-selector-to-container-node-here")
+	.jstree({
+		core : {
+			/* core options go here */
+		}
+	});
+</pre></div>
+
+<p class="note">Please note that if your options for a given plugin are the same as the defaults you may omit those options or omit the subobject completely (if you do not need to modify the defaults).</p>
+
+<p>There is only one special config option that is not a part of any plugin - this is the <code>plugins</code> option, which defines a list of active plugins for the instance being created. Although many plugins may be included, only the ones listed in this option will be active. The only autoincluded "plugin" is the jstree core.</p>
+
+<div class="code_f"><pre class="brush:js;">
+jQuery("some-selector-to-container-node-here")
+	.jstree({
+		core : { /* core options go here */ },
+		plugins : { "themes", "html_data", "some-other-plugin" }
+	});
+</pre></div>
+
+<h3>Interacting with the tree</h3>
+
+<p>To perform an operation programatically on a given instance you can use two methods:</p>
+<div class="code_f"><pre class="brush:js;">
+/* METHOD ONE */
+jQuery("some-selector-to-container-node-here")
+	.jstree("operation_name" [, argument_1, argument_2, ...]);
+
+/* METHOD TWO */
+jQuery.jstree._reference(needle) 
+	/* NEEDLE can be a DOM node or selector for the container or a node within the container */
+	.operation_name([ argument_1, argument_2, ...]);
+</pre></div>
+
+<p>jsTree uses events to notify of any changes happening in the tree. All events fire on the tree container in the <code>jstree</code> namespace and are named after the function that triggered them. Please note that for some events it is best to bind before creating the instance. For example:</p>
+<div class="code_f"><pre class="brush:js;">
+jQuery("some-container")
+	.bind("loaded.jstree", function (event, data) {
+		alert("TREE IS LOADED");
+	})
+	.jstree({ /* configuration here */ });
+</pre></div>
+<p>Please note the second parameter <code>data</code>. Its structure is as follows:</p>
+<div class="code_f"><pre class="brush:js;">
+{ 
+	"inst" : /* the actual tree instance */, 
+	"args" : /* arguments passed to the function */, 
+	"rslt" : /* any data the function passed to the event */, 
+	"rlbk" : /* an optional rollback object - it is not always present */
+}
+</pre></div>
+<p>There is also one special event - <code>before.jstree</code>. This events enables you to prevent an operation from executing. Look at the <a href="#demos">demo</a> below.</p>
+
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+
+<h3>html_titles</h3>
+<p class="meta">Boolean. Default is <code>false</code>.</p>
+<p>Defines whether titles can contain HTML code.</p>
+
+<h3>animation</h3>
+<p class="meta">A number. Default is <code>500</code>.</p>
+<p>Defines the duration of open/close animations. <code>0</code> means no animation.</p>
+
+<h3>initially_open</h3>
+<p class="meta">An array. Default is <code>[]</code>.</p>
+<p>Defines which nodes are to be automatically opened when the tree finishes loading - a list of IDs is expected.</p>
+
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+
+<h3>Binding to an event and executing an action</h3>
+<input type="button" class="button" value="toggle_node" id="toggle_node" style="clear:both;" />
+<div id="demo1" class="demo">
+	<ul>
+		<li id="phtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="phtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="phtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="phtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#toggle_node").click(function () { 
+		$("#demo1").jstree("toggle_node","#phtml_1");
+	});
+	$("#demo1")
+		.bind("open_node.jstree close_node.jstree", function (e) {
+			$("#log1").html("Last operation: " + e.type);
+		})
+		.jstree({ "plugins" : [ "themes", "html_data" ] });
+	});
+</script>
+<p class="log" id="log1" style="clear:both;">&#160;</p>
+
+<h3>Preventing an action</h3>
+<p>This is the same demo as above, but this time the operation will be prevented.</p>
+<input type="button" class="button" value="toggle_node" id="toggle_node2" style="clear:both;" />
+<div id="demo2" class="demo">
+	<ul>
+		<li id="html_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="html_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="html_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="html_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript">
+$(function () {
+	$("#toggle_node2").click(function () { 
+		$("#demo2").jstree("toggle_node","#html_1");
+	});
+	$("#demo2")
+		.bind("open_node.jstree close_node.jstree", function (e) {
+			$("#log2").html("Last operation: " + e.type);
+		})
+		.jstree({ "plugins" : [ "themes", "html_data" ] });
+	});
+</script>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo2").bind("before.jstree", function (e, data) {
+		if(data.func === "open_node") {
+			$("#log2").html(data.args[0].attr("id"));
+			e.stopImmediatePropagation();
+			return false;
+		}
+	});
+});
+</script>
+<p class="log" id="log2" style="clear:both;">&#160;</p>
+<p>The important part is <code>e.stopImmediatePropagation(); return false</code>.</p>
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+<p class="note">Use extra caution when working with functions prefixed with an underscore - <code>_</code>!<br />Those functions are probably for internal usage only.</p>
+
+
+<h3 id="jstree.defaults">jQuery.jstree.defaults</h3>
+<p class="meta">An object. Default is a collection of all included plugin's defaults.</p>
+<p>This object is exposed so that you can apply standart settings to all future instances</p>
+
+<h3 id="jstree.plugin">jQuery.jstree.plugin ( plugin_name , plugin_data )</h3>
+<p>This function is used by developers to extend jstree (add "plugins").</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">string</code> <strong>plugin_name</strong>
+		<p>The plugin name - it should be unique.</p>
+	</li>
+	<li>
+		<code class="tp">object</code> <strong>plugin_data</strong>
+		<p>The plugin itself. It consists of <code>__init</code> &amp; <code>__destroy</code> functions, <code>defaults</code> object (that of course could be an array or a simple value) and a <code>_fn</code> object, whose keys are all the functions you are extending jstree with. You can overwrite functions (but you can in your function call the overriden old function), and you are responsible for triggering events and setting rollback points. You can omit any of the elements in the <code>plugin_data</code> param. Keep in mind jstree will automatically clear classes prepended with <code>jstree-</code> and all events in the <code>jstree</code> namespace when destroying a tree, so you do not need to worry about those.</p>
+		<p>Read jstree's code for examples on how to develop plugins.</p>
+	</li>
+</ul>
+
+<h3 id="jstree.rollback">jQuery.jstree.rollback ( rollback_object )</h3>
+<p>This function will roll the tree back to the state specified by the rollback object</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">string</code> <strong>rollback_object</strong>
+		<p>Normally you will get this object from the event you are handling. You can of course use <code>.get_rollback()</code> to get the current state of the tree as a rollback object.</p>
+		<div class="code_f"><pre class="brush:js;">
+$("some-container").bind("some-event.jstree", function (e, data) {
+	$.jstree.rollback(data.rlbk);
+});</pre></div>
+		<p>Keep in mind that not all events will give you a rollback object - sometimes <code>data.rlbk</code> will be <code>false</code>.</p>
+	</li>
+</ul>
+
+<h3 id="jstree._focused">jQuery.jstree._focused ()</h3>
+<p>Returns the currently focused tree instance on the page. If not interaction has been made - it is the last one to be created.</p>
+
+<h3 id="jstree._reference">jQuery.jstree._reference ( needle )</h3>
+<p>Returns the tree instance for the specified <code>needle</code>.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>needle</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the tree container, or an element within the tree.</p>
+	</li>
+</ul>
+
+<h3 id="jstree._instance">jQuery.jstree._instance ( index , container , settings )</h3>
+<p>This function is used internally when creating new tree instances. Calling this function by itself is not enough to create a new instance. To create a tree use the documented method <code>$("selector").jstree([ options ])</code>.</p>
+
+<h3 id="jstree._fn">jQuery.jstree._fn</h3>
+<p>This object stores all functions included by plugins. It is used internally as a prototype for all instances - do not modify manually.</p>
+
+<h3 id="data">.data</h3>
+<p>An object where all plugins store instance specific data. Do not modify manually.</p>
+
+<h3 id="get_settings">.get_settings ()</h3>
+<p>Returns the instance's settings object - the defaults, extended by your own config object.</p>
+
+<h3 id="get_index">.get_index ()</h3>
+<p>Returns the internal instance index.</p>
+
+<h3 id="get_container">.get_container ()</h3>
+<p>Returns the jQuery extended container node of the tree.</p>
+
+<h3 id="_set_settings">._set_settings ( settings )</h3>
+<p>Replace the settings object with the <code>settings</code> param. Please note that not all plugins will react to the change. Unless you know exactly what you are doing you'd be better off recreating the tree with the new settings.</p>
+
+<h3 id="init">.init ()</h3>
+<p>This function is used internally when creating a new instance. Triggers an event, which fires after the tree is initialized, but not yet loaded.</p>
+
+<h3 id="destroy">.destroy ()</h3>
+<p>Destroys the instance - it will automatically remove all bound events in the <code>jstree</code> namespace &amp; remove all classes starting with <code>jstree-</code>. Triggers an event.</p>
+
+<h3 id="save_opened">.save_opened ()</h3>
+<p>Stores the currently open nodes before refreshing. Used internally. Triggers an event.</p>
+
+<h3 id="reopen">.reopen ( is_callback )</h3>
+<p>Reopens all the nodes stored by <code>save_opened</code> or set in the <code>initially_open</code> config option on first load. It is called multiple times while reopening nodes - the <code>is_callback</code> param determines if this is the first call (<code>false</code>) or not. Used internally. Triggers an event.</p>
+
+<h3 id="refresh">.refresh ( node )</h3>
+<p>Refreshes the tree. Saves all open nodes, and reloads and then reopens all saved nodes. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree. If set this will reload only the given node - otherwise - the whole tree. Passing <code>-1</code> also reloads the whole tree.</p>
+	</li>
+</ul>
+
+<h3 id="loaded">.loaded ()</h3>
+<p>A dummy function, whose purpose is only to trigger the loaded event. This event is triggered once after the tree's root nodes are loaded, but before any nodes set in <code>initially_open</code> are opened.</p>
+
+<h3 id="set_focus">.set_focus ()</h3>
+<p>Makes the current instance the focused one on the page. Triggers an event.</p>
+
+<h3 id="is_focused">.is_focused ()</h3>
+<p>Returns <code>true</code> if the current instance is the focused one, otherwise returns <code>false</code>.</p>
+
+<h3 id="_get_node">._get_node ( node )</h3>
+<p>Return the jQuery extended <code>LI</code> element of the node, <code>-1</code> if the container node is passed, or <code>false</code> otherwise.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+</ul>
+
+<h3 id="_get_next">._get_next ( node , strict )</h3>
+<p>Gets the <code>LI</code> element representing the node next to the passed <code>node</code>. Returns <code>false</code> on failure.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree, whose next sibling we want.</p>
+	</li>
+	<li>
+		<code class="tp">bool</code> <strong>strict</strong>
+		<p>If set to <code>true</code> only immediate siblings are calculated. Otherwise if the <code>node</code> is the last child of its parent this function will "jump out" and return the parent's next sibling, etc. Default is <code>false</code>.</p>
+	</li>
+</ul>
+
+<h3 id="_get_prev">._get_prev ( node , strict )</h3>
+<p>Gets the <code>LI</code> element representing the node previous to the passed <code>node</code>. Returns <code>false</code> on failure.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree, whose previous sibling we want.</p>
+	</li>
+	<li>
+		<code class="tp">bool</code> <strong>strict</strong>
+		<p>If set to <code>true</code> only immediate siblings are calculated. Otherwise if the <code>node</code> is the first child of its parent this function will "jump out" and return the parent itself. Default is <code>false</code>.</p>
+	</li>
+</ul>
+
+<h3 id="_get_parent">._get_parent ( node )</h3>
+<p>Gets the <code>LI</code> element representing the parent of the passed <code>node</code>. Returns <code>false</code> on failure.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree, whose parent we want.</p>
+	</li>
+</ul>
+
+<h3 id="_get_children">._get_children ( node )</h3>
+<p>Gets the <code>LI</code> elements representing the children of the passed <code>node</code>. Returns <code>false</code> on failure (or if the node has no children).</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree, whose children we want. Use <code>-1</code> to return all root nodes.</p>
+	</li>
+</ul>
+
+<h3 id="get_path">.get_path ( node , id_mode )</h3>
+<p>Return the path to a node, either as an array of IDs or as an array of node names.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree, whose path we want.</p>
+	</li>
+	<li>
+		<code class="tp">bool</code> <strong>id_mode</strong>
+		<p>If set to <code>true</code> IDs are returned instead of the names of the parents. Default is <code>false</code>.</p>
+	</li>
+</ul>
+
+<h3 id="open_node">.open_node ( node , callback , skip_animation )</h3>
+<p>Opens a closed node, so that its children are visible. If the <code>animation</code> config option is greater than <code>0</code> the children are revealed using a slide down animation, whose duration is the value of the <code>animation</code> config option in milliseconds. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element we want opened.</p>
+	</li>
+	<li>
+		<code class="tp">function</code> <strong>callback</strong>
+		<p>A callback function executed once the node is opened. Used mostly internally, you'd be better of waiting for the event. You can skip this, by not specifying it, or by passing <code>false</code>.</p>
+	</li>
+	<li>
+		<code class="tp">bool</code> <strong>skip_animation</strong>
+		<p>If set to <code>true</code> the animation set in the <code>animation</code> config option is skipped. Default is <code>false</code>.</p>
+	</li>
+</ul>
+
+<h3 id="close_node">.close_node ( node , skip_animation )</h3>
+<p>Closes an open node, so that its children are not visible. If the <code>animation</code> config option is greater than <code>0</code> the children are hidden using a slide up animation, whose duration is the value of the <code>animation</code> config option in milliseconds. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element we want closed.</p>
+	</li>
+	<li>
+		<code class="tp">bool</code> <strong>skip_animation</strong>
+		<p>If set to <code>true</code> the animation set in the <code>animation</code> config option is skipped. Default is <code>false</code>.</p>
+	</li>
+</ul>
+
+<h3 id="toggle_node">.toggle_node ( node )</h3>
+<p>If a node is closed - this function opens it, if it is open - calling this function will close it.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element we want toggled.</p>
+	</li>
+</ul>
+
+<h3 id="open_all">.open_all ( node , original_obj )</h3>
+<p>Opens all descendants of the <code>node</code> node.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element whose descendants you want opened. If this param is omitted or set to <code>-1</code> all nodes in the tree are opened.</p>
+	</li>
+	<li>
+		<code class="tp">mixed</code> <strong>original_obj</strong>
+		<p>Used internally when recursively calling the same function - do not pass this param.</p>
+	</li>
+</ul>
+
+<h3 id="close_all">.close_all ( node )</h3>
+<p>Closes all descendants of the <code>node</code> node.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element whose descendants you want closed. If this param is omitted or set to <code>-1</code> all nodes in the tree are closed.</p>
+	</li>
+</ul>
+
+<h3 id="clean_node">.clean_node ( node )</h3>
+<p>Applies all necessary classes to the <code>node</code> and its descendants. Used internally. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element you want cleaned. If this param is omitted or set to <code>-1</code> all nodes in the tree are cleaned.</p>
+	</li>
+</ul>
+
+<h3 id="get_rollback">.get_rollback ()</h3>
+<p>Get the current tree's state in the rollback format. Used mainly internally by plugins.</p>
+
+<h3 id="set_rollback">.set_rollback ( html , data )</h3>
+<p>Rollback the tree. Used ONLY internally! Both arguments are part of the rollback object. If you need to rollback - take a look at <a href="#jstree.rollback">jQuery.jstree.rollback()</a>. Triggers event.</p>
+
+<h3 id="load_node">.load_node ( node , success_callback , error_callback )</h3>
+<p>A dummy function that is overwritten by data plugins. Triggers event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element you want loaded. Use <code>-1</code> for root nodes.</p>
+	</li>
+	<li>
+		<code class="tp">function</code> <strong>success_callback</strong>
+		<p>A function to be executed once the node is loaded successfully - used internally. You should wait for the event.</p>
+	</li>
+	<li>
+		<code class="tp">function</code> <strong>error_callback</strong>
+		<p>A function to be executed if the node is not loaded due to an error - used internally. You should wait for the event.</p>
+	</li>
+</ul>
+
+<h3 id="_is_loaded">._is_loaded ( node )</h3>
+<p>A dummy function that should return <code>true</code> if the node's children are loaded or <code>false</code> otherwise.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element you want to check.</p>
+	</li>
+</ul>
+
+<h3 id="create_node">.create_node ( node , position , js , callback , is_loaded )</h3>
+<p>Creates the DOM structure necessary for a new node. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element you want to create in (or next to).</p>
+	</li>
+	<li>
+		<code class="tp">mixed</code> <strong>position</strong>
+		<p>The position of the newly created node. This can be a zero based index to position the element at a specific point among the current children. You can also pass in one of those strings: <code>"before"</code>, <code>"after"</code>, <code>"inside"</code>, <code>"first"</code>, <code>"last"</code>.</p>
+	</li>
+	<li>
+		<code class="tp">object</code> <strong>js</strong>
+		<p>The data for the newly created node. Consists of three keys:</p><p style="margin-left:25px;"><code class="tp">attr</code> - an object of attributes (same used for <code>jQuery.attr()</code>. You can omit this key;<br /><code class="tp">state</code> - a string - either <code>"open"</code> or <code>"closed"</code>, for a leaf node - omit this key;<br /><code class="tp">data</code> - a string or an object - if a string is passed it is used for the title of the node, if an object is passed there are two keys you can specify: <code>attr</code> and <code>title</code>;</p>
+	</li>
+	<li>
+		<code class="tp">function</code> <strong>callback</strong>
+		<p>A function to be executed once the node is created - used internally. You should wait for the event.</p>
+	</li>
+	<li>
+		<code class="tp">bool</code> <strong>is_loaded</strong>
+		<p>Specifies if the parent of the node is loaded or not - used ONLY internally.</p>
+	</li>
+</ul>
+
+<h3 id="get_text">.get_text ( node )</h3>
+<p>Returns the title of a node.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element whose title you need.</p>
+	</li>
+</ul>
+
+<h3 id="set_text">.set_text ( node , text )</h3>
+<p>Sets the title of a node. Triggers an event. This is used mostly internally - wait for a <a href="#rename_node">.rename_node event</a> to avoid confusion.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element whose title you want to change.</p>
+	</li>
+	<li>
+		<code class="tp">string</code> <strong>text</strong>
+		<p>The new title.</p>
+	</li>
+</ul>
+
+<h3 id="rename_node">.rename_node ( node , text )</h3>
+<p>Sets the title of a node. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element whose title you want to change.</p>
+	</li>
+	<li>
+		<code class="tp">string</code> <strong>text</strong>
+		<p>The new title.</p>
+	</li>
+</ul>
+
+<h3 id="delete_node">.delete_node ( node )</h3>
+<p>Removes a node. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element you want to remove.</p>
+	</li>
+</ul>
+
+<h3 id="prepare_move">.prepare_move ( o , r , pos , cb , is_cb )</h3>
+<p>This function is used internally to prepare all necessary variables and nodes when moving a node around. It is automatically called as needed - you do not need to call it manually. Triggers an event.</p>
+
+<h3 id="check_move">.check_move ()</h3>
+<p>Checks if the prepared move is a valid one.</p>
+
+<h3 id="move_node">.move_node ( node , ref , position , is_copy , is_prepared , skip_check )</h3>
+<p>Moves a node to a new place. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element you want to move.</p>
+	</li>
+	<li>
+		<code class="tp">mixed</code> <strong>ref</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element which will be the reference element in the move. <code>-1</code> may be used too (to indicate the container node).</p>
+	</li>
+	<li>
+		<code class="tp">mixed</code> <strong>position</strong>
+		<p>The new position of the moved node. This can be a zero based index to position the element at a specific point among the reference node's current children. You can also use one of these strings: <code>"before"</code>, <code>"after"</code>, <code>"inside"</code>, <code>"first"</code>, <code>"last"</code>.</p>
+	</li>
+	<li>
+		<code class="tp">bool</code> <strong>is_copy</strong>
+		<p>Should this be a copy or a move operation.</p>
+	</li>
+	<li>
+		<code class="tp">bool</code> <strong>is_prepared</strong>
+		<p>Used internally when this function is called recursively.</p>
+	</li>
+	<li>
+		<code class="tp">bool</code> <strong>skip_check</strong>
+		<p>If this is set to <code>true</code> <a href="#check_move">check_move</a> is not called.</p>
+	</li>
+</ul>
+
+<h3 id="_get_move">._get_move ()</h3>
+<p>Returns the lastly prepared move. The returned object contains:<br />
+<code>.o</code> - the node being moved<br />
+<code>.r</code> - the reference node in the move<br />
+<code>.ot</code> - the origin tree instance<br />
+<code>.rt</code> - the reference tree instance<br />
+<code>.p</code> - the position to move to (may be a string - <code>"last"</code>, <code>"first"</code>, etc)<br />
+<code>.cp</code> - the calculated position to move to (always a number)<br />
+<code>.np</code> - the new parent<br />
+</p>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/crrm.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/crrm.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/crrm.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,315 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - CRRM documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - CRRM plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>CRRM</code> plugin handles creating, renaming, removing and moving nodes by the user.</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+<h3>input_width_limit</h3>
+<p class="meta">A number. Default is <code>200</code>.</p>
+<p>When renaming (or creating) nodes the input for the text will autosize - this number sets the maximum size for the input.</p>
+
+<h3>move</h3>
+<p class="meta">An object, containing various settings - see below for more.</p>
+
+<h3>move.always_copy</h3>
+<p class="meta"><code>true</code>, <code>false</code> or <code>"multitree"</code>. Default is <code>false</code>.</p>
+<p>Defines how moves are handled - if set to <code>true</code> every move will be forced to a copy (leaving the original node in place). If set to <code>"multitree"</code> only moves between trees will be forced to a copy.</p>
+
+<h3>move.open_onmove</h3>
+<p class="meta">A Boolean. Default is <code>true</code>.</p>
+<p>If set to true, when moving a node to a new, closed parent, the parent node will be opened when the move completes.</p>
+
+<h3>move.default_position</h3>
+<p class="meta">A string or a number. Default is <code>"last"</code>.</p>
+<p>The default position to move to if no position is specified. This can be a zero based index to position the element at a specific point among the new parent's current children. You can also use one of these strings: <code>"before"</code>, <code>"after"</code>, <code>"inside"</code>, <code>"first"</code>, <code>"last"</code>.</p>
+
+<h3>move.check_move</h3>
+<p class="meta">A function. Default is <code>function (m) { return true; }</code>.</p>
+<p>The callback function enabling you to prevent some moves - just return <code>false</code>. The <code>m</code> parameter is the move object generated by jstree. The object follows the structure described in <a href="core.html#_get_move">._get_move</a>.</p>
+
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+
+<h3>Creating nodes</h3>
+<input type="button" class="button" value="create_1" id="create_1" style="float:left;" />
+<input type="button" class="button" value="create_2" id="create_2" style="float:left;" />
+<input type="button" class="button" value="create_3" id="create_3" style="" />
+<div id="demo1" class="demo">
+	<ul>
+		<li id="phtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="phtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="phtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="phtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#create_1").click(function () { 
+		$("#demo1").jstree("create"); 
+	});
+	$("#create_2").click(function () { 
+		$("#demo1").jstree("create","#phtml_1","first","Enter a new name"); 
+	});
+	$("#create_3").click(function () { 
+		$("#demo1").jstree("create",-1,false,"No rename",false,true); 
+	});
+	$("#demo1").jstree({ 
+		"ui" : {
+			"initially_select" : [ "phtml_2" ]
+		},
+		"core" : { "initially_open" : [ "phtml_1" ] },
+		"plugins" : [ "themes", "html_data", "ui", "crrm" ]
+	});
+});
+</script>
+
+<h3>Removing nodes</h3>
+<input type="button" class="button" value="remove_1" id="remove_1" style="float:left;" />
+<input type="button" class="button" value="remove_2" id="remove_2" style="" />
+<div id="demo2" class="demo">
+	<ul>
+		<li id="rhtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="rhtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="rhtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="rhtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#remove_1").click(function () { 
+		$("#demo2").jstree("remove"); 
+	});
+	$("#remove_2").click(function () { 
+		$("#demo2").jstree("remove","#rhtml_1"); 
+	});
+	$("#demo2").jstree({ 
+		"ui" : {
+			"initially_select" : [ "rhtml_2" ]
+		},
+		"core" : { "initially_open" : [ "rhtml_1" ] },
+		"plugins" : [ "themes", "html_data", "ui", "crrm" ]
+	});
+});
+</script>
+
+<h3>Renaming nodes</h3>
+<input type="button" class="button" value="rename_1" id="rename_1" style="float:left;" />
+<input type="button" class="button" value="rename_2" id="rename_2" style="" />
+<div id="demo3" class="demo">
+	<ul>
+		<li id="shtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="shtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="shtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="shtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#rename_1").click(function () { 
+		$("#demo3").jstree("rename"); 
+	});
+	$("#rename_2").click(function () { 
+		$("#demo3").jstree("rename","#shtml_1"); 
+	});
+	$("#demo3").jstree({ 
+		"ui" : {
+			"initially_select" : [ "shtml_2" ]
+		},
+		"core" : { "initially_open" : [ "shtml_1" ] },
+		"plugins" : [ "themes", "html_data", "ui", "crrm" ]
+	});
+});
+</script>
+
+<h3>Moving nodes</h3>
+<p><strong>move_1</strong> uses the default position - <code>"first"</code></p>
+<p><strong>move_2</strong> specifies a position - <code>"before"</code> - meaning that the node specified as a first argument will come above the node specified as the second argument</p>
+<p><strong>move_3</strong> will never work, because of the specified <code>check_move</code> function which prevents the first root node from being moved</p>
+<input type="button" class="button" value="move_1" id="move_1" style="float:left;" />
+<input type="button" class="button" value="move_2" id="move_2" style="float:left;" />
+<input type="button" class="button" value="move_3" id="move_3" style="" />
+<div id="demo4" class="demo">
+	<ul>
+		<li id="thtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="thtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="thtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="thtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#move_1").click(function () { 
+		$("#demo4").jstree("move_node","#thtml_4","#thtml_1"); 
+	});
+	$("#move_2").click(function () { 
+		$("#demo4").jstree("move_node","#thtml_4","#thtml_1", "before"); 
+	});
+	$("#move_3").click(function () { 
+		$("#demo4").jstree("move_node","#thtml_1","#thtml_4"); 
+	});
+	$("#demo4").jstree({ 
+		"crrm" : {
+			"move" : {
+				"default_position" : "first",
+				"check_move" : function (m) { return (m.o[0].id === "thtml_1") ? false : true;  }
+			}
+		},
+		"ui" : {
+			"initially_select" : [ "thtml_2" ]
+		},
+		"core" : { "initially_open" : [ "thtml_1" ] },
+		"plugins" : [ "themes", "html_data", "ui", "crrm" ]
+	});
+});
+</script>
+
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+
+<h3 id="_show_input">._show_input ( node , callback )</h3>
+<p>Renders an input field in a node. Used only internally.</p>
+
+<h3 id="rename">.rename ( node )</h3>
+<p>Sets a node in rename mode and when the user has entered changes, an event is triggered.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree. If you use the UI plugin - pass <code>null</code> to use the currently selected item.</p>
+	</li>
+</ul>
+
+<h3 id="create">.create ( node , position , js , callback , skip_rename )</h3>
+<p>Creates a new node. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element you want to create in (or next to). If you use the UI plugin - pass <code>null</code> to use the currently selected item.</p>
+	</li>
+	<li>
+		<code class="tp">mixed</code> <strong>position</strong>
+		<p>The position of the newly created node. This can be a zero based index to position the element at a specific point among the current children. You can also pass in one of those strings: <code>"before"</code>, <code>"after"</code>, <code>"inside"</code>, <code>"first"</code>, <code>"last"</code>.</p>
+	</li>
+	<li>
+		<code class="tp">object</code> <strong>js</strong>
+		<p>The data for the newly created node. Consists of three keys:</p><p style="margin-left:25px;"><code class="tp">attr</code> - an object of attributes (same used for <code>jQuery.attr()</code>. You can omit this key;<br /><code class="tp">state</code> - a string - either <code>"open"</code> or <code>"closed"</code>, for a leaf node - omit this key;<br /><code class="tp">data</code> - a string or an object - if a string is passed it is used for the title of the node, if an object is passed there are two keys you can specify: <code>attr</code> and <code>title</code>;</p>
+	</li>
+	<li>
+		<code class="tp">function</code> <strong>callback</strong>
+		<p>A function to be executed once the node is created. You'd be better off waiting for the event.</p>
+	</li>
+	<li>
+		<code class="tp">bool</code> <strong>skip_rename</strong>
+		<p>Skips the user input step. The node is created with the data you have supplied.</p>
+	</li>
+</ul>
+
+<h3 id="remove">.remove ( node )</h3>
+<p>Removes a node. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree. If you use the UI plugin - pass <code>null</code> to use the currently selected items.</p>
+	</li>
+</ul>
+
+<div style="height:1px; visibility:hidden; overflow:hidden;"><span id="check_move">&#160;</span></div>
+<h3 id="move_node">.check_move ( ), .move_node ( )</h3>
+<p>Both functions are overwritten from the <a href="core.html#check_move">core</a> in order to implement the new functionality.</p>
+
+<h3 id="cut">.cut ( node )</h3>
+<p>Cuts a node (prepares it for pasting).</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree. If you use the UI plugin - pass <code>null</code> to use the currently selected item.</p>
+	</li>
+</ul>
+
+<h3 id="copy">.copy ( node )</h3>
+<p>Copies a node (prepares it for pasting).</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree. If you use the UI plugin - pass <code>null</code> to use the currently selected item.</p>
+	</li>
+</ul>
+
+<h3 id="paste">.paste ( node )</h3>
+<p>Pastes copied or cut nodes inside a node.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree. If you use the UI plugin - pass <code>null</code> to use the currently selected item.</p>
+	</li>
+</ul>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/dnd.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/dnd.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/dnd.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,200 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - dnd documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - drag'n'drop plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>dnd</code> plugin enables drag'n'drop support for jstree, also using foreign nodes and drop targets.</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+
+<h3>copy_modifier</h3>
+<p class="meta">A string. Default is <code>"ctrl"</code>.</p>
+<p>The special key used to make a drag copy instead of move (<code>"ctrl"</code>, <code>"shift"</code>, <code>"alt"</code>, <code>"meta"</code>).</p>
+
+<h3>check_timeout</h3>
+<p class="meta">A number. Default is <code>200</code>.</p>
+<p>The number of milliseconds to wait before checking if a move is valid upon hovering a node (while dragging). <code>200</code> is a reasonable value - a higher number means better performance but slow feedback to the user, a lower number means lower performance (possibly) but the user will get feedback faster.</p>
+
+<h3>open_timeout</h3>
+<p class="meta">A number. Default is <code>500</code>.</p>
+<p>The number of milliseconds to wait before opening a hovered if it has children (while dragging). This means that the user has to stop over the node for half a second in order to trigger the open operation. Keep in mind that a low value in combination with async data could mean a lot of unneeded traffic, so <code>500</code> is quite reasonable.</p>
+
+<h3>drop_target</h3>
+<p class="meta">A string (jQuery selector) (or <code>false</code>). Default is <code>".jstree-drop"</code>.</p>
+<p>A jquery selector matching all drop targets (you can also use the comma <code>,</code> in the string to specify multiple valid targets). If set to <code>false</code> drop targets are disabled.</p>
+
+<h3>drop_check</h3>
+<p class="meta">A function. Default is <code>function (data) { return true; }</code>.</p>
+<p>Return <code>false</code> to mark the move as invalid, otherwise return <code>true</code>. The <code>data</code> parameter is as follows:</p>
+<p style="margin-left:2em;"><code>data.o</code> - the object being dragged</p>
+<p style="margin-left:2em;"><code>data.r</code> - the drop target</p>
+
+<h3>drop_finish</h3>
+<p class="meta">A function. Default is <code>$.noop</code>.</p>
+<p>Gets executed after a valid drop, you get one parameter, which is as follows:</p>
+<p style="margin-left:2em;"><code>data.o</code> - the object being dragged</p>
+<p style="margin-left:2em;"><code>data.r</code> - the drop target</p>
+
+<h3>drag_target</h3>
+<p class="meta">A string (jQuery selector) (or <code>false</code>). Default is <code>".jstree-draggable"</code>.</p>
+<p>A jquery selector matching all foreign nodes that can be dropped on the tree (you can also use the comma <code>,</code> in the string to specify multiple valid foreign nodes). If set to <code>false</code> dragging foreign nodes is disabled.</p>
+
+<h3>drag_check</h3>
+<p class="meta">A function. Default is <code>function (data) { return { after : false, before : false, inside : true }; }</code>.</p>
+<p>Return a boolean for each position. The <code>data</code> parameter is as follows:</p>
+<p style="margin-left:2em;"><code>data.o</code> - the foreign object being dragged</p>
+<p style="margin-left:2em;"><code>data.r</code> - the hovered node</p>
+
+<h3>drag_finish</h3>
+<p class="meta">A function. Default is <code>$.noop</code>.</p>
+<p>Gets executed after a dropping a foreign element on a tree item, you get one parameter, which is as follows:</p>
+<p style="margin-left:2em;"><code>data.o</code> - the foreign object being dragged</p>
+<p style="margin-left:2em;"><code>data.r</code> - the target node</p>
+
+
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+<h3>Using the dnd plugin</h3>
+<p>Drag stuff around!</p>
+<div class="jstree-drop" style="clear:both; border:5px solid green; background:lime; color:green; height:40px; line-height:40px; text-align:center; font-size:20px;">I have the jstree-drop class</div>
+<div class="jstree-draggable" style="margin:10px 0; clear:both; border:5px solid navy; background:aqua; color:navy; height:40px; line-height:40px; text-align:center; font-size:20px;">I have the jstree-draggable class</div>
+<div id="demo1" class="demo">
+	<ul>
+		<li id="phtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="phtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="phtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="phtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo1").jstree({ 
+		"dnd" : {
+			"drop_finish" : function () { 
+				alert("DROP"); 
+			},
+			"drag_check" : function (data) {
+				if(data.r.attr("id") == "phtml_1") {
+					return false;
+				}
+				return { 
+					after : false, 
+					before : false, 
+					inside : true 
+				};
+			},
+			"drag_finish" : function () { 
+				alert("DRAG OK"); 
+			}
+		},
+		"plugins" : [ "themes", "html_data", "dnd" ]
+	});
+});
+</script>
+
+<h3>Reorder only demo</h3>
+<div id="demo2" class="demo">
+	<ul>
+		<li id="rhtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="rhtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="rhtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+				<li id="rhtml_4">
+					<a href="#">Child node 3</a>
+				</li>
+				<li id="rhtml_5">
+					<a href="#">Child node 4</a>
+				</li>
+			</ul>
+		</li>
+		<li id="rhtml_6">
+			<a href="#">Root node 2</a>
+		</li>
+		<li id="rhtml_7">
+			<a href="#">Root node 3</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo2").jstree({ 
+		"crrm" : { 
+			"move" : {
+				"check_move" : function (m) { 
+					var p = this._get_parent(m.o);
+					if(!p) return false;
+					p = p == -1 ? this.get_container() : p;
+					console.log(p);
+					console.log(m.np);
+					console.log("DDDD");
+					if(p === m.np) return true;
+					if(p[0] && m.np[0] && p[0] === m.np[0]) return true;
+					return false;
+				}
+			}
+		},
+		"dnd" : {
+			"drop_target" : false,
+			"drag_target" : false
+		},
+		"plugins" : [ "themes", "html_data", "crrm", "dnd" ]
+	});
+});
+</script>
+
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+
+<div style="height:1px; visibility:hidden;">
+	<span id="dnd_show">&nbsp;</span>
+	<span id="dnd_open">&nbsp;</span>
+	<span id="dnd_finish">&nbsp;</span>
+	<span id="dnd_enter">&nbsp;</span>
+	<span id="start_drag">&nbsp;</span>
+</div>
+<h3 id="dnd_prepare">.dnd_prepare ( ), .dnd_show ( ), .dnd_open ( ), .dnd_finish ( ), .dnd_enter ( ), .start_drag ( )</h3>
+<p>All those functions are used internally only. If you want more information - examine the source code.</p>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/hotkeys.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/hotkeys.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/hotkeys.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,81 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - hotkeys documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - hotkeys plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>hotkeys</code> plugin enables keyboard navigation and shortcuts. Depends on the  <a href="http://github.com/jeresig/jquery.hotkeys/">jquery.hotkeys plugin</a></p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+<p>Expects an object:<br />each key is the keyboard shortcut (for possible values check <a href="http://github.com/jeresig/jquery.hotkeys/">the hotkeys plugin</a>)<br />each values is a function executed in the instance's context, the return value is used as a return value for the event.</p>
+<p>Simple example:</p>
+<p><code>"del" : function () { this.remove(); }</code></p>
+
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+
+<h3>Using the hotkeys plugin</h3>
+<p>Try pressing <code>up</code>/<code>down</code>/<code>left</code>/<code>right</code>/<code>space</code>/<code>f2</code>/<code>del</code>.</p>
+<div id="demo1" class="demo">
+	<ul>
+		<li id="phtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="phtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="phtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="phtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo1").jstree({ 
+	  "core" : { "initially_open" : [ "phtml_1" ] },
+	  "plugins" : ["themes","html_data","ui","crrm","hotkeys"]
+	});
+});
+</script>
+
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+
+<h3 id="enable_hotkeys">.enable_hotkeys ( )</h3>
+<p>Enable shortcuts on the instance (enabled by default).</p>
+
+<h3 id="disable_hotkeys">.disable_hotkeys ( )</h3>
+<p>Disable shortcuts on the instance.</p>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/html_data.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/html_data.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/html_data.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,173 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - html_data documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - html_data plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>html_data</code> plugin enables jsTree to convert nested unordered lists to interactive trees. jsTree can also get HTML from the server insert it into the DOM and convert that to a tree.</p>
+<p>The basic structure you need to follow when supplying data in the HTML format is:</p>
+<div class="code_f">
+<pre class="brush:xml;">
+&lt;li&gt;
+	&lt;a href="some_value_here"&gt;Node title&lt;/a&gt;
+	&lt;!-- UL node only needed for children - omit if there are no children --&gt;
+	&lt;ul&gt;
+		&lt;!-- Children LI nodes here --&gt;
+	&lt;/ul&gt;
+&lt;/li&gt;
+</pre>
+</div>
+<p>If you inspect the resulting structure you will find it a bit different - that is because jstree will automatically do some corrections.</p>
+<div class="code_f">
+<pre class="brush:xml;">
+&lt;!-- one of the three classes will be applied depending on node structure --&gt;
+&lt;li class="[ jstree-open | jstree-closed | jstree-leaf ]"&gt;
+	&lt;!-- an INS element is inserted --&gt;
+	&lt;ins class="jstree-icon"&gt;&amp;#160;&lt;/ins&gt;
+	&lt;a href="some_value_here"&gt;
+		&lt;!-- another INS element is inserted --&gt;
+		&lt;ins class="jstree-icon"&gt;&amp;#160;&lt;/ins&gt;
+		Node title
+	&lt;/a&gt;
+&lt;/li&gt;
+</pre>
+</div>
+<p>Both <code>ins</code> elements are inserted for visualization purposes. As for the class (<code>jstree-open</code>, <code>jstree-closed</code>) - you can specify that yourself to force the node to appear either closed or opened. Making a node with no children appear closed is often used - if you use ajax, opening a closed node with no children will result in jstree making a server call for the children (see the <a href="#demo3">demo below</a>).</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+<h3>data</h3>
+<p class="meta">A HTML string (or <code>false</code> if not used). Default is <code>false</code>.</p>
+<p>Specifies the content to load into the container and convert to a tree.</p>
+<h3>ajax</h3>
+<p class="meta">An object (or <code>false</code> if not used). Default is <code>false</code>.</p>
+<p>The ajax config object is pretty much the same as the <a href="http://api.jquery.com/jQuery.ajax/">jQuery ajax settings object</a>.</p>
+<p>The only difference is that you can set the <code>data</code> option to a function, that will be executed in the current tree's scope (<code>this</code> will be the tree instance) and gets the node about to be open as a paramater (or <code>-1</code> for initial load). Whatever you return in the function will be sent to the server as data (so for example you can send the node's ID).</p>
+<p>The <code>error</code> and <code>success</code> functions (if present) also fire in the context of the tree, and if you return a value in the <code>success</code> function it will be used to populate the tree - this can be useful if you want to somehow change what the server returned on the client side before it is displayed in the tree.</p>
+<h3>correct_state</h3>
+<p class="meta">A Boolean. Default is <code>false</code>.</p>
+<p>If this option is set to <code>true</code> if an AJAX request fails (or returns an empty result), the node that was about to be opened will be converted to a leaf node (the open icon will no longer be displayed).</p>
+
+<p class="note"><strong>NOTE:</strong><br />If both <code>data</code> and <code>ajax</code> are not set, the current container's HTML is used to build the tree.<br />If both <code>data</code> and <code>ajax</code> are set the initial tree is rendered from the <code>data</code> string. When opening a closed node (that has no loaded children) an AJAX request is made.</p>
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+
+<h3>Using initial content (convert an existing list)</h3>
+<div id="demo1" class="demo">
+	<ul>
+		<li id="phtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="phtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="phtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="phtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo1").jstree({ 
+		"plugins" : [ "themes", "html_data" ]
+	});
+});
+</script>
+
+<h3>Using the data config option</h3>
+<div id="demo2" class="demo"></div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo2").jstree({ 
+		"core" : { "initially_open" : [ "root" ] },
+		"html_data" : {
+			"data" : "<li id='root'><a href='#'>Root node</a><ul><li><a href='#'>Child node</a></li></ul></li>"
+		},
+		"plugins" : [ "themes", "html_data" ]
+	});
+});
+</script>
+
+<h3>Using the ajax config option</h3>
+<div id="demo3" class="demo"></div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo3").jstree({ 
+		"html_data" : {
+			"ajax" : {
+				"url" : "_html_data.html",
+				"data" : function (n) { 
+					return { id : n.attr ? n.attr("id") : 0 }; 
+				}
+			}
+		},
+		"plugins" : [ "themes", "html_data" ]
+	});
+});
+</script>
+
+<h3>Using both the data &amp; ajax config options</h3>
+<div id="demo4" class="demo"></div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo4").jstree({ 
+		"core" : { "initially_open" : [ "root2" ] },
+		"html_data" : {
+			"data" : "<li class='jstree-closed' id='root2'><a href='#'>Root node</a></li>",
+			"ajax" : { "url" : "_html_data.html" }
+		},
+		"plugins" : [ "themes", "html_data" ]
+	});
+});
+</script>
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+<p>Both dummy functions - <code>_is_loaded</code> and <code>load_node</code> are overwritten.</p>
+<h3 id="load_node_html">.load_node_html ( node , success_callback , error_callback )</h3>
+<p>This function is called instead of <code>load_node</code>.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element you want loaded. Use <code>-1</code> for root nodes.</p>
+	</li>
+	<li>
+		<code class="tp">function</code> <strong>success_callback</strong>
+		<p>A function to be executed once the node is loaded successfully - used internally. You should wait for the <code>load_node</code> event.</p>
+	</li>
+	<li>
+		<code class="tp">function</code> <strong>error_callback</strong>
+		<p>A function to be executed if the node is not loaded due to an error - used internally. You should wait for the <code>load_node</code> event.</p>
+	</li>
+</ul>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/index.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/index.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/index.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,71 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 Documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0</h1>
+<h2>Description</h2>
+<div id="description">
+<p>jsTree is a javascript based, cross browser tree component. It is packaged as a <a href="http://jquery.com">jQuery</a> plugin.</p>
+<p>jsTree is absolutely free (licensed same as jQuery – under both GPL and MIT – whichever suits your needs).</p>
+<h3>Features at a glance</h3>
+<ul class="columns">
+	<li>Various data sources - HTML, JSON, XML</li>
+	<li>Supports AJAX loading</li>
+	<li>Drag &amp; drop support</li>
+	<li>Highly configurable</li>
+	<li>Theme support + included themes</li> 
+	<li>Uses jQuery's event system</li> 
+	<li>Optional keyboard navigation</li> 
+	<li>Maintain the same tree in many languages</li>
+	<li>Inline editing</li>
+	<li>Open/close optional animation</li>
+	<li>Define node types and fine tune them</li>
+	<li>Configurable multitree drag &amp; drop</li>
+	<li>Optional checkbox tree support</li>
+	<li>Search function</li>
+	<li>Supports plugins</li>
+	<li>Optional state saving using cookies</li>
+</ul>
+<p>As of version 1.0 jsTree is extremely plugin friendly, so all functionality is now wrapped in plugins, which take care of various aspects of the tree and can be removed without affecting the functionality of other plugins. Below you will find a list of plugins - each with its own documentation page. Probably a good place to start is the <a href="core.html">core</a>.</p>
+</div>
+
+<h2 id="plugins">Plugins</h2>
+<div class="panel">
+<ul class="columns plugins">
+	<li style="float:none; width:660px;"><a href="core.html" style="font-weight:bold;">Core functionality</a><p>all core functions for manipulating the tree + basic examples of including, configuring and working with the tree, along with demos of the new event system</p></li>
+	<li><a href="html_data.html">HTML_DATA plugin</a><p>enables jsTree to convert nested unordered lists to interactive trees, an already existing UL may be used or data could be retrieved from a server</p></li>
+	<li><a href="json_data.html">JSON_DATA plugin</a><p>enables jsTree to convert JSON objects to interactive trees, data can be set up in the config or retrieved from a server</p></li>
+	<li><a href="xml_data.html">XML_DATA plugin</a><p>enables jsTree to convert XML objects to interactive trees (using XSL), data can be set up in the config or retrieved from a server</p></li>
+	<li><a href="themes.html">Themes plugin</a><p>controls the looks of jstree - without this plugin you will get a functional tree, but it will look just like an ordinary UL list</p></li>
+	<li><a href="ui.html">UI plugin</a><p>handles selecting, deselecting and hovering tree items</p></li>
+	<li><a href="crrm.html">CRRM plugin</a><p>handles creating, renaming, removing and moving nodes by the user, also includes cut/copy/paste functions</p></li>
+	<li><a href="hotkeys.html">Hotkeys plugin</a><p>enables support for keyboard navigation &amp; shortcuts, highly configurable</p></li>
+	<li><a href="languages.html">Languages plugin</a><p>enables multilanguage support - each node can have multiple titles, but only one is visible</p></li>
+	<li><a href="cookies.html">Cookies plugin</a><p>enables jstree to save the state of the tree across sessions, by saving selected and opened nodes in a cookie</p></li>
+	<li><a href="sort.html">Sort plugin</a><p>enables jstree to automatically sort all nodes<br />using a specified function</p></li>
+	<li><a href="dnd.html">DND plugin</a><p>enables drag'n'drop support for jstree, also using foreign nodes and drop targets</p></li>
+	<li><a href="checkbox.html">Checkbox plugin</a><p>makes multiselection possible using three-state checkboxes</p></li>
+	<li><a href="search.html">Search plugin</a><p>enables searching for nodes whose title contains a given string, works on async trees too</p></li>
+	<li><a href="contextmenu.html">Contextmenu plugin</a><p>enables a multilevel context menu on tree items</p></li>
+	<li><a href="types.html">Types plugin</a><p>each node can have a type, and you can define rules on how that type should behave</p></li>
+</ul>
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/json_data.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/json_data.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/json_data.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,235 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - json_data documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - json_data plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>json_data</code> plugin enables jsTree to convert JSON objects to interactive trees. The data (JSON) can be set up in the config or retrieved from a server (also ondemand). Version 1.0 also introduces the experimental progressive render feature, which is suitable for large heavy trees, when the DOM would be too heavy to manipulate.</p>
+<p>The basic structure you need to follow when supplying data in the JSON format is:</p>
+<div class="code_f">
+<pre class="brush:js;">
+{ 
+	data : "node_title", 
+	// omit `attr` if not needed; the `attr` object gets passed to the jQuery `attr` function
+	attr : { id : "node_identificator", some-other-attribute : "attribute_value" }, 
+	// `state` and `children` are only used for NON-leaf nodes
+	state: "closed", // or "open", defaults to "closed"
+	children: [ /* an array of child nodes objects */ ]
+}
+</pre>
+</div>
+<p>The attr object will appear as attributes on the resulting <code>li</code> node.</p>
+<p>You may need to pass some attributes to the <code>a</code> node, or set some metadata, or use language versions (for the <a href="languages.html">languages plugin</a>):</p>
+<div class="code_f">
+<pre class="brush:js;">
+{
+	// `data` can also be an object
+	data : { 
+		title : "The node title", 
+		// omit when not needed
+		attr : {}, 
+		// if `icon` contains a slash <code>/</code> it is treated as a file, used for background
+		// otherwise - it is added as a class to the &lt;ins&gt; node
+		icon : "folder"
+	},
+
+	// the `metadata` property will be saved using the jQuery `data` function on the `li` node
+	metadata : "a string, array, object, etc",
+
+	// if you use the language plugin - just set this property
+	// also make sure that `data` is an array of objects
+	language : "en" // any code you are using
+}
+</pre>
+</div>
+<p>As seen in the first example below - you can also use a simple string to define a node (Child 1 &amp; Child 2).</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+<h3>data</h3>
+<p class="meta">A JSON object (or <code>false</code> if not used). Default is <code>false</code>.</p>
+<p>Specifies the content to load into the container and convert to a tree.</p>
+<h3>ajax</h3>
+<p class="meta">An object (or <code>false</code> if not used). Default is <code>false</code>.</p>
+<p>The ajax config object is pretty much the same as the <a href="http://api.jquery.com/jQuery.ajax/">jQuery ajax settings object</a>.</p>
+<p>The only difference is that you can set the <code>data</code> option to a function, that will be executed in the current tree's scope (<code>this</code> will be the tree instance) and gets the node about to be open as a paramater (or <code>-1</code> for initial load). Whatever you return in the function will be sent to the server as data (so for example you can send the node's ID).</p>
+<p>The <code>error</code> and <code>success</code> functions (if present) also fire in the context of the tree, and if you return a value in the <code>success</code> function it will be used to populate the tree - this can be useful if you want to somehow change what the server returned on the client side before it is displayed in the tree.</p>
+<h3>correct_state</h3>
+<p class="meta">A Boolean. Default is <code>false</code>.</p>
+<p>If this option is set to <code>true</code> if an AJAX request fails (or returns an empty result), the node that was about to be opened will be converted to a leaf node (the open icon will no longer be displayed).</p>
+<h3>progressive_render</h3>
+<p class="meta">A Boolean. Default is <code>false</code>.</p>
+<p>If this option is set to <code>true</code> only the visible (open nodes) parts of the returned JSON are converted to DOM nodes, any hidden parts are saved away and parsed ondemand (when a node becomes visible). This is useful when you have a large nested tree which would result in a heavy DOM.</p>
+
+<p class="note"><strong>NOTE:</strong><br />If both <code>data</code> and <code>ajax</code> are set the initial tree is rendered from the <code>data</code> string. When opening a closed node (that has no loaded children) an AJAX request is made.</p>
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+
+<h3>Using the data config option</h3>
+<div id="demo1" class="demo"></div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo1").jstree({ 
+		"json_data" : {
+			"data" : [
+				{ 
+					"data" : "A node", 
+					"children" : [ "Child 1", "Child 2" ]
+				},
+				{ 
+					"attr" : { "id" : "li.node.id" }, 
+					"data" : { 
+						"title" : "Long format demo", 
+						"attr" : { "href" : "#" } 
+					} 
+				}
+			]
+		},
+		"plugins" : [ "themes", "json_data" ]
+	});
+});
+</script>
+
+<h3>Using the ajax config option</h3>
+<div id="demo2" class="demo"></div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo2").jstree({ 
+		"json_data" : {
+			"ajax" : {
+				"url" : "_json_data.json",
+				"data" : function (n) { 
+					return { id : n.attr ? n.attr("id") : 0 }; 
+				}
+			}
+		},
+		"plugins" : [ "themes", "json_data" ]
+	});
+});
+</script>
+
+<h3>Using the progressive render config option</h3>
+<div id="demo3" class="demo"></div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo3").jstree({ 
+		"json_data" : {
+			"data" : [
+				{ 
+					"data" : "A node", 
+					"children" : [ "Child 1", "Child 2" ]
+				},
+				{ 
+					"attr" : { "id" : "li.node.id" }, 
+					"data" : { 
+						"title" : "Long format demo", 
+						"attr" : { "href" : "#" } 
+					} 
+				}
+			],
+			"progressive_render" : true
+		},
+		"plugins" : [ "themes", "json_data" ]
+	});
+});
+</script>
+
+<h3>Using both the data &amp; ajax config options</h3>
+<div id="demo4" class="demo"></div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo4").jstree({ 
+		"json_data" : {
+			"data" : [
+				{ 
+					"data" : "A node", 
+					"state" : "closed"
+				},
+				{ 
+					"attr" : { "id" : "li.node.id" }, 
+					"data" : { 
+						"title" : "Long format demo", 
+						"attr" : { "href" : "#" } 
+					} 
+				}
+			],
+			"ajax" : { "url" : "_json_data.json" }
+		},
+		"plugins" : [ "themes", "json_data" ]
+	});
+});
+</script>
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+<p>Both dummy functions - <code>_is_loaded</code> and <code>load_node</code> are overwritten.</p>
+<h3 id="load_node_json">.load_node_json ( node , success_callback , error_callback )</h3>
+<p>This function is called instead of <code>load_node</code>.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element you want loaded. Use <code>-1</code> for root nodes.</p>
+	</li>
+	<li>
+		<code class="tp">function</code> <strong>success_callback</strong>
+		<p>A function to be executed once the node is loaded successfully - used internally. You should wait for the <code>load_node</code> event.</p>
+	</li>
+	<li>
+		<code class="tp">function</code> <strong>error_callback</strong>
+		<p>A function to be executed if the node is not loaded due to an error - used internally. You should wait for the <code>load_node</code> event.</p>
+	</li>
+</ul>
+<h3 id="parse_json">.parse_json ( data , is_callback )</h3>
+<p>This function converts JSON nodes to the DOM structure required by jstree. Returns a jQuery object.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a tree node in the JSON format described above, or an array of such JSON nodes, may also be a string.</p>
+	</li>
+	<li>
+		<code class="tp">bool</code> <strong>is_callback</strong>
+		<p>Specifies if the function is called recursively - used ONLY internally.</p>
+	</li>
+</ul>
+<h3 id="get_json">.get_json ( node , li_attr , a_attr )</h3>
+<p>This function returns an array of tree nodes converted back to JSON.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element you want returned. Use <code>-1</code> or omit to get the whole tree.</p>
+	</li>
+	<li>
+		<code class="tp">array</code> <strong>li_attr</strong>
+		<p>The attributes to collect from the <code>LI</code> node. Defaults to <code>[ "id" , "class" ]</p>
+	</li>
+	<li>
+		<code class="tp">array</code> <strong>a_attr</strong>
+		<p>The attributes to collect from the <code>A</code> node. Defaults to <code>[ ]</p>
+	</li>
+</ul>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/languages.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/languages.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/languages.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,138 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - languages documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - languages plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>languages</code> plugin enables multilanguage trees. This means that each node has a specified number of titles - each in a different "language". Only one language set is visible at any given time. This is useful for maintaining the same structure in many languages (hence the name of the plugin)</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+<p>Expects an array of language codes. Each of the items is used as a CSS class name, so make sure you specify only valid CSS class name strings.  The first langauge will be visible onload. For example:</p>
+<p><code>[ "en", "de", "bg" ]</code></p>
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+<p>Check your data plugin documentation (<a href="html_data.html">html_data</a>, <a href="xml_data.html">xml_data</a>, <a href="json_data.html">json_data</a>) or take a close look at these examples for information on how to specify multilanguage nodes.</p>
+
+<h3>Using the languages plugin with HTML data</h3>
+<input type="button" class="button" value="en" id="en_1" style="float:left;" />
+<input type="button" class="button" value="bg" id="bg_1" style="float:left;" />
+<input type="button" class="button" value="rename_1" id="rename_1" style="float:left;" />
+<input type="button" class="button" value="rename_2" id="rename_2" style="" />
+<div id="demo1" class="demo">
+	<ul>
+		<li id="phtml_1">
+			<a href="#" class="en">Root node 1</a>
+			<a href="#" class="bg">Корен 1</a>
+			<ul>
+				<li id="phtml_2">
+					<a href="#" class="en">Child node 1</a>
+					<a href="#" class="bg">Дете 1</a>
+				</li>
+				<li id="phtml_3">
+					<a href="#" class="en">Child node 2</a>
+					<a href="#" class="bg">Дете 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="phtml_4">
+			<a href="#" class="en">Root node 2</a>
+			<a href="#" class="bg">Корен 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#en_1, #bg_1").click(function () { 
+		$("#demo1").jstree("set_lang", this.value);
+	});
+	$("#rename_1").click(function () { 
+		$("#demo1").jstree("rename_node", "#phtml_1", "Rename visible lang");
+	});
+	$("#rename_2").click(function () { 
+		$("#demo1").jstree("rename_node", "#phtml_1", "Rename `bg`", "bg");
+	});
+	$("#demo1").jstree({ 
+		"languages" : [ "en", "bg" ],
+		"plugins" : [ "themes", "html_data", "languages"]
+	});
+});
+</script>
+
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+
+<h3 id="set_lang">.set_lang ( lang )</h3>
+<p>Set the tree's visible language. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">string <br />number</code> <strong>lang</strong>
+		<p>Either the language code string (as specified in the config) or an index from the config array.</p>
+	</li>
+</ul>
+<h3 id="get_lang">.get_lang ( )</h3>
+<p>Returns the name of the currently visible language.</p>
+
+<h3 id="get_text">.get_text ( node , lang )</h3>
+<p>Returns the title of a node. Overwrites the <a href="core.html#get_text">get_text function</a> from the core.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element whose title you need.</p>
+	</li>
+	<li>
+		<code class="tp">string</code> <strong>lang</strong>
+		<p>The language code string (as specified in the config) to get the title in. If you omit this - the currently visible language is used.</p>
+	</li>
+</ul>
+
+<h3 id="set_text">.set_text ( node , text , lang )</h3>
+<p>Sets the title of a node. Overwrites the <a href="core.html#set_text">set_text function</a> from the core. This is used internally - you should use <a href="core.html#rename_node">rename_node</a>. Since <code>rename_node</code> uses <code>set_text</code> internally you can pass a language string as a third parameter to rename_node.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element whose title you want to change.</p>
+	</li>
+	<li>
+		<code class="tp">string</code> <strong>text</strong>
+		<p>The new title.</p>
+	</li>
+	<li>
+		<code class="tp">string</code> <strong>lang</strong>
+		<p>The language code string (as specified in the config) to get the title in. If you omit this - the currently visible language is used.</p>
+	</li>
+</ul>
+
+<h3 id="_load_css">._load_css ( )</h3>
+<p>used only internally to include the CSS necessary for the plugin onload.</p>
+
+<h3 id="create_node">.create_node ( obj , position , js , callback )</h3>
+<p>Overwrites the <a href="core.html#create_node">create_node</a> function from the core. To create a node with a few titles use an array for the <code>data</code> property of the <code>js</code> parameter:</p>
+<p><code>{ "data" : [ { "title" : "EN title", language : "en" }, { "title" : "BG заглавие", language : "bg" } ] }</code></p>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/search.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/search.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/search.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,112 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - CRRM documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - search plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>search</code> plugin enables searching for nodes whose title contains a given string, works on async trees too. All found nodes get the <code>jstree-search</code> class applied to their contained <code>a</code> nodes - you can use that class to style search results.</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+
+<h3>case_insensitive</h3>
+<p class="meta">A boolean. Default is <code>false</code>.</p>
+<p>Whether to search in a case-insensitive manner or not.</p>
+
+<h3>ajax</h3>
+<p class="meta">An object (or <code>false</code> if not used). Default is <code>false</code>.</p>
+<p>This object can be used to make a request to the server on each search - useful if you are using async trees. That way you can return an array of IDs that need to be loaded before the actual DOM search is performed (so that all the nodes that will match the search are loaded). For example if the user searches for "string", you get that on the server side, check the database and find out that there is a node containing that string. But the node is the child of some other node, etc - so in your response you must return the path to the node (without the node itself) as ids: <code>["#root_node","#child_node_3"]</code>. This means that jstree will load those two nodes before doing the client side search, ensuring that your node will be visible.</p>
+<p>The ajax config object is pretty much the same as the <a href="http://api.jquery.com/jQuery.ajax/">jQuery ajax settings object</a>.</p>
+<p>The only difference is that you can set the <code>data</code> option to a function, that will be executed in the current tree's scope (<code>this</code> will be the tree instance) and gets the search string as a paramater. Whatever you return in the function will be sent to the server as data.</p>
+<p>The <code>error</code> and <code>success</code> functions (if present) also fire in the context of the tree, and if you return a value in the <code>success</code> function it will be used as the array of IDs.</p>
+
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+
+<h3>Searching nodes</h3>
+<p>Do not open the node - instead - just press the button.</p>
+<input type="button" class="button" value="Search" id="search" style="" />
+<div id="demo1" class="demo"></div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#search").click(function () {
+		$("#demo1").jstree("search","TARGET");
+	});
+	$("#demo1")
+		.jstree({ 
+			"json_data" : {
+				"data" : [
+					{ 
+						"attr" : { "id" : "root_node" },
+						"data" : "A closed node", 
+						"state" : "closed"
+					}
+				],
+				"ajax" : {
+					"url" : "_search_data.json",
+					"data" : function (n) { 
+						return { id : n.attr ? n.attr("id") : 0 }; 
+					}
+				}
+			},
+			"search" : {
+				"ajax" : {
+					"url" : "_search_result.json"
+				}
+			},
+			"plugins" : [ "themes", "json_data", "search" ]
+		})
+		.bind("search.jstree", function (e, data) {
+			alert("Found " + data.rslt.nodes.length + " nodes matching '" + data.rslt.str + "'.");
+		});
+});
+</script>
+
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+
+<h3 id="search">.search ( str , skip_async )</h3>
+<p>Searches for nodes matching the supplied string. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">string</code> <strong>str</strong>
+		<p>The string to search for.</p>
+	</li>
+	<li>
+		<code class="tp">boolean</code> <strong>skip_async</strong>
+		<p>If set to <code>true</code> - skip the async search (if setup in the config). This is used mostly internally.</p>
+	</li>
+</ul>
+
+<h3 id="clear_search">.clear_search ( )</h3>
+<p>Clears the current search. This function is automatically called when doing a new search. Triggers an event.</p>
+
+<h3 id="_search_open">._search_open ( is_callback )</h3>
+<p>Used internally if async is setup in the config. This functions loads the nodes returned by the server one by one.</p>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/sort.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/sort.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/sort.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,84 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - sort documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - sort plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>sort</code> enables jstree to automatically sort all nodes using a specified function. This means that when the user creates, renames or moves nodes around - they will automatically sort.</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+
+<p>Expects a function. The functions receives two arguments - two nodes to be compared. Return <code>-1</code> or <code>1</code>. Default is: </p>
+<p><code>function (a, b) { return this.get_text(a) > this.get_text(b) ? 1 : -1; }</code></p>
+
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+<h3>Using the sort plugin</h3>
+<input type="button" class="button" value="rename" id="rename" style="" />
+<div id="demo1" class="demo">
+	<ul>
+		<li id="phtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="phtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="phtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="phtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#rename").click(function () { 
+		$("#demo1").jstree("rename");
+	});
+	$("#demo1").jstree({ 
+		"plugins" : [ "themes", "html_data", "ui", "crrm", "sort" ]
+	});
+});
+</script>
+
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+
+<h3 id="sort">.sort ( node )</h3>
+<p>Sorts the children of the specified node - this function is called automatically.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element.</p>
+	</li>
+</ul>
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/!script.js
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/!script.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/!script.js	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,2232 @@
+/**
+ * SyntaxHighlighter
+ * http://alexgorbatchev.com/
+ *
+ * SyntaxHighlighter is donationware. If you are using it, please donate.
+ * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate
+ *
+ * @version
+ * 2.1.364 (October 15 2009)
+ * 
+ * @copyright
+ * Copyright (C) 2004-2009 Alex Gorbatchev.
+ *
+ * @license
+ * This file is part of SyntaxHighlighter.
+ * 
+ * SyntaxHighlighter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * SyntaxHighlighter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with SyntaxHighlighter.  If not, see <http://www.gnu.org/copyleft/lesser.html>.
+ */
+//
+// Begin anonymous function. This is used to contain local scope variables without polutting global scope.
+//
+if (!window.SyntaxHighlighter) var SyntaxHighlighter = function() { 
+
+// Shortcut object which will be assigned to the SyntaxHighlighter variable.
+// This is a shorthand for local reference in order to avoid long namespace 
+// references to SyntaxHighlighter.whatever...
+var sh = {
+	defaults : {
+		/** Additional CSS class names to be added to highlighter elements. */
+		'class-name' : '',
+		
+		/** First line number. */
+		'first-line' : 1,
+		
+		/**
+		 * Pads line numbers. Possible values are:
+		 *
+		 *   false - don't pad line numbers.
+		 *   true  - automaticaly pad numbers with minimum required number of leading zeroes.
+		 *   [int] - length up to which pad line numbers.
+		 */
+		'pad-line-numbers' : true,
+		
+		/** Lines to highlight. */
+		'highlight' : null,
+		
+		/** Enables or disables smart tabs. */
+		'smart-tabs' : true,
+		
+		/** Gets or sets tab size. */
+		'tab-size' : 4,
+		
+		/** Enables or disables gutter. */
+		'gutter' : true,
+		
+		/** Enables or disables toolbar. */
+		'toolbar' : true,
+		
+		/** Forces code view to be collapsed. */
+		'collapse' : false,
+		
+		/** Enables or disables automatic links. */
+		'auto-links' : true,
+		
+		/** Gets or sets light mode. Equavalent to turning off gutter and toolbar. */
+		'light' : false,
+		
+		/** Enables or disables automatic line wrapping. */
+		'wrap-lines' : true,
+		
+		'html-script' : false
+	},
+	
+	config : {
+		/** Enables use of <SCRIPT type="syntaxhighlighter" /> tags. */
+		useScriptTags : true,
+		
+		/** Path to the copy to clipboard SWF file. */
+		clipboardSwf : null,
+
+		/** Width of an item in the toolbar. */
+		toolbarItemWidth : 16,
+
+		/** Height of an item in the toolbar. */
+		toolbarItemHeight : 16,
+		
+		/** Blogger mode flag. */
+		bloggerMode : false,
+		
+		stripBrs : false,
+		
+		/** Name of the tag that SyntaxHighlighter will automatically look for. */
+		tagName : 'pre',
+		
+		strings : {
+			expandSource : 'show source',
+			viewSource : 'view source',
+			copyToClipboard : 'copy to clipboard',
+			copyToClipboardConfirmation : 'The code is in your clipboard now',
+			print : 'print',
+			help : '?',
+			alert: 'SyntaxHighlighter\n\n',
+			noBrush : 'Can\'t find brush for: ',
+			brushNotHtmlScript : 'Brush wasn\'t configured for html-script option: ',
+			
+			// this is populated by the build script
+			aboutDialog : '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>About SyntaxHighlighter</title></head><body style="font-family:Geneva,Arial,Helvetica,sans-serif;background-color:#fff;color:#000;font-size:1em;text-align:center;"><div style="text-align:center;margin-top:3em;"><div style="font-size:xx-large;">SyntaxHighlighter</div><div style="font-size:.75em;margin-bottom:4em;"><div>version 2.1.364 (October 15 2009)</div><div><a href="http://alexgorbatchev.com" target="_blank" style="color:#0099FF;text-decoration:none;">http://alexgorbatchev.com</a></div><div>If you like this script, please <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=2930402" style="color:#0099FF;text-decoration:none;">donate</a> to keep development active!</div></div><div>JavaScript code syntax highlighter.</div><div>Copyright 2004-2009 Alex Gorbatchev.</div></div></body></html>'
+		},
+
+		/** If true, output will show HTML produces instead. */
+		debug : false
+	},
+	
+	/** Internal 'global' variables. */
+	vars : {
+		discoveredBrushes : null,
+		spaceWidth : null,
+		printFrame : null,
+		highlighters : {}
+	},
+	
+	/** This object is populated by user included external brush files. */
+	brushes : {},
+
+	/** Common regular expressions. */
+	regexLib : {
+		multiLineCComments			: /\/\*[\s\S]*?\*\//gm,
+		singleLineCComments			: /\/\/.*$/gm,
+		singleLinePerlComments		: /#.*$/gm,
+		doubleQuotedString			: /"([^\\"\n]|\\.)*"/g,
+		singleQuotedString			: /'([^\\'\n]|\\.)*'/g,
+		multiLineDoubleQuotedString	: /"([^\\"]|\\.)*"/g,
+		multiLineSingleQuotedString	: /'([^\\']|\\.)*'/g,
+		xmlComments					: /(&lt;|<)!--[\s\S]*?--(&gt;|>)/gm,
+		url							: /&lt;\w+:\/\/[\w-.\/?%&=@:;]*&gt;|\w+:\/\/[\w-.\/?%&=@:;]*/g,
+		
+		/** <?= ?> tags. */
+		phpScriptTags 				: { left: /(&lt;|<)\?=?/g, right: /\?(&gt;|>)/g },
+		
+		/** <%= %> tags. */
+		aspScriptTags				: { left: /(&lt;|<)%=?/g, right: /%(&gt;|>)/g },
+		
+		/** <script></script> tags. */
+		scriptScriptTags			: { left: /(&lt;|<)\s*script.*?(&gt;|>)/gi, right: /(&lt;|<)\/\s*script\s*(&gt;|>)/gi }
+	},
+
+	toolbar : {
+		/**
+		 * Creates new toolbar for a highlighter.
+		 * @param {Highlighter} highlighter    Target highlighter.
+		 */
+		create : function(highlighter)
+		{
+			var div = document.createElement('DIV'),
+				items = sh.toolbar.items
+				;
+			
+			div.className = 'toolbar';
+			
+			for (var name in items) 
+			{
+				var constructor = items[name],
+					command = new constructor(highlighter),
+					element = command.create()
+					;
+				
+				highlighter.toolbarCommands[name] = command;
+				
+				if (element == null)
+					continue;
+					
+				if (typeof(element) == 'string')
+					element = sh.toolbar.createButton(element, highlighter.id, name);
+				
+				element.className += 'item ' + name;
+				div.appendChild(element);
+			}
+			
+			return div;
+		},
+		
+		/**
+		 * Create a standard anchor button for the toolbar.
+		 * @param {String} label			Label text to display.
+		 * @param {String} highlighterId	Highlighter ID that this button would belong to.
+		 * @param {String} commandName		Command name that would be executed.
+		 * @return {Element}				Returns an 'A' element.
+		 */
+		createButton : function(label, highlighterId, commandName)
+		{
+			var a = document.createElement('a'),
+				style = a.style,
+				config = sh.config,
+				width = config.toolbarItemWidth,
+				height = config.toolbarItemHeight
+				;
+			
+			a.href = '#' + commandName;
+			a.title = label;
+			a.highlighterId = highlighterId;
+			a.commandName = commandName;
+			a.innerHTML = label;
+			
+			if (isNaN(width) == false)
+				style.width = width + 'px';
+
+			if (isNaN(height) == false)
+				style.height = height + 'px';
+			
+			a.onclick = function(e)
+			{
+				try
+				{
+					sh.toolbar.executeCommand(
+						this, 
+						e || window.event,
+						this.highlighterId, 
+						this.commandName
+					);
+				}
+				catch(e)
+				{
+					sh.utils.alert(e.message);
+				}
+				
+				return false;
+			};
+			
+			return a;
+		},
+		
+		/**
+		 * Executes a toolbar command.
+		 * @param {Element}		sender  		Sender element.
+		 * @param {MouseEvent}	event			Original mouse event object.
+		 * @param {String}		highlighterId	Highlighter DIV element ID.
+		 * @param {String}		commandName		Name of the command to execute.
+		 * @return {Object} Passes out return value from command execution.
+		 */
+		executeCommand : function(sender, event, highlighterId, commandName, args)
+		{
+			var highlighter = sh.vars.highlighters[highlighterId], 
+				command
+				;
+
+			if (highlighter == null || (command = highlighter.toolbarCommands[commandName]) == null) 
+				return null;
+
+			return command.execute(sender, event, args);
+		},
+		
+		/** Collection of toolbar items. */
+		items : {
+			expandSource : function(highlighter)
+			{
+				this.create = function()
+				{
+					if (highlighter.getParam('collapse') != true)
+						return;
+					
+					return sh.config.strings.expandSource;
+				};
+			
+				this.execute = function(sender, event, args)
+				{
+					var div = highlighter.div;
+					
+					sender.parentNode.removeChild(sender);
+					div.className = div.className.replace('collapsed', '');
+				};
+			},
+		
+			/** 
+			 * Command to open a new window and display the original unformatted source code inside.
+			 */
+			viewSource : function(highlighter)
+			{
+				this.create = function()
+				{
+					return sh.config.strings.viewSource;
+				};
+				
+				this.execute = function(sender, event, args)
+				{
+					var code = sh.utils.fixInputString(highlighter.originalCode).replace(/</g, '&lt;'),
+						wnd = sh.utils.popup('', '_blank', 750, 400, 'location=0, resizable=1, menubar=0, scrollbars=1')
+						;
+					
+					code = sh.utils.unindent(code);
+					
+					wnd.document.write('<pre>' + code + '</pre>');
+					wnd.document.close();
+				};
+			},
+			
+			/**
+			 * Command to copy the original source code in to the clipboard.
+			 * Uses Flash method if <code>clipboardSwf</code> is configured.
+			 */
+			copyToClipboard : function(highlighter)
+			{
+				var flashDiv, flashSwf,
+					highlighterId = highlighter.id
+					;
+				
+				this.create = function()
+				{
+					var config = sh.config;
+					
+					// disable functionality if running locally
+					if (config.clipboardSwf == null)
+						return null;
+
+					function params(list)
+					{
+						var result = '';
+						
+						for (var name in list)
+							result += "<param name='" + name + "' value='" + list[name] + "'/>";
+							
+						return result;
+					};
+					
+					function attributes(list)
+					{
+						var result = '';
+						
+						for (var name in list)
+							result += " " + name + "='" + list[name] + "'";
+							
+						return result;
+					};
+					
+					var args1 = {
+							width				: config.toolbarItemWidth,
+							height				: config.toolbarItemHeight,
+							id					: highlighterId + '_clipboard',
+							type				: 'application/x-shockwave-flash',
+							title				: sh.config.strings.copyToClipboard
+						},
+						
+						// these arguments are used in IE's <param /> collection
+						args2 = {
+							allowScriptAccess	: 'always',
+							wmode				: 'transparent',
+							flashVars			: 'highlighterId=' + highlighterId,
+							menu				: 'false'
+						},
+						swf = config.clipboardSwf,
+						html
+					;
+
+					if (/msie/i.test(navigator.userAgent))
+					{
+						html = '<object'
+							+ attributes({
+								classid : 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000',
+								codebase : 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0'
+							})
+							+ attributes(args1)
+							+ '>'
+							+ params(args2)
+							+ params({ movie : swf })
+							+ '</object>'
+						;
+					}
+					else
+					{
+						html = '<embed'
+							+ attributes(args1)
+							+ attributes(args2)
+							+ attributes({ src : swf })
+							+ '/>'
+						;
+					}
+
+					flashDiv = document.createElement('div');
+					flashDiv.innerHTML = html;
+					
+					return flashDiv;
+				};
+				
+				this.execute = function(sender, event, args)
+				{
+					var command = args.command;
+
+					switch (command)
+					{
+						case 'get':
+							var code = sh.utils.unindent(
+								sh.utils.fixInputString(highlighter.originalCode)
+									.replace(/&lt;/g, '<')
+									.replace(/&gt;/g, '>')
+									.replace(/&amp;/g, '&')
+								);
+
+							if(window.clipboardData)
+								// will fall through to the confirmation because there isn't a break
+								window.clipboardData.setData('text', code);
+							else
+								return sh.utils.unindent(code);
+							
+						case 'ok':
+							sh.utils.alert(sh.config.strings.copyToClipboardConfirmation);
+							break;
+							
+						case 'error':
+							sh.utils.alert(args.message);
+							break;
+					}
+				};
+			},
+			
+			/** Command to print the colored source code. */
+			printSource : function(highlighter)
+			{
+				this.create = function()
+				{
+					return sh.config.strings.print;
+				};
+				
+				this.execute = function(sender, event, args)
+				{
+					var iframe = document.createElement('IFRAME'),
+						doc = null
+						;
+					
+					// make sure there is never more than one hidden iframe created by SH
+					if (sh.vars.printFrame != null)
+						document.body.removeChild(sh.vars.printFrame);
+					
+					sh.vars.printFrame = iframe;
+					
+					// this hides the iframe
+					iframe.style.cssText = 'position:absolute;width:0px;height:0px;left:-500px;top:-500px;';
+				
+					document.body.appendChild(iframe);
+					doc = iframe.contentWindow.document;
+					
+					copyStyles(doc, window.document);
+					doc.write('<div class="' + highlighter.div.className.replace('collapsed', '') + ' printing">' + highlighter.div.innerHTML + '</div>');
+					doc.close();
+					
+					iframe.contentWindow.focus();
+					iframe.contentWindow.print();
+					
+					function copyStyles(destDoc, sourceDoc)
+					{
+						var links = sourceDoc.getElementsByTagName('link');
+					
+						for(var i = 0; i < links.length; i++)
+							if(links[i].rel.toLowerCase() == 'stylesheet' && /shCore\.css$/.test(links[i].href))
+								destDoc.write('<link type="text/css" rel="stylesheet" href="' + links[i].href + '"></link>');
+					};
+				};
+			},
+
+			/** Command to display the about dialog window. */
+			about : function(highlighter)
+			{
+				this.create = function()
+				{	
+					return sh.config.strings.help;
+				};
+
+				this.execute = function(sender, event)
+				{	
+					var wnd = sh.utils.popup('', '_blank', 500, 250, 'scrollbars=0'),
+						doc = wnd.document
+						;
+					
+					doc.write(sh.config.strings.aboutDialog);
+					doc.close();
+					wnd.focus();
+				};
+			}
+		}
+	},
+
+	utils : {
+		/**
+		 * Finds an index of element in the array.
+		 * @ignore
+		 * @param {Object} searchElement
+		 * @param {Number} fromIndex
+		 * @return {Number} Returns index of element if found; -1 otherwise.
+		 */
+		indexOf : function(array, searchElement, fromIndex)
+		{
+			fromIndex = Math.max(fromIndex || 0, 0);
+
+			for (var i = fromIndex; i < array.length; i++)
+				if(array[i] == searchElement)
+					return i;
+
+			return -1;
+		},
+		
+		/**
+		 * Generates a unique element ID.
+		 */
+		guid : function(prefix)
+		{
+			return prefix + Math.round(Math.random() * 1000000).toString();
+		},
+		
+		/**
+		 * Merges two objects. Values from obj2 override values in obj1.
+		 * Function is NOT recursive and works only for one dimensional objects.
+		 * @param {Object} obj1 First object.
+		 * @param {Object} obj2 Second object.
+		 * @return {Object} Returns combination of both objects.
+		 */
+		merge: function(obj1, obj2)
+		{
+			var result = {}, name;
+
+			for (name in obj1) 
+				result[name] = obj1[name];
+			
+			for (name in obj2) 
+				result[name] = obj2[name];
+				
+			return result;
+		},
+		
+		/**
+		 * Attempts to convert string to boolean.
+		 * @param {String} value Input string.
+		 * @return {Boolean} Returns true if input was "true", false if input was "false" and value otherwise.
+		 */
+		toBoolean: function(value)
+		{
+			switch (value)
+			{
+				case "true":
+					return true;
+					
+				case "false":
+					return false;
+			}
+			
+			return value;
+		},
+		
+		/**
+		 * Opens up a centered popup window.
+		 * @param {String} url		URL to open in the window.
+		 * @param {String} name		Popup name.
+		 * @param {int} width		Popup width.
+		 * @param {int} height		Popup height.
+		 * @param {String} options	window.open() options.
+		 * @return {Window}			Returns window instance.
+		 */
+		popup: function(url, name, width, height, options)
+		{
+			var x = (screen.width - width) / 2,
+				y = (screen.height - height) / 2
+				;
+				
+			options +=	', left=' + x + 
+						', top=' + y +
+						', width=' + width +
+						', height=' + height
+				;
+			options = options.replace(/^,/, '');
+
+			var win = window.open(url, name, options);
+			win.focus();
+			return win;
+		},
+		
+		/**
+		 * Adds event handler to the target object.
+		 * @param {Object} obj		Target object.
+		 * @param {String} type		Name of the event.
+		 * @param {Function} func	Handling function.
+		 */
+		addEvent: function(obj, type, func)
+		{
+			if (obj.attachEvent) 
+			{
+				obj['e' + type + func] = func;
+				obj[type + func] = function()
+				{
+					obj['e' + type + func](window.event);
+				}
+				obj.attachEvent('on' + type, obj[type + func]);
+			}
+			else 
+			{
+				obj.addEventListener(type, func, false);
+			}
+		},
+		
+		/**
+		 * Displays an alert.
+		 * @param {String} str String to display.
+		 */
+		alert: function(str)
+		{
+			alert(sh.config.strings.alert + str)
+		},
+		
+		/**
+		 * Finds a brush by its alias.
+		 *
+		 * @param {String} alias	Brush alias.
+		 * @param {Boolean} alert	Suppresses the alert if false.
+		 * @return {Brush}			Returns bursh constructor if found, null otherwise.
+		 */
+		findBrush: function(alias, alert)
+		{
+			var brushes = sh.vars.discoveredBrushes,
+				result = null
+				;
+			
+			if (brushes == null) 
+			{
+				brushes = {};
+				
+				// Find all brushes
+				for (var brush in sh.brushes) 
+				{
+					var aliases = sh.brushes[brush].aliases;
+					
+					if (aliases == null) 
+						continue;
+					
+					// keep the brush name
+					sh.brushes[brush].name = brush.toLowerCase();
+					
+					for (var i = 0; i < aliases.length; i++) 
+						brushes[aliases[i]] = brush;
+				}
+				
+				sh.vars.discoveredBrushes = brushes;
+			}
+			
+			result = sh.brushes[brushes[alias]];
+
+			if (result == null && alert != false)
+				sh.utils.alert(sh.config.strings.noBrush + alias);
+			
+			return result;
+		},
+		
+		/**
+		 * Executes a callback on each line and replaces each line with result from the callback.
+		 * @param {Object} str			Input string.
+		 * @param {Object} callback		Callback function taking one string argument and returning a string.
+		 */
+		eachLine: function(str, callback)
+		{
+			var lines = str.split('\n');
+			
+			for (var i = 0; i < lines.length; i++)
+				lines[i] = callback(lines[i]);
+				
+			return lines.join('\n');
+		},
+		
+		/**
+		 * This is a special trim which only removes first and last empty lines
+		 * and doesn't affect valid leading space on the first line.
+		 * 
+		 * @param {String} str   Input string
+		 * @return {String}      Returns string without empty first and last lines.
+		 */
+		trimFirstAndLastLines: function(str)
+		{
+			return str.replace(/^[ ]*[\n]+|[\n]*[ ]*$/g, '');
+		},
+		
+		/**
+		 * Parses key/value pairs into hash object.
+		 * 
+		 * Understands the following formats:
+		 * - name: word;
+		 * - name: [word, word];
+		 * - name: "string";
+		 * - name: 'string';
+		 * 
+		 * For example:
+		 *   name1: value; name2: [value, value]; name3: 'value'
+		 *   
+		 * @param {String} str    Input string.
+		 * @return {Object}       Returns deserialized object.
+		 */
+		parseParams: function(str)
+		{
+			var match, 
+				result = {},
+				arrayRegex = new XRegExp("^\\[(?<values>(.*?))\\]$"),
+				regex = new XRegExp(
+					"(?<name>[\\w-]+)" +
+					"\\s*:\\s*" +
+					"(?<value>" +
+						"[\\w-%#]+|" +		// word
+						"\\[.*?\\]|" +		// [] array
+						'".*?"|' +			// "" string
+						"'.*?'" +			// '' string
+					")\\s*;?",
+					"g"
+				)
+				;
+
+			while ((match = regex.exec(str)) != null) 
+			{
+				var value = match.value
+					.replace(/^['"]|['"]$/g, '') // strip quotes from end of strings
+					;
+				
+				// try to parse array value
+				if (value != null && arrayRegex.test(value))
+				{
+					var m = arrayRegex.exec(value);
+					value = m.values.length > 0 ? m.values.split(/\s*,\s*/) : [];
+				}
+				
+				result[match.name] = value;
+			}
+			
+			return result;
+		},
+	
+		/**
+		 * Wraps each line of the string into <code/> tag with given style applied to it.
+		 * 
+		 * @param {String} str   Input string.
+		 * @param {String} css   Style name to apply to the string.
+		 * @return {String}      Returns input string with each line surrounded by <span/> tag.
+		 */
+		decorate: function(str, css)
+		{
+			if (str == null || str.length == 0 || str == '\n') 
+				return str;
+	
+			str = str.replace(/</g, '&lt;');
+	
+			// Replace two or more sequential spaces with &nbsp; leaving last space untouched.
+			str = str.replace(/ {2,}/g, function(m)
+			{
+				var spaces = '';
+				
+				for (var i = 0; i < m.length - 1; i++)
+					spaces += '&nbsp;';
+				
+				return spaces + ' ';
+			});
+
+			// Split each line and apply <span class="...">...</span> to them so that
+			// leading spaces aren't included.
+			if (css != null) 
+				str = sh.utils.eachLine(str, function(line)
+				{
+					if (line.length == 0) 
+						return '';
+					
+					var spaces = '';
+					
+					line = line.replace(/^(&nbsp;| )+/, function(s)
+					{
+						spaces = s;
+						return '';
+					});
+					
+					if (line.length == 0) 
+						return spaces;
+					
+					return spaces + '<code class="' + css + '">' + line + '</code>';
+				});
+
+			return str;
+		},
+	
+		/**
+		 * Pads number with zeros until it's length is the same as given length.
+		 * 
+		 * @param {Number} number	Number to pad.
+		 * @param {Number} length	Max string length with.
+		 * @return {String}			Returns a string padded with proper amount of '0'.
+		 */
+		padNumber : function(number, length)
+		{
+			var result = number.toString();
+			
+			while (result.length < length)
+				result = '0' + result;
+			
+			return result;
+		},
+		
+		/**
+		 * Measures width of a single space character.
+		 * @return {Number} Returns width of a single space character.
+		 */
+		measureSpace : function()
+		{
+			var container = document.createElement('div'),
+				span,
+				result = 0,
+				body = document.body,
+				id = sh.utils.guid('measureSpace'),
+				
+				// variable names will be compressed, so it's better than a plain string
+				divOpen = '<div class="',
+				closeDiv = '</div>',
+				closeSpan = '</span>'
+				;
+
+			// we have to duplicate highlighter nested structure in order to get an acurate space measurment
+			container.innerHTML = 
+				divOpen + 'syntaxhighlighter">' 
+					+ divOpen + 'lines">' 
+						+ divOpen + 'line">' 
+							+ divOpen + 'content'
+								+ '"><span class="block"><span id="' + id + '">&nbsp;' + closeSpan + closeSpan
+							+ closeDiv 
+						+ closeDiv 
+					+ closeDiv 
+				+ closeDiv
+				;
+			
+			body.appendChild(container);
+			span = document.getElementById(id);
+			
+			if (/opera/i.test(navigator.userAgent))
+			{
+				var style = window.getComputedStyle(span, null);
+				result = parseInt(style.getPropertyValue("width"));
+			}
+			else
+			{
+				result = span.offsetWidth;
+			}
+
+			body.removeChild(container);
+
+			return result;
+		},
+		
+		/**
+		 * Replaces tabs with spaces.
+		 * 
+		 * @param {String} code		Source code.
+		 * @param {Number} tabSize	Size of the tab.
+		 * @return {String}			Returns code with all tabs replaces by spaces.
+		 */
+		processTabs : function(code, tabSize)
+		{
+			var tab = '';
+			
+			for (var i = 0; i < tabSize; i++)
+				tab += ' ';
+
+			return code.replace(/\t/g, tab);
+		},
+		
+		/**
+		 * Replaces tabs with smart spaces.
+		 * 
+		 * @param {String} code    Code to fix the tabs in.
+		 * @param {Number} tabSize Number of spaces in a column.
+		 * @return {String}        Returns code with all tabs replaces with roper amount of spaces.
+		 */
+		processSmartTabs : function(code, tabSize)
+		{
+			var lines = code.split('\n'),
+				tab = '\t',
+				spaces = ''
+				;
+			
+			// Create a string with 1000 spaces to copy spaces from... 
+			// It's assumed that there would be no indentation longer than that.
+			for (var i = 0; i < 50; i++) 
+				spaces += '                    '; // 20 spaces * 50
+					
+			// This function inserts specified amount of spaces in the string
+			// where a tab is while removing that given tab.
+			function insertSpaces(line, pos, count)
+			{
+				return line.substr(0, pos)
+					+ spaces.substr(0, count)
+					+ line.substr(pos + 1, line.length) // pos + 1 will get rid of the tab
+					;
+			};
+	
+			// Go through all the lines and do the 'smart tabs' magic.
+			code = sh.utils.eachLine(code, function(line)
+			{
+				if (line.indexOf(tab) == -1) 
+					return line;
+				
+				var pos = 0;
+				
+				while ((pos = line.indexOf(tab)) != -1) 
+				{
+					// This is pretty much all there is to the 'smart tabs' logic.
+					// Based on the position within the line and size of a tab,
+					// calculate the amount of spaces we need to insert.
+					var spaces = tabSize - pos % tabSize;
+					line = insertSpaces(line, pos, spaces);
+				}
+				
+				return line;
+			});
+			
+			return code;
+		},
+		
+		/**
+		 * Performs various string fixes based on configuration.
+		 */
+		fixInputString : function(str)
+		{
+			var br = /<br\s*\/?>|&lt;br\s*\/?&gt;/gi;
+			
+			if (sh.config.bloggerMode == true)
+				str = str.replace(br, '\n');
+
+			if (sh.config.stripBrs == true)
+				str = str.replace(br, '');
+				
+			return str;
+		},
+		
+		/**
+		 * Removes all white space at the begining and end of a string.
+		 * 
+		 * @param {String} str   String to trim.
+		 * @return {String}      Returns string without leading and following white space characters.
+		 */
+		trim: function(str)
+		{
+			return str.replace(/^\s+|\s+$/g, '');
+		},
+		
+		/**
+		 * Unindents a block of text by the lowest common indent amount.
+		 * @param {String} str   Text to unindent.
+		 * @return {String}      Returns unindented text block.
+		 */
+		unindent: function(str)
+		{
+			var lines = sh.utils.fixInputString(str).split('\n'),
+				indents = new Array(),
+				regex = /^\s*/,
+				min = 1000
+				;
+			
+			// go through every line and check for common number of indents
+			for (var i = 0; i < lines.length && min > 0; i++) 
+			{
+				var line = lines[i];
+				
+				if (sh.utils.trim(line).length == 0) 
+					continue;
+				
+				var matches = regex.exec(line);
+				
+				// In the event that just one line doesn't have leading white space
+				// we can't unindent anything, so bail completely.
+				if (matches == null) 
+					return str;
+					
+				min = Math.min(matches[0].length, min);
+			}
+			
+			// trim minimum common number of white space from the begining of every line
+			if (min > 0) 
+				for (var i = 0; i < lines.length; i++) 
+					lines[i] = lines[i].substr(min);
+			
+			return lines.join('\n');
+		},
+	
+		/**
+		 * Callback method for Array.sort() which sorts matches by
+		 * index position and then by length.
+		 * 
+		 * @param {Match} m1	Left object.
+		 * @param {Match} m2    Right object.
+		 * @return {Number}     Returns -1, 0 or -1 as a comparison result.
+		 */
+		matchesSortCallback: function(m1, m2)
+		{
+			// sort matches by index first
+			if(m1.index < m2.index)
+				return -1;
+			else if(m1.index > m2.index)
+				return 1;
+			else
+			{
+				// if index is the same, sort by length
+				if(m1.length < m2.length)
+					return -1;
+				else if(m1.length > m2.length)
+					return 1;
+			}
+			
+			return 0;
+		},
+	
+		/**
+		 * Executes given regular expression on provided code and returns all
+		 * matches that are found.
+		 * 
+		 * @param {String} code    Code to execute regular expression on.
+		 * @param {Object} regex   Regular expression item info from <code>regexList</code> collection.
+		 * @return {Array}         Returns a list of Match objects.
+		 */ 
+		getMatches: function(code, regexInfo)
+		{
+			function defaultAdd(match, regexInfo)
+			{
+				return [new sh.Match(match[0], match.index, regexInfo.css)];
+			};
+			
+			var index = 0,
+				match = null,
+				result = [],
+				func = regexInfo.func ? regexInfo.func : defaultAdd
+				;
+			
+			while((match = regexInfo.regex.exec(code)) != null)
+				result = result.concat(func(match, regexInfo));
+				
+			return result;
+		},
+		
+		processUrls: function(code)
+		{
+			var lt = '&lt;',
+				gt = '&gt;'
+				;
+			
+			return code.replace(sh.regexLib.url, function(m)
+			{
+				var suffix = '', prefix = '';
+				
+				// We include &lt; and &gt; in the URL for the common cases like <http://google.com>
+				// The problem is that they get transformed into &lt;http://google.com&gt;
+				// Where as &gt; easily looks like part of the URL string.
+				
+				if (m.indexOf(lt) == 0)
+				{
+					prefix = lt;
+					m = m.substring(lt.length);
+				}
+
+				if (m.indexOf(gt) == m.length - gt.length)
+				{
+					m = m.substring(0, m.length - gt.length);
+					suffix = gt;
+				}
+				
+				return prefix + '<a href="' + m + '">' + m + '</a>' + suffix;
+			});
+		},
+		
+		/**
+		 * Finds all <SCRIPT TYPE="syntaxhighlighter" /> elements.
+		 * @return {Array} Returns array of all found SyntaxHighlighter tags.
+		 */
+		getSyntaxHighlighterScriptTags: function()
+		{
+			var tags = document.getElementsByTagName('script'),
+				result = []
+				;
+			
+			for (var i = 0; i < tags.length; i++)
+				if (tags[i].type == 'syntaxhighlighter')
+					result.push(tags[i]);
+					
+			return result;
+		},
+		
+		/**
+		 * Strips <![CDATA[]]> from <SCRIPT /> content because it should be used
+		 * there in most cases for XHTML compliance.
+		 * @param {String} original	Input code.
+		 * @return {String} Returns code without leading <![CDATA[]]> tags.
+		 */
+		stripCData: function(original)
+		{
+			var left = '<![CDATA[',
+				right = ']]>',
+				// for some reason IE inserts some leading blanks here
+				copy = sh.utils.trim(original),
+				changed = false
+				;
+			
+			if (copy.indexOf(left) == 0)
+			{
+				copy = copy.substring(left.length);
+				changed = true;
+			}
+			
+			if (copy.indexOf(right) == copy.length - right.length)
+			{
+				copy = copy.substring(0, copy.length - right.length);
+				changed = true;
+			}
+			
+			return changed ? copy : original;
+		}
+	}, // end of utils
+	
+	/**
+	 * Shorthand to highlight all elements on the page that are marked as 
+	 * SyntaxHighlighter source code.
+	 * 
+	 * @param {Object} globalParams		Optional parameters which override element's 
+	 * 									parameters. Only used if element is specified.
+	 * 
+	 * @param {Object} element	Optional element to highlight. If none is
+	 * 							provided, all elements in the current document 
+	 * 							are highlighted.
+	 */ 
+	highlight : function(globalParams, element)
+	{
+		function toArray(source)
+		{
+			var result = [];
+			
+			for (var i = 0; i < source.length; i++) 
+				result.push(source[i]);
+				
+			return result;
+		};
+		
+		var elements = element ? [element] : toArray(document.getElementsByTagName(sh.config.tagName)), 
+			propertyName = 'innerHTML', 
+			highlighter = null,
+			conf = sh.config
+			;
+
+		// support for <SCRIPT TYPE="syntaxhighlighter" /> feature
+		if (conf.useScriptTags)
+			elements = elements.concat(sh.utils.getSyntaxHighlighterScriptTags());
+
+		if (elements.length === 0) 
+			return;
+	
+		for (var i = 0; i < elements.length; i++) 
+		{
+			var target = elements[i], 
+				params = sh.utils.parseParams(target.className),
+				brushName,
+				code,
+				result
+				;
+
+			// local params take precedence over globals
+			params = sh.utils.merge(globalParams, params);
+			brushName = params['brush'];
+
+			if (brushName == null)
+				continue;
+
+			// Instantiate a brush
+			if (params['html-script'] == 'true' || sh.defaults['html-script'] == true) 
+			{
+				highlighter = new sh.HtmlScript(brushName);
+				brushName = 'htmlscript';
+			}
+			else
+			{
+				var brush = sh.utils.findBrush(brushName);
+				
+				if (brush)
+				{
+					brushName = brush.name;
+					highlighter = new brush();
+				}
+				else
+				{
+					continue;
+				}
+			}
+			
+			code = target[propertyName];
+			
+			// remove CDATA from <SCRIPT/> tags if it's present
+			if (conf.useScriptTags)
+				code = sh.utils.stripCData(code);
+			
+			params['brush-name'] = brushName;
+			highlighter.highlight(code, params);
+			
+			result = highlighter.div;
+			
+			if (sh.config.debug) 
+			{
+				result = document.createElement('textarea');
+				result.value = highlighter.div.innerHTML;
+				result.style.width = '70em';
+				result.style.height = '30em';
+			}
+			
+			target.parentNode.replaceChild(result, target);
+		}
+	},
+
+	/**
+	 * Main entry point for the SyntaxHighlighter.
+	 * @param {Object} params Optional params to apply to all highlighted elements.
+	 */
+	all : function(params)
+	{
+		sh.utils.addEvent(
+			window,
+			'load',
+			function() { sh.highlight(params); }
+		);
+	}
+}; // end of sh
+
+/**
+ * Match object.
+ */
+sh.Match = function(value, index, css)
+{
+	this.value = value;
+	this.index = index;
+	this.length = value.length;
+	this.css = css;
+	this.brushName = null;
+};
+
+sh.Match.prototype.toString = function()
+{
+	return this.value;
+};
+
+/**
+ * Simulates HTML code with a scripting language embedded.
+ * 
+ * @param {String} scriptBrushName Brush name of the scripting language.
+ */
+sh.HtmlScript = function(scriptBrushName)
+{
+	var brushClass = sh.utils.findBrush(scriptBrushName),
+		scriptBrush,
+		xmlBrush = new sh.brushes.Xml(),
+		bracketsRegex = null
+		;
+
+	if (brushClass == null)
+		return;
+	
+	scriptBrush = new brushClass();
+	this.xmlBrush = xmlBrush;
+	
+	if (scriptBrush.htmlScript == null)
+	{
+		sh.utils.alert(sh.config.strings.brushNotHtmlScript + scriptBrushName);
+		return;
+	}
+	
+	xmlBrush.regexList.push(
+		{ regex: scriptBrush.htmlScript.code, func: process }
+	);
+	
+	function offsetMatches(matches, offset)
+	{
+		for (var j = 0; j < matches.length; j++) 
+			matches[j].index += offset;
+	}
+	
+	function process(match, info)
+	{
+		var code = match.code,
+			matches = [],
+			regexList = scriptBrush.regexList,
+			offset = match.index + match.left.length,
+			htmlScript = scriptBrush.htmlScript,
+			result
+			;
+
+		// add all matches from the code
+		for (var i = 0; i < regexList.length; i++)
+		{
+			result = sh.utils.getMatches(code, regexList[i]);
+			offsetMatches(result, offset);
+			matches = matches.concat(result);
+		}
+		
+		// add left script bracket
+		if (htmlScript.left != null && match.left != null)
+		{
+			result = sh.utils.getMatches(match.left, htmlScript.left);
+			offsetMatches(result, match.index);
+			matches = matches.concat(result);
+		}
+		
+		// add right script bracket
+		if (htmlScript.right != null && match.right != null)
+		{
+			result = sh.utils.getMatches(match.right, htmlScript.right);
+			offsetMatches(result, match.index + match[0].lastIndexOf(match.right));
+			matches = matches.concat(result);
+		}
+		
+		for (var j = 0; j < matches.length; j++)
+			matches[j].brushName = brushClass.name;
+
+		return matches;
+	}
+};
+
+sh.HtmlScript.prototype.highlight = function(code, params)
+{
+	this.xmlBrush.highlight(code, params);
+	this.div = this.xmlBrush.div;
+}
+
+/**
+ * Main Highlither class.
+ * @constructor
+ */
+sh.Highlighter = function()
+{
+};
+
+sh.Highlighter.prototype = {
+	/**
+	 * Returns value of the parameter passed to the highlighter.
+	 * @param {String} name				Name of the parameter.
+	 * @param {Object} defaultValue		Default value.
+	 * @return {Object}					Returns found value or default value otherwise.
+	 */
+	getParam : function(name, defaultValue)
+	{
+		var result = this.params[name];
+		return sh.utils.toBoolean(result == null ? defaultValue : result);
+	},
+	
+	/**
+	 * Shortcut to document.createElement().
+	 * @param {String} name		Name of the element to create (DIV, A, etc).
+	 * @return {HTMLElement}	Returns new HTML element.
+	 */
+	create: function(name)
+	{
+		return document.createElement(name);
+	},
+	
+	/**
+	 * Applies all regular expression to the code and stores all found
+	 * matches in the `this.matches` array.
+	 * @param {Array} regexList		List of regular expressions.
+	 * @param {String} code			Source code.
+	 * @return {Array}				Returns list of matches.
+	 */
+	findMatches: function(regexList, code)
+	{
+		var result = [];
+		
+		if (regexList != null)
+			for (var i = 0; i < regexList.length; i++) 
+				// BUG: length returns len+1 for array if methods added to prototype chain (oising at gmail.com)
+				if (typeof (regexList[i]) == "object")
+					result = result.concat(sh.utils.getMatches(code, regexList[i]));
+		
+		// sort the matches
+		return result.sort(sh.utils.matchesSortCallback);
+	},
+	
+	/**
+	 * Checks to see if any of the matches are inside of other matches. 
+	 * This process would get rid of highligted strings inside comments, 
+	 * keywords inside strings and so on.
+	 */
+	removeNestedMatches: function()
+	{
+		var matches = this.matches;
+		
+		// Optimized by Jose Prado (http://joseprado.com)
+		for (var i = 0; i < matches.length; i++) 
+		{ 
+			if (matches[i] === null)
+				continue;
+			
+			var itemI = matches[i],
+				itemIEndPos = itemI.index + itemI.length
+				;
+			
+			for (var j = i + 1; j < matches.length && matches[i] !== null; j++) 
+			{
+				var itemJ = matches[j];
+				
+				if (itemJ === null) 
+					continue;
+				else if (itemJ.index > itemIEndPos) 
+					break;
+				else if (itemJ.index == itemI.index && itemJ.length > itemI.length)
+					this.matches[i] = null;
+				else if (itemJ.index >= itemI.index && itemJ.index < itemIEndPos) 
+					this.matches[j] = null;
+			}
+		}
+	},
+	
+	/**
+	 * Splits block of text into individual DIV lines.
+	 * @param {String} code     Code to highlight.
+	 * @return {String}         Returns highlighted code in HTML form.
+	 */
+	createDisplayLines : function(code)
+	{
+		var lines = code.split(/\n/g),
+			firstLine = parseInt(this.getParam('first-line')),
+			padLength = this.getParam('pad-line-numbers'),
+			highlightedLines = this.getParam('highlight', []),
+			hasGutter = this.getParam('gutter')
+			;
+		
+		code = '';
+		
+		if (padLength == true)
+			padLength = (firstLine + lines.length - 1).toString().length;
+		else if (isNaN(padLength) == true)
+			padLength = 0;
+
+		for (var i = 0; i < lines.length; i++)
+		{
+			var line = lines[i],
+				indent = /^(&nbsp;|\s)+/.exec(line),
+				lineClass = 'alt' + (i % 2 == 0 ? 1 : 2),
+				lineNumber = sh.utils.padNumber(firstLine + i, padLength),
+				highlighted = sh.utils.indexOf(highlightedLines, (firstLine + i).toString()) != -1,
+				spaces = null
+				;
+
+			if (indent != null)
+			{
+				spaces = indent[0].toString();
+				line = line.substr(spaces.length);
+			}
+
+			line = sh.utils.trim(line);
+			
+			if (line.length == 0)
+				line = '&nbsp;';
+			
+			if (highlighted)
+				lineClass += ' highlighted';
+			
+			code += 
+				'<div class="line ' + lineClass + '">'
+					+ '<table>'
+						+ '<tr>'
+							+ (hasGutter ? '<td class="number"><code>' + lineNumber + '</code></td>' : '')
+							+ '<td class="content">'
+								+ (spaces != null ? '<code class="spaces">' + spaces.replace(' ', '&nbsp;') + '</code>' : '')
+								+ line
+							+ '</td>'
+						+ '</tr>'
+					+ '</table>'
+				+ '</div>'
+				;
+		}
+		
+		return code;
+	},
+	
+	/**
+	 * Finds all matches in the source code.
+	 * @param {String} code		Source code to process matches in.
+	 * @param {Array} matches	Discovered regex matches.
+	 * @return {String} Returns formatted HTML with processed mathes.
+	 */
+	processMatches: function(code, matches)
+	{
+		var pos = 0, 
+			result = '',
+			decorate = sh.utils.decorate, // make an alias to save some bytes
+			brushName = this.getParam('brush-name', '')
+			;
+		
+		function getBrushNameCss(match)
+		{
+			var result = match ? (match.brushName || brushName) : brushName;
+			return result ? result + ' ' : '';
+		};
+		
+		// Finally, go through the final list of matches and pull the all
+		// together adding everything in between that isn't a match.
+		for (var i = 0; i < matches.length; i++) 
+		{
+			var match = matches[i],
+				matchBrushName
+				;
+			
+			if (match === null || match.length === 0) 
+				continue;
+			
+			matchBrushName = getBrushNameCss(match);
+			
+			result += decorate(code.substr(pos, match.index - pos), matchBrushName + 'plain')
+					+ decorate(match.value, matchBrushName + match.css)
+					;
+
+			pos = match.index + match.length;
+		}
+
+		// don't forget to add whatever's remaining in the string
+		result += decorate(code.substr(pos), getBrushNameCss() + 'plain');
+
+		return result;
+	},
+	
+	/**
+	 * Highlights the code and returns complete HTML.
+	 * @param {String} code     Code to highlight.
+	 * @param {Object} params   Parameters object.
+	 */
+	highlight: function(code, params)
+	{
+		// using variables for shortcuts because JS compressor will shorten local variable names
+		var conf = sh.config,
+			vars = sh.vars,
+			div,
+			divClassName,
+			tabSize,
+			important = 'important'
+			;
+
+		this.params = {};
+		this.div = null;
+		this.lines = null;
+		this.code = null;
+		this.bar = null;
+		this.toolbarCommands = {};
+		this.id = sh.utils.guid('highlighter_');
+
+		// register this instance in the highlighters list
+		vars.highlighters[this.id] = this;
+
+		if (code === null) 
+			code = '';
+		
+		// local params take precedence over defaults
+		this.params = sh.utils.merge(sh.defaults, params || {});
+
+		// process light mode
+		if (this.getParam('light') == true)
+			this.params.toolbar = this.params.gutter = false;
+		
+		this.div = div = this.create('DIV');
+		this.lines = this.create('DIV');
+		this.lines.className = 'lines';
+
+		className = 'syntaxhighlighter';
+		div.id = this.id;
+		
+		// make collapsed
+		if (this.getParam('collapse'))
+			className += ' collapsed';
+		
+		// disable gutter
+		if (this.getParam('gutter') == false)
+			className += ' nogutter';
+		
+		// disable line wrapping
+		if (this.getParam('wrap-lines') == false)
+		 	this.lines.className += ' no-wrap';
+
+		// add custom user style name
+		className += ' ' + this.getParam('class-name');
+		
+		// add brush alias to the class name for custom CSS
+		className += ' ' + this.getParam('brush-name');
+		
+		div.className = className;
+		
+		this.originalCode = code;
+		this.code = sh.utils.trimFirstAndLastLines(code)
+			.replace(/\r/g, ' ') // IE lets these buggers through
+			;
+		
+		tabSize = this.getParam('tab-size');
+		
+		// replace tabs with spaces
+		this.code = this.getParam('smart-tabs') == true
+			? sh.utils.processSmartTabs(this.code, tabSize)
+			: sh.utils.processTabs(this.code, tabSize)
+			;
+
+		this.code = sh.utils.unindent(this.code);
+
+		// add controls toolbar
+		if (this.getParam('toolbar')) 
+		{
+			this.bar = this.create('DIV');
+			this.bar.className = 'bar';
+			this.bar.appendChild(sh.toolbar.create(this));
+			div.appendChild(this.bar);
+			
+			// set up toolbar rollover
+			var bar = this.bar;
+			function hide() { bar.className = bar.className.replace('show', ''); }
+			div.onmouseover = function() { hide(); bar.className += ' show'; };
+			div.onmouseout = function() { hide(); }
+		}
+		
+		div.appendChild(this.lines);
+	
+		this.matches = this.findMatches(this.regexList, this.code);
+		this.removeNestedMatches();
+		
+		code = this.processMatches(this.code, this.matches);
+		
+		// finally, split all lines so that they wrap well
+		code = this.createDisplayLines(sh.utils.trim(code));
+		
+		// finally, process the links
+		if (this.getParam('auto-links'))
+			code = sh.utils.processUrls(code);
+
+		this.lines.innerHTML = code;
+	},
+	
+	/**
+	 * Converts space separated list of keywords into a regular expression string.
+	 * @param {String} str    Space separated keywords.
+	 * @return {String}       Returns regular expression string.
+	 */	
+	getKeywords: function(str)
+	{
+		str = str
+			.replace(/^\s+|\s+$/g, '')
+			.replace(/\s+/g, '|')
+			;
+		
+		return '\\b(?:' + str + ')\\b';
+	},
+	
+	/**
+	 * Makes a brush compatible with the `html-script` functionality.
+	 * @param {Object} regexGroup Object containing `left` and `right` regular expressions.
+	 */
+	forHtmlScript: function(regexGroup)
+	{
+		this.htmlScript = {
+			left : { regex: regexGroup.left, css: 'script' },
+			right : { regex: regexGroup.right, css: 'script' },
+			code : new XRegExp(
+				"(?<left>" + regexGroup.left.source + ")" +
+				"(?<code>.*?)" +
+				"(?<right>" + regexGroup.right.source + ")",
+				"sgi"
+				)
+		};
+	}
+}; // end of Highlighter
+
+return sh;
+}(); // end of anonymous function
+
+
+/**
+ * XRegExp 0.6.1
+ * (c) 2007-2008 Steven Levithan
+ * <http://stevenlevithan.com/regex/xregexp/>
+ * MIT License
+ * 
+ * provides an augmented, cross-browser implementation of regular expressions
+ * including support for additional modifiers and syntax. several convenience
+ * methods and a recursive-construct parser are also included.
+ */
+
+// prevent running twice, which would break references to native globals
+if (!window.XRegExp) {
+// anonymous function to avoid global variables
+(function () {
+// copy various native globals for reference. can't use the name ``native``
+// because it's a reserved JavaScript keyword.
+var real = {
+        exec:    RegExp.prototype.exec,
+        match:   String.prototype.match,
+        replace: String.prototype.replace,
+        split:   String.prototype.split
+    },
+    /* regex syntax parsing with support for all the necessary cross-
+       browser and context issues (escapings, character classes, etc.) */
+    lib = {
+        part:       /(?:[^\\([#\s.]+|\\(?!k<[\w$]+>|[pP]{[^}]+})[\S\s]?|\((?=\?(?!#|<[\w$]+>)))+|(\()(?:\?(?:(#)[^)]*\)|<([$\w]+)>))?|\\(?:k<([\w$]+)>|[pP]{([^}]+)})|(\[\^?)|([\S\s])/g,
+        replaceVar: /(?:[^$]+|\$(?![1-9$&`']|{[$\w]+}))+|\$(?:([1-9]\d*|[$&`'])|{([$\w]+)})/g,
+        extended:   /^(?:\s+|#.*)+/,
+        quantifier: /^(?:[?*+]|{\d+(?:,\d*)?})/,
+        classLeft:  /&&\[\^?/g,
+        classRight: /]/g
+    },
+    indexOf = function (array, item, from) {
+        for (var i = from || 0; i < array.length; i++)
+            if (array[i] === item) return i;
+        return -1;
+    },
+    brokenExecUndef = /()??/.exec("")[1] !== undefined,
+    plugins = {};
+
+/**
+ * Accepts a pattern and flags, returns a new, extended RegExp object.
+ * differs from a native regex in that additional flags and syntax are
+ * supported and browser inconsistencies are ameliorated.
+ * @ignore
+ */
+XRegExp = function (pattern, flags) {
+    if (pattern instanceof RegExp) {
+        if (flags !== undefined)
+            throw TypeError("can't supply flags when constructing one RegExp from another");
+        return pattern.addFlags(); // new copy
+    }
+
+    var flags           = flags || "",
+        singleline      = flags.indexOf("s") > -1,
+        extended        = flags.indexOf("x") > -1,
+        hasNamedCapture = false,
+        captureNames    = [],
+        output          = [],
+        part            = lib.part,
+        match, cc, len, index, regex;
+
+    part.lastIndex = 0; // in case the last XRegExp compilation threw an error (unbalanced character class)
+
+    while (match = real.exec.call(part, pattern)) {
+        // comment pattern. this check must come before the capturing group check,
+        // because both match[1] and match[2] will be non-empty.
+        if (match[2]) {
+            // keep tokens separated unless the following token is a quantifier
+            if (!lib.quantifier.test(pattern.slice(part.lastIndex)))
+                output.push("(?:)");
+        // capturing group
+        } else if (match[1]) {
+            captureNames.push(match[3] || null);
+            if (match[3])
+                hasNamedCapture = true;
+            output.push("(");
+        // named backreference
+        } else if (match[4]) {
+            index = indexOf(captureNames, match[4]);
+            // keep backreferences separate from subsequent literal numbers
+            // preserve backreferences to named groups that are undefined at this point as literal strings
+            output.push(index > -1 ?
+                "\\" + (index + 1) + (isNaN(pattern.charAt(part.lastIndex)) ? "" : "(?:)") :
+                match[0]
+            );
+        // unicode element (requires plugin)
+        } else if (match[5]) {
+            output.push(plugins.unicode ?
+                plugins.unicode.get(match[5], match[0].charAt(1) === "P") :
+                match[0]
+            );
+        // character class opening delimiter ("[" or "[^")
+        // (non-native unicode elements are not supported within character classes)
+        } else if (match[6]) {
+            if (pattern.charAt(part.lastIndex) === "]") {
+                // for cross-browser compatibility with ECMA-262 v3 behavior,
+                // convert [] to (?!) and [^] to [\S\s].
+                output.push(match[6] === "[" ? "(?!)" : "[\\S\\s]");
+                part.lastIndex++;
+            } else {
+                // parse the character class with support for inner escapes and
+                // ES4's infinitely nesting intersection syntax ([&&[^&&[]]]).
+                cc = XRegExp.matchRecursive("&&" + pattern.slice(match.index), lib.classLeft, lib.classRight, "", {escapeChar: "\\"})[0];
+                output.push(match[6] + cc + "]");
+                part.lastIndex += cc.length + 1;
+            }
+        // dot ("."), pound sign ("#"), or whitespace character
+        } else if (match[7]) {
+            if (singleline && match[7] === ".") {
+                output.push("[\\S\\s]");
+            } else if (extended && lib.extended.test(match[7])) {
+                len = real.exec.call(lib.extended, pattern.slice(part.lastIndex - 1))[0].length;
+                // keep tokens separated unless the following token is a quantifier
+                if (!lib.quantifier.test(pattern.slice(part.lastIndex - 1 + len)))
+                    output.push("(?:)");
+                part.lastIndex += len - 1;
+            } else {
+                output.push(match[7]);
+            }
+        } else {
+            output.push(match[0]);
+        }
+    }
+
+    regex = RegExp(output.join(""), real.replace.call(flags, /[sx]+/g, ""));
+    regex._x = {
+        source:       pattern,
+        captureNames: hasNamedCapture ? captureNames : null
+    };
+    return regex;
+};
+
+/**
+ * Barebones plugin support for now (intentionally undocumented)
+ * @ignore
+ * @param {Object} name
+ * @param {Object} o
+ */
+XRegExp.addPlugin = function (name, o) {
+    plugins[name] = o;
+};
+
+/**
+ * Adds named capture support, with values returned as ``result.name``.
+ * 
+ * Also fixes two cross-browser issues, following the ECMA-262 v3 spec:
+ *  - captured values for non-participating capturing groups should be returned
+ *    as ``undefined``, rather than the empty string.
+ *  - the regex's ``lastIndex`` should not be incremented after zero-length
+ *    matches.
+ * @ignore
+ */
+RegExp.prototype.exec = function (str) {
+    var match = real.exec.call(this, str),
+        name, i, r2;
+    if (match) {
+        // fix browsers whose exec methods don't consistently return
+        // undefined for non-participating capturing groups
+        if (brokenExecUndef && match.length > 1) {
+            // r2 doesn't need /g or /y, but they shouldn't hurt
+            r2 = new RegExp("^" + this.source + "$(?!\\s)", this.getNativeFlags());
+            real.replace.call(match[0], r2, function () {
+                for (i = 1; i < arguments.length - 2; i++) {
+                    if (arguments[i] === undefined) match[i] = undefined;
+                }
+            });
+        }
+        // attach named capture properties
+        if (this._x && this._x.captureNames) {
+            for (i = 1; i < match.length; i++) {
+                name = this._x.captureNames[i - 1];
+                if (name) match[name] = match[i];
+            }
+        }
+        // fix browsers that increment lastIndex after zero-length matches
+        if (this.global && this.lastIndex > (match.index + match[0].length))
+            this.lastIndex--;
+    }
+    return match;
+};
+})(); // end anonymous function
+} // end if(!window.XRegExp)
+
+/**
+ * intentionally undocumented
+ * @ignore
+ */
+RegExp.prototype.getNativeFlags = function () {
+    return (this.global     ? "g" : "") +
+           (this.ignoreCase ? "i" : "") +
+           (this.multiline  ? "m" : "") +
+           (this.extended   ? "x" : "") +
+           (this.sticky     ? "y" : "");
+};
+
+/**
+ * Accepts flags; returns a new XRegExp object generated by recompiling
+ * the regex with the additional flags (may include non-native flags).
+ * The original regex object is not altered.
+ * @ignore
+ */
+RegExp.prototype.addFlags = function (flags) {
+    var regex = new XRegExp(this.source, (flags || "") + this.getNativeFlags());
+    if (this._x) {
+        regex._x = {
+            source:       this._x.source,
+            captureNames: this._x.captureNames ? this._x.captureNames.slice(0) : null
+        };
+    }
+    return regex;
+};
+
+/**
+ * Accepts a context object and string; returns the result of calling
+ * ``exec`` with the provided string. the context is ignored but is
+ * accepted for congruity with ``Function.prototype.call``.
+ * @ignore
+ */
+RegExp.prototype.call = function (context, str) {
+    return this.exec(str);
+};
+
+/**
+ * Accepts a context object and arguments array; returns the result of
+ * calling ``exec`` with the first value in the arguments array. the context
+ * is ignored but is accepted for congruity with ``Function.prototype.apply``.
+ * @ignore
+ */
+RegExp.prototype.apply = function (context, args) {
+    return this.exec(args[0]);
+};
+
+/**
+ * Accepts a pattern and flags; returns an XRegExp object. if the pattern
+ * and flag combination has previously been cached, the cached copy is
+ * returned, otherwise the new object is cached.
+ * @ignore
+ */
+XRegExp.cache = function (pattern, flags) {
+    var key = "/" + pattern + "/" + (flags || "");
+    return XRegExp.cache[key] || (XRegExp.cache[key] = new XRegExp(pattern, flags));
+};
+
+/**
+ * Accepts a string; returns the string with regex metacharacters escaped.
+ * the returned string can safely be used within a regex to match a literal
+ * string. escaped characters are [, ], {, }, (, ), -, *, +, ?, ., \, ^, $,
+ * |, #, [comma], and whitespace.
+ * @ignore
+ */
+XRegExp.escape = function (str) {
+    return str.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, "\\$&");
+};
+
+/**
+ * Accepts a string to search, left and right delimiters as regex pattern
+ * strings, optional regex flags (may include non-native s, x, and y flags),
+ * and an options object which allows setting an escape character and changing
+ * the return format from an array of matches to a two-dimensional array of
+ * string parts with extended position data. returns an array of matches
+ * (optionally with extended data), allowing nested instances of left and right
+ * delimiters. use the g flag to return all matches, otherwise only the first
+ * is returned. if delimiters are unbalanced within the subject data, an error
+ * is thrown.
+ * 
+ * This function admittedly pushes the boundaries of what can be accomplished
+ * sensibly without a "real" parser. however, by doing so it provides flexible
+ * and powerful recursive parsing capabilities with minimal code weight.
+ * 
+ * Warning: the ``escapeChar`` option is considered experimental and might be
+ * changed or removed in future versions of XRegExp.
+ * 
+ * unsupported features:
+ *  - backreferences within delimiter patterns when using ``escapeChar``.
+ *  - although providing delimiters as regex objects adds the minor feature of
+ *    independent delimiter flags, it introduces other limitations and is only
+ *    intended to be done by the ``XRegExp`` constructor (which can't call
+ *    itself while building a regex).
+ * 
+ * @ignore
+ */
+XRegExp.matchRecursive = function (str, left, right, flags, options) {
+    var options      = options || {},
+        escapeChar   = options.escapeChar,
+        vN           = options.valueNames,
+        flags        = flags || "",
+        global       = flags.indexOf("g") > -1,
+        ignoreCase   = flags.indexOf("i") > -1,
+        multiline    = flags.indexOf("m") > -1,
+        sticky       = flags.indexOf("y") > -1,
+        /* sticky mode has its own handling in this function, which means you
+           can use flag "y" even in browsers which don't support it natively */
+        flags        = flags.replace(/y/g, ""),
+        left         = left  instanceof RegExp ? (left.global  ? left  : left.addFlags("g"))  : new XRegExp(left,  "g" + flags),
+        right        = right instanceof RegExp ? (right.global ? right : right.addFlags("g")) : new XRegExp(right, "g" + flags),
+        output       = [],
+        openTokens   = 0,
+        delimStart   = 0,
+        delimEnd     = 0,
+        lastOuterEnd = 0,
+        outerStart, innerStart, leftMatch, rightMatch, escaped, esc;
+
+    if (escapeChar) {
+        if (escapeChar.length > 1) throw SyntaxError("can't supply more than one escape character");
+        if (multiline)             throw TypeError("can't supply escape character when using the multiline flag");
+        escaped = XRegExp.escape(escapeChar);
+        /* Escape pattern modifiers:
+            /g - not needed here
+            /i - included
+            /m - **unsupported**, throws error
+            /s - handled by XRegExp when delimiters are provided as strings
+            /x - handled by XRegExp when delimiters are provided as strings
+            /y - not needed here; supported by other handling in this function
+        */
+        esc = new RegExp(
+            "^(?:" + escaped + "[\\S\\s]|(?:(?!" + left.source + "|" + right.source + ")[^" + escaped + "])+)+",
+            ignoreCase ? "i" : ""
+        );
+    }
+
+    while (true) {
+        /* advance the starting search position to the end of the last delimiter match.
+           a couple special cases are also covered:
+            - if using an escape character, advance to the next delimiter's starting position,
+              skipping any escaped characters
+            - first time through, reset lastIndex in case delimiters were provided as regexes
+        */
+        left.lastIndex = right.lastIndex = delimEnd +
+            (escapeChar ? (esc.exec(str.slice(delimEnd)) || [""])[0].length : 0);
+
+        leftMatch  = left.exec(str);
+        rightMatch = right.exec(str);
+
+        // only keep the result which matched earlier in the string
+        if (leftMatch && rightMatch) {
+            if (leftMatch.index <= rightMatch.index)
+                 rightMatch = null;
+            else leftMatch  = null;
+        }
+
+        /* paths*:
+        leftMatch | rightMatch | openTokens | result
+        1         | 0          | 1          | ...
+        1         | 0          | 0          | ...
+        0         | 1          | 1          | ...
+        0         | 1          | 0          | throw
+        0         | 0          | 1          | throw
+        0         | 0          | 0          | break
+        * - does not include the sticky mode special case
+          - the loop ends after the first completed match if not in global mode
+        */
+
+        if (leftMatch || rightMatch) {
+            delimStart = (leftMatch || rightMatch).index;
+            delimEnd   = (leftMatch ? left : right).lastIndex;
+        } else if (!openTokens) {
+            break;
+        }
+
+        if (sticky && !openTokens && delimStart > lastOuterEnd)
+            break;
+
+        if (leftMatch) {
+            if (!openTokens++) {
+                outerStart = delimStart;
+                innerStart = delimEnd;
+            }
+        } else if (rightMatch && openTokens) {
+            if (!--openTokens) {
+                if (vN) {
+                    if (vN[0] && outerStart > lastOuterEnd)
+                               output.push([vN[0], str.slice(lastOuterEnd, outerStart), lastOuterEnd, outerStart]);
+                    if (vN[1]) output.push([vN[1], str.slice(outerStart,   innerStart), outerStart,   innerStart]);
+                    if (vN[2]) output.push([vN[2], str.slice(innerStart,   delimStart), innerStart,   delimStart]);
+                    if (vN[3]) output.push([vN[3], str.slice(delimStart,   delimEnd),   delimStart,   delimEnd]);
+                } else {
+                    output.push(str.slice(innerStart, delimStart));
+                }
+                lastOuterEnd = delimEnd;
+                if (!global)
+                    break;
+            }
+        } else {
+            // reset lastIndex in case delimiters were provided as regexes
+            left.lastIndex = right.lastIndex = 0;
+            throw Error("subject data contains unbalanced delimiters");
+        }
+
+        // if the delimiter matched an empty string, advance delimEnd to avoid an infinite loop
+        if (delimStart === delimEnd)
+            delimEnd++;
+    }
+
+    if (global && !sticky && vN && vN[0] && str.length > lastOuterEnd)
+        output.push([vN[0], str.slice(lastOuterEnd), lastOuterEnd, str.length]);
+
+    // reset lastIndex in case delimiters were provided as regexes
+    left.lastIndex = right.lastIndex = 0;
+
+    return output;
+};
+/**
+ * SyntaxHighlighter
+ * http://alexgorbatchev.com/
+ *
+ * SyntaxHighlighter is donationware. If you are using it, please donate.
+ * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate
+ *
+ * @version
+ * 2.0.320 (May 03 2009)
+ * 
+ * @copyright
+ * Copyright (C) 2004-2009 Alex Gorbatchev.
+ *
+ * @license
+ * This file is part of SyntaxHighlighter.
+ * 
+ * SyntaxHighlighter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * SyntaxHighlighter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with SyntaxHighlighter.  If not, see <http://www.gnu.org/copyleft/lesser.html>.
+ */
+SyntaxHighlighter.brushes.Xml = function()
+{
+	function process(match, regexInfo)
+	{
+		var constructor = SyntaxHighlighter.Match,
+			code = match[0],
+			tag = new XRegExp('(&lt;|<)[\\s\\/\\?]*(?<name>[:\\w-\\.]+)', 'xg').exec(code),
+			result = []
+			;
+		
+		if (match.attributes != null) 
+		{
+			var attributes,
+				regex = new XRegExp('(?<name> [\\w:\\-\\.]+)' +
+									'\\s*=\\s*' +
+									'(?<value> ".*?"|\'.*?\'|\\w+)',
+									'xg');
+
+			while ((attributes = regex.exec(code)) != null) 
+			{
+				result.push(new constructor(attributes.name, match.index + attributes.index, 'color1'));
+				result.push(new constructor(attributes.value, match.index + attributes.index + attributes[0].indexOf(attributes.value), 'string'));
+			}
+		}
+
+		if (tag != null)
+			result.push(
+				new constructor(tag.name, match.index + tag[0].indexOf(tag.name), 'keyword')
+			);
+
+		return result;
+	}
+	
+	this.regexList = [
+		{ regex: new XRegExp('(\\&lt;|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\&gt;|>)', 'gm'),			css: 'color2' },	// <![ ... [ ... ]]>
+		{ regex: new XRegExp('(\\&lt;|<)!--\\s*.*?\\s*--(\\&gt;|>)', 'gm'),								css: 'comments' },	// <!-- ... -->
+		{ regex: new XRegExp('(&lt;|<)[\\s\\/\\?]*(\\w+)(?<attributes>.*?)[\\s\\/\\?]*(&gt;|>)', 'sg'), func: process }
+	];
+};
+
+SyntaxHighlighter.brushes.Xml.prototype	= new SyntaxHighlighter.Highlighter();
+SyntaxHighlighter.brushes.Xml.aliases	= ['xml', 'xhtml', 'xslt', 'html', 'xhtml'];
+/**
+ * SyntaxHighlighter
+ * http://alexgorbatchev.com/
+ *
+ * SyntaxHighlighter is donationware. If you are using it, please donate.
+ * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate
+ *
+ * @version
+ * 2.0.320 (May 03 2009)
+ * 
+ * @copyright
+ * Copyright (C) 2004-2009 Alex Gorbatchev.
+ *
+ * @license
+ * This file is part of SyntaxHighlighter.
+ * 
+ * SyntaxHighlighter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * SyntaxHighlighter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with SyntaxHighlighter.  If not, see <http://www.gnu.org/copyleft/lesser.html>.
+ */
+SyntaxHighlighter.brushes.JScript = function()
+{
+	var keywords =	'break case catch continue ' +
+					'default delete do else false  ' +
+					'for function if in instanceof ' +
+					'new null return super switch ' +
+					'this throw true try typeof var while with'
+					;
+
+	this.regexList = [
+		{ regex: SyntaxHighlighter.regexLib.singleLineCComments,	css: 'comments' },			// one line comments
+		{ regex: SyntaxHighlighter.regexLib.multiLineCComments,		css: 'comments' },			// multiline comments
+		{ regex: SyntaxHighlighter.regexLib.doubleQuotedString,		css: 'string' },			// double quoted strings
+		{ regex: SyntaxHighlighter.regexLib.singleQuotedString,		css: 'string' },			// single quoted strings
+		{ regex: /\s*#.*/gm,										css: 'preprocessor' },		// preprocessor tags like #region and #endregion
+		{ regex: new RegExp(this.getKeywords(keywords), 'gm'),		css: 'keyword' }			// keywords
+		];
+	
+	this.forHtmlScript(SyntaxHighlighter.regexLib.scriptScriptTags);
+};
+
+SyntaxHighlighter.brushes.JScript.prototype	= new SyntaxHighlighter.Highlighter();
+SyntaxHighlighter.brushes.JScript.aliases	= ['js', 'jscript', 'javascript'];
+
+
+SyntaxHighlighter.config.clipboardSwf = 'syntax/clipboard.swf';
+$(function () {
+	var divs = $([]);
+	$("#container .source").each(function () {
+		var code = $(this).html().replace(/</g,'&lt;').replace(/>/g,'&gt;'),
+			div  = $('<div class="code"><pre class="brush:' + ( $(this).is("script") ? 'js' : 'xml' ) + ';">' + code + '</pre></div>'),
+			demo = $(this).prevAll(".demo:eq(0)");
+		$(this).after(div);
+		divs = divs.add(div);
+	});
+	SyntaxHighlighter.all();
+
+	setTimeout((function (divs) { 
+		return function () {
+			divs.each(function () {
+				var div		= $(this),
+					demo	= $(this).prevAll(".demo:eq(0)"),
+					h		= false;
+				var h = Math.max(demo[0].offsetHeight, div[0].offsetHeight);
+				if(h) {
+					if(h < 198) h = 198;
+					div.height(h);
+					demo.height(h);
+				}
+			});
+		}
+	})(divs), 500);
+
+	// $(".panel").hide().prev().click(function () { $(this).next().toggle(); }).css("cursor","pointer");
+});
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/!style.css
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/!style.css	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/!style.css	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,511 @@
+/**
+ * SyntaxHighlighter
+ * http://alexgorbatchev.com/
+ *
+ * SyntaxHighlighter is donationware. If you are using it, please donate.
+ * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate
+ *
+ * @version
+ * 2.1.364 (October 15 2009)
+ * 
+ * @copyright
+ * Copyright (C) 2004-2009 Alex Gorbatchev.
+ *
+ * @license
+ * This file is part of SyntaxHighlighter.
+ * 
+ * SyntaxHighlighter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * SyntaxHighlighter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with SyntaxHighlighter.  If not, see <http://www.gnu.org/copyleft/lesser.html>.
+ */
+.syntaxhighlighter,
+.syntaxhighlighter div,
+.syntaxhighlighter code,
+.syntaxhighlighter table,
+.syntaxhighlighter table td,
+.syntaxhighlighter table tr,
+.syntaxhighlighter table tbody
+{
+	margin: 0 !important;
+	padding: 0 !important;
+	border: 0 !important;
+	outline: 0 !important;
+	background: none !important;
+	text-align: left !important;
+	float: none !important;
+	vertical-align: baseline !important;
+	position: static !important;
+	left: auto !important;
+	top: auto !important;
+	right: auto !important;
+	bottom: auto !important;
+	height: auto !important;
+	width: auto !important;
+	font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important;
+	font-weight: normal !important;
+	font-style: normal !important;
+	min-height: inherit !important; /* For IE8, FF & WebKit */
+	min-height: auto !important; /* For IE7 */
+
+
+/*
+	line-height: 1.1em !important;
+	font-size: 1em !important;
+*/
+
+	font-size:12px !important;
+	line-height:18px !important;
+
+}
+
+.syntaxhighlighter
+{
+	width: 99.9% !important; /* 99% fixes IE8 horizontal scrollbar */
+	margin: 1em 0 1em 0 !important;
+	padding: 1px !important; /* adds a little border on top and bottom */
+	position: relative !important;
+}
+
+.syntaxhighlighter .bold 
+{
+	font-weight: bold !important;
+}
+
+.syntaxhighlighter .italic 
+{
+	font-style: italic !important;
+}
+
+.syntaxhighlighter .line
+{
+}
+
+.syntaxhighlighter .no-wrap .line .content
+{
+	white-space: pre !important;
+}
+
+.syntaxhighlighter .line table 
+{
+	border-collapse: collapse !important;
+}
+
+.syntaxhighlighter .line td
+{
+	vertical-align: top !important;
+}
+
+.syntaxhighlighter .line .number
+{
+	width: 3em !important;
+}
+
+.syntaxhighlighter .line .number code
+{
+	width: 2.7em !important;
+	padding-right: .3em !important;
+	text-align: right !important;
+	display: block !important;
+}
+
+.syntaxhighlighter .line .content
+{
+	padding-left: .5em !important;
+}
+
+.syntaxhighlighter .line .spaces
+{
+}
+
+/* Disable border and margin on the lines when no gutter option is set */
+.syntaxhighlighter.nogutter .line .content
+{
+	border-left: none !important;
+}
+
+.syntaxhighlighter .bar
+{
+	display: none !important;
+}
+
+.syntaxhighlighter .bar.show 
+{
+	display: block !important;
+}
+
+.syntaxhighlighter.collapsed .bar
+{
+	display: block !important;
+}
+
+/* Adjust some properties when collapsed */
+
+.syntaxhighlighter.collapsed .lines
+{
+	display: none !important;
+}
+
+.syntaxhighlighter .lines.no-wrap
+{
+	overflow: auto !important;
+	overflow-y: hidden !important;
+}
+
+/* Styles for the toolbar */
+
+.syntaxhighlighter .toolbar
+{
+	position: absolute !important;
+	right: 0px !important;
+	top: 0px !important;
+	font-size: 1px !important;
+	padding: 8px 8px 8px 0 !important; /* in px because images don't scale with ems */
+}
+
+.syntaxhighlighter.collapsed .toolbar
+{
+	font-size: 80% !important;
+	padding: .2em 0 .5em .5em !important;
+	position: static !important;
+}
+
+.syntaxhighlighter .toolbar a.item,
+.syntaxhighlighter .toolbar .item
+{
+	display: block !important;
+	float: left !important;
+	margin-left: 8px !important;
+	background-repeat: no-repeat !important;
+	overflow: hidden !important;
+	text-indent: -5000px !important;
+}
+
+.syntaxhighlighter.collapsed .toolbar .item
+{
+	display: none !important;
+}
+
+.syntaxhighlighter.collapsed .toolbar .item.expandSource
+{
+	background-image: url(magnifier.png) !important;
+	display: inline !important;
+	text-indent: 0 !important;
+	width: auto !important;
+	float: none !important;
+	height: 16px !important;
+	padding-left: 20px !important;
+}
+
+.syntaxhighlighter .toolbar .item.viewSource
+{
+	background-image: url(page_white_code.png) !important;
+}
+
+.syntaxhighlighter .toolbar .item.printSource
+{
+	background-image: url(printer.png) !important;
+}
+
+.syntaxhighlighter .toolbar .item.copyToClipboard
+{
+	text-indent: 0 !important;
+	background: none !important;
+	overflow: visible !important;
+}
+
+.syntaxhighlighter .toolbar .item.about
+{
+	background-image: url(help.png) !important;
+}
+
+/** 
+ * Print view.
+ * Colors are based on the default theme without background.
+ */
+
+.syntaxhighlighter.printing,
+.syntaxhighlighter.printing .line.alt1 .content,
+.syntaxhighlighter.printing .line.alt2 .content,
+.syntaxhighlighter.printing .line.highlighted .number,
+.syntaxhighlighter.printing .line.highlighted.alt1 .content,
+.syntaxhighlighter.printing .line.highlighted.alt2 .content,
+{
+	background: none !important;
+}
+
+/* Gutter line numbers */
+.syntaxhighlighter.printing .line .number
+{
+	color: #bbb !important;
+}
+
+/* Add border to the lines */
+.syntaxhighlighter.printing .line .content
+{
+	color: #000 !important;
+}
+
+/* Toolbar when visible */
+.syntaxhighlighter.printing .toolbar
+{
+	display: none !important;
+}
+
+.syntaxhighlighter.printing a
+{
+	text-decoration: none !important;
+}
+
+.syntaxhighlighter.printing .plain,
+.syntaxhighlighter.printing .plain a
+{ 
+	color: #000 !important;
+}
+
+.syntaxhighlighter.printing .comments,
+.syntaxhighlighter.printing .comments a
+{ 
+	color: #008200 !important;
+}
+
+.syntaxhighlighter.printing .string,
+.syntaxhighlighter.printing .string a
+{
+	color: blue !important; 
+}
+
+.syntaxhighlighter.printing .keyword
+{ 
+	color: #069 !important; 
+	font-weight: bold !important; 
+}
+
+.syntaxhighlighter.printing .preprocessor 
+{ 
+	color: gray !important; 
+}
+
+.syntaxhighlighter.printing .variable 
+{ 
+	color: #a70 !important; 
+}
+
+.syntaxhighlighter.printing .value
+{ 
+	color: #090 !important; 
+}
+
+.syntaxhighlighter.printing .functions
+{ 
+	color: #ff1493 !important; 
+}
+
+.syntaxhighlighter.printing .constants
+{ 
+	color: #0066CC !important; 
+}
+
+.syntaxhighlighter.printing .script
+{
+	font-weight: bold !important;
+}
+
+.syntaxhighlighter.printing .color1,
+.syntaxhighlighter.printing .color1 a
+{ 
+	color: #808080 !important; 
+}
+
+.syntaxhighlighter.printing .color2,
+.syntaxhighlighter.printing .color2 a
+{ 
+	color: #ff1493 !important; 
+}
+
+.syntaxhighlighter.printing .color3,
+.syntaxhighlighter.printing .color3 a
+{ 
+	color: red !important; 
+}
+/**
+ * SyntaxHighlighter
+ * http://alexgorbatchev.com/
+ *
+ * SyntaxHighlighter is donationware. If you are using it, please donate.
+ * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate
+ *
+ * @version
+ * 2.1.364 (October 15 2009)
+ * 
+ * @copyright
+ * Copyright (C) 2004-2009 Alex Gorbatchev.
+ *
+ * @license
+ * This file is part of SyntaxHighlighter.
+ * 
+ * SyntaxHighlighter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * SyntaxHighlighter is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with SyntaxHighlighter.  If not, see <http://www.gnu.org/copyleft/lesser.html>.
+ */
+/************************************
+ * Default Syntax Highlighter theme.
+ * 
+ * Interface elements.
+ ************************************/
+
+.syntaxhighlighter
+{
+	background-color: #fff !important;
+}
+
+/* Highlighed line number */
+.syntaxhighlighter .line.highlighted .number
+{
+	color: black !important;
+}
+
+/* Highlighed line */
+.syntaxhighlighter .line.highlighted.alt1,
+.syntaxhighlighter .line.highlighted.alt2
+{
+	background-color: #e0e0e0 !important;
+}
+
+/* Gutter line numbers */
+.syntaxhighlighter .line .number
+{
+	color: #afafaf !important;
+}
+
+/* Add border to the lines */
+.syntaxhighlighter .line .content
+{
+	border-left: 1px solid gray !important;
+	color: #000 !important;
+}
+
+.syntaxhighlighter.printing .line .content 
+{
+	border: 0 !important;
+}
+
+/* First line */
+.syntaxhighlighter .line.alt1
+{
+	background-color: #fff !important;
+}
+
+/* Second line */
+.syntaxhighlighter .line.alt2
+{
+	background-color: #F8F8F8 !important;
+}
+
+.syntaxhighlighter .toolbar
+{
+	background-color: #F8F8F8 !important;
+	border: #E7E5DC solid 1px !important;
+}
+
+.syntaxhighlighter .toolbar a
+{
+	color: #a0a0a0 !important;
+}
+
+.syntaxhighlighter .toolbar a:hover
+{
+	color: red !important;
+}
+
+/************************************
+ * Actual syntax highlighter colors.
+ ************************************/
+.syntaxhighlighter .plain,
+.syntaxhighlighter .plain a
+{ 
+	color: #000 !important;
+}
+
+.syntaxhighlighter .comments,
+.syntaxhighlighter .comments a
+{ 
+	color: #008200 !important;
+}
+
+.syntaxhighlighter .string,
+.syntaxhighlighter .string a
+{
+	color: blue !important; 
+}
+
+.syntaxhighlighter .keyword
+{ 
+	color: #069 !important; 
+	font-weight: bold !important; 
+}
+
+.syntaxhighlighter .preprocessor 
+{ 
+	color: gray !important; 
+}
+
+.syntaxhighlighter .variable 
+{ 
+	color: #a70 !important; 
+}
+
+.syntaxhighlighter .value
+{ 
+	color: #090 !important; 
+}
+
+.syntaxhighlighter .functions
+{ 
+	color: #ff1493 !important; 
+}
+
+.syntaxhighlighter .constants
+{ 
+	color: #0066CC !important; 
+}
+
+.syntaxhighlighter .script
+{ 
+	background-color: yellow !important;
+}
+
+.syntaxhighlighter .color1,
+.syntaxhighlighter .color1 a
+{ 
+	color: #808080 !important; 
+}
+
+.syntaxhighlighter .color2,
+.syntaxhighlighter .color2 a
+{ 
+	color: #ff1493 !important; 
+}
+
+.syntaxhighlighter .color3,
+.syntaxhighlighter .color3 a
+{ 
+	color: red !important; 
+}

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/clipboard.swf
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/clipboard.swf
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/help.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/help.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/magnifier.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/magnifier.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/page_white_code.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/page_white_code.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/page_white_copy.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/page_white_copy.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/printer.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/printer.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/wrapping.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/syntax/wrapping.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/themes.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/themes.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/themes.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,118 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - themes documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - themes plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>themes</code> plugin controls the looks of jstree - without this plugin you will get a functional tree, but it will look just like an ordinary UL list.</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+<h3>theme</h3>
+<p class="meta">A string. Default is <code>"default"</code>.</p>
+<p>The name of the theme to use to style the tree.</p>
+
+<h3>url</h3>
+<p class="meta">A string (or <code>false</code> if not used). Default is <code>false</code>.</p>
+<p>The location of the theme's CSS file, if set to <code>false</code> jstree will look for the file in <code><em>&lt; theme folder &gt;</em>/themes/<em>&lt; theme name &gt;</em>/style.css</code>. You can set the theme folder using <code>$.jstree._themes = "PATH/TO/FOLDER/";</code>, otherwise it is autodetected as <code><em>&lt;jquery.tree.js location&gt;</em>/themes/</code>.</p>
+
+<h3>dots</h3>
+<p class="meta">A Boolean. Default is <code>true</code>.</p>
+<p>Whether to show the connecting dots or not.</p>
+
+<h3>icons</h3>
+<p class="meta">A Boolean. Default is <code>true</code>.</p>
+<p>Whether to show the node icons or not.</p>
+
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+
+<h3>Using the themes plugin</h3>
+<input type="button" class="button" value="toggle_dots" id="toggle_dots" style="float:left;" />
+<input type="button" class="button" value="toggle_icons" id="toggle_icons" style="" />
+<div id="demo1" class="demo">
+	<ul>
+		<li id="phtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="phtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="phtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="phtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#toggle_dots, #toggle_icons").click(function () { 
+		$("#demo1").jstree(this.value);
+	});
+	$("#demo1").jstree({ 
+		"themes" : {
+			"theme" : "default",
+			"dots" : false,
+			"icons" : false
+		},
+		"plugins" : [ "themes", "html_data" ]
+	});
+});
+</script>
+
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+
+<h3 id="set_theme">.set_theme ( name , url )</h3>
+<p>Set the tree's theme. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">string</code> <strong>name</strong>
+		<p>The name of the theme to use to style the tree.</p>
+	</li>
+	<li>
+		<code class="tp">string</code> <strong>url</strong>
+		<p>The location of the theme's CSS file, if omitted jstree will look for the file in:<br /><code><em>&lt; theme folder &gt;</em>/themes/<em>&lt; name &gt;</em>/style.css</code>.<br />You can set the theme folder using:<br /><code>$.jstree._themes = "PATH/TO/FOLDER/";</code>, otherwise it is autodetected as <code><em>&lt;jquery.tree.js location&gt;</em>/themes/</code>.</p>
+	</li>
+</ul>
+<h3 id="get_theme">.get_theme ( )</h3>
+<p>Returns the name of the currently active theme.</p>
+
+<div style="height:1px; visibility:hidden;"><span id="hide_dots">&nbsp;</span><span id="toggle_dots">&nbsp;</span></div>
+<h3 id="show_dots">.show_dots ( ), .hide_dots ( ), .toggle_dots ( )</h3>
+<p>Show, hide or toggle the visibility of the dots connecting the tree's nodes.</p>
+
+<div style="height:1px; visibility:hidden;"><span id="hide_icons">&nbsp;</span><span id="toggle_icons">&nbsp;</span></div>
+<h3 id="show_icons">.show_icons ( ), .hide_icons ( ), .toggle_icons ( )</h3>
+<p>Show, hide or toggle the visibility of the icons next to the title of each the tree node.</p>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/types.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/types.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/types.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,173 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - types documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - types plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>types</code> enables node types - each node can have a type, and you can define rules on how that type should behave - maximum children count, maximum depth, valid children types, selectable or not, etc.</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+
+<h3>max_children</h3>
+<p class="meta">A number. Default is <code>-1</code>.</p>
+<p>Defines maximum number of root nodes (<code>-1</code> means unlimited, <code>-2</code> means disable max_children checking in the tree).</p>
+
+<h3>max_depth</h3>
+<p class="meta">A number. Default is <code>-1</code>.</p>
+<p>Defines maximum depth of the tree (<code>-1</code> means unlimited, <code>-2</code> means disable max_depth checking in the tree).</p>
+
+<h3>valid_children</h3>
+<p class="meta">A string or array. Default is <code>"all"</code>.</p>
+<p>Defines valid root node types (could be <code>"all"</code>, <code>"none"</code>, or an array of type strings).</p>
+
+<h3>type_attr</h3>
+<p class="meta">A string. Default is <code>"rel"</code>.</p>
+<p>Defines the attribute on each <code>li</code> node, where the type attribute will be stored.</p>
+
+<h3>types</h3>
+<p class="meta">An object.</p>
+<p>Defines all the active types in the tree. Each key is the type name, and each value represents the rules for this type. A <code>default</code> type is defined - all nodes with no explicit type set are treated as if they were of the <code>default</code> type.</p>
+<div style="border:1px solid gray;">
+<pre class="brush:js">
+types : {
+	// the default type
+	"default" : {
+		"max_children"	: -1,
+		"max_depth"		: -1,
+		"valid_children": "all"
+
+		// Bound functions - you can bind any other function here (using boolean or function)
+		//"select_node"	: true,
+		//"open_node"	: true,
+		//"close_node"	: true,
+		//"create_node"	: true,
+		//"delete_node"	: true
+	}
+}
+</pre>
+</div>
+<p>For <code>max_children</code>, <code>max_depth</code> &amp; <code>valid_children</code> use the same values as for the tree, but the value you set will only apply for that node type.</p>
+<p>You can set an <code>icon</code> key - it should be an object consisting of two keys - <code>image</code> (string - location of the image to be used as an icon) &amp; <code>position</code> (string - left and top pixels of the image - 10px 40px, only useful when using sprites - omit otherwise).</p>
+<p>You can set more keys in that object - each key should be a function name, and each value - either a boolean (in order to allow or disallow that operation, on that node type) or a function. If you supply a function - your function will be called with two arguments - the name of the called function (the key) and the arguments passed to that function - you can then decide whether to return <code>true</code> or <code>false</code>.</p>
+<p class="note">For any type - for now you can control only functions that take the node being manipulated as the first argument.</p>
+
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+<h3>Using the types plugin</h3>
+
+<div id="demo1" class="demo">
+	<ul>
+		<li id="phtml_1" rel="root">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="phtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="phtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="phtml_4" rel="root">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo1").jstree({ 
+		"types" : {
+			"valid_children" : [ "root" ],
+			"types" : {
+				"root" : {
+					"icon" : { 
+						"image" : "./_drive.png" 
+					},
+					"valid_children" : [ "default" ],
+					"max_depth" : 2,
+					"hover_node" : false,
+					"select_node" : function () {return false;}
+				},
+				"default" : {
+					"valid_children" : [ "default" ]
+				}
+			}
+		},
+		"plugins" : ["themes","html_data","dnd","ui","types"]
+	});
+});
+</script>
+
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+
+<h3 id="_get_type">._get_type ( node )</h3>
+<p>Get the type of a node.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element.</p>
+	</li>
+</ul>
+
+<h3 id="set_type">.set_type ( type , node )</h3>
+<p>Set the type of a node.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">string</code> <strong>type</strong>
+		<p>The new type.</p>
+	</li>
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element.</p>
+	</li>
+</ul>
+
+<h3 id="_check">._check ( rule , node , opts )</h3>
+<p>Checks a rule on a give node. Used mostly internally.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">string</code> <strong>rule</strong>
+		<p>The rule to check.</p>
+	</li>
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to the element.</p>
+	</li>
+	<li>
+		<code class="tp">mixed</code> <strong>opts</strong>
+		<p>Any additional options regarding the rule. Used internally.</p>
+	</li>
+</ul>
+
+<div style="height:1px; visibility:hidden;"><span id="check_move">&nbsp;</span></div>
+<h3 id="create_node">.create_node ( ), .check_move ( )</h3>
+<p>Both functions are overwritten to accomodate the new functionality presented by the plugin.</p>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/ui.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/ui.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/ui.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,180 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - UI documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - UI plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The <code>UI</code> plugin handles selecting, deselecting and hovering tree items.</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+<h3>select_limit</h3>
+<p class="meta">A number. Default is <code>-1</code>.</p>
+<p>Defines how many nodes can be selected at a given time (<code>-1</code> means unlimited).</p>
+
+<h3>select_multiple_modifier</h3>
+<p class="meta">A string. Default is <code>"ctrl"</code>.</p>
+<p>The special key used to make a click add to the selection and not replace it (<code>"ctrl"</code>, <code>"shift"</code>, <code>"alt"</code>, <code>"meta"</code>).<br />You can also set this to <code>"on"</code> making every click add to the selection.</p>
+
+<h3>selected_parent_close</h3>
+<p class="meta">A string (or <code>false</code>). Default is <code>"select_parent"</code>.</p>
+<p>What action to take when a selected node's parent is closed (making the selected node invisible). Possible values are <code>false</code> - do nothing, <code>"select_parent"</code> - select the closed node's parent and <code>"deselect"</code> - deselect the node.</p>
+
+<h3>initially_select</h3>
+<p class="meta">An array. Default is <code>[]</code>.</p>
+<p>Defines which nodes are to be automatically selected when the tree finishes loading - a list of IDs is expected.</p>
+
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+
+<h3>Using the UI plugin</h3>
+<div id="demo1" class="demo">
+	<ul>
+		<li id="phtml_1">
+			<a href="#">Root node 1</a>
+			<ul>
+				<li id="phtml_2">
+					<a href="#">Child node 1</a>
+				</li>
+				<li id="phtml_3">
+					<a href="#">Child node 2</a>
+				</li>
+			</ul>
+		</li>
+		<li id="phtml_4">
+			<a href="#">Root node 2</a>
+		</li>
+	</ul>
+</div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo1").jstree({ 
+		"ui" : {
+			"select_limit" : 2,
+			"select_multiple_modifier" : "alt",
+			"selected_parent_close" : "select_parent",
+			"initially_select" : [ "phtml_2" ]
+		},
+		"core" : { "initially_open" : [ "phtml_1" ] },
+		"plugins" : [ "themes", "html_data", "ui" ]
+	});
+});
+</script>
+
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+
+<h3 id="_get_node">._get_node ( node , allow_multiple )</h3>
+<p>Overrides the function form the <a href="core.html#_get_node">core</a> module.<br />if <code>node</code> is <code>undefined</code> or <code>null</code> and <code>allow_multiple</code> is <code>true</code> all the currently selected nodes are returned<br />if <code>node</code> is <code>undefined</code> or <code>null</code> and <code>allow_multiple</code> is NOT <code>true</code> only the last selected node is returned.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+	<li>
+		<code class="tp">boolean</code> <strong>allow_multiple</strong>
+		<p>Whether to return all selected nodes or only the last selected one if <code>obj</code> is <code>null</code>.</p>
+	</li>
+</ul>
+
+<h3 id="save_selected">.save_selected ( )</h3>
+<p>Saves away the current selection state of the tree (saves it in a variable, so do not expect a restore after a refresh - for that functionality refer to the <a href="cookies.html">cookies plugin</a>. Used mostly internally. Triggers an event.</p>
+
+<h3 id="reselect">.reselect ( )</h3>
+<p>Restores the state of the tree using the variable saved in the above function. Used mostly internally. Triggers an event.</p>
+
+<h3 id="refresh">.refresh ( node )</h3>
+<p>Overrides the function form the <a href="core.html#refresh">core</a> module.<br />Enables saving the selection state before the refresh and restoring it afterwards.</p>
+
+<h3 id="hover_node">.hover_node ( node )</h3>
+<p>Sets the specified node as hovered. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+</ul>
+
+<h3 id="dehover_node">.dehover_node ( )</h3>
+<p>Removes the hover state from the currently hovered node (if there is one). Triggers an event.</p>
+
+
+<h3 id="select_node">.select_node ( node , check , event )</h3>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+	<li>
+		<code class="tp">bool</code> <strong>check</strong>
+		<p>Whether to check the specified rules and do appropriate actions (check <code>select_limit</code>, deselect other nodes respectively, etc) or to just force selection of the node regardless of <code>select_limit</code>.</p>
+	</li>
+	<li>
+		<code class="tp">event</code> <strong>event</strong>
+		<p>Used internally - when a click on a node caused this function to be executed.</p>
+	</li>
+</ul>
+
+<div style="height:1px; visibility:hidden; overflow:hidden;"><span id="toggle_select">&#160;</span></div>
+<h3 id="deselect_node">.deselect_node ( node ), .toggle_select ( node )</h3>
+<p>There functions control the selected state on a node. <code>deselect_node</code> triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+</ul>
+
+<h3 id="deselect_all">.deselect_all ( context )</h3>
+<p>Deselects all selected nodes. If context is set - only the selected nodes within that context are deselected. Triggers an event.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>context</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+</ul>
+
+<h3 id="get_selected">.get_selected ( context )</h3>
+<p>Returns all selected nodes. If context is set - only the selected nodes within that context are returned.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>context</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+</ul>
+
+<h3 id="is_selected">.is_selected ( node )</h3>
+<p>Returns whether the specified node is selected or not.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element within the tree.</p>
+	</li>
+</ul>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/xml_data.html
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/xml_data.html	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_docs/xml_data.html	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,210 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+	<title>jsTree v.1.0 - xml_data documentation</title>
+	<script type="text/javascript" src="../_lib/jquery.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.cookie.js"></script>
+	<script type="text/javascript" src="../_lib/jquery.hotkeys.js"></script>
+	<script type="text/javascript" src="../jquery.jstree.js"></script>
+
+	<link type="text/css" rel="stylesheet" href="syntax/!style.css"/>
+	<link type="text/css" rel="stylesheet" href="!style.css"/>
+	<script type="text/javascript" src="syntax/!script.js"></script>
+</head>
+<body>
+<div id="container">
+
+<h1>jsTree v.1.0 - xml_data plugin</h1>
+<h2>Description</h2>
+<div id="description">
+<p>The sxml_data</code> plugin enables jsTree to convert XML objects to interactive trees (using XSL). The data (XML) can be set up in the config (as a string) or retrieved from a server (also ondemand).</p>
+<p>Two types of XML structures are supported - flat and nested:</p>
+<div class="code_f">
+<pre class="brush:xml;">
+&lt;!-- FLAT --&gt;
+&lt;root&gt;
+	&lt;item id="root_1" parent_id="0" state="closed"&gt;
+		&lt;content&gt;
+			&lt;name&gt;&lt;![CDATA[Node 1]]&gt;&lt;/name&gt;
+		&lt;/content&gt;
+	&lt;/item&gt;
+	&lt;item id="node_2" parent_id="root_1"&gt;
+		&lt;content&gt;
+			&lt;name&gt;&lt;![CDATA[Node 2]]&gt;&lt;/name&gt;
+		&lt;/content&gt;
+	&lt;/item&gt;
+&lt;/root&gt;
+
+&lt;!-- NESTED --&gt;
+&lt;root&gt;
+	&lt;item id="xml_1"&gt;
+		&lt;content&gt;&lt;name&gt;&lt;![CDATA[Root node 1]]&gt;&lt;/name&gt;&lt;/content&gt;
+		&lt;item id="xml_2"&gt;
+			&lt;content&gt;&lt;name&gt;&lt;![CDATA[Child node 1]]&gt;&lt;/name&gt;&lt;/content&gt;
+		&lt;/item&gt;
+	&lt;/item&gt;
+&lt;/root&gt;
+</pre>
+</div>
+<p>Aside from nesting the only difference is the <code>parent_id</code> attribute used in <code>xml_flat</code>.</p>
+<p><code>parent_id</code> defines the parent of the node in XML flat, use <code>0</code> for root nodes. Also when using async - use <code>0</code> for the first level.</p>
+<p><code>state</code> defines the state of the node (<code>open</code> or <code>closed</code>). You can omit it too - jstree will handle the data automatically - nodes with no children will be leaf nodes, nodes with children will be closed.</p>
+<p>All attributes you set on the <code>item</code> node will be transfered to the resulting <code>li</code> node. All attributes you set on the <code>name</code> node will be transfered to the resulting <code>a</code> node.</p>
+<p>If you are using the <a href="languages.html">languages plugin</a> you can have multiple <code>name</code> nodes in a every <code>item</code> node, just set a <code>language</code> attribute on each one (<code>&lt;name language="en" ...</code>).</p>
+<p class="note">Remember to always set the XML header on your XML files.</p>
+</div>
+
+<h2 id="configuration">Configuration</h2>
+<div class="panel configuration">
+<h3>data</h3>
+<p class="meta">A XML string (or <code>false</code> if not used). Default is <code>false</code>.</p>
+<p>Specifies the content to load into the container and convert to a tree.</p>
+<h3>ajax</h3>
+<p class="meta">An object (or <code>false</code> if not used). Default is <code>false</code>.</p>
+<p>The ajax config object is pretty much the same as the <a href="http://api.jquery.com/jQuery.ajax/">jQuery ajax settings object</a>.</p>
+<p>The only difference is that you can set the <code>data</code> option to a function, that will be executed in the current tree's scope (<code>this</code> will be the tree instance) and gets the node about to be open as a paramater (or <code>-1</code> for initial load). Whatever you return in the function will be sent to the server as data (so for example you can send the node's ID).</p>
+<p>The <code>error</code> and <code>success</code> functions (if present) also fire in the context of the tree, and if you return a value in the <code>success</code> function it will be used to populate the tree - this can be useful if you want to somehow change what the server returned on the client side before it is displayed in the tree.</p>
+<h3>correct_state</h3>
+<p class="meta">A Boolean. Default is <code>false</code>.</p>
+<p>If this option is set to <code>true</code> if an AJAX request fails (or returns an empty result), the node that was about to be opened will be converted to a leaf node (the open icon will no longer be displayed).</p>
+<h3>xsl</h3>
+<p class="meta">A string. Default is <code>"flat"</code>.</p>
+<p>The type of structure you wiil be using - set either to <code>"flat"</code> or <code>"nest"</code>.</p>
+
+<p class="note"><strong>NOTE:</strong><br />If both <code>data</code> and <code>ajax</code> are set the initial tree is rendered from the <code>data</code> string. When opening a closed node (that has no loaded children) an AJAX request is made.</p>
+</div>
+
+<h2 id="demos">Demos</h2>
+<div class="panel">
+
+<h3>Using the data config option (flat)</h3>
+<div id="demo1" class="demo"></div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo1").jstree({ 
+		"xml_data" : {
+			"data" : "" + 
+"<root>" + 
+	"<item id='node_1'>" + 
+		"<content><name>Root node 1</name></content>" + 
+	"</item>" + 
+	"<item>" + 
+		"<content><name>Root node 2</name></content>" + 
+	"</item>" + 
+	"<item parent_id='node_1'>" + 
+		"<content><name>Child node</name></content>" + 
+	"</item>" + 
+"</root>"
+		},
+		"plugins" : [ "themes", "xml_data" ]
+	});
+});
+</script>
+
+<h3>Using the ajax config option (nested)</h3>
+<div id="demo2" class="demo"></div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo2").jstree({ 
+		"xml_data" : {
+			"ajax" : {
+				"url" : "_xml_nest.xml",
+			},
+			"xsl" : "nest"
+		},
+		"plugins" : [ "themes", "xml_data" ]
+	});
+});
+</script>
+
+<h3>Using both the data &amp; ajax config options (flat)</h3>
+<div id="demo4" class="demo"></div>
+<script type="text/javascript" class="source">
+$(function () {
+	$("#demo4").jstree({ 
+		"xml_data" : {
+			"data" : "" + 
+"<root>" + 
+	"<item id='node_1' state='closed'>" + 
+		"<content><name>Root node 1</name></content>" + 
+	"</item>" + 
+	"<item>" + 
+		"<content><name>Root node 2</name></content>" + 
+	"</item>" + 
+"</root>",
+			"ajax" : {
+				"url" : "_xml_flat.xml",
+				"data" : function (n) { 
+					return { 
+						id : n.attr ? n.attr("id") : 0, 
+						rand : new Date().getTime()
+					}; 
+				}
+			}
+		},
+		"plugins" : [ "themes", "xml_data" ]
+	});
+});
+</script>
+</div>
+
+<h2 id="api">API</h2>
+<div class="panel api">
+<p>Both dummy functions - <code>_is_loaded</code> and <code>load_node</code> are overwritten.</p>
+<h3 id="load_node_xml">.load_node_xml ( node , success_callback , error_callback )</h3>
+<p>This function is called instead of <code>load_node</code>.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element you want loaded. Use <code>-1</code> for root nodes.</p>
+	</li>
+	<li>
+		<code class="tp">function</code> <strong>success_callback</strong>
+		<p>A function to be executed once the node is loaded successfully - used internally. You should wait for the <code>load_node</code> event.</p>
+	</li>
+	<li>
+		<code class="tp">function</code> <strong>error_callback</strong>
+		<p>A function to be executed if the node is not loaded due to an error - used internally. You should wait for the <code>load_node</code> event.</p>
+	</li>
+</ul>
+<h3 id="parse_xml">.parse_xml ( data )</h3>
+<p>This function converts XML strings or objects to the DOM structure required by jstree. Returns a jQuery object.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">mixed</code> <strong>data</strong>
+		<p>The XML string/object.</p>
+	</li>
+</ul>
+<h3 id="get_xml">.get_xml ( type , node , li_attr , a_attr , is_callback )</h3>
+<p>This function returns an array of tree nodes converted back to XML.</p>
+<ul class="arguments">
+	<li>
+		<code class="tp">string</code> <strong>type</strong>
+		<p>Either <code>"flat"</code> or <code>"nest"</code>. Default is <code>"flat"</code>.</p>
+	</li>
+	<li>
+		<code class="tp">mixed</code> <strong>node</strong>
+		<p>This can be a DOM node, jQuery node or selector pointing to an element you want returned. Use <code>-1</code> or omit to get the whole tree.</p>
+	</li>
+	<li>
+		<code class="tp">array</code> <strong>li_attr</strong>
+		<p>The attributes to collect from the <code>LI</code> node. Defaults to <code>[ "id" , "class" ]</p>
+	</li>
+	<li>
+		<code class="tp">array</code> <strong>a_attr</strong>
+		<p>The attributes to collect from the <code>A</code> node. Defaults to <code>[ ]</p>
+	</li>
+	<li>
+		<code class="tp">string</code> <strong>is_callback</strong>
+		<p>Used internally.</p>
+	</li>
+</ul>
+
+</div>
+
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_lib/jquery.cookie.js
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_lib/jquery.cookie.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_lib/jquery.cookie.js	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,96 @@
+/**
+ * Cookie plugin
+ *
+ * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+
+/**
+ * Create a cookie with the given name and value and other optional parameters.
+ *
+ * @example $.cookie('the_cookie', 'the_value');
+ * @desc Set the value of a cookie.
+ * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
+ * @desc Create a cookie with all available options.
+ * @example $.cookie('the_cookie', 'the_value');
+ * @desc Create a session cookie.
+ * @example $.cookie('the_cookie', null);
+ * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
+ *       used when the cookie was set.
+ *
+ * @param String name The name of the cookie.
+ * @param String value The value of the cookie.
+ * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
+ * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
+ *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
+ *                             If set to null or omitted, the cookie will be a session cookie and will not be retained
+ *                             when the the browser exits.
+ * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
+ * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
+ * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
+ *                        require a secure protocol (like HTTPS).
+ * @type undefined
+ *
+ * @name $.cookie
+ * @cat Plugins/Cookie
+ * @author Klaus Hartl/klaus.hartl at stilbuero.de
+ */
+
+/**
+ * Get the value of a cookie with the given name.
+ *
+ * @example $.cookie('the_cookie');
+ * @desc Get the value of a cookie.
+ *
+ * @param String name The name of the cookie.
+ * @return The value of the cookie.
+ * @type String
+ *
+ * @name $.cookie
+ * @cat Plugins/Cookie
+ * @author Klaus Hartl/klaus.hartl at stilbuero.de
+ */
+jQuery.cookie = function(name, value, options) {
+    if (typeof value != 'undefined') { // name and value given, set cookie
+        options = options || {};
+        if (value === null) {
+            value = '';
+            options.expires = -1;
+        }
+        var expires = '';
+        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
+            var date;
+            if (typeof options.expires == 'number') {
+                date = new Date();
+                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
+            } else {
+                date = options.expires;
+            }
+            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
+        }
+        // CAUTION: Needed to parenthesize options.path and options.domain
+        // in the following expressions, otherwise they evaluate to undefined
+        // in the packed version for some reason...
+        var path = options.path ? '; path=' + (options.path) : '';
+        var domain = options.domain ? '; domain=' + (options.domain) : '';
+        var secure = options.secure ? '; secure' : '';
+        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
+    } else { // only name given, get cookie
+        var cookieValue = null;
+        if (document.cookie && document.cookie != '') {
+            var cookies = document.cookie.split(';');
+            for (var i = 0; i < cookies.length; i++) {
+                var cookie = jQuery.trim(cookies[i]);
+                // Does this cookie string begin with the name we want?
+                if (cookie.substring(0, name.length + 1) == (name + '=')) {
+                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+                    break;
+                }
+            }
+        }
+        return cookieValue;
+    }
+};
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_lib/jquery.hotkeys.js
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_lib/jquery.hotkeys.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_lib/jquery.hotkeys.js	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,99 @@
+/*
+ * jQuery Hotkeys Plugin
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ *
+ * Based upon the plugin by Tzury Bar Yochay:
+ * http://github.com/tzuryby/hotkeys
+ *
+ * Original idea by:
+ * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
+*/
+
+(function(jQuery){
+	
+	jQuery.hotkeys = {
+		version: "0.8",
+
+		specialKeys: {
+			8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
+			20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
+			37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del", 
+			96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
+			104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/", 
+			112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8", 
+			120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
+		},
+	
+		shiftNums: {
+			"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&", 
+			"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<", 
+			".": ">",  "/": "?",  "\\": "|"
+		}
+	};
+
+	function keyHandler( handleObj ) {
+		// Only care when a possible input has been specified
+		if ( typeof handleObj.data !== "string" ) {
+			return;
+		}
+		
+		var origHandler = handleObj.handler,
+			keys = handleObj.data.toLowerCase().split(" ");
+	
+		handleObj.handler = function( event ) {
+			// Don't fire in text-accepting inputs that we didn't directly bind to
+			if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
+				 event.target.type === "text") ) {
+				return;
+			}
+			
+			// Keypress represents characters, not special keys
+			var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
+				character = String.fromCharCode( event.which ).toLowerCase(),
+				key, modif = "", possible = {};
+
+			// check combinations (alt|ctrl|shift+anything)
+			if ( event.altKey && special !== "alt" ) {
+				modif += "alt+";
+			}
+
+			if ( event.ctrlKey && special !== "ctrl" ) {
+				modif += "ctrl+";
+			}
+			
+			// TODO: Need to make sure this works consistently across platforms
+			if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
+				modif += "meta+";
+			}
+
+			if ( event.shiftKey && special !== "shift" ) {
+				modif += "shift+";
+			}
+
+			if ( special ) {
+				possible[ modif + special ] = true;
+
+			} else {
+				possible[ modif + character ] = true;
+				possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
+
+				// "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
+				if ( modif === "shift+" ) {
+					possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
+				}
+			}
+
+			for ( var i = 0, l = keys.length; i < l; i++ ) {
+				if ( possible[ keys[i] ] ) {
+					return origHandler.apply( this, arguments );
+				}
+			}
+		};
+	}
+
+	jQuery.each([ "keydown", "keyup", "keypress" ], function() {
+		jQuery.event.special[ this ] = { add: keyHandler };
+	});
+
+})( jQuery );
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/_lib/jquery.js
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/_lib/jquery.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/_lib/jquery.js	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,6240 @@
+/*!
+ * jQuery JavaScript Library v1.4.2
+ * http://jquery.com/
+ *
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Sat Feb 13 22:33:48 2010 -0500
+ */
+(function( window, undefined ) {
+
+// Define a local copy of jQuery
+var jQuery = function( selector, context ) {
+		// The jQuery object is actually just the init constructor 'enhanced'
+		return new jQuery.fn.init( selector, context );
+	},
+
+	// Map over jQuery in case of overwrite
+	_jQuery = window.jQuery,
+
+	// Map over the $ in case of overwrite
+	_$ = window.$,
+
+	// Use the correct document accordingly with window argument (sandbox)
+	document = window.document,
+
+	// A central reference to the root jQuery(document)
+	rootjQuery,
+
+	// A simple way to check for HTML strings or ID strings
+	// (both of which we optimize for)
+	quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,
+
+	// Is it a simple selector
+	isSimple = /^.[^:#\[\.,]*$/,
+
+	// Check if a string has a non-whitespace character in it
+	rnotwhite = /\S/,
+
+	// Used for trimming whitespace
+	rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g,
+
+	// Match a standalone tag
+	rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+
+	// Keep a UserAgent string for use with jQuery.browser
+	userAgent = navigator.userAgent,
+
+	// For matching the engine and version of the browser
+	browserMatch,
+	
+	// Has the ready events already been bound?
+	readyBound = false,
+	
+	// The functions to execute on DOM ready
+	readyList = [],
+
+	// The ready event handler
+	DOMContentLoaded,
+
+	// Save a reference to some core methods
+	toString = Object.prototype.toString,
+	hasOwnProperty = Object.prototype.hasOwnProperty,
+	push = Array.prototype.push,
+	slice = Array.prototype.slice,
+	indexOf = Array.prototype.indexOf;
+
+jQuery.fn = jQuery.prototype = {
+	init: function( selector, context ) {
+		var match, elem, ret, doc;
+
+		// Handle $(""), $(null), or $(undefined)
+		if ( !selector ) {
+			return this;
+		}
+
+		// Handle $(DOMElement)
+		if ( selector.nodeType ) {
+			this.context = this[0] = selector;
+			this.length = 1;
+			return this;
+		}
+		
+		// The body element only exists once, optimize finding it
+		if ( selector === "body" && !context ) {
+			this.context = document;
+			this[0] = document.body;
+			this.selector = "body";
+			this.length = 1;
+			return this;
+		}
+
+		// Handle HTML strings
+		if ( typeof selector === "string" ) {
+			// Are we dealing with HTML string or an ID?
+			match = quickExpr.exec( selector );
+
+			// Verify a match, and that no context was specified for #id
+			if ( match && (match[1] || !context) ) {
+
+				// HANDLE: $(html) -> $(array)
+				if ( match[1] ) {
+					doc = (context ? context.ownerDocument || context : document);
+
+					// If a single string is passed in and it's a single tag
+					// just do a createElement and skip the rest
+					ret = rsingleTag.exec( selector );
+
+					if ( ret ) {
+						if ( jQuery.isPlainObject( context ) ) {
+							selector = [ document.createElement( ret[1] ) ];
+							jQuery.fn.attr.call( selector, context, true );
+
+						} else {
+							selector = [ doc.createElement( ret[1] ) ];
+						}
+
+					} else {
+						ret = buildFragment( [ match[1] ], [ doc ] );
+						selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
+					}
+					
+					return jQuery.merge( this, selector );
+					
+				// HANDLE: $("#id")
+				} else {
+					elem = document.getElementById( match[2] );
+
+					if ( elem ) {
+						// Handle the case where IE and Opera return items
+						// by name instead of ID
+						if ( elem.id !== match[2] ) {
+							return rootjQuery.find( selector );
+						}
+
+						// Otherwise, we inject the element directly into the jQuery object
+						this.length = 1;
+						this[0] = elem;
+					}
+
+					this.context = document;
+					this.selector = selector;
+					return this;
+				}
+
+			// HANDLE: $("TAG")
+			} else if ( !context && /^\w+$/.test( selector ) ) {
+				this.selector = selector;
+				this.context = document;
+				selector = document.getElementsByTagName( selector );
+				return jQuery.merge( this, selector );
+
+			// HANDLE: $(expr, $(...))
+			} else if ( !context || context.jquery ) {
+				return (context || rootjQuery).find( selector );
+
+			// HANDLE: $(expr, context)
+			// (which is just equivalent to: $(context).find(expr)
+			} else {
+				return jQuery( context ).find( selector );
+			}
+
+		// HANDLE: $(function)
+		// Shortcut for document ready
+		} else if ( jQuery.isFunction( selector ) ) {
+			return rootjQuery.ready( selector );
+		}
+
+		if (selector.selector !== undefined) {
+			this.selector = selector.selector;
+			this.context = selector.context;
+		}
+
+		return jQuery.makeArray( selector, this );
+	},
+
+	// Start with an empty selector
+	selector: "",
+
+	// The current version of jQuery being used
+	jquery: "1.4.2",
+
+	// The default length of a jQuery object is 0
+	length: 0,
+
+	// The number of elements contained in the matched element set
+	size: function() {
+		return this.length;
+	},
+
+	toArray: function() {
+		return slice.call( this, 0 );
+	},
+
+	// Get the Nth element in the matched element set OR
+	// Get the whole matched element set as a clean array
+	get: function( num ) {
+		return num == null ?
+
+			// Return a 'clean' array
+			this.toArray() :
+
+			// Return just the object
+			( num < 0 ? this.slice(num)[ 0 ] : this[ num ] );
+	},
+
+	// Take an array of elements and push it onto the stack
+	// (returning the new matched element set)
+	pushStack: function( elems, name, selector ) {
+		// Build a new jQuery matched element set
+		var ret = jQuery();
+
+		if ( jQuery.isArray( elems ) ) {
+			push.apply( ret, elems );
+		
+		} else {
+			jQuery.merge( ret, elems );
+		}
+
+		// Add the old object onto the stack (as a reference)
+		ret.prevObject = this;
+
+		ret.context = this.context;
+
+		if ( name === "find" ) {
+			ret.selector = this.selector + (this.selector ? " " : "") + selector;
+		} else if ( name ) {
+			ret.selector = this.selector + "." + name + "(" + selector + ")";
+		}
+
+		// Return the newly-formed element set
+		return ret;
+	},
+
+	// Execute a callback for every element in the matched set.
+	// (You can seed the arguments with an array of args, but this is
+	// only used internally.)
+	each: function( callback, args ) {
+		return jQuery.each( this, callback, args );
+	},
+	
+	ready: function( fn ) {
+		// Attach the listeners
+		jQuery.bindReady();
+
+		// If the DOM is already ready
+		if ( jQuery.isReady ) {
+			// Execute the function immediately
+			fn.call( document, jQuery );
+
+		// Otherwise, remember the function for later
+		} else if ( readyList ) {
+			// Add the function to the wait list
+			readyList.push( fn );
+		}
+
+		return this;
+	},
+	
+	eq: function( i ) {
+		return i === -1 ?
+			this.slice( i ) :
+			this.slice( i, +i + 1 );
+	},
+
+	first: function() {
+		return this.eq( 0 );
+	},
+
+	last: function() {
+		return this.eq( -1 );
+	},
+
+	slice: function() {
+		return this.pushStack( slice.apply( this, arguments ),
+			"slice", slice.call(arguments).join(",") );
+	},
+
+	map: function( callback ) {
+		return this.pushStack( jQuery.map(this, function( elem, i ) {
+			return callback.call( elem, i, elem );
+		}));
+	},
+	
+	end: function() {
+		return this.prevObject || jQuery(null);
+	},
+
+	// For internal use only.
+	// Behaves like an Array's method, not like a jQuery method.
+	push: push,
+	sort: [].sort,
+	splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+	// copy reference to target object
+	var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;
+
+	// Handle a deep copy situation
+	if ( typeof target === "boolean" ) {
+		deep = target;
+		target = arguments[1] || {};
+		// skip the boolean and the target
+		i = 2;
+	}
+
+	// Handle case when target is a string or something (possible in deep copy)
+	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+		target = {};
+	}
+
+	// extend jQuery itself if only one argument is passed
+	if ( length === i ) {
+		target = this;
+		--i;
+	}
+
+	for ( ; i < length; i++ ) {
+		// Only deal with non-null/undefined values
+		if ( (options = arguments[ i ]) != null ) {
+			// Extend the base object
+			for ( name in options ) {
+				src = target[ name ];
+				copy = options[ name ];
+
+				// Prevent never-ending loop
+				if ( target === copy ) {
+					continue;
+				}
+
+				// Recurse if we're merging object literal values or arrays
+				if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) {
+					var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src
+						: jQuery.isArray(copy) ? [] : {};
+
+					// Never move original objects, clone them
+					target[ name ] = jQuery.extend( deep, clone, copy );
+
+				// Don't bring in undefined values
+				} else if ( copy !== undefined ) {
+					target[ name ] = copy;
+				}
+			}
+		}
+	}
+
+	// Return the modified object
+	return target;
+};
+
+jQuery.extend({
+	noConflict: function( deep ) {
+		window.$ = _$;
+
+		if ( deep ) {
+			window.jQuery = _jQuery;
+		}
+
+		return jQuery;
+	},
+	
+	// Is the DOM ready to be used? Set to true once it occurs.
+	isReady: false,
+	
+	// Handle when the DOM is ready
+	ready: function() {
+		// Make sure that the DOM is not already loaded
+		if ( !jQuery.isReady ) {
+			// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+			if ( !document.body ) {
+				return setTimeout( jQuery.ready, 13 );
+			}
+
+			// Remember that the DOM is ready
+			jQuery.isReady = true;
+
+			// If there are functions bound, to execute
+			if ( readyList ) {
+				// Execute all of them
+				var fn, i = 0;
+				while ( (fn = readyList[ i++ ]) ) {
+					fn.call( document, jQuery );
+				}
+
+				// Reset the list of functions
+				readyList = null;
+			}
+
+			// Trigger any bound ready events
+			if ( jQuery.fn.triggerHandler ) {
+				jQuery( document ).triggerHandler( "ready" );
+			}
+		}
+	},
+	
+	bindReady: function() {
+		if ( readyBound ) {
+			return;
+		}
+
+		readyBound = true;
+
+		// Catch cases where $(document).ready() is called after the
+		// browser event has already occurred.
+		if ( document.readyState === "complete" ) {
+			return jQuery.ready();
+		}
+
+		// Mozilla, Opera and webkit nightlies currently support this event
+		if ( document.addEventListener ) {
+			// Use the handy event callback
+			document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+			
+			// A fallback to window.onload, that will always work
+			window.addEventListener( "load", jQuery.ready, false );
+
+		// If IE event model is used
+		} else if ( document.attachEvent ) {
+			// ensure firing before onload,
+			// maybe late but safe also for iframes
+			document.attachEvent("onreadystatechange", DOMContentLoaded);
+			
+			// A fallback to window.onload, that will always work
+			window.attachEvent( "onload", jQuery.ready );
+
+			// If IE and not a frame
+			// continually check to see if the document is ready
+			var toplevel = false;
+
+			try {
+				toplevel = window.frameElement == null;
+			} catch(e) {}
+
+			if ( document.documentElement.doScroll && toplevel ) {
+				doScrollCheck();
+			}
+		}
+	},
+
+	// See test/unit/core.js for details concerning isFunction.
+	// Since version 1.3, DOM methods and functions like alert
+	// aren't supported. They return false on IE (#2968).
+	isFunction: function( obj ) {
+		return toString.call(obj) === "[object Function]";
+	},
+
+	isArray: function( obj ) {
+		return toString.call(obj) === "[object Array]";
+	},
+
+	isPlainObject: function( obj ) {
+		// Must be an Object.
+		// Because of IE, we also have to check the presence of the constructor property.
+		// Make sure that DOM nodes and window objects don't pass through, as well
+		if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {
+			return false;
+		}
+		
+		// Not own constructor property must be Object
+		if ( obj.constructor
+			&& !hasOwnProperty.call(obj, "constructor")
+			&& !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {
+			return false;
+		}
+		
+		// Own properties are enumerated firstly, so to speed up,
+		// if last one is own, then all properties are own.
+	
+		var key;
+		for ( key in obj ) {}
+		
+		return key === undefined || hasOwnProperty.call( obj, key );
+	},
+
+	isEmptyObject: function( obj ) {
+		for ( var name in obj ) {
+			return false;
+		}
+		return true;
+	},
+	
+	error: function( msg ) {
+		throw msg;
+	},
+	
+	parseJSON: function( data ) {
+		if ( typeof data !== "string" || !data ) {
+			return null;
+		}
+
+		// Make sure leading/trailing whitespace is removed (IE can't handle it)
+		data = jQuery.trim( data );
+		
+		// Make sure the incoming data is actual JSON
+		// Logic borrowed from http://json.org/json2.js
+		if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@")
+			.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]")
+			.replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) {
+
+			// Try to use the native JSON parser first
+			return window.JSON && window.JSON.parse ?
+				window.JSON.parse( data ) :
+				(new Function("return " + data))();
+
+		} else {
+			jQuery.error( "Invalid JSON: " + data );
+		}
+	},
+
+	noop: function() {},
+
+	// Evalulates a script in a global context
+	globalEval: function( data ) {
+		if ( data && rnotwhite.test(data) ) {
+			// Inspired by code by Andrea Giammarchi
+			// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
+			var head = document.getElementsByTagName("head")[0] || document.documentElement,
+				script = document.createElement("script");
+
+			script.type = "text/javascript";
+
+			if ( jQuery.support.scriptEval ) {
+				script.appendChild( document.createTextNode( data ) );
+			} else {
+				script.text = data;
+			}
+
+			// Use insertBefore instead of appendChild to circumvent an IE6 bug.
+			// This arises when a base node is used (#2709).
+			head.insertBefore( script, head.firstChild );
+			head.removeChild( script );
+		}
+	},
+
+	nodeName: function( elem, name ) {
+		return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
+	},
+
+	// args is for internal usage only
+	each: function( object, callback, args ) {
+		var name, i = 0,
+			length = object.length,
+			isObj = length === undefined || jQuery.isFunction(object);
+
+		if ( args ) {
+			if ( isObj ) {
+				for ( name in object ) {
+					if ( callback.apply( object[ name ], args ) === false ) {
+						break;
+					}
+				}
+			} else {
+				for ( ; i < length; ) {
+					if ( callback.apply( object[ i++ ], args ) === false ) {
+						break;
+					}
+				}
+			}
+
+		// A special, fast, case for the most common use of each
+		} else {
+			if ( isObj ) {
+				for ( name in object ) {
+					if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
+						break;
+					}
+				}
+			} else {
+				for ( var value = object[0];
+					i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
+			}
+		}
+
+		return object;
+	},
+
+	trim: function( text ) {
+		return (text || "").replace( rtrim, "" );
+	},
+
+	// results is for internal usage only
+	makeArray: function( array, results ) {
+		var ret = results || [];
+
+		if ( array != null ) {
+			// The window, strings (and functions) also have 'length'
+			// The extra typeof function check is to prevent crashes
+			// in Safari 2 (See: #3039)
+			if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) {
+				push.call( ret, array );
+			} else {
+				jQuery.merge( ret, array );
+			}
+		}
+
+		return ret;
+	},
+
+	inArray: function( elem, array ) {
+		if ( array.indexOf ) {
+			return array.indexOf( elem );
+		}
+
+		for ( var i = 0, length = array.length; i < length; i++ ) {
+			if ( array[ i ] === elem ) {
+				return i;
+			}
+		}
+
+		return -1;
+	},
+
+	merge: function( first, second ) {
+		var i = first.length, j = 0;
+
+		if ( typeof second.length === "number" ) {
+			for ( var l = second.length; j < l; j++ ) {
+				first[ i++ ] = second[ j ];
+			}
+		
+		} else {
+			while ( second[j] !== undefined ) {
+				first[ i++ ] = second[ j++ ];
+			}
+		}
+
+		first.length = i;
+
+		return first;
+	},
+
+	grep: function( elems, callback, inv ) {
+		var ret = [];
+
+		// Go through the array, only saving the items
+		// that pass the validator function
+		for ( var i = 0, length = elems.length; i < length; i++ ) {
+			if ( !inv !== !callback( elems[ i ], i ) ) {
+				ret.push( elems[ i ] );
+			}
+		}
+
+		return ret;
+	},
+
+	// arg is for internal usage only
+	map: function( elems, callback, arg ) {
+		var ret = [], value;
+
+		// Go through the array, translating each of the items to their
+		// new value (or values).
+		for ( var i = 0, length = elems.length; i < length; i++ ) {
+			value = callback( elems[ i ], i, arg );
+
+			if ( value != null ) {
+				ret[ ret.length ] = value;
+			}
+		}
+
+		return ret.concat.apply( [], ret );
+	},
+
+	// A global GUID counter for objects
+	guid: 1,
+
+	proxy: function( fn, proxy, thisObject ) {
+		if ( arguments.length === 2 ) {
+			if ( typeof proxy === "string" ) {
+				thisObject = fn;
+				fn = thisObject[ proxy ];
+				proxy = undefined;
+
+			} else if ( proxy && !jQuery.isFunction( proxy ) ) {
+				thisObject = proxy;
+				proxy = undefined;
+			}
+		}
+
+		if ( !proxy && fn ) {
+			proxy = function() {
+				return fn.apply( thisObject || this, arguments );
+			};
+		}
+
+		// Set the guid of unique handler to the same of original handler, so it can be removed
+		if ( fn ) {
+			proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
+		}
+
+		// So proxy can be declared as an argument
+		return proxy;
+	},
+
+	// Use of jQuery.browser is frowned upon.
+	// More details: http://docs.jquery.com/Utilities/jQuery.browser
+	uaMatch: function( ua ) {
+		ua = ua.toLowerCase();
+
+		var match = /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
+			/(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) ||
+			/(msie) ([\w.]+)/.exec( ua ) ||
+			!/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) ||
+		  	[];
+
+		return { browser: match[1] || "", version: match[2] || "0" };
+	},
+
+	browser: {}
+});
+
+browserMatch = jQuery.uaMatch( userAgent );
+if ( browserMatch.browser ) {
+	jQuery.browser[ browserMatch.browser ] = true;
+	jQuery.browser.version = browserMatch.version;
+}
+
+// Deprecated, use jQuery.browser.webkit instead
+if ( jQuery.browser.webkit ) {
+	jQuery.browser.safari = true;
+}
+
+if ( indexOf ) {
+	jQuery.inArray = function( elem, array ) {
+		return indexOf.call( array, elem );
+	};
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+
+// Cleanup functions for the document ready method
+if ( document.addEventListener ) {
+	DOMContentLoaded = function() {
+		document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+		jQuery.ready();
+	};
+
+} else if ( document.attachEvent ) {
+	DOMContentLoaded = function() {
+		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+		if ( document.readyState === "complete" ) {
+			document.detachEvent( "onreadystatechange", DOMContentLoaded );
+			jQuery.ready();
+		}
+	};
+}
+
+// The DOM ready check for Internet Explorer
+function doScrollCheck() {
+	if ( jQuery.isReady ) {
+		return;
+	}
+
+	try {
+		// If IE is used, use the trick by Diego Perini
+		// http://javascript.nwbox.com/IEContentLoaded/
+		document.documentElement.doScroll("left");
+	} catch( error ) {
+		setTimeout( doScrollCheck, 1 );
+		return;
+	}
+
+	// and execute any waiting functions
+	jQuery.ready();
+}
+
+function evalScript( i, elem ) {
+	if ( elem.src ) {
+		jQuery.ajax({
+			url: elem.src,
+			async: false,
+			dataType: "script"
+		});
+	} else {
+		jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
+	}
+
+	if ( elem.parentNode ) {
+		elem.parentNode.removeChild( elem );
+	}
+}
+
+// Mutifunctional method to get and set values to a collection
+// The value/s can be optionally by executed if its a function
+function access( elems, key, value, exec, fn, pass ) {
+	var length = elems.length;
+	
+	// Setting many attributes
+	if ( typeof key === "object" ) {
+		for ( var k in key ) {
+			access( elems, k, key[k], exec, fn, value );
+		}
+		return elems;
+	}
+	
+	// Setting one attribute
+	if ( value !== undefined ) {
+		// Optionally, function values get executed if exec is true
+		exec = !pass && exec && jQuery.isFunction(value);
+		
+		for ( var i = 0; i < length; i++ ) {
+			fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+		}
+		
+		return elems;
+	}
+	
+	// Getting an attribute
+	return length ? fn( elems[0], key ) : undefined;
+}
+
+function now() {
+	return (new Date).getTime();
+}
+(function() {
+
+	jQuery.support = {};
+
+	var root = document.documentElement,
+		script = document.createElement("script"),
+		div = document.createElement("div"),
+		id = "script" + now();
+
+	div.style.display = "none";
+	div.innerHTML = "   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+
+	var all = div.getElementsByTagName("*"),
+		a = div.getElementsByTagName("a")[0];
+
+	// Can't get basic test support
+	if ( !all || !all.length || !a ) {
+		return;
+	}
+
+	jQuery.support = {
+		// IE strips leading whitespace when .innerHTML is used
+		leadingWhitespace: div.firstChild.nodeType === 3,
+
+		// Make sure that tbody elements aren't automatically inserted
+		// IE will insert them into empty tables
+		tbody: !div.getElementsByTagName("tbody").length,
+
+		// Make sure that link elements get serialized correctly by innerHTML
+		// This requires a wrapper element in IE
+		htmlSerialize: !!div.getElementsByTagName("link").length,
+
+		// Get the style information from getAttribute
+		// (IE uses .cssText insted)
+		style: /red/.test( a.getAttribute("style") ),
+
+		// Make sure that URLs aren't manipulated
+		// (IE normalizes it by default)
+		hrefNormalized: a.getAttribute("href") === "/a",
+
+		// Make sure that element opacity exists
+		// (IE uses filter instead)
+		// Use a regex to work around a WebKit issue. See #5145
+		opacity: /^0.55$/.test( a.style.opacity ),
+
+		// Verify style float existence
+		// (IE uses styleFloat instead of cssFloat)
+		cssFloat: !!a.style.cssFloat,
+
+		// Make sure that if no value is specified for a checkbox
+		// that it defaults to "on".
+		// (WebKit defaults to "" instead)
+		checkOn: div.getElementsByTagName("input")[0].value === "on",
+
+		// Make sure that a selected-by-default option has a working selected property.
+		// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+		optSelected: document.createElement("select").appendChild( document.createElement("option") ).selected,
+
+		parentNode: div.removeChild( div.appendChild( document.createElement("div") ) ).parentNode === null,
+
+		// Will be defined later
+		deleteExpando: true,
+		checkClone: false,
+		scriptEval: false,
+		noCloneEvent: true,
+		boxModel: null
+	};
+
+	script.type = "text/javascript";
+	try {
+		script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
+	} catch(e) {}
+
+	root.insertBefore( script, root.firstChild );
+
+	// Make sure that the execution of code works by injecting a script
+	// tag with appendChild/createTextNode
+	// (IE doesn't support this, fails, and uses .text instead)
+	if ( window[ id ] ) {
+		jQuery.support.scriptEval = true;
+		delete window[ id ];
+	}
+
+	// Test to see if it's possible to delete an expando from an element
+	// Fails in Internet Explorer
+	try {
+		delete script.test;
+	
+	} catch(e) {
+		jQuery.support.deleteExpando = false;
+	}
+
+	root.removeChild( script );
+
+	if ( div.attachEvent && div.fireEvent ) {
+		div.attachEvent("onclick", function click() {
+			// Cloning a node shouldn't copy over any
+			// bound event handlers (IE does this)
+			jQuery.support.noCloneEvent = false;
+			div.detachEvent("onclick", click);
+		});
+		div.cloneNode(true).fireEvent("onclick");
+	}
+
+	div = document.createElement("div");
+	div.innerHTML = "<input type='radio' name='radiotest' checked='checked'/>";
+
+	var fragment = document.createDocumentFragment();
+	fragment.appendChild( div.firstChild );
+
+	// WebKit doesn't clone checked state correctly in fragments
+	jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked;
+
+	// Figure out if the W3C box model works as expected
+	// document.body must exist before we can do this
+	jQuery(function() {
+		var div = document.createElement("div");
+		div.style.width = div.style.paddingLeft = "1px";
+
+		document.body.appendChild( div );
+		jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
+		document.body.removeChild( div ).style.display = 'none';
+
+		div = null;
+	});
+
+	// Technique from Juriy Zaytsev
+	// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
+	var eventSupported = function( eventName ) { 
+		var el = document.createElement("div"); 
+		eventName = "on" + eventName; 
+
+		var isSupported = (eventName in el); 
+		if ( !isSupported ) { 
+			el.setAttribute(eventName, "return;"); 
+			isSupported = typeof el[eventName] === "function"; 
+		} 
+		el = null; 
+
+		return isSupported; 
+	};
+	
+	jQuery.support.submitBubbles = eventSupported("submit");
+	jQuery.support.changeBubbles = eventSupported("change");
+
+	// release memory in IE
+	root = script = div = all = a = null;
+})();
+
+jQuery.props = {
+	"for": "htmlFor",
+	"class": "className",
+	readonly: "readOnly",
+	maxlength: "maxLength",
+	cellspacing: "cellSpacing",
+	rowspan: "rowSpan",
+	colspan: "colSpan",
+	tabindex: "tabIndex",
+	usemap: "useMap",
+	frameborder: "frameBorder"
+};
+var expando = "jQuery" + now(), uuid = 0, windowData = {};
+
+jQuery.extend({
+	cache: {},
+	
+	expando:expando,
+
+	// The following elements throw uncatchable exceptions if you
+	// attempt to add expando properties to them.
+	noData: {
+		"embed": true,
+		"object": true,
+		"applet": true
+	},
+
+	data: function( elem, name, data ) {
+		if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+			return;
+		}
+
+		elem = elem == window ?
+			windowData :
+			elem;
+
+		var id = elem[ expando ], cache = jQuery.cache, thisCache;
+
+		if ( !id && typeof name === "string" && data === undefined ) {
+			return null;
+		}
+
+		// Compute a unique ID for the element
+		if ( !id ) { 
+			id = ++uuid;
+		}
+
+		// Avoid generating a new cache unless none exists and we
+		// want to manipulate it.
+		if ( typeof name === "object" ) {
+			elem[ expando ] = id;
+			thisCache = cache[ id ] = jQuery.extend(true, {}, name);
+
+		} else if ( !cache[ id ] ) {
+			elem[ expando ] = id;
+			cache[ id ] = {};
+		}
+
+		thisCache = cache[ id ];
+
+		// Prevent overriding the named cache with undefined values
+		if ( data !== undefined ) {
+			thisCache[ name ] = data;
+		}
+
+		return typeof name === "string" ? thisCache[ name ] : thisCache;
+	},
+
+	removeData: function( elem, name ) {
+		if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+			return;
+		}
+
+		elem = elem == window ?
+			windowData :
+			elem;
+
+		var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ];
+
+		// If we want to remove a specific section of the element's data
+		if ( name ) {
+			if ( thisCache ) {
+				// Remove the section of cache data
+				delete thisCache[ name ];
+
+				// If we've removed all the data, remove the element's cache
+				if ( jQuery.isEmptyObject(thisCache) ) {
+					jQuery.removeData( elem );
+				}
+			}
+
+		// Otherwise, we want to remove all of the element's data
+		} else {
+			if ( jQuery.support.deleteExpando ) {
+				delete elem[ jQuery.expando ];
+
+			} else if ( elem.removeAttribute ) {
+				elem.removeAttribute( jQuery.expando );
+			}
+
+			// Completely remove the data cache
+			delete cache[ id ];
+		}
+	}
+});
+
+jQuery.fn.extend({
+	data: function( key, value ) {
+		if ( typeof key === "undefined" && this.length ) {
+			return jQuery.data( this[0] );
+
+		} else if ( typeof key === "object" ) {
+			return this.each(function() {
+				jQuery.data( this, key );
+			});
+		}
+
+		var parts = key.split(".");
+		parts[1] = parts[1] ? "." + parts[1] : "";
+
+		if ( value === undefined ) {
+			var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+
+			if ( data === undefined && this.length ) {
+				data = jQuery.data( this[0], key );
+			}
+			return data === undefined && parts[1] ?
+				this.data( parts[0] ) :
+				data;
+		} else {
+			return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() {
+				jQuery.data( this, key, value );
+			});
+		}
+	},
+
+	removeData: function( key ) {
+		return this.each(function() {
+			jQuery.removeData( this, key );
+		});
+	}
+});
+jQuery.extend({
+	queue: function( elem, type, data ) {
+		if ( !elem ) {
+			return;
+		}
+
+		type = (type || "fx") + "queue";
+		var q = jQuery.data( elem, type );
+
+		// Speed up dequeue by getting out quickly if this is just a lookup
+		if ( !data ) {
+			return q || [];
+		}
+
+		if ( !q || jQuery.isArray(data) ) {
+			q = jQuery.data( elem, type, jQuery.makeArray(data) );
+
+		} else {
+			q.push( data );
+		}
+
+		return q;
+	},
+
+	dequeue: function( elem, type ) {
+		type = type || "fx";
+
+		var queue = jQuery.queue( elem, type ), fn = queue.shift();
+
+		// If the fx queue is dequeued, always remove the progress sentinel
+		if ( fn === "inprogress" ) {
+			fn = queue.shift();
+		}
+
+		if ( fn ) {
+			// Add a progress sentinel to prevent the fx queue from being
+			// automatically dequeued
+			if ( type === "fx" ) {
+				queue.unshift("inprogress");
+			}
+
+			fn.call(elem, function() {
+				jQuery.dequeue(elem, type);
+			});
+		}
+	}
+});
+
+jQuery.fn.extend({
+	queue: function( type, data ) {
+		if ( typeof type !== "string" ) {
+			data = type;
+			type = "fx";
+		}
+
+		if ( data === undefined ) {
+			return jQuery.queue( this[0], type );
+		}
+		return this.each(function( i, elem ) {
+			var queue = jQuery.queue( this, type, data );
+
+			if ( type === "fx" && queue[0] !== "inprogress" ) {
+				jQuery.dequeue( this, type );
+			}
+		});
+	},
+	dequeue: function( type ) {
+		return this.each(function() {
+			jQuery.dequeue( this, type );
+		});
+	},
+
+	// Based off of the plugin by Clint Helfers, with permission.
+	// http://blindsignals.com/index.php/2009/07/jquery-delay/
+	delay: function( time, type ) {
+		time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
+		type = type || "fx";
+
+		return this.queue( type, function() {
+			var elem = this;
+			setTimeout(function() {
+				jQuery.dequeue( elem, type );
+			}, time );
+		});
+	},
+
+	clearQueue: function( type ) {
+		return this.queue( type || "fx", [] );
+	}
+});
+var rclass = /[\n\t]/g,
+	rspace = /\s+/,
+	rreturn = /\r/g,
+	rspecialurl = /href|src|style/,
+	rtype = /(button|input)/i,
+	rfocusable = /(button|input|object|select|textarea)/i,
+	rclickable = /^(a|area)$/i,
+	rradiocheck = /radio|checkbox/;
+
+jQuery.fn.extend({
+	attr: function( name, value ) {
+		return access( this, name, value, true, jQuery.attr );
+	},
+
+	removeAttr: function( name, fn ) {
+		return this.each(function(){
+			jQuery.attr( this, name, "" );
+			if ( this.nodeType === 1 ) {
+				this.removeAttribute( name );
+			}
+		});
+	},
+
+	addClass: function( value ) {
+		if ( jQuery.isFunction(value) ) {
+			return this.each(function(i) {
+				var self = jQuery(this);
+				self.addClass( value.call(this, i, self.attr("class")) );
+			});
+		}
+
+		if ( value && typeof value === "string" ) {
+			var classNames = (value || "").split( rspace );
+
+			for ( var i = 0, l = this.length; i < l; i++ ) {
+				var elem = this[i];
+
+				if ( elem.nodeType === 1 ) {
+					if ( !elem.className ) {
+						elem.className = value;
+
+					} else {
+						var className = " " + elem.className + " ", setClass = elem.className;
+						for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
+							if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
+								setClass += " " + classNames[c];
+							}
+						}
+						elem.className = jQuery.trim( setClass );
+					}
+				}
+			}
+		}
+
+		return this;
+	},
+
+	removeClass: function( value ) {
+		if ( jQuery.isFunction(value) ) {
+			return this.each(function(i) {
+				var self = jQuery(this);
+				self.removeClass( value.call(this, i, self.attr("class")) );
+			});
+		}
+
+		if ( (value && typeof value === "string") || value === undefined ) {
+			var classNames = (value || "").split(rspace);
+
+			for ( var i = 0, l = this.length; i < l; i++ ) {
+				var elem = this[i];
+
+				if ( elem.nodeType === 1 && elem.className ) {
+					if ( value ) {
+						var className = (" " + elem.className + " ").replace(rclass, " ");
+						for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
+							className = className.replace(" " + classNames[c] + " ", " ");
+						}
+						elem.className = jQuery.trim( className );
+
+					} else {
+						elem.className = "";
+					}
+				}
+			}
+		}
+
+		return this;
+	},
+
+	toggleClass: function( value, stateVal ) {
+		var type = typeof value, isBool = typeof stateVal === "boolean";
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function(i) {
+				var self = jQuery(this);
+				self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal );
+			});
+		}
+
+		return this.each(function() {
+			if ( type === "string" ) {
+				// toggle individual class names
+				var className, i = 0, self = jQuery(this),
+					state = stateVal,
+					classNames = value.split( rspace );
+
+				while ( (className = classNames[ i++ ]) ) {
+					// check each className given, space seperated list
+					state = isBool ? state : !self.hasClass( className );
+					self[ state ? "addClass" : "removeClass" ]( className );
+				}
+
+			} else if ( type === "undefined" || type === "boolean" ) {
+				if ( this.className ) {
+					// store className if set
+					jQuery.data( this, "__className__", this.className );
+				}
+
+				// toggle whole className
+				this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || "";
+			}
+		});
+	},
+
+	hasClass: function( selector ) {
+		var className = " " + selector + " ";
+		for ( var i = 0, l = this.length; i < l; i++ ) {
+			if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
+				return true;
+			}
+		}
+
+		return false;
+	},
+
+	val: function( value ) {
+		if ( value === undefined ) {
+			var elem = this[0];
+
+			if ( elem ) {
+				if ( jQuery.nodeName( elem, "option" ) ) {
+					return (elem.attributes.value || {}).specified ? elem.value : elem.text;
+				}
+
+				// We need to handle select boxes special
+				if ( jQuery.nodeName( elem, "select" ) ) {
+					var index = elem.selectedIndex,
+						values = [],
+						options = elem.options,
+						one = elem.type === "select-one";
+
+					// Nothing was selected
+					if ( index < 0 ) {
+						return null;
+					}
+
+					// Loop through all the selected options
+					for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
+						var option = options[ i ];
+
+						if ( option.selected ) {
+							// Get the specifc value for the option
+							value = jQuery(option).val();
+
+							// We don't need an array for one selects
+							if ( one ) {
+								return value;
+							}
+
+							// Multi-Selects return an array
+							values.push( value );
+						}
+					}
+
+					return values;
+				}
+
+				// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+				if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) {
+					return elem.getAttribute("value") === null ? "on" : elem.value;
+				}
+				
+
+				// Everything else, we just grab the value
+				return (elem.value || "").replace(rreturn, "");
+
+			}
+
+			return undefined;
+		}
+
+		var isFunction = jQuery.isFunction(value);
+
+		return this.each(function(i) {
+			var self = jQuery(this), val = value;
+
+			if ( this.nodeType !== 1 ) {
+				return;
+			}
+
+			if ( isFunction ) {
+				val = value.call(this, i, self.val());
+			}
+
+			// Typecast each time if the value is a Function and the appended
+			// value is therefore different each time.
+			if ( typeof val === "number" ) {
+				val += "";
+			}
+
+			if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) {
+				this.checked = jQuery.inArray( self.val(), val ) >= 0;
+
+			} else if ( jQuery.nodeName( this, "select" ) ) {
+				var values = jQuery.makeArray(val);
+
+				jQuery( "option", this ).each(function() {
+					this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+				});
+
+				if ( !values.length ) {
+					this.selectedIndex = -1;
+				}
+
+			} else {
+				this.value = val;
+			}
+		});
+	}
+});
+
+jQuery.extend({
+	attrFn: {
+		val: true,
+		css: true,
+		html: true,
+		text: true,
+		data: true,
+		width: true,
+		height: true,
+		offset: true
+	},
+		
+	attr: function( elem, name, value, pass ) {
+		// don't set attributes on text and comment nodes
+		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
+			return undefined;
+		}
+
+		if ( pass && name in jQuery.attrFn ) {
+			return jQuery(elem)[name](value);
+		}
+
+		var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),
+			// Whether we are setting (or getting)
+			set = value !== undefined;
+
+		// Try to normalize/fix the name
+		name = notxml && jQuery.props[ name ] || name;
+
+		// Only do all the following if this is a node (faster for style)
+		if ( elem.nodeType === 1 ) {
+			// These attributes require special treatment
+			var special = rspecialurl.test( name );
+
+			// Safari mis-reports the default selected property of an option
+			// Accessing the parent's selectedIndex property fixes it
+			if ( name === "selected" && !jQuery.support.optSelected ) {
+				var parent = elem.parentNode;
+				if ( parent ) {
+					parent.selectedIndex;
+	
+					// Make sure that it also works with optgroups, see #5701
+					if ( parent.parentNode ) {
+						parent.parentNode.selectedIndex;
+					}
+				}
+			}
+
+			// If applicable, access the attribute via the DOM 0 way
+			if ( name in elem && notxml && !special ) {
+				if ( set ) {
+					// We can't allow the type property to be changed (since it causes problems in IE)
+					if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) {
+						jQuery.error( "type property can't be changed" );
+					}
+
+					elem[ name ] = value;
+				}
+
+				// browsers index elements by id/name on forms, give priority to attributes.
+				if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) {
+					return elem.getAttributeNode( name ).nodeValue;
+				}
+
+				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+				if ( name === "tabIndex" ) {
+					var attributeNode = elem.getAttributeNode( "tabIndex" );
+
+					return attributeNode && attributeNode.specified ?
+						attributeNode.value :
+						rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+							0 :
+							undefined;
+				}
+
+				return elem[ name ];
+			}
+
+			if ( !jQuery.support.style && notxml && name === "style" ) {
+				if ( set ) {
+					elem.style.cssText = "" + value;
+				}
+
+				return elem.style.cssText;
+			}
+
+			if ( set ) {
+				// convert the value to a string (all browsers do this but IE) see #1070
+				elem.setAttribute( name, "" + value );
+			}
+
+			var attr = !jQuery.support.hrefNormalized && notxml && special ?
+					// Some attributes require a special call on IE
+					elem.getAttribute( name, 2 ) :
+					elem.getAttribute( name );
+
+			// Non-existent attributes return null, we normalize to undefined
+			return attr === null ? undefined : attr;
+		}
+
+		// elem is actually elem.style ... set the style
+		// Using attr for specific style information is now deprecated. Use style instead.
+		return jQuery.style( elem, name, value );
+	}
+});
+var rnamespaces = /\.(.*)$/,
+	fcleanup = function( nm ) {
+		return nm.replace(/[^\w\s\.\|`]/g, function( ch ) {
+			return "\\" + ch;
+		});
+	};
+
+/*
+ * A number of helper functions used for managing events.
+ * Many of the ideas behind this code originated from
+ * Dean Edwards' addEvent library.
+ */
+jQuery.event = {
+
+	// Bind an event to an element
+	// Original by Dean Edwards
+	add: function( elem, types, handler, data ) {
+		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+			return;
+		}
+
+		// For whatever reason, IE has trouble passing the window object
+		// around, causing it to be cloned in the process
+		if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {
+			elem = window;
+		}
+
+		var handleObjIn, handleObj;
+
+		if ( handler.handler ) {
+			handleObjIn = handler;
+			handler = handleObjIn.handler;
+		}
+
+		// Make sure that the function being executed has a unique ID
+		if ( !handler.guid ) {
+			handler.guid = jQuery.guid++;
+		}
+
+		// Init the element's event structure
+		var elemData = jQuery.data( elem );
+
+		// If no elemData is found then we must be trying to bind to one of the
+		// banned noData elements
+		if ( !elemData ) {
+			return;
+		}
+
+		var events = elemData.events = elemData.events || {},
+			eventHandle = elemData.handle, eventHandle;
+
+		if ( !eventHandle ) {
+			elemData.handle = eventHandle = function() {
+				// Handle the second event of a trigger and when
+				// an event is called after a page has unloaded
+				return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
+					jQuery.event.handle.apply( eventHandle.elem, arguments ) :
+					undefined;
+			};
+		}
+
+		// Add elem as a property of the handle function
+		// This is to prevent a memory leak with non-native events in IE.
+		eventHandle.elem = elem;
+
+		// Handle multiple events separated by a space
+		// jQuery(...).bind("mouseover mouseout", fn);
+		types = types.split(" ");
+
+		var type, i = 0, namespaces;
+
+		while ( (type = types[ i++ ]) ) {
+			handleObj = handleObjIn ?
+				jQuery.extend({}, handleObjIn) :
+				{ handler: handler, data: data };
+
+			// Namespaced event handlers
+			if ( type.indexOf(".") > -1 ) {
+				namespaces = type.split(".");
+				type = namespaces.shift();
+				handleObj.namespace = namespaces.slice(0).sort().join(".");
+
+			} else {
+				namespaces = [];
+				handleObj.namespace = "";
+			}
+
+			handleObj.type = type;
+			handleObj.guid = handler.guid;
+
+			// Get the current list of functions bound to this event
+			var handlers = events[ type ],
+				special = jQuery.event.special[ type ] || {};
+
+			// Init the event handler queue
+			if ( !handlers ) {
+				handlers = events[ type ] = [];
+
+				// Check for a special event handler
+				// Only use addEventListener/attachEvent if the special
+				// events handler returns false
+				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+					// Bind the global event handler to the element
+					if ( elem.addEventListener ) {
+						elem.addEventListener( type, eventHandle, false );
+
+					} else if ( elem.attachEvent ) {
+						elem.attachEvent( "on" + type, eventHandle );
+					}
+				}
+			}
+			
+			if ( special.add ) { 
+				special.add.call( elem, handleObj ); 
+
+				if ( !handleObj.handler.guid ) {
+					handleObj.handler.guid = handler.guid;
+				}
+			}
+
+			// Add the function to the element's handler list
+			handlers.push( handleObj );
+
+			// Keep track of which events have been used, for global triggering
+			jQuery.event.global[ type ] = true;
+		}
+
+		// Nullify elem to prevent memory leaks in IE
+		elem = null;
+	},
+
+	global: {},
+
+	// Detach an event or set of events from an element
+	remove: function( elem, types, handler, pos ) {
+		// don't do events on text and comment nodes
+		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+			return;
+		}
+
+		var ret, type, fn, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
+			elemData = jQuery.data( elem ),
+			events = elemData && elemData.events;
+
+		if ( !elemData || !events ) {
+			return;
+		}
+
+		// types is actually an event object here
+		if ( types && types.type ) {
+			handler = types.handler;
+			types = types.type;
+		}
+
+		// Unbind all events for the element
+		if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
+			types = types || "";
+
+			for ( type in events ) {
+				jQuery.event.remove( elem, type + types );
+			}
+
+			return;
+		}
+
+		// Handle multiple events separated by a space
+		// jQuery(...).unbind("mouseover mouseout", fn);
+		types = types.split(" ");
+
+		while ( (type = types[ i++ ]) ) {
+			origType = type;
+			handleObj = null;
+			all = type.indexOf(".") < 0;
+			namespaces = [];
+
+			if ( !all ) {
+				// Namespaced event handlers
+				namespaces = type.split(".");
+				type = namespaces.shift();
+
+				namespace = new RegExp("(^|\\.)" + 
+					jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)")
+			}
+
+			eventType = events[ type ];
+
+			if ( !eventType ) {
+				continue;
+			}
+
+			if ( !handler ) {
+				for ( var j = 0; j < eventType.length; j++ ) {
+					handleObj = eventType[ j ];
+
+					if ( all || namespace.test( handleObj.namespace ) ) {
+						jQuery.event.remove( elem, origType, handleObj.handler, j );
+						eventType.splice( j--, 1 );
+					}
+				}
+
+				continue;
+			}
+
+			special = jQuery.event.special[ type ] || {};
+
+			for ( var j = pos || 0; j < eventType.length; j++ ) {
+				handleObj = eventType[ j ];
+
+				if ( handler.guid === handleObj.guid ) {
+					// remove the given handler for the given type
+					if ( all || namespace.test( handleObj.namespace ) ) {
+						if ( pos == null ) {
+							eventType.splice( j--, 1 );
+						}
+
+						if ( special.remove ) {
+							special.remove.call( elem, handleObj );
+						}
+					}
+
+					if ( pos != null ) {
+						break;
+					}
+				}
+			}
+
+			// remove generic event handler if no more handlers exist
+			if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
+				if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
+					removeEvent( elem, type, elemData.handle );
+				}
+
+				ret = null;
+				delete events[ type ];
+			}
+		}
+
+		// Remove the expando if it's no longer used
+		if ( jQuery.isEmptyObject( events ) ) {
+			var handle = elemData.handle;
+			if ( handle ) {
+				handle.elem = null;
+			}
+
+			delete elemData.events;
+			delete elemData.handle;
+
+			if ( jQuery.isEmptyObject( elemData ) ) {
+				jQuery.removeData( elem );
+			}
+		}
+	},
+
+	// bubbling is internal
+	trigger: function( event, data, elem /*, bubbling */ ) {
+		// Event object or event type
+		var type = event.type || event,
+			bubbling = arguments[3];
+
+		if ( !bubbling ) {
+			event = typeof event === "object" ?
+				// jQuery.Event object
+				event[expando] ? event :
+				// Object literal
+				jQuery.extend( jQuery.Event(type), event ) :
+				// Just the event type (string)
+				jQuery.Event(type);
+
+			if ( type.indexOf("!") >= 0 ) {
+				event.type = type = type.slice(0, -1);
+				event.exclusive = true;
+			}
+
+			// Handle a global trigger
+			if ( !elem ) {
+				// Don't bubble custom events when global (to avoid too much overhead)
+				event.stopPropagation();
+
+				// Only trigger if we've ever bound an event for it
+				if ( jQuery.event.global[ type ] ) {
+					jQuery.each( jQuery.cache, function() {
+						if ( this.events && this.events[type] ) {
+							jQuery.event.trigger( event, data, this.handle.elem );
+						}
+					});
+				}
+			}
+
+			// Handle triggering a single element
+
+			// don't do events on text and comment nodes
+			if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
+				return undefined;
+			}
+
+			// Clean up in case it is reused
+			event.result = undefined;
+			event.target = elem;
+
+			// Clone the incoming data, if any
+			data = jQuery.makeArray( data );
+			data.unshift( event );
+		}
+
+		event.currentTarget = elem;
+
+		// Trigger the event, it is assumed that "handle" is a function
+		var handle = jQuery.data( elem, "handle" );
+		if ( handle ) {
+			handle.apply( elem, data );
+		}
+
+		var parent = elem.parentNode || elem.ownerDocument;
+
+		// Trigger an inline bound script
+		try {
+			if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
+				if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
+					event.result = false;
+				}
+			}
+
+		// prevent IE from throwing an error for some elements with some event types, see #3533
+		} catch (e) {}
+
+		if ( !event.isPropagationStopped() && parent ) {
+			jQuery.event.trigger( event, data, parent, true );
+
+		} else if ( !event.isDefaultPrevented() ) {
+			var target = event.target, old,
+				isClick = jQuery.nodeName(target, "a") && type === "click",
+				special = jQuery.event.special[ type ] || {};
+
+			if ( (!special._default || special._default.call( elem, event ) === false) && 
+				!isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
+
+				try {
+					if ( target[ type ] ) {
+						// Make sure that we don't accidentally re-trigger the onFOO events
+						old = target[ "on" + type ];
+
+						if ( old ) {
+							target[ "on" + type ] = null;
+						}
+
+						jQuery.event.triggered = true;
+						target[ type ]();
+					}
+
+				// prevent IE from throwing an error for some elements with some event types, see #3533
+				} catch (e) {}
+
+				if ( old ) {
+					target[ "on" + type ] = old;
+				}
+
+				jQuery.event.triggered = false;
+			}
+		}
+	},
+
+	handle: function( event ) {
+		var all, handlers, namespaces, namespace, events;
+
+		event = arguments[0] = jQuery.event.fix( event || window.event );
+		event.currentTarget = this;
+
+		// Namespaced event handlers
+		all = event.type.indexOf(".") < 0 && !event.exclusive;
+
+		if ( !all ) {
+			namespaces = event.type.split(".");
+			event.type = namespaces.shift();
+			namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
+		}
+
+		var events = jQuery.data(this, "events"), handlers = events[ event.type ];
+
+		if ( events && handlers ) {
+			// Clone the handlers to prevent manipulation
+			handlers = handlers.slice(0);
+
+			for ( var j = 0, l = handlers.length; j < l; j++ ) {
+				var handleObj = handlers[ j ];
+
+				// Filter the functions by class
+				if ( all || namespace.test( handleObj.namespace ) ) {
+					// Pass in a reference to the handler function itself
+					// So that we can later remove it
+					event.handler = handleObj.handler;
+					event.data = handleObj.data;
+					event.handleObj = handleObj;
+	
+					var ret = handleObj.handler.apply( this, arguments );
+
+					if ( ret !== undefined ) {
+						event.result = ret;
+						if ( ret === false ) {
+							event.preventDefault();
+							event.stopPropagation();
+						}
+					}
+
+					if ( event.isImmediatePropagationStopped() ) {
+						break;
+					}
+				}
+			}
+		}
+
+		return event.result;
+	},
+
+	props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+
+	fix: function( event ) {
+		if ( event[ expando ] ) {
+			return event;
+		}
+
+		// store a copy of the original event object
+		// and "clone" to set read-only properties
+		var originalEvent = event;
+		event = jQuery.Event( originalEvent );
+
+		for ( var i = this.props.length, prop; i; ) {
+			prop = this.props[ --i ];
+			event[ prop ] = originalEvent[ prop ];
+		}
+
+		// Fix target property, if necessary
+		if ( !event.target ) {
+			event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
+		}
+
+		// check if target is a textnode (safari)
+		if ( event.target.nodeType === 3 ) {
+			event.target = event.target.parentNode;
+		}
+
+		// Add relatedTarget, if necessary
+		if ( !event.relatedTarget && event.fromElement ) {
+			event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
+		}
+
+		// Calculate pageX/Y if missing and clientX/Y available
+		if ( event.pageX == null && event.clientX != null ) {
+			var doc = document.documentElement, body = document.body;
+			event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
+			event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
+		}
+
+		// Add which for key events
+		if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
+			event.which = event.charCode || event.keyCode;
+		}
+
+		// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
+		if ( !event.metaKey && event.ctrlKey ) {
+			event.metaKey = event.ctrlKey;
+		}
+
+		// Add which for click: 1 === left; 2 === middle; 3 === right
+		// Note: button is not normalized, so don't use it
+		if ( !event.which && event.button !== undefined ) {
+			event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+		}
+
+		return event;
+	},
+
+	// Deprecated, use jQuery.guid instead
+	guid: 1E8,
+
+	// Deprecated, use jQuery.proxy instead
+	proxy: jQuery.proxy,
+
+	special: {
+		ready: {
+			// Make sure the ready event is setup
+			setup: jQuery.bindReady,
+			teardown: jQuery.noop
+		},
+
+		live: {
+			add: function( handleObj ) {
+				jQuery.event.add( this, handleObj.origType, jQuery.extend({}, handleObj, {handler: liveHandler}) ); 
+			},
+
+			remove: function( handleObj ) {
+				var remove = true,
+					type = handleObj.origType.replace(rnamespaces, "");
+				
+				jQuery.each( jQuery.data(this, "events").live || [], function() {
+					if ( type === this.origType.replace(rnamespaces, "") ) {
+						remove = false;
+						return false;
+					}
+				});
+
+				if ( remove ) {
+					jQuery.event.remove( this, handleObj.origType, liveHandler );
+				}
+			}
+
+		},
+
+		beforeunload: {
+			setup: function( data, namespaces, eventHandle ) {
+				// We only want to do this special case on windows
+				if ( this.setInterval ) {
+					this.onbeforeunload = eventHandle;
+				}
+
+				return false;
+			},
+			teardown: function( namespaces, eventHandle ) {
+				if ( this.onbeforeunload === eventHandle ) {
+					this.onbeforeunload = null;
+				}
+			}
+		}
+	}
+};
+
+var removeEvent = document.removeEventListener ?
+	function( elem, type, handle ) {
+		elem.removeEventListener( type, handle, false );
+	} : 
+	function( elem, type, handle ) {
+		elem.detachEvent( "on" + type, handle );
+	};
+
+jQuery.Event = function( src ) {
+	// Allow instantiation without the 'new' keyword
+	if ( !this.preventDefault ) {
+		return new jQuery.Event( src );
+	}
+
+	// Event object
+	if ( src && src.type ) {
+		this.originalEvent = src;
+		this.type = src.type;
+	// Event type
+	} else {
+		this.type = src;
+	}
+
+	// timeStamp is buggy for some events on Firefox(#3843)
+	// So we won't rely on the native value
+	this.timeStamp = now();
+
+	// Mark it as fixed
+	this[ expando ] = true;
+};
+
+function returnFalse() {
+	return false;
+}
+function returnTrue() {
+	return true;
+}
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+	preventDefault: function() {
+		this.isDefaultPrevented = returnTrue;
+
+		var e = this.originalEvent;
+		if ( !e ) {
+			return;
+		}
+		
+		// if preventDefault exists run it on the original event
+		if ( e.preventDefault ) {
+			e.preventDefault();
+		}
+		// otherwise set the returnValue property of the original event to false (IE)
+		e.returnValue = false;
+	},
+	stopPropagation: function() {
+		this.isPropagationStopped = returnTrue;
+
+		var e = this.originalEvent;
+		if ( !e ) {
+			return;
+		}
+		// if stopPropagation exists run it on the original event
+		if ( e.stopPropagation ) {
+			e.stopPropagation();
+		}
+		// otherwise set the cancelBubble property of the original event to true (IE)
+		e.cancelBubble = true;
+	},
+	stopImmediatePropagation: function() {
+		this.isImmediatePropagationStopped = returnTrue;
+		this.stopPropagation();
+	},
+	isDefaultPrevented: returnFalse,
+	isPropagationStopped: returnFalse,
+	isImmediatePropagationStopped: returnFalse
+};
+
+// Checks if an event happened on an element within another element
+// Used in jQuery.event.special.mouseenter and mouseleave handlers
+var withinElement = function( event ) {
+	// Check if mouse(over|out) are still within the same parent element
+	var parent = event.relatedTarget;
+
+	// Firefox sometimes assigns relatedTarget a XUL element
+	// which we cannot access the parentNode property of
+	try {
+		// Traverse up the tree
+		while ( parent && parent !== this ) {
+			parent = parent.parentNode;
+		}
+
+		if ( parent !== this ) {
+			// set the correct event type
+			event.type = event.data;
+
+			// handle event if we actually just moused on to a non sub-element
+			jQuery.event.handle.apply( this, arguments );
+		}
+
+	// assuming we've left the element since we most likely mousedover a xul element
+	} catch(e) { }
+},
+
+// In case of event delegation, we only need to rename the event.type,
+// liveHandler will take care of the rest.
+delegate = function( event ) {
+	event.type = event.data;
+	jQuery.event.handle.apply( this, arguments );
+};
+
+// Create mouseenter and mouseleave events
+jQuery.each({
+	mouseenter: "mouseover",
+	mouseleave: "mouseout"
+}, function( orig, fix ) {
+	jQuery.event.special[ orig ] = {
+		setup: function( data ) {
+			jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
+		},
+		teardown: function( data ) {
+			jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
+		}
+	};
+});
+
+// submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+	jQuery.event.special.submit = {
+		setup: function( data, namespaces ) {
+			if ( this.nodeName.toLowerCase() !== "form" ) {
+				jQuery.event.add(this, "click.specialSubmit", function( e ) {
+					var elem = e.target, type = elem.type;
+
+					if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
+						return trigger( "submit", this, arguments );
+					}
+				});
+	 
+				jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
+					var elem = e.target, type = elem.type;
+
+					if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
+						return trigger( "submit", this, arguments );
+					}
+				});
+
+			} else {
+				return false;
+			}
+		},
+
+		teardown: function( namespaces ) {
+			jQuery.event.remove( this, ".specialSubmit" );
+		}
+	};
+
+}
+
+// change delegation, happens here so we have bind.
+if ( !jQuery.support.changeBubbles ) {
+
+	var formElems = /textarea|input|select/i,
+
+	changeFilters,
+
+	getVal = function( elem ) {
+		var type = elem.type, val = elem.value;
+
+		if ( type === "radio" || type === "checkbox" ) {
+			val = elem.checked;
+
+		} else if ( type === "select-multiple" ) {
+			val = elem.selectedIndex > -1 ?
+				jQuery.map( elem.options, function( elem ) {
+					return elem.selected;
+				}).join("-") :
+				"";
+
+		} else if ( elem.nodeName.toLowerCase() === "select" ) {
+			val = elem.selectedIndex;
+		}
+
+		return val;
+	},
+
+	testChange = function testChange( e ) {
+		var elem = e.target, data, val;
+
+		if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
+			return;
+		}
+
+		data = jQuery.data( elem, "_change_data" );
+		val = getVal(elem);
+
+		// the current data will be also retrieved by beforeactivate
+		if ( e.type !== "focusout" || elem.type !== "radio" ) {
+			jQuery.data( elem, "_change_data", val );
+		}
+		
+		if ( data === undefined || val === data ) {
+			return;
+		}
+
+		if ( data != null || val ) {
+			e.type = "change";
+			return jQuery.event.trigger( e, arguments[1], elem );
+		}
+	};
+
+	jQuery.event.special.change = {
+		filters: {
+			focusout: testChange, 
+
+			click: function( e ) {
+				var elem = e.target, type = elem.type;
+
+				if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
+					return testChange.call( this, e );
+				}
+			},
+
+			// Change has to be called before submit
+			// Keydown will be called before keypress, which is used in submit-event delegation
+			keydown: function( e ) {
+				var elem = e.target, type = elem.type;
+
+				if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
+					(e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
+					type === "select-multiple" ) {
+					return testChange.call( this, e );
+				}
+			},
+
+			// Beforeactivate happens also before the previous element is blurred
+			// with this event you can't trigger a change event, but you can store
+			// information/focus[in] is not needed anymore
+			beforeactivate: function( e ) {
+				var elem = e.target;
+				jQuery.data( elem, "_change_data", getVal(elem) );
+			}
+		},
+
+		setup: function( data, namespaces ) {
+			if ( this.type === "file" ) {
+				return false;
+			}
+
+			for ( var type in changeFilters ) {
+				jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
+			}
+
+			return formElems.test( this.nodeName );
+		},
+
+		teardown: function( namespaces ) {
+			jQuery.event.remove( this, ".specialChange" );
+
+			return formElems.test( this.nodeName );
+		}
+	};
+
+	changeFilters = jQuery.event.special.change.filters;
+}
+
+function trigger( type, elem, args ) {
+	args[0].type = type;
+	return jQuery.event.handle.apply( elem, args );
+}
+
+// Create "bubbling" focus and blur events
+if ( document.addEventListener ) {
+	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+		jQuery.event.special[ fix ] = {
+			setup: function() {
+				this.addEventListener( orig, handler, true );
+			}, 
+			teardown: function() { 
+				this.removeEventListener( orig, handler, true );
+			}
+		};
+
+		function handler( e ) { 
+			e = jQuery.event.fix( e );
+			e.type = fix;
+			return jQuery.event.handle.call( this, e );
+		}
+	});
+}
+
+jQuery.each(["bind", "one"], function( i, name ) {
+	jQuery.fn[ name ] = function( type, data, fn ) {
+		// Handle object literals
+		if ( typeof type === "object" ) {
+			for ( var key in type ) {
+				this[ name ](key, data, type[key], fn);
+			}
+			return this;
+		}
+		
+		if ( jQuery.isFunction( data ) ) {
+			fn = data;
+			data = undefined;
+		}
+
+		var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
+			jQuery( this ).unbind( event, handler );
+			return fn.apply( this, arguments );
+		}) : fn;
+
+		if ( type === "unload" && name !== "one" ) {
+			this.one( type, data, fn );
+
+		} else {
+			for ( var i = 0, l = this.length; i < l; i++ ) {
+				jQuery.event.add( this[i], type, handler, data );
+			}
+		}
+
+		return this;
+	};
+});
+
+jQuery.fn.extend({
+	unbind: function( type, fn ) {
+		// Handle object literals
+		if ( typeof type === "object" && !type.preventDefault ) {
+			for ( var key in type ) {
+				this.unbind(key, type[key]);
+			}
+
+		} else {
+			for ( var i = 0, l = this.length; i < l; i++ ) {
+				jQuery.event.remove( this[i], type, fn );
+			}
+		}
+
+		return this;
+	},
+	
+	delegate: function( selector, types, data, fn ) {
+		return this.live( types, data, fn, selector );
+	},
+	
+	undelegate: function( selector, types, fn ) {
+		if ( arguments.length === 0 ) {
+				return this.unbind( "live" );
+		
+		} else {
+			return this.die( types, null, fn, selector );
+		}
+	},
+	
+	trigger: function( type, data ) {
+		return this.each(function() {
+			jQuery.event.trigger( type, data, this );
+		});
+	},
+
+	triggerHandler: function( type, data ) {
+		if ( this[0] ) {
+			var event = jQuery.Event( type );
+			event.preventDefault();
+			event.stopPropagation();
+			jQuery.event.trigger( event, data, this[0] );
+			return event.result;
+		}
+	},
+
+	toggle: function( fn ) {
+		// Save reference to arguments for access in closure
+		var args = arguments, i = 1;
+
+		// link all the functions, so any of them can unbind this click handler
+		while ( i < args.length ) {
+			jQuery.proxy( fn, args[ i++ ] );
+		}
+
+		return this.click( jQuery.proxy( fn, function( event ) {
+			// Figure out which function to execute
+			var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+			jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+			// Make sure that clicks stop
+			event.preventDefault();
+
+			// and execute the function
+			return args[ lastToggle ].apply( this, arguments ) || false;
+		}));
+	},
+
+	hover: function( fnOver, fnOut ) {
+		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+	}
+});
+
+var liveMap = {
+	focus: "focusin",
+	blur: "focusout",
+	mouseenter: "mouseover",
+	mouseleave: "mouseout"
+};
+
+jQuery.each(["live", "die"], function( i, name ) {
+	jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
+		var type, i = 0, match, namespaces, preType,
+			selector = origSelector || this.selector,
+			context = origSelector ? this : jQuery( this.context );
+
+		if ( jQuery.isFunction( data ) ) {
+			fn = data;
+			data = undefined;
+		}
+
+		types = (types || "").split(" ");
+
+		while ( (type = types[ i++ ]) != null ) {
+			match = rnamespaces.exec( type );
+			namespaces = "";
+
+			if ( match )  {
+				namespaces = match[0];
+				type = type.replace( rnamespaces, "" );
+			}
+
+			if ( type === "hover" ) {
+				types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
+				continue;
+			}
+
+			preType = type;
+
+			if ( type === "focus" || type === "blur" ) {
+				types.push( liveMap[ type ] + namespaces );
+				type = type + namespaces;
+
+			} else {
+				type = (liveMap[ type ] || type) + namespaces;
+			}
+
+			if ( name === "live" ) {
+				// bind live handler
+				context.each(function(){
+					jQuery.event.add( this, liveConvert( type, selector ),
+						{ data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
+				});
+
+			} else {
+				// unbind live handler
+				context.unbind( liveConvert( type, selector ), fn );
+			}
+		}
+		
+		return this;
+	}
+});
+
+function liveHandler( event ) {
+	var stop, elems = [], selectors = [], args = arguments,
+		related, match, handleObj, elem, j, i, l, data,
+		events = jQuery.data( this, "events" );
+
+	// Make sure we avoid non-left-click bubbling in Firefox (#3861)
+	if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
+		return;
+	}
+
+	event.liveFired = this;
+
+	var live = events.live.slice(0);
+
+	for ( j = 0; j < live.length; j++ ) {
+		handleObj = live[j];
+
+		if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
+			selectors.push( handleObj.selector );
+
+		} else {
+			live.splice( j--, 1 );
+		}
+	}
+
+	match = jQuery( event.target ).closest( selectors, event.currentTarget );
+
+	for ( i = 0, l = match.length; i < l; i++ ) {
+		for ( j = 0; j < live.length; j++ ) {
+			handleObj = live[j];
+
+			if ( match[i].selector === handleObj.selector ) {
+				elem = match[i].elem;
+				related = null;
+
+				// Those two events require additional checking
+				if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
+					related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
+				}
+
+				if ( !related || related !== elem ) {
+					elems.push({ elem: elem, handleObj: handleObj });
+				}
+			}
+		}
+	}
+
+	for ( i = 0, l = elems.length; i < l; i++ ) {
+		match = elems[i];
+		event.currentTarget = match.elem;
+		event.data = match.handleObj.data;
+		event.handleObj = match.handleObj;
+
+		if ( match.handleObj.origHandler.apply( match.elem, args ) === false ) {
+			stop = false;
+			break;
+		}
+	}
+
+	return stop;
+}
+
+function liveConvert( type, selector ) {
+	return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
+}
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+	"change select submit keydown keypress keyup error").split(" "), function( i, name ) {
+
+	// Handle event binding
+	jQuery.fn[ name ] = function( fn ) {
+		return fn ? this.bind( name, fn ) : this.trigger( name );
+	};
+
+	if ( jQuery.attrFn ) {
+		jQuery.attrFn[ name ] = true;
+	}
+});
+
+// Prevent memory leaks in IE
+// Window isn't included so as not to unbind existing unload events
+// More info:
+//  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
+if ( window.attachEvent && !window.addEventListener ) {
+	window.attachEvent("onunload", function() {
+		for ( var id in jQuery.cache ) {
+			if ( jQuery.cache[ id ].handle ) {
+				// Try/Catch is to handle iframes being unloaded, see #4280
+				try {
+					jQuery.event.remove( jQuery.cache[ id ].handle.elem );
+				} catch(e) {}
+			}
+		}
+	});
+}
+/*!
+ * Sizzle CSS Selector Engine - v1.0
+ *  Copyright 2009, The Dojo Foundation
+ *  Released under the MIT, BSD, and GPL Licenses.
+ *  More information: http://sizzlejs.com/
+ */
+(function(){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+	done = 0,
+	toString = Object.prototype.toString,
+	hasDuplicate = false,
+	baseHasDuplicate = true;
+
+// Here we check if the JavaScript engine is using some sort of
+// optimization where it does not always call our comparision
+// function. If that is the case, discard the hasDuplicate value.
+//   Thus far that includes Google Chrome.
+[0, 0].sort(function(){
+	baseHasDuplicate = false;
+	return 0;
+});
+
+var Sizzle = function(selector, context, results, seed) {
+	results = results || [];
+	var origContext = context = context || document;
+
+	if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+		return [];
+	}
+	
+	if ( !selector || typeof selector !== "string" ) {
+		return results;
+	}
+
+	var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context),
+		soFar = selector;
+	
+	// Reset the position of the chunker regexp (start from head)
+	while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
+		soFar = m[3];
+		
+		parts.push( m[1] );
+		
+		if ( m[2] ) {
+			extra = m[3];
+			break;
+		}
+	}
+
+	if ( parts.length > 1 && origPOS.exec( selector ) ) {
+		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+			set = posProcess( parts[0] + parts[1], context );
+		} else {
+			set = Expr.relative[ parts[0] ] ?
+				[ context ] :
+				Sizzle( parts.shift(), context );
+
+			while ( parts.length ) {
+				selector = parts.shift();
+
+				if ( Expr.relative[ selector ] ) {
+					selector += parts.shift();
+				}
+				
+				set = posProcess( selector, set );
+			}
+		}
+	} else {
+		// Take a shortcut and set the context if the root selector is an ID
+		// (but not if it'll be faster if the inner selector is an ID)
+		if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+				Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+			var ret = Sizzle.find( parts.shift(), context, contextXML );
+			context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
+		}
+
+		if ( context ) {
+			var ret = seed ?
+				{ expr: parts.pop(), set: makeArray(seed) } :
+				Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
+			set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
+
+			if ( parts.length > 0 ) {
+				checkSet = makeArray(set);
+			} else {
+				prune = false;
+			}
+
+			while ( parts.length ) {
+				var cur = parts.pop(), pop = cur;
+
+				if ( !Expr.relative[ cur ] ) {
+					cur = "";
+				} else {
+					pop = parts.pop();
+				}
+
+				if ( pop == null ) {
+					pop = context;
+				}
+
+				Expr.relative[ cur ]( checkSet, pop, contextXML );
+			}
+		} else {
+			checkSet = parts = [];
+		}
+	}
+
+	if ( !checkSet ) {
+		checkSet = set;
+	}
+
+	if ( !checkSet ) {
+		Sizzle.error( cur || selector );
+	}
+
+	if ( toString.call(checkSet) === "[object Array]" ) {
+		if ( !prune ) {
+			results.push.apply( results, checkSet );
+		} else if ( context && context.nodeType === 1 ) {
+			for ( var i = 0; checkSet[i] != null; i++ ) {
+				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
+					results.push( set[i] );
+				}
+			}
+		} else {
+			for ( var i = 0; checkSet[i] != null; i++ ) {
+				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+					results.push( set[i] );
+				}
+			}
+		}
+	} else {
+		makeArray( checkSet, results );
+	}
+
+	if ( extra ) {
+		Sizzle( extra, origContext, results, seed );
+		Sizzle.uniqueSort( results );
+	}
+
+	return results;
+};
+
+Sizzle.uniqueSort = function(results){
+	if ( sortOrder ) {
+		hasDuplicate = baseHasDuplicate;
+		results.sort(sortOrder);
+
+		if ( hasDuplicate ) {
+			for ( var i = 1; i < results.length; i++ ) {
+				if ( results[i] === results[i-1] ) {
+					results.splice(i--, 1);
+				}
+			}
+		}
+	}
+
+	return results;
+};
+
+Sizzle.matches = function(expr, set){
+	return Sizzle(expr, null, null, set);
+};
+
+Sizzle.find = function(expr, context, isXML){
+	var set, match;
+
+	if ( !expr ) {
+		return [];
+	}
+
+	for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
+		var type = Expr.order[i], match;
+		
+		if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+			var left = match[1];
+			match.splice(1,1);
+
+			if ( left.substr( left.length - 1 ) !== "\\" ) {
+				match[1] = (match[1] || "").replace(/\\/g, "");
+				set = Expr.find[ type ]( match, context, isXML );
+				if ( set != null ) {
+					expr = expr.replace( Expr.match[ type ], "" );
+					break;
+				}
+			}
+		}
+	}
+
+	if ( !set ) {
+		set = context.getElementsByTagName("*");
+	}
+
+	return {set: set, expr: expr};
+};
+
+Sizzle.filter = function(expr, set, inplace, not){
+	var old = expr, result = [], curLoop = set, match, anyFound,
+		isXMLFilter = set && set[0] && isXML(set[0]);
+
+	while ( expr && set.length ) {
+		for ( var type in Expr.filter ) {
+			if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
+				var filter = Expr.filter[ type ], found, item, left = match[1];
+				anyFound = false;
+
+				match.splice(1,1);
+
+				if ( left.substr( left.length - 1 ) === "\\" ) {
+					continue;
+				}
+
+				if ( curLoop === result ) {
+					result = [];
+				}
+
+				if ( Expr.preFilter[ type ] ) {
+					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+					if ( !match ) {
+						anyFound = found = true;
+					} else if ( match === true ) {
+						continue;
+					}
+				}
+
+				if ( match ) {
+					for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
+						if ( item ) {
+							found = filter( item, match, i, curLoop );
+							var pass = not ^ !!found;
+
+							if ( inplace && found != null ) {
+								if ( pass ) {
+									anyFound = true;
+								} else {
+									curLoop[i] = false;
+								}
+							} else if ( pass ) {
+								result.push( item );
+								anyFound = true;
+							}
+						}
+					}
+				}
+
+				if ( found !== undefined ) {
+					if ( !inplace ) {
+						curLoop = result;
+					}
+
+					expr = expr.replace( Expr.match[ type ], "" );
+
+					if ( !anyFound ) {
+						return [];
+					}
+
+					break;
+				}
+			}
+		}
+
+		// Improper expression
+		if ( expr === old ) {
+			if ( anyFound == null ) {
+				Sizzle.error( expr );
+			} else {
+				break;
+			}
+		}
+
+		old = expr;
+	}
+
+	return curLoop;
+};
+
+Sizzle.error = function( msg ) {
+	throw "Syntax error, unrecognized expression: " + msg;
+};
+
+var Expr = Sizzle.selectors = {
+	order: [ "ID", "NAME", "TAG" ],
+	match: {
+		ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+		CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
+		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
+		TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
+		CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
+		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
+		PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
+	},
+	leftMatch: {},
+	attrMap: {
+		"class": "className",
+		"for": "htmlFor"
+	},
+	attrHandle: {
+		href: function(elem){
+			return elem.getAttribute("href");
+		}
+	},
+	relative: {
+		"+": function(checkSet, part){
+			var isPartStr = typeof part === "string",
+				isTag = isPartStr && !/\W/.test(part),
+				isPartStrNotTag = isPartStr && !isTag;
+
+			if ( isTag ) {
+				part = part.toLowerCase();
+			}
+
+			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+				if ( (elem = checkSet[i]) ) {
+					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+					checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
+						elem || false :
+						elem === part;
+				}
+			}
+
+			if ( isPartStrNotTag ) {
+				Sizzle.filter( part, checkSet, true );
+			}
+		},
+		">": function(checkSet, part){
+			var isPartStr = typeof part === "string";
+
+			if ( isPartStr && !/\W/.test(part) ) {
+				part = part.toLowerCase();
+
+				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+					var elem = checkSet[i];
+					if ( elem ) {
+						var parent = elem.parentNode;
+						checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
+					}
+				}
+			} else {
+				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+					var elem = checkSet[i];
+					if ( elem ) {
+						checkSet[i] = isPartStr ?
+							elem.parentNode :
+							elem.parentNode === part;
+					}
+				}
+
+				if ( isPartStr ) {
+					Sizzle.filter( part, checkSet, true );
+				}
+			}
+		},
+		"": function(checkSet, part, isXML){
+			var doneName = done++, checkFn = dirCheck;
+
+			if ( typeof part === "string" && !/\W/.test(part) ) {
+				var nodeCheck = part = part.toLowerCase();
+				checkFn = dirNodeCheck;
+			}
+
+			checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
+		},
+		"~": function(checkSet, part, isXML){
+			var doneName = done++, checkFn = dirCheck;
+
+			if ( typeof part === "string" && !/\W/.test(part) ) {
+				var nodeCheck = part = part.toLowerCase();
+				checkFn = dirNodeCheck;
+			}
+
+			checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
+		}
+	},
+	find: {
+		ID: function(match, context, isXML){
+			if ( typeof context.getElementById !== "undefined" && !isXML ) {
+				var m = context.getElementById(match[1]);
+				return m ? [m] : [];
+			}
+		},
+		NAME: function(match, context){
+			if ( typeof context.getElementsByName !== "undefined" ) {
+				var ret = [], results = context.getElementsByName(match[1]);
+
+				for ( var i = 0, l = results.length; i < l; i++ ) {
+					if ( results[i].getAttribute("name") === match[1] ) {
+						ret.push( results[i] );
+					}
+				}
+
+				return ret.length === 0 ? null : ret;
+			}
+		},
+		TAG: function(match, context){
+			return context.getElementsByTagName(match[1]);
+		}
+	},
+	preFilter: {
+		CLASS: function(match, curLoop, inplace, result, not, isXML){
+			match = " " + match[1].replace(/\\/g, "") + " ";
+
+			if ( isXML ) {
+				return match;
+			}
+
+			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+				if ( elem ) {
+					if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) {
+						if ( !inplace ) {
+							result.push( elem );
+						}
+					} else if ( inplace ) {
+						curLoop[i] = false;
+					}
+				}
+			}
+
+			return false;
+		},
+		ID: function(match){
+			return match[1].replace(/\\/g, "");
+		},
+		TAG: function(match, curLoop){
+			return match[1].toLowerCase();
+		},
+		CHILD: function(match){
+			if ( match[1] === "nth" ) {
+				// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+				var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
+					match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
+					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+				// calculate the numbers (first)n+(last) including if they are negative
+				match[2] = (test[1] + (test[2] || 1)) - 0;
+				match[3] = test[3] - 0;
+			}
+
+			// TODO: Move to normal caching system
+			match[0] = done++;
+
+			return match;
+		},
+		ATTR: function(match, curLoop, inplace, result, not, isXML){
+			var name = match[1].replace(/\\/g, "");
+			
+			if ( !isXML && Expr.attrMap[name] ) {
+				match[1] = Expr.attrMap[name];
+			}
+
+			if ( match[2] === "~=" ) {
+				match[4] = " " + match[4] + " ";
+			}
+
+			return match;
+		},
+		PSEUDO: function(match, curLoop, inplace, result, not){
+			if ( match[1] === "not" ) {
+				// If we're dealing with a complex expression, or a simple one
+				if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+					match[3] = Sizzle(match[3], null, null, curLoop);
+				} else {
+					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+					if ( !inplace ) {
+						result.push.apply( result, ret );
+					}
+					return false;
+				}
+			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+				return true;
+			}
+			
+			return match;
+		},
+		POS: function(match){
+			match.unshift( true );
+			return match;
+		}
+	},
+	filters: {
+		enabled: function(elem){
+			return elem.disabled === false && elem.type !== "hidden";
+		},
+		disabled: function(elem){
+			return elem.disabled === true;
+		},
+		checked: function(elem){
+			return elem.checked === true;
+		},
+		selected: function(elem){
+			// Accessing this property makes selected-by-default
+			// options in Safari work properly
+			elem.parentNode.selectedIndex;
+			return elem.selected === true;
+		},
+		parent: function(elem){
+			return !!elem.firstChild;
+		},
+		empty: function(elem){
+			return !elem.firstChild;
+		},
+		has: function(elem, i, match){
+			return !!Sizzle( match[3], elem ).length;
+		},
+		header: function(elem){
+			return /h\d/i.test( elem.nodeName );
+		},
+		text: function(elem){
+			return "text" === elem.type;
+		},
+		radio: function(elem){
+			return "radio" === elem.type;
+		},
+		checkbox: function(elem){
+			return "checkbox" === elem.type;
+		},
+		file: function(elem){
+			return "file" === elem.type;
+		},
+		password: function(elem){
+			return "password" === elem.type;
+		},
+		submit: function(elem){
+			return "submit" === elem.type;
+		},
+		image: function(elem){
+			return "image" === elem.type;
+		},
+		reset: function(elem){
+			return "reset" === elem.type;
+		},
+		button: function(elem){
+			return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
+		},
+		input: function(elem){
+			return /input|select|textarea|button/i.test(elem.nodeName);
+		}
+	},
+	setFilters: {
+		first: function(elem, i){
+			return i === 0;
+		},
+		last: function(elem, i, match, array){
+			return i === array.length - 1;
+		},
+		even: function(elem, i){
+			return i % 2 === 0;
+		},
+		odd: function(elem, i){
+			return i % 2 === 1;
+		},
+		lt: function(elem, i, match){
+			return i < match[3] - 0;
+		},
+		gt: function(elem, i, match){
+			return i > match[3] - 0;
+		},
+		nth: function(elem, i, match){
+			return match[3] - 0 === i;
+		},
+		eq: function(elem, i, match){
+			return match[3] - 0 === i;
+		}
+	},
+	filter: {
+		PSEUDO: function(elem, match, i, array){
+			var name = match[1], filter = Expr.filters[ name ];
+
+			if ( filter ) {
+				return filter( elem, i, match, array );
+			} else if ( name === "contains" ) {
+				return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
+			} else if ( name === "not" ) {
+				var not = match[3];
+
+				for ( var i = 0, l = not.length; i < l; i++ ) {
+					if ( not[i] === elem ) {
+						return false;
+					}
+				}
+
+				return true;
+			} else {
+				Sizzle.error( "Syntax error, unrecognized expression: " + name );
+			}
+		},
+		CHILD: function(elem, match){
+			var type = match[1], node = elem;
+			switch (type) {
+				case 'only':
+				case 'first':
+					while ( (node = node.previousSibling) )	 {
+						if ( node.nodeType === 1 ) { 
+							return false; 
+						}
+					}
+					if ( type === "first" ) { 
+						return true; 
+					}
+					node = elem;
+				case 'last':
+					while ( (node = node.nextSibling) )	 {
+						if ( node.nodeType === 1 ) { 
+							return false; 
+						}
+					}
+					return true;
+				case 'nth':
+					var first = match[2], last = match[3];
+
+					if ( first === 1 && last === 0 ) {
+						return true;
+					}
+					
+					var doneName = match[0],
+						parent = elem.parentNode;
+	
+					if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
+						var count = 0;
+						for ( node = parent.firstChild; node; node = node.nextSibling ) {
+							if ( node.nodeType === 1 ) {
+								node.nodeIndex = ++count;
+							}
+						} 
+						parent.sizcache = doneName;
+					}
+					
+					var diff = elem.nodeIndex - last;
+					if ( first === 0 ) {
+						return diff === 0;
+					} else {
+						return ( diff % first === 0 && diff / first >= 0 );
+					}
+			}
+		},
+		ID: function(elem, match){
+			return elem.nodeType === 1 && elem.getAttribute("id") === match;
+		},
+		TAG: function(elem, match){
+			return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
+		},
+		CLASS: function(elem, match){
+			return (" " + (elem.className || elem.getAttribute("class")) + " ")
+				.indexOf( match ) > -1;
+		},
+		ATTR: function(elem, match){
+			var name = match[1],
+				result = Expr.attrHandle[ name ] ?
+					Expr.attrHandle[ name ]( elem ) :
+					elem[ name ] != null ?
+						elem[ name ] :
+						elem.getAttribute( name ),
+				value = result + "",
+				type = match[2],
+				check = match[4];
+
+			return result == null ?
+				type === "!=" :
+				type === "=" ?
+				value === check :
+				type === "*=" ?
+				value.indexOf(check) >= 0 :
+				type === "~=" ?
+				(" " + value + " ").indexOf(check) >= 0 :
+				!check ?
+				value && result !== false :
+				type === "!=" ?
+				value !== check :
+				type === "^=" ?
+				value.indexOf(check) === 0 :
+				type === "$=" ?
+				value.substr(value.length - check.length) === check :
+				type === "|=" ?
+				value === check || value.substr(0, check.length + 1) === check + "-" :
+				false;
+		},
+		POS: function(elem, match, i, array){
+			var name = match[2], filter = Expr.setFilters[ name ];
+
+			if ( filter ) {
+				return filter( elem, i, match, array );
+			}
+		}
+	}
+};
+
+var origPOS = Expr.match.POS;
+
+for ( var type in Expr.match ) {
+	Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
+	Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){
+		return "\\" + (num - 0 + 1);
+	}));
+}
+
+var makeArray = function(array, results) {
+	array = Array.prototype.slice.call( array, 0 );
+
+	if ( results ) {
+		results.push.apply( results, array );
+		return results;
+	}
+	
+	return array;
+};
+
+// Perform a simple check to determine if the browser is capable of
+// converting a NodeList to an array using builtin methods.
+// Also verifies that the returned array holds DOM nodes
+// (which is not the case in the Blackberry browser)
+try {
+	Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
+
+// Provide a fallback method if it does not work
+} catch(e){
+	makeArray = function(array, results) {
+		var ret = results || [];
+
+		if ( toString.call(array) === "[object Array]" ) {
+			Array.prototype.push.apply( ret, array );
+		} else {
+			if ( typeof array.length === "number" ) {
+				for ( var i = 0, l = array.length; i < l; i++ ) {
+					ret.push( array[i] );
+				}
+			} else {
+				for ( var i = 0; array[i]; i++ ) {
+					ret.push( array[i] );
+				}
+			}
+		}
+
+		return ret;
+	};
+}
+
+var sortOrder;
+
+if ( document.documentElement.compareDocumentPosition ) {
+	sortOrder = function( a, b ) {
+		if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+			if ( a == b ) {
+				hasDuplicate = true;
+			}
+			return a.compareDocumentPosition ? -1 : 1;
+		}
+
+		var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
+		if ( ret === 0 ) {
+			hasDuplicate = true;
+		}
+		return ret;
+	};
+} else if ( "sourceIndex" in document.documentElement ) {
+	sortOrder = function( a, b ) {
+		if ( !a.sourceIndex || !b.sourceIndex ) {
+			if ( a == b ) {
+				hasDuplicate = true;
+			}
+			return a.sourceIndex ? -1 : 1;
+		}
+
+		var ret = a.sourceIndex - b.sourceIndex;
+		if ( ret === 0 ) {
+			hasDuplicate = true;
+		}
+		return ret;
+	};
+} else if ( document.createRange ) {
+	sortOrder = function( a, b ) {
+		if ( !a.ownerDocument || !b.ownerDocument ) {
+			if ( a == b ) {
+				hasDuplicate = true;
+			}
+			return a.ownerDocument ? -1 : 1;
+		}
+
+		var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
+		aRange.setStart(a, 0);
+		aRange.setEnd(a, 0);
+		bRange.setStart(b, 0);
+		bRange.setEnd(b, 0);
+		var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
+		if ( ret === 0 ) {
+			hasDuplicate = true;
+		}
+		return ret;
+	};
+}
+
+// Utility function for retreiving the text value of an array of DOM nodes
+function getText( elems ) {
+	var ret = "", elem;
+
+	for ( var i = 0; elems[i]; i++ ) {
+		elem = elems[i];
+
+		// Get the text from text nodes and CDATA nodes
+		if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
+			ret += elem.nodeValue;
+
+		// Traverse everything else, except comment nodes
+		} else if ( elem.nodeType !== 8 ) {
+			ret += getText( elem.childNodes );
+		}
+	}
+
+	return ret;
+}
+
+// Check to see if the browser returns elements by name when
+// querying by getElementById (and provide a workaround)
+(function(){
+	// We're going to inject a fake input element with a specified name
+	var form = document.createElement("div"),
+		id = "script" + (new Date).getTime();
+	form.innerHTML = "<a name='" + id + "'/>";
+
+	// Inject it into the root element, check its status, and remove it quickly
+	var root = document.documentElement;
+	root.insertBefore( form, root.firstChild );
+
+	// The workaround has to do additional checks after a getElementById
+	// Which slows things down for other browsers (hence the branching)
+	if ( document.getElementById( id ) ) {
+		Expr.find.ID = function(match, context, isXML){
+			if ( typeof context.getElementById !== "undefined" && !isXML ) {
+				var m = context.getElementById(match[1]);
+				return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
+			}
+		};
+
+		Expr.filter.ID = function(elem, match){
+			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+			return elem.nodeType === 1 && node && node.nodeValue === match;
+		};
+	}
+
+	root.removeChild( form );
+	root = form = null; // release memory in IE
+})();
+
+(function(){
+	// Check to see if the browser returns only elements
+	// when doing getElementsByTagName("*")
+
+	// Create a fake element
+	var div = document.createElement("div");
+	div.appendChild( document.createComment("") );
+
+	// Make sure no comments are found
+	if ( div.getElementsByTagName("*").length > 0 ) {
+		Expr.find.TAG = function(match, context){
+			var results = context.getElementsByTagName(match[1]);
+
+			// Filter out possible comments
+			if ( match[1] === "*" ) {
+				var tmp = [];
+
+				for ( var i = 0; results[i]; i++ ) {
+					if ( results[i].nodeType === 1 ) {
+						tmp.push( results[i] );
+					}
+				}
+
+				results = tmp;
+			}
+
+			return results;
+		};
+	}
+
+	// Check to see if an attribute returns normalized href attributes
+	div.innerHTML = "<a href='#'></a>";
+	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+			div.firstChild.getAttribute("href") !== "#" ) {
+		Expr.attrHandle.href = function(elem){
+			return elem.getAttribute("href", 2);
+		};
+	}
+
+	div = null; // release memory in IE
+})();
+
+if ( document.querySelectorAll ) {
+	(function(){
+		var oldSizzle = Sizzle, div = document.createElement("div");
+		div.innerHTML = "<p class='TEST'></p>";
+
+		// Safari can't handle uppercase or unicode characters when
+		// in quirks mode.
+		if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+			return;
+		}
+	
+		Sizzle = function(query, context, extra, seed){
+			context = context || document;
+
+			// Only use querySelectorAll on non-XML documents
+			// (ID selectors don't work in non-HTML documents)
+			if ( !seed && context.nodeType === 9 && !isXML(context) ) {
+				try {
+					return makeArray( context.querySelectorAll(query), extra );
+				} catch(e){}
+			}
+		
+			return oldSizzle(query, context, extra, seed);
+		};
+
+		for ( var prop in oldSizzle ) {
+			Sizzle[ prop ] = oldSizzle[ prop ];
+		}
+
+		div = null; // release memory in IE
+	})();
+}
+
+(function(){
+	var div = document.createElement("div");
+
+	div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+	// Opera can't find a second classname (in 9.6)
+	// Also, make sure that getElementsByClassName actually exists
+	if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
+		return;
+	}
+
+	// Safari caches class attributes, doesn't catch changes (in 3.2)
+	div.lastChild.className = "e";
+
+	if ( div.getElementsByClassName("e").length === 1 ) {
+		return;
+	}
+	
+	Expr.order.splice(1, 0, "CLASS");
+	Expr.find.CLASS = function(match, context, isXML) {
+		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+			return context.getElementsByClassName(match[1]);
+		}
+	};
+
+	div = null; // release memory in IE
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+		var elem = checkSet[i];
+		if ( elem ) {
+			elem = elem[dir];
+			var match = false;
+
+			while ( elem ) {
+				if ( elem.sizcache === doneName ) {
+					match = checkSet[elem.sizset];
+					break;
+				}
+
+				if ( elem.nodeType === 1 && !isXML ){
+					elem.sizcache = doneName;
+					elem.sizset = i;
+				}
+
+				if ( elem.nodeName.toLowerCase() === cur ) {
+					match = elem;
+					break;
+				}
+
+				elem = elem[dir];
+			}
+
+			checkSet[i] = match;
+		}
+	}
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+		var elem = checkSet[i];
+		if ( elem ) {
+			elem = elem[dir];
+			var match = false;
+
+			while ( elem ) {
+				if ( elem.sizcache === doneName ) {
+					match = checkSet[elem.sizset];
+					break;
+				}
+
+				if ( elem.nodeType === 1 ) {
+					if ( !isXML ) {
+						elem.sizcache = doneName;
+						elem.sizset = i;
+					}
+					if ( typeof cur !== "string" ) {
+						if ( elem === cur ) {
+							match = true;
+							break;
+						}
+
+					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+						match = elem;
+						break;
+					}
+				}
+
+				elem = elem[dir];
+			}
+
+			checkSet[i] = match;
+		}
+	}
+}
+
+var contains = document.compareDocumentPosition ? function(a, b){
+	return !!(a.compareDocumentPosition(b) & 16);
+} : function(a, b){
+	return a !== b && (a.contains ? a.contains(b) : true);
+};
+
+var isXML = function(elem){
+	// documentElement is verified for cases where it doesn't yet exist
+	// (such as loading iframes in IE - #4833) 
+	var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
+	return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+var posProcess = function(selector, context){
+	var tmpSet = [], later = "", match,
+		root = context.nodeType ? [context] : context;
+
+	// Position selectors must be done after the filter
+	// And so must :not(positional) so we move all PSEUDOs to the end
+	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+		later += match[0];
+		selector = selector.replace( Expr.match.PSEUDO, "" );
+	}
+
+	selector = Expr.relative[selector] ? selector + "*" : selector;
+
+	for ( var i = 0, l = root.length; i < l; i++ ) {
+		Sizzle( selector, root[i], tmpSet );
+	}
+
+	return Sizzle.filter( later, tmpSet );
+};
+
+// EXPOSE
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.filters;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = getText;
+jQuery.isXMLDoc = isXML;
+jQuery.contains = contains;
+
+return;
+
+window.Sizzle = Sizzle;
+
+})();
+var runtil = /Until$/,
+	rparentsprev = /^(?:parents|prevUntil|prevAll)/,
+	// Note: This RegExp should be improved, or likely pulled from Sizzle
+	rmultiselector = /,/,
+	slice = Array.prototype.slice;
+
+// Implement the identical functionality for filter and not
+var winnow = function( elements, qualifier, keep ) {
+	if ( jQuery.isFunction( qualifier ) ) {
+		return jQuery.grep(elements, function( elem, i ) {
+			return !!qualifier.call( elem, i, elem ) === keep;
+		});
+
+	} else if ( qualifier.nodeType ) {
+		return jQuery.grep(elements, function( elem, i ) {
+			return (elem === qualifier) === keep;
+		});
+
+	} else if ( typeof qualifier === "string" ) {
+		var filtered = jQuery.grep(elements, function( elem ) {
+			return elem.nodeType === 1;
+		});
+
+		if ( isSimple.test( qualifier ) ) {
+			return jQuery.filter(qualifier, filtered, !keep);
+		} else {
+			qualifier = jQuery.filter( qualifier, filtered );
+		}
+	}
+
+	return jQuery.grep(elements, function( elem, i ) {
+		return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
+	});
+};
+
+jQuery.fn.extend({
+	find: function( selector ) {
+		var ret = this.pushStack( "", "find", selector ), length = 0;
+
+		for ( var i = 0, l = this.length; i < l; i++ ) {
+			length = ret.length;
+			jQuery.find( selector, this[i], ret );
+
+			if ( i > 0 ) {
+				// Make sure that the results are unique
+				for ( var n = length; n < ret.length; n++ ) {
+					for ( var r = 0; r < length; r++ ) {
+						if ( ret[r] === ret[n] ) {
+							ret.splice(n--, 1);
+							break;
+						}
+					}
+				}
+			}
+		}
+
+		return ret;
+	},
+
+	has: function( target ) {
+		var targets = jQuery( target );
+		return this.filter(function() {
+			for ( var i = 0, l = targets.length; i < l; i++ ) {
+				if ( jQuery.contains( this, targets[i] ) ) {
+					return true;
+				}
+			}
+		});
+	},
+
+	not: function( selector ) {
+		return this.pushStack( winnow(this, selector, false), "not", selector);
+	},
+
+	filter: function( selector ) {
+		return this.pushStack( winnow(this, selector, true), "filter", selector );
+	},
+	
+	is: function( selector ) {
+		return !!selector && jQuery.filter( selector, this ).length > 0;
+	},
+
+	closest: function( selectors, context ) {
+		if ( jQuery.isArray( selectors ) ) {
+			var ret = [], cur = this[0], match, matches = {}, selector;
+
+			if ( cur && selectors.length ) {
+				for ( var i = 0, l = selectors.length; i < l; i++ ) {
+					selector = selectors[i];
+
+					if ( !matches[selector] ) {
+						matches[selector] = jQuery.expr.match.POS.test( selector ) ? 
+							jQuery( selector, context || this.context ) :
+							selector;
+					}
+				}
+
+				while ( cur && cur.ownerDocument && cur !== context ) {
+					for ( selector in matches ) {
+						match = matches[selector];
+
+						if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {
+							ret.push({ selector: selector, elem: cur });
+							delete matches[selector];
+						}
+					}
+					cur = cur.parentNode;
+				}
+			}
+
+			return ret;
+		}
+
+		var pos = jQuery.expr.match.POS.test( selectors ) ? 
+			jQuery( selectors, context || this.context ) : null;
+
+		return this.map(function( i, cur ) {
+			while ( cur && cur.ownerDocument && cur !== context ) {
+				if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) {
+					return cur;
+				}
+				cur = cur.parentNode;
+			}
+			return null;
+		});
+	},
+	
+	// Determine the position of an element within
+	// the matched set of elements
+	index: function( elem ) {
+		if ( !elem || typeof elem === "string" ) {
+			return jQuery.inArray( this[0],
+				// If it receives a string, the selector is used
+				// If it receives nothing, the siblings are used
+				elem ? jQuery( elem ) : this.parent().children() );
+		}
+		// Locate the position of the desired element
+		return jQuery.inArray(
+			// If it receives a jQuery object, the first element is used
+			elem.jquery ? elem[0] : elem, this );
+	},
+
+	add: function( selector, context ) {
+		var set = typeof selector === "string" ?
+				jQuery( selector, context || this.context ) :
+				jQuery.makeArray( selector ),
+			all = jQuery.merge( this.get(), set );
+
+		return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
+			all :
+			jQuery.unique( all ) );
+	},
+
+	andSelf: function() {
+		return this.add( this.prevObject );
+	}
+});
+
+// A painfully simple check to see if an element is disconnected
+// from a document (should be improved, where feasible).
+function isDisconnected( node ) {
+	return !node || !node.parentNode || node.parentNode.nodeType === 11;
+}
+
+jQuery.each({
+	parent: function( elem ) {
+		var parent = elem.parentNode;
+		return parent && parent.nodeType !== 11 ? parent : null;
+	},
+	parents: function( elem ) {
+		return jQuery.dir( elem, "parentNode" );
+	},
+	parentsUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "parentNode", until );
+	},
+	next: function( elem ) {
+		return jQuery.nth( elem, 2, "nextSibling" );
+	},
+	prev: function( elem ) {
+		return jQuery.nth( elem, 2, "previousSibling" );
+	},
+	nextAll: function( elem ) {
+		return jQuery.dir( elem, "nextSibling" );
+	},
+	prevAll: function( elem ) {
+		return jQuery.dir( elem, "previousSibling" );
+	},
+	nextUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "nextSibling", until );
+	},
+	prevUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "previousSibling", until );
+	},
+	siblings: function( elem ) {
+		return jQuery.sibling( elem.parentNode.firstChild, elem );
+	},
+	children: function( elem ) {
+		return jQuery.sibling( elem.firstChild );
+	},
+	contents: function( elem ) {
+		return jQuery.nodeName( elem, "iframe" ) ?
+			elem.contentDocument || elem.contentWindow.document :
+			jQuery.makeArray( elem.childNodes );
+	}
+}, function( name, fn ) {
+	jQuery.fn[ name ] = function( until, selector ) {
+		var ret = jQuery.map( this, fn, until );
+		
+		if ( !runtil.test( name ) ) {
+			selector = until;
+		}
+
+		if ( selector && typeof selector === "string" ) {
+			ret = jQuery.filter( selector, ret );
+		}
+
+		ret = this.length > 1 ? jQuery.unique( ret ) : ret;
+
+		if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
+			ret = ret.reverse();
+		}
+
+		return this.pushStack( ret, name, slice.call(arguments).join(",") );
+	};
+});
+
+jQuery.extend({
+	filter: function( expr, elems, not ) {
+		if ( not ) {
+			expr = ":not(" + expr + ")";
+		}
+
+		return jQuery.find.matches(expr, elems);
+	},
+	
+	dir: function( elem, dir, until ) {
+		var matched = [], cur = elem[dir];
+		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+			if ( cur.nodeType === 1 ) {
+				matched.push( cur );
+			}
+			cur = cur[dir];
+		}
+		return matched;
+	},
+
+	nth: function( cur, result, dir, elem ) {
+		result = result || 1;
+		var num = 0;
+
+		for ( ; cur; cur = cur[dir] ) {
+			if ( cur.nodeType === 1 && ++num === result ) {
+				break;
+			}
+		}
+
+		return cur;
+	},
+
+	sibling: function( n, elem ) {
+		var r = [];
+
+		for ( ; n; n = n.nextSibling ) {
+			if ( n.nodeType === 1 && n !== elem ) {
+				r.push( n );
+			}
+		}
+
+		return r;
+	}
+});
+var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
+	rleadingWhitespace = /^\s+/,
+	rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g,
+	rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,
+	rtagName = /<([\w:]+)/,
+	rtbody = /<tbody/i,
+	rhtml = /<|&#?\w+;/,
+	rnocache = /<script|<object|<embed|<option|<style/i,
+	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,  // checked="checked" or checked (html5)
+	fcloseTag = function( all, front, tag ) {
+		return rselfClosing.test( tag ) ?
+			all :
+			front + "></" + tag + ">";
+	},
+	wrapMap = {
+		option: [ 1, "<select multiple='multiple'>", "</select>" ],
+		legend: [ 1, "<fieldset>", "</fieldset>" ],
+		thead: [ 1, "<table>", "</table>" ],
+		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+		area: [ 1, "<map>", "</map>" ],
+		_default: [ 0, "", "" ]
+	};
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// IE can't serialize <link> and <script> tags normally
+if ( !jQuery.support.htmlSerialize ) {
+	wrapMap._default = [ 1, "div<div>", "</div>" ];
+}
+
+jQuery.fn.extend({
+	text: function( text ) {
+		if ( jQuery.isFunction(text) ) {
+			return this.each(function(i) {
+				var self = jQuery(this);
+				self.text( text.call(this, i, self.text()) );
+			});
+		}
+
+		if ( typeof text !== "object" && text !== undefined ) {
+			return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
+		}
+
+		return jQuery.text( this );
+	},
+
+	wrapAll: function( html ) {
+		if ( jQuery.isFunction( html ) ) {
+			return this.each(function(i) {
+				jQuery(this).wrapAll( html.call(this, i) );
+			});
+		}
+
+		if ( this[0] ) {
+			// The elements to wrap the target around
+			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+			if ( this[0].parentNode ) {
+				wrap.insertBefore( this[0] );
+			}
+
+			wrap.map(function() {
+				var elem = this;
+
+				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+					elem = elem.firstChild;
+				}
+
+				return elem;
+			}).append(this);
+		}
+
+		return this;
+	},
+
+	wrapInner: function( html ) {
+		if ( jQuery.isFunction( html ) ) {
+			return this.each(function(i) {
+				jQuery(this).wrapInner( html.call(this, i) );
+			});
+		}
+
+		return this.each(function() {
+			var self = jQuery( this ), contents = self.contents();
+
+			if ( contents.length ) {
+				contents.wrapAll( html );
+
+			} else {
+				self.append( html );
+			}
+		});
+	},
+
+	wrap: function( html ) {
+		return this.each(function() {
+			jQuery( this ).wrapAll( html );
+		});
+	},
+
+	unwrap: function() {
+		return this.parent().each(function() {
+			if ( !jQuery.nodeName( this, "body" ) ) {
+				jQuery( this ).replaceWith( this.childNodes );
+			}
+		}).end();
+	},
+
+	append: function() {
+		return this.domManip(arguments, true, function( elem ) {
+			if ( this.nodeType === 1 ) {
+				this.appendChild( elem );
+			}
+		});
+	},
+
+	prepend: function() {
+		return this.domManip(arguments, true, function( elem ) {
+			if ( this.nodeType === 1 ) {
+				this.insertBefore( elem, this.firstChild );
+			}
+		});
+	},
+
+	before: function() {
+		if ( this[0] && this[0].parentNode ) {
+			return this.domManip(arguments, false, function( elem ) {
+				this.parentNode.insertBefore( elem, this );
+			});
+		} else if ( arguments.length ) {
+			var set = jQuery(arguments[0]);
+			set.push.apply( set, this.toArray() );
+			return this.pushStack( set, "before", arguments );
+		}
+	},
+
+	after: function() {
+		if ( this[0] && this[0].parentNode ) {
+			return this.domManip(arguments, false, function( elem ) {
+				this.parentNode.insertBefore( elem, this.nextSibling );
+			});
+		} else if ( arguments.length ) {
+			var set = this.pushStack( this, "after", arguments );
+			set.push.apply( set, jQuery(arguments[0]).toArray() );
+			return set;
+		}
+	},
+	
+	// keepData is for internal use only--do not document
+	remove: function( selector, keepData ) {
+		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+			if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
+				if ( !keepData && elem.nodeType === 1 ) {
+					jQuery.cleanData( elem.getElementsByTagName("*") );
+					jQuery.cleanData( [ elem ] );
+				}
+
+				if ( elem.parentNode ) {
+					 elem.parentNode.removeChild( elem );
+				}
+			}
+		}
+		
+		return this;
+	},
+
+	empty: function() {
+		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+			// Remove element nodes and prevent memory leaks
+			if ( elem.nodeType === 1 ) {
+				jQuery.cleanData( elem.getElementsByTagName("*") );
+			}
+
+			// Remove any remaining nodes
+			while ( elem.firstChild ) {
+				elem.removeChild( elem.firstChild );
+			}
+		}
+		
+		return this;
+	},
+
+	clone: function( events ) {
+		// Do the clone
+		var ret = this.map(function() {
+			if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
+				// IE copies events bound via attachEvent when
+				// using cloneNode. Calling detachEvent on the
+				// clone will also remove the events from the orignal
+				// In order to get around this, we use innerHTML.
+				// Unfortunately, this means some modifications to
+				// attributes in IE that are actually only stored
+				// as properties will not be copied (such as the
+				// the name attribute on an input).
+				var html = this.outerHTML, ownerDocument = this.ownerDocument;
+				if ( !html ) {
+					var div = ownerDocument.createElement("div");
+					div.appendChild( this.cloneNode(true) );
+					html = div.innerHTML;
+				}
+
+				return jQuery.clean([html.replace(rinlinejQuery, "")
+					// Handle the case in IE 8 where action=/test/> self-closes a tag
+					.replace(/=([^="'>\s]+\/)>/g, '="$1">')
+					.replace(rleadingWhitespace, "")], ownerDocument)[0];
+			} else {
+				return this.cloneNode(true);
+			}
+		});
+
+		// Copy the events from the original to the clone
+		if ( events === true ) {
+			cloneCopyEvent( this, ret );
+			cloneCopyEvent( this.find("*"), ret.find("*") );
+		}
+
+		// Return the cloned set
+		return ret;
+	},
+
+	html: function( value ) {
+		if ( value === undefined ) {
+			return this[0] && this[0].nodeType === 1 ?
+				this[0].innerHTML.replace(rinlinejQuery, "") :
+				null;
+
+		// See if we can take a shortcut and just use innerHTML
+		} else if ( typeof value === "string" && !rnocache.test( value ) &&
+			(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
+			!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
+
+			value = value.replace(rxhtmlTag, fcloseTag);
+
+			try {
+				for ( var i = 0, l = this.length; i < l; i++ ) {
+					// Remove element nodes and prevent memory leaks
+					if ( this[i].nodeType === 1 ) {
+						jQuery.cleanData( this[i].getElementsByTagName("*") );
+						this[i].innerHTML = value;
+					}
+				}
+
+			// If using innerHTML throws an exception, use the fallback method
+			} catch(e) {
+				this.empty().append( value );
+			}
+
+		} else if ( jQuery.isFunction( value ) ) {
+			this.each(function(i){
+				var self = jQuery(this), old = self.html();
+				self.empty().append(function(){
+					return value.call( this, i, old );
+				});
+			});
+
+		} else {
+			this.empty().append( value );
+		}
+
+		return this;
+	},
+
+	replaceWith: function( value ) {
+		if ( this[0] && this[0].parentNode ) {
+			// Make sure that the elements are removed from the DOM before they are inserted
+			// this can help fix replacing a parent with child elements
+			if ( jQuery.isFunction( value ) ) {
+				return this.each(function(i) {
+					var self = jQuery(this), old = self.html();
+					self.replaceWith( value.call( this, i, old ) );
+				});
+			}
+
+			if ( typeof value !== "string" ) {
+				value = jQuery(value).detach();
+			}
+
+			return this.each(function() {
+				var next = this.nextSibling, parent = this.parentNode;
+
+				jQuery(this).remove();
+
+				if ( next ) {
+					jQuery(next).before( value );
+				} else {
+					jQuery(parent).append( value );
+				}
+			});
+		} else {
+			return this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value );
+		}
+	},
+
+	detach: function( selector ) {
+		return this.remove( selector, true );
+	},
+
+	domManip: function( args, table, callback ) {
+		var results, first, value = args[0], scripts = [], fragment, parent;
+
+		// We can't cloneNode fragments that contain checked, in WebKit
+		if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
+			return this.each(function() {
+				jQuery(this).domManip( args, table, callback, true );
+			});
+		}
+
+		if ( jQuery.isFunction(value) ) {
+			return this.each(function(i) {
+				var self = jQuery(this);
+				args[0] = value.call(this, i, table ? self.html() : undefined);
+				self.domManip( args, table, callback );
+			});
+		}
+
+		if ( this[0] ) {
+			parent = value && value.parentNode;
+
+			// If we're in a fragment, just use that instead of building a new one
+			if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
+				results = { fragment: parent };
+
+			} else {
+				results = buildFragment( args, this, scripts );
+			}
+			
+			fragment = results.fragment;
+			
+			if ( fragment.childNodes.length === 1 ) {
+				first = fragment = fragment.firstChild;
+			} else {
+				first = fragment.firstChild;
+			}
+
+			if ( first ) {
+				table = table && jQuery.nodeName( first, "tr" );
+
+				for ( var i = 0, l = this.length; i < l; i++ ) {
+					callback.call(
+						table ?
+							root(this[i], first) :
+							this[i],
+						i > 0 || results.cacheable || this.length > 1  ?
+							fragment.cloneNode(true) :
+							fragment
+					);
+				}
+			}
+
+			if ( scripts.length ) {
+				jQuery.each( scripts, evalScript );
+			}
+		}
+
+		return this;
+
+		function root( elem, cur ) {
+			return jQuery.nodeName(elem, "table") ?
+				(elem.getElementsByTagName("tbody")[0] ||
+				elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
+				elem;
+		}
+	}
+});
+
+function cloneCopyEvent(orig, ret) {
+	var i = 0;
+
+	ret.each(function() {
+		if ( this.nodeName !== (orig[i] && orig[i].nodeName) ) {
+			return;
+		}
+
+		var oldData = jQuery.data( orig[i++] ), curData = jQuery.data( this, oldData ), events = oldData && oldData.events;
+
+		if ( events ) {
+			delete curData.handle;
+			curData.events = {};
+
+			for ( var type in events ) {
+				for ( var handler in events[ type ] ) {
+					jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
+				}
+			}
+		}
+	});
+}
+
+function buildFragment( args, nodes, scripts ) {
+	var fragment, cacheable, cacheresults,
+		doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);
+
+	// Only cache "small" (1/2 KB) strings that are associated with the main document
+	// Cloning options loses the selected state, so don't cache them
+	// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
+	// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
+	if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
+		!rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {
+
+		cacheable = true;
+		cacheresults = jQuery.fragments[ args[0] ];
+		if ( cacheresults ) {
+			if ( cacheresults !== 1 ) {
+				fragment = cacheresults;
+			}
+		}
+	}
+
+	if ( !fragment ) {
+		fragment = doc.createDocumentFragment();
+		jQuery.clean( args, doc, fragment, scripts );
+	}
+
+	if ( cacheable ) {
+		jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
+	}
+
+	return { fragment: fragment, cacheable: cacheable };
+}
+
+jQuery.fragments = {};
+
+jQuery.each({
+	appendTo: "append",
+	prependTo: "prepend",
+	insertBefore: "before",
+	insertAfter: "after",
+	replaceAll: "replaceWith"
+}, function( name, original ) {
+	jQuery.fn[ name ] = function( selector ) {
+		var ret = [], insert = jQuery( selector ),
+			parent = this.length === 1 && this[0].parentNode;
+		
+		if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
+			insert[ original ]( this[0] );
+			return this;
+			
+		} else {
+			for ( var i = 0, l = insert.length; i < l; i++ ) {
+				var elems = (i > 0 ? this.clone(true) : this).get();
+				jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
+				ret = ret.concat( elems );
+			}
+		
+			return this.pushStack( ret, name, insert.selector );
+		}
+	};
+});
+
+jQuery.extend({
+	clean: function( elems, context, fragment, scripts ) {
+		context = context || document;
+
+		// !context.createElement fails in IE with an error but returns typeof 'object'
+		if ( typeof context.createElement === "undefined" ) {
+			context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+		}
+
+		var ret = [];
+
+		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+			if ( typeof elem === "number" ) {
+				elem += "";
+			}
+
+			if ( !elem ) {
+				continue;
+			}
+
+			// Convert html string into DOM nodes
+			if ( typeof elem === "string" && !rhtml.test( elem ) ) {
+				elem = context.createTextNode( elem );
+
+			} else if ( typeof elem === "string" ) {
+				// Fix "XHTML"-style tags in all browsers
+				elem = elem.replace(rxhtmlTag, fcloseTag);
+
+				// Trim whitespace, otherwise indexOf won't work as expected
+				var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
+					wrap = wrapMap[ tag ] || wrapMap._default,
+					depth = wrap[0],
+					div = context.createElement("div");
+
+				// Go to html and back, then peel off extra wrappers
+				div.innerHTML = wrap[1] + elem + wrap[2];
+
+				// Move to the right depth
+				while ( depth-- ) {
+					div = div.lastChild;
+				}
+
+				// Remove IE's autoinserted <tbody> from table fragments
+				if ( !jQuery.support.tbody ) {
+
+					// String was a <table>, *may* have spurious <tbody>
+					var hasBody = rtbody.test(elem),
+						tbody = tag === "table" && !hasBody ?
+							div.firstChild && div.firstChild.childNodes :
+
+							// String was a bare <thead> or <tfoot>
+							wrap[1] === "<table>" && !hasBody ?
+								div.childNodes :
+								[];
+
+					for ( var j = tbody.length - 1; j >= 0 ; --j ) {
+						if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
+							tbody[ j ].parentNode.removeChild( tbody[ j ] );
+						}
+					}
+
+				}
+
+				// IE completely kills leading whitespace when innerHTML is used
+				if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+					div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
+				}
+
+				elem = div.childNodes;
+			}
+
+			if ( elem.nodeType ) {
+				ret.push( elem );
+			} else {
+				ret = jQuery.merge( ret, elem );
+			}
+		}
+
+		if ( fragment ) {
+			for ( var i = 0; ret[i]; i++ ) {
+				if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
+					scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
+				
+				} else {
+					if ( ret[i].nodeType === 1 ) {
+						ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
+					}
+					fragment.appendChild( ret[i] );
+				}
+			}
+		}
+
+		return ret;
+	},
+	
+	cleanData: function( elems ) {
+		var data, id, cache = jQuery.cache,
+			special = jQuery.event.special,
+			deleteExpando = jQuery.support.deleteExpando;
+		
+		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+			id = elem[ jQuery.expando ];
+			
+			if ( id ) {
+				data = cache[ id ];
+				
+				if ( data.events ) {
+					for ( var type in data.events ) {
+						if ( special[ type ] ) {
+							jQuery.event.remove( elem, type );
+
+						} else {
+							removeEvent( elem, type, data.handle );
+						}
+					}
+				}
+				
+				if ( deleteExpando ) {
+					delete elem[ jQuery.expando ];
+
+				} else if ( elem.removeAttribute ) {
+					elem.removeAttribute( jQuery.expando );
+				}
+				
+				delete cache[ id ];
+			}
+		}
+	}
+});
+// exclude the following css properties to add px
+var rexclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
+	ralpha = /alpha\([^)]*\)/,
+	ropacity = /opacity=([^)]*)/,
+	rfloat = /float/i,
+	rdashAlpha = /-([a-z])/ig,
+	rupper = /([A-Z])/g,
+	rnumpx = /^-?\d+(?:px)?$/i,
+	rnum = /^-?\d/,
+
+	cssShow = { position: "absolute", visibility: "hidden", display:"block" },
+	cssWidth = [ "Left", "Right" ],
+	cssHeight = [ "Top", "Bottom" ],
+
+	// cache check for defaultView.getComputedStyle
+	getComputedStyle = document.defaultView && document.defaultView.getComputedStyle,
+	// normalize float css property
+	styleFloat = jQuery.support.cssFloat ? "cssFloat" : "styleFloat",
+	fcamelCase = function( all, letter ) {
+		return letter.toUpperCase();
+	};
+
+jQuery.fn.css = function( name, value ) {
+	return access( this, name, value, true, function( elem, name, value ) {
+		if ( value === undefined ) {
+			return jQuery.curCSS( elem, name );
+		}
+		
+		if ( typeof value === "number" && !rexclude.test(name) ) {
+			value += "px";
+		}
+
+		jQuery.style( elem, name, value );
+	});
+};
+
+jQuery.extend({
+	style: function( elem, name, value ) {
+		// don't set styles on text and comment nodes
+		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
+			return undefined;
+		}
+
+		// ignore negative width and height values #1599
+		if ( (name === "width" || name === "height") && parseFloat(value) < 0 ) {
+			value = undefined;
+		}
+
+		var style = elem.style || elem, set = value !== undefined;
+
+		// IE uses filters for opacity
+		if ( !jQuery.support.opacity && name === "opacity" ) {
+			if ( set ) {
+				// IE has trouble with opacity if it does not have layout
+				// Force it by setting the zoom level
+				style.zoom = 1;
+
+				// Set the alpha filter to set the opacity
+				var opacity = parseInt( value, 10 ) + "" === "NaN" ? "" : "alpha(opacity=" + value * 100 + ")";
+				var filter = style.filter || jQuery.curCSS( elem, "filter" ) || "";
+				style.filter = ralpha.test(filter) ? filter.replace(ralpha, opacity) : opacity;
+			}
+
+			return style.filter && style.filter.indexOf("opacity=") >= 0 ?
+				(parseFloat( ropacity.exec(style.filter)[1] ) / 100) + "":
+				"";
+		}
+
+		// Make sure we're using the right name for getting the float value
+		if ( rfloat.test( name ) ) {
+			name = styleFloat;
+		}
+
+		name = name.replace(rdashAlpha, fcamelCase);
+
+		if ( set ) {
+			style[ name ] = value;
+		}
+
+		return style[ name ];
+	},
+
+	css: function( elem, name, force, extra ) {
+		if ( name === "width" || name === "height" ) {
+			var val, props = cssShow, which = name === "width" ? cssWidth : cssHeight;
+
+			function getWH() {
+				val = name === "width" ? elem.offsetWidth : elem.offsetHeight;
+
+				if ( extra === "border" ) {
+					return;
+				}
+
+				jQuery.each( which, function() {
+					if ( !extra ) {
+						val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
+					}
+
+					if ( extra === "margin" ) {
+						val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
+					} else {
+						val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
+					}
+				});
+			}
+
+			if ( elem.offsetWidth !== 0 ) {
+				getWH();
+			} else {
+				jQuery.swap( elem, props, getWH );
+			}
+
+			return Math.max(0, Math.round(val));
+		}
+
+		return jQuery.curCSS( elem, name, force );
+	},
+
+	curCSS: function( elem, name, force ) {
+		var ret, style = elem.style, filter;
+
+		// IE uses filters for opacity
+		if ( !jQuery.support.opacity && name === "opacity" && elem.currentStyle ) {
+			ret = ropacity.test(elem.currentStyle.filter || "") ?
+				(parseFloat(RegExp.$1) / 100) + "" :
+				"";
+
+			return ret === "" ?
+				"1" :
+				ret;
+		}
+
+		// Make sure we're using the right name for getting the float value
+		if ( rfloat.test( name ) ) {
+			name = styleFloat;
+		}
+
+		if ( !force && style && style[ name ] ) {
+			ret = style[ name ];
+
+		} else if ( getComputedStyle ) {
+
+			// Only "float" is needed here
+			if ( rfloat.test( name ) ) {
+				name = "float";
+			}
+
+			name = name.replace( rupper, "-$1" ).toLowerCase();
+
+			var defaultView = elem.ownerDocument.defaultView;
+
+			if ( !defaultView ) {
+				return null;
+			}
+
+			var computedStyle = defaultView.getComputedStyle( elem, null );
+
+			if ( computedStyle ) {
+				ret = computedStyle.getPropertyValue( name );
+			}
+
+			// We should always get a number back from opacity
+			if ( name === "opacity" && ret === "" ) {
+				ret = "1";
+			}
+
+		} else if ( elem.currentStyle ) {
+			var camelCase = name.replace(rdashAlpha, fcamelCase);
+
+			ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
+
+			// From the awesome hack by Dean Edwards
+			// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+			// If we're not dealing with a regular pixel number
+			// but a number that has a weird ending, we need to convert it to pixels
+			if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
+				// Remember the original values
+				var left = style.left, rsLeft = elem.runtimeStyle.left;
+
+				// Put in the new values to get a computed value out
+				elem.runtimeStyle.left = elem.currentStyle.left;
+				style.left = camelCase === "fontSize" ? "1em" : (ret || 0);
+				ret = style.pixelLeft + "px";
+
+				// Revert the changed values
+				style.left = left;
+				elem.runtimeStyle.left = rsLeft;
+			}
+		}
+
+		return ret;
+	},
+
+	// A method for quickly swapping in/out CSS properties to get correct calculations
+	swap: function( elem, options, callback ) {
+		var old = {};
+
+		// Remember the old values, and insert the new ones
+		for ( var name in options ) {
+			old[ name ] = elem.style[ name ];
+			elem.style[ name ] = options[ name ];
+		}
+
+		callback.call( elem );
+
+		// Revert the old values
+		for ( var name in options ) {
+			elem.style[ name ] = old[ name ];
+		}
+	}
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+	jQuery.expr.filters.hidden = function( elem ) {
+		var width = elem.offsetWidth, height = elem.offsetHeight,
+			skip = elem.nodeName.toLowerCase() === "tr";
+
+		return width === 0 && height === 0 && !skip ?
+			true :
+			width > 0 && height > 0 && !skip ?
+				false :
+				jQuery.curCSS(elem, "display") === "none";
+	};
+
+	jQuery.expr.filters.visible = function( elem ) {
+		return !jQuery.expr.filters.hidden( elem );
+	};
+}
+var jsc = now(),
+	rscript = /<script(.|\s)*?\/script>/gi,
+	rselectTextarea = /select|textarea/i,
+	rinput = /color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,
+	jsre = /=\?(&|$)/,
+	rquery = /\?/,
+	rts = /(\?|&)_=.*?(&|$)/,
+	rurl = /^(\w+:)?\/\/([^\/?#]+)/,
+	r20 = /%20/g,
+
+	// Keep a copy of the old load method
+	_load = jQuery.fn.load;
+
+jQuery.fn.extend({
+	load: function( url, params, callback ) {
+		if ( typeof url !== "string" ) {
+			return _load.call( this, url );
+
+		// Don't do a request if no elements are being requested
+		} else if ( !this.length ) {
+			return this;
+		}
+
+		var off = url.indexOf(" ");
+		if ( off >= 0 ) {
+			var selector = url.slice(off, url.length);
+			url = url.slice(0, off);
+		}
+
+		// Default to a GET request
+		var type = "GET";
+
+		// If the second parameter was provided
+		if ( params ) {
+			// If it's a function
+			if ( jQuery.isFunction( params ) ) {
+				// We assume that it's the callback
+				callback = params;
+				params = null;
+
+			// Otherwise, build a param string
+			} else if ( typeof params === "object" ) {
+				params = jQuery.param( params, jQuery.ajaxSettings.traditional );
+				type = "POST";
+			}
+		}
+
+		var self = this;
+
+		// Request the remote document
+		jQuery.ajax({
+			url: url,
+			type: type,
+			dataType: "html",
+			data: params,
+			complete: function( res, status ) {
+				// If successful, inject the HTML into all the matched elements
+				if ( status === "success" || status === "notmodified" ) {
+					// See if a selector was specified
+					self.html( selector ?
+						// Create a dummy div to hold the results
+						jQuery("<div />")
+							// inject the contents of the document in, removing the scripts
+							// to avoid any 'Permission Denied' errors in IE
+							.append(res.responseText.replace(rscript, ""))
+
+							// Locate the specified elements
+							.find(selector) :
+
+						// If not, just inject the full result
+						res.responseText );
+				}
+
+				if ( callback ) {
+					self.each( callback, [res.responseText, status, res] );
+				}
+			}
+		});
+
+		return this;
+	},
+
+	serialize: function() {
+		return jQuery.param(this.serializeArray());
+	},
+	serializeArray: function() {
+		return this.map(function() {
+			return this.elements ? jQuery.makeArray(this.elements) : this;
+		})
+		.filter(function() {
+			return this.name && !this.disabled &&
+				(this.checked || rselectTextarea.test(this.nodeName) ||
+					rinput.test(this.type));
+		})
+		.map(function( i, elem ) {
+			var val = jQuery(this).val();
+
+			return val == null ?
+				null :
+				jQuery.isArray(val) ?
+					jQuery.map( val, function( val, i ) {
+						return { name: elem.name, value: val };
+					}) :
+					{ name: elem.name, value: val };
+		}).get();
+	}
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), function( i, o ) {
+	jQuery.fn[o] = function( f ) {
+		return this.bind(o, f);
+	};
+});
+
+jQuery.extend({
+
+	get: function( url, data, callback, type ) {
+		// shift arguments if data argument was omited
+		if ( jQuery.isFunction( data ) ) {
+			type = type || callback;
+			callback = data;
+			data = null;
+		}
+
+		return jQuery.ajax({
+			type: "GET",
+			url: url,
+			data: data,
+			success: callback,
+			dataType: type
+		});
+	},
+
+	getScript: function( url, callback ) {
+		return jQuery.get(url, null, callback, "script");
+	},
+
+	getJSON: function( url, data, callback ) {
+		return jQuery.get(url, data, callback, "json");
+	},
+
+	post: function( url, data, callback, type ) {
+		// shift arguments if data argument was omited
+		if ( jQuery.isFunction( data ) ) {
+			type = type || callback;
+			callback = data;
+			data = {};
+		}
+
+		return jQuery.ajax({
+			type: "POST",
+			url: url,
+			data: data,
+			success: callback,
+			dataType: type
+		});
+	},
+
+	ajaxSetup: function( settings ) {
+		jQuery.extend( jQuery.ajaxSettings, settings );
+	},
+
+	ajaxSettings: {
+		url: location.href,
+		global: true,
+		type: "GET",
+		contentType: "application/x-www-form-urlencoded",
+		processData: true,
+		async: true,
+		/*
+		timeout: 0,
+		data: null,
+		username: null,
+		password: null,
+		traditional: false,
+		*/
+		// Create the request object; Microsoft failed to properly
+		// implement the XMLHttpRequest in IE7 (can't request local files),
+		// so we use the ActiveXObject when it is available
+		// This function can be overriden by calling jQuery.ajaxSetup
+		xhr: window.XMLHttpRequest && (window.location.protocol !== "file:" || !window.ActiveXObject) ?
+			function() {
+				return new window.XMLHttpRequest();
+			} :
+			function() {
+				try {
+					return new window.ActiveXObject("Microsoft.XMLHTTP");
+				} catch(e) {}
+			},
+		accepts: {
+			xml: "application/xml, text/xml",
+			html: "text/html",
+			script: "text/javascript, application/javascript",
+			json: "application/json, text/javascript",
+			text: "text/plain",
+			_default: "*/*"
+		}
+	},
+
+	// Last-Modified header cache for next request
+	lastModified: {},
+	etag: {},
+
+	ajax: function( origSettings ) {
+		var s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings);
+		
+		var jsonp, status, data,
+			callbackContext = origSettings && origSettings.context || s,
+			type = s.type.toUpperCase();
+
+		// convert data if not already a string
+		if ( s.data && s.processData && typeof s.data !== "string" ) {
+			s.data = jQuery.param( s.data, s.traditional );
+		}
+
+		// Handle JSONP Parameter Callbacks
+		if ( s.dataType === "jsonp" ) {
+			if ( type === "GET" ) {
+				if ( !jsre.test( s.url ) ) {
+					s.url += (rquery.test( s.url ) ? "&" : "?") + (s.jsonp || "callback") + "=?";
+				}
+			} else if ( !s.data || !jsre.test(s.data) ) {
+				s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
+			}
+			s.dataType = "json";
+		}
+
+		// Build temporary JSONP function
+		if ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
+			jsonp = s.jsonpCallback || ("jsonp" + jsc++);
+
+			// Replace the =? sequence both in the query string and the data
+			if ( s.data ) {
+				s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
+			}
+
+			s.url = s.url.replace(jsre, "=" + jsonp + "$1");
+
+			// We need to make sure
+			// that a JSONP style response is executed properly
+			s.dataType = "script";
+
+			// Handle JSONP-style loading
+			window[ jsonp ] = window[ jsonp ] || function( tmp ) {
+				data = tmp;
+				success();
+				complete();
+				// Garbage collect
+				window[ jsonp ] = undefined;
+
+				try {
+					delete window[ jsonp ];
+				} catch(e) {}
+
+				if ( head ) {
+					head.removeChild( script );
+				}
+			};
+		}
+
+		if ( s.dataType === "script" && s.cache === null ) {
+			s.cache = false;
+		}
+
+		if ( s.cache === false && type === "GET" ) {
+			var ts = now();
+
+			// try replacing _= if it is there
+			var ret = s.url.replace(rts, "$1_=" + ts + "$2");
+
+			// if nothing was replaced, add timestamp to the end
+			s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
+		}
+
+		// If data is available, append data to url for get requests
+		if ( s.data && type === "GET" ) {
+			s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
+		}
+
+		// Watch for a new set of requests
+		if ( s.global && ! jQuery.active++ ) {
+			jQuery.event.trigger( "ajaxStart" );
+		}
+
+		// Matches an absolute URL, and saves the domain
+		var parts = rurl.exec( s.url ),
+			remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
+
+		// If we're requesting a remote document
+		// and trying to load JSON or Script with a GET
+		if ( s.dataType === "script" && type === "GET" && remote ) {
+			var head = document.getElementsByTagName("head")[0] || document.documentElement;
+			var script = document.createElement("script");
+			script.src = s.url;
+			if ( s.scriptCharset ) {
+				script.charset = s.scriptCharset;
+			}
+
+			// Handle Script loading
+			if ( !jsonp ) {
+				var done = false;
+
+				// Attach handlers for all browsers
+				script.onload = script.onreadystatechange = function() {
+					if ( !done && (!this.readyState ||
+							this.readyState === "loaded" || this.readyState === "complete") ) {
+						done = true;
+						success();
+						complete();
+
+						// Handle memory leak in IE
+						script.onload = script.onreadystatechange = null;
+						if ( head && script.parentNode ) {
+							head.removeChild( script );
+						}
+					}
+				};
+			}
+
+			// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
+			// This arises when a base node is used (#2709 and #4378).
+			head.insertBefore( script, head.firstChild );
+
+			// We handle everything using the script element injection
+			return undefined;
+		}
+
+		var requestDone = false;
+
+		// Create the request object
+		var xhr = s.xhr();
+
+		if ( !xhr ) {
+			return;
+		}
+
+		// Open the socket
+		// Passing null username, generates a login popup on Opera (#2865)
+		if ( s.username ) {
+			xhr.open(type, s.url, s.async, s.username, s.password);
+		} else {
+			xhr.open(type, s.url, s.async);
+		}
+
+		// Need an extra try/catch for cross domain requests in Firefox 3
+		try {
+			// Set the correct header, if data is being sent
+			if ( s.data || origSettings && origSettings.contentType ) {
+				xhr.setRequestHeader("Content-Type", s.contentType);
+			}
+
+			// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+			if ( s.ifModified ) {
+				if ( jQuery.lastModified[s.url] ) {
+					xhr.setRequestHeader("If-Modified-Since", jQuery.lastModified[s.url]);
+				}
+
+				if ( jQuery.etag[s.url] ) {
+					xhr.setRequestHeader("If-None-Match", jQuery.etag[s.url]);
+				}
+			}
+
+			// Set header so the called script knows that it's an XMLHttpRequest
+			// Only send the header if it's not a remote XHR
+			if ( !remote ) {
+				xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+			}
+
+			// Set the Accepts header for the server, depending on the dataType
+			xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
+				s.accepts[ s.dataType ] + ", */*" :
+				s.accepts._default );
+		} catch(e) {}
+
+		// Allow custom headers/mimetypes and early abort
+		if ( s.beforeSend && s.beforeSend.call(callbackContext, xhr, s) === false ) {
+			// Handle the global AJAX counter
+			if ( s.global && ! --jQuery.active ) {
+				jQuery.event.trigger( "ajaxStop" );
+			}
+
+			// close opended socket
+			xhr.abort();
+			return false;
+		}
+
+		if ( s.global ) {
+			trigger("ajaxSend", [xhr, s]);
+		}
+
+		// Wait for a response to come back
+		var onreadystatechange = xhr.onreadystatechange = function( isTimeout ) {
+			// The request was aborted
+			if ( !xhr || xhr.readyState === 0 || isTimeout === "abort" ) {
+				// Opera doesn't call onreadystatechange before this point
+				// so we simulate the call
+				if ( !requestDone ) {
+					complete();
+				}
+
+				requestDone = true;
+				if ( xhr ) {
+					xhr.onreadystatechange = jQuery.noop;
+				}
+
+			// The transfer is complete and the data is available, or the request timed out
+			} else if ( !requestDone && xhr && (xhr.readyState === 4 || isTimeout === "timeout") ) {
+				requestDone = true;
+				xhr.onreadystatechange = jQuery.noop;
+
+				status = isTimeout === "timeout" ?
+					"timeout" :
+					!jQuery.httpSuccess( xhr ) ?
+						"error" :
+						s.ifModified && jQuery.httpNotModified( xhr, s.url ) ?
+							"notmodified" :
+							"success";
+
+				var errMsg;
+
+				if ( status === "success" ) {
+					// Watch for, and catch, XML document parse errors
+					try {
+						// process the data (runs the xml through httpData regardless of callback)
+						data = jQuery.httpData( xhr, s.dataType, s );
+					} catch(err) {
+						status = "parsererror";
+						errMsg = err;
+					}
+				}
+
+				// Make sure that the request was successful or notmodified
+				if ( status === "success" || status === "notmodified" ) {
+					// JSONP handles its own success callback
+					if ( !jsonp ) {
+						success();
+					}
+				} else {
+					jQuery.handleError(s, xhr, status, errMsg);
+				}
+
+				// Fire the complete handlers
+				complete();
+
+				if ( isTimeout === "timeout" ) {
+					xhr.abort();
+				}
+
+				// Stop memory leaks
+				if ( s.async ) {
+					xhr = null;
+				}
+			}
+		};
+
+		// Override the abort handler, if we can (IE doesn't allow it, but that's OK)
+		// Opera doesn't fire onreadystatechange at all on abort
+		try {
+			var oldAbort = xhr.abort;
+			xhr.abort = function() {
+				if ( xhr ) {
+					oldAbort.call( xhr );
+				}
+
+				onreadystatechange( "abort" );
+			};
+		} catch(e) { }
+
+		// Timeout checker
+		if ( s.async && s.timeout > 0 ) {
+			setTimeout(function() {
+				// Check to see if the request is still happening
+				if ( xhr && !requestDone ) {
+					onreadystatechange( "timeout" );
+				}
+			}, s.timeout);
+		}
+
+		// Send the data
+		try {
+			xhr.send( type === "POST" || type === "PUT" || type === "DELETE" ? s.data : null );
+		} catch(e) {
+			jQuery.handleError(s, xhr, null, e);
+			// Fire the complete handlers
+			complete();
+		}
+
+		// firefox 1.5 doesn't fire statechange for sync requests
+		if ( !s.async ) {
+			onreadystatechange();
+		}
+
+		function success() {
+			// If a local callback was specified, fire it and pass it the data
+			if ( s.success ) {
+				s.success.call( callbackContext, data, status, xhr );
+			}
+
+			// Fire the global callback
+			if ( s.global ) {
+				trigger( "ajaxSuccess", [xhr, s] );
+			}
+		}
+
+		function complete() {
+			// Process result
+			if ( s.complete ) {
+				s.complete.call( callbackContext, xhr, status);
+			}
+
+			// The request was completed
+			if ( s.global ) {
+				trigger( "ajaxComplete", [xhr, s] );
+			}
+
+			// Handle the global AJAX counter
+			if ( s.global && ! --jQuery.active ) {
+				jQuery.event.trigger( "ajaxStop" );
+			}
+		}
+		
+		function trigger(type, args) {
+			(s.context ? jQuery(s.context) : jQuery.event).trigger(type, args);
+		}
+
+		// return XMLHttpRequest to allow aborting the request etc.
+		return xhr;
+	},
+
+	handleError: function( s, xhr, status, e ) {
+		// If a local callback was specified, fire it
+		if ( s.error ) {
+			s.error.call( s.context || s, xhr, status, e );
+		}
+
+		// Fire the global callback
+		if ( s.global ) {
+			(s.context ? jQuery(s.context) : jQuery.event).trigger( "ajaxError", [xhr, s, e] );
+		}
+	},
+
+	// Counter for holding the number of active queries
+	active: 0,
+
+	// Determines if an XMLHttpRequest was successful or not
+	httpSuccess: function( xhr ) {
+		try {
+			// IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
+			return !xhr.status && location.protocol === "file:" ||
+				// Opera returns 0 when status is 304
+				( xhr.status >= 200 && xhr.status < 300 ) ||
+				xhr.status === 304 || xhr.status === 1223 || xhr.status === 0;
+		} catch(e) {}
+
+		return false;
+	},
+
+	// Determines if an XMLHttpRequest returns NotModified
+	httpNotModified: function( xhr, url ) {
+		var lastModified = xhr.getResponseHeader("Last-Modified"),
+			etag = xhr.getResponseHeader("Etag");
+
+		if ( lastModified ) {
+			jQuery.lastModified[url] = lastModified;
+		}
+
+		if ( etag ) {
+			jQuery.etag[url] = etag;
+		}
+
+		// Opera returns 0 when status is 304
+		return xhr.status === 304 || xhr.status === 0;
+	},
+
+	httpData: function( xhr, type, s ) {
+		var ct = xhr.getResponseHeader("content-type") || "",
+			xml = type === "xml" || !type && ct.indexOf("xml") >= 0,
+			data = xml ? xhr.responseXML : xhr.responseText;
+
+		if ( xml && data.documentElement.nodeName === "parsererror" ) {
+			jQuery.error( "parsererror" );
+		}
+
+		// Allow a pre-filtering function to sanitize the response
+		// s is checked to keep backwards compatibility
+		if ( s && s.dataFilter ) {
+			data = s.dataFilter( data, type );
+		}
+
+		// The filter can actually parse the response
+		if ( typeof data === "string" ) {
+			// Get the JavaScript object, if JSON is used.
+			if ( type === "json" || !type && ct.indexOf("json") >= 0 ) {
+				data = jQuery.parseJSON( data );
+
+			// If the type is "script", eval it in global context
+			} else if ( type === "script" || !type && ct.indexOf("javascript") >= 0 ) {
+				jQuery.globalEval( data );
+			}
+		}
+
+		return data;
+	},
+
+	// Serialize an array of form elements or a set of
+	// key/values into a query string
+	param: function( a, traditional ) {
+		var s = [];
+		
+		// Set traditional to true for jQuery <= 1.3.2 behavior.
+		if ( traditional === undefined ) {
+			traditional = jQuery.ajaxSettings.traditional;
+		}
+		
+		// If an array was passed in, assume that it is an array of form elements.
+		if ( jQuery.isArray(a) || a.jquery ) {
+			// Serialize the form elements
+			jQuery.each( a, function() {
+				add( this.name, this.value );
+			});
+			
+		} else {
+			// If traditional, encode the "old" way (the way 1.3.2 or older
+			// did it), otherwise encode params recursively.
+			for ( var prefix in a ) {
+				buildParams( prefix, a[prefix] );
+			}
+		}
+
+		// Return the resulting serialization
+		return s.join("&").replace(r20, "+");
+
+		function buildParams( prefix, obj ) {
+			if ( jQuery.isArray(obj) ) {
+				// Serialize array item.
+				jQuery.each( obj, function( i, v ) {
+					if ( traditional || /\[\]$/.test( prefix ) ) {
+						// Treat each array item as a scalar.
+						add( prefix, v );
+					} else {
+						// If array item is non-scalar (array or object), encode its
+						// numeric index to resolve deserialization ambiguity issues.
+						// Note that rack (as of 1.0.0) can't currently deserialize
+						// nested arrays properly, and attempting to do so may cause
+						// a server error. Possible fixes are to modify rack's
+						// deserialization algorithm or to provide an option or flag
+						// to force array serialization to be shallow.
+						buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v );
+					}
+				});
+					
+			} else if ( !traditional && obj != null && typeof obj === "object" ) {
+				// Serialize object item.
+				jQuery.each( obj, function( k, v ) {
+					buildParams( prefix + "[" + k + "]", v );
+				});
+					
+			} else {
+				// Serialize scalar item.
+				add( prefix, obj );
+			}
+		}
+
+		function add( key, value ) {
+			// If value is a function, invoke it and return its value
+			value = jQuery.isFunction(value) ? value() : value;
+			s[ s.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value);
+		}
+	}
+});
+var elemdisplay = {},
+	rfxtypes = /toggle|show|hide/,
+	rfxnum = /^([+-]=)?([\d+-.]+)(.*)$/,
+	timerId,
+	fxAttrs = [
+		// height animations
+		[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
+		// width animations
+		[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
+		// opacity animations
+		[ "opacity" ]
+	];
+
+jQuery.fn.extend({
+	show: function( speed, callback ) {
+		if ( speed || speed === 0) {
+			return this.animate( genFx("show", 3), speed, callback);
+
+		} else {
+			for ( var i = 0, l = this.length; i < l; i++ ) {
+				var old = jQuery.data(this[i], "olddisplay");
+
+				this[i].style.display = old || "";
+
+				if ( jQuery.css(this[i], "display") === "none" ) {
+					var nodeName = this[i].nodeName, display;
+
+					if ( elemdisplay[ nodeName ] ) {
+						display = elemdisplay[ nodeName ];
+
+					} else {
+						var elem = jQuery("<" + nodeName + " />").appendTo("body");
+
+						display = elem.css("display");
+
+						if ( display === "none" ) {
+							display = "block";
+						}
+
+						elem.remove();
+
+						elemdisplay[ nodeName ] = display;
+					}
+
+					jQuery.data(this[i], "olddisplay", display);
+				}
+			}
+
+			// Set the display of the elements in a second loop
+			// to avoid the constant reflow
+			for ( var j = 0, k = this.length; j < k; j++ ) {
+				this[j].style.display = jQuery.data(this[j], "olddisplay") || "";
+			}
+
+			return this;
+		}
+	},
+
+	hide: function( speed, callback ) {
+		if ( speed || speed === 0 ) {
+			return this.animate( genFx("hide", 3), speed, callback);
+
+		} else {
+			for ( var i = 0, l = this.length; i < l; i++ ) {
+				var old = jQuery.data(this[i], "olddisplay");
+				if ( !old && old !== "none" ) {
+					jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
+				}
+			}
+
+			// Set the display of the elements in a second loop
+			// to avoid the constant reflow
+			for ( var j = 0, k = this.length; j < k; j++ ) {
+				this[j].style.display = "none";
+			}
+
+			return this;
+		}
+	},
+
+	// Save the old toggle function
+	_toggle: jQuery.fn.toggle,
+
+	toggle: function( fn, fn2 ) {
+		var bool = typeof fn === "boolean";
+
+		if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
+			this._toggle.apply( this, arguments );
+
+		} else if ( fn == null || bool ) {
+			this.each(function() {
+				var state = bool ? fn : jQuery(this).is(":hidden");
+				jQuery(this)[ state ? "show" : "hide" ]();
+			});
+
+		} else {
+			this.animate(genFx("toggle", 3), fn, fn2);
+		}
+
+		return this;
+	},
+
+	fadeTo: function( speed, to, callback ) {
+		return this.filter(":hidden").css("opacity", 0).show().end()
+					.animate({opacity: to}, speed, callback);
+	},
+
+	animate: function( prop, speed, easing, callback ) {
+		var optall = jQuery.speed(speed, easing, callback);
+
+		if ( jQuery.isEmptyObject( prop ) ) {
+			return this.each( optall.complete );
+		}
+
+		return this[ optall.queue === false ? "each" : "queue" ](function() {
+			var opt = jQuery.extend({}, optall), p,
+				hidden = this.nodeType === 1 && jQuery(this).is(":hidden"),
+				self = this;
+
+			for ( p in prop ) {
+				var name = p.replace(rdashAlpha, fcamelCase);
+
+				if ( p !== name ) {
+					prop[ name ] = prop[ p ];
+					delete prop[ p ];
+					p = name;
+				}
+
+				if ( prop[p] === "hide" && hidden || prop[p] === "show" && !hidden ) {
+					return opt.complete.call(this);
+				}
+
+				if ( ( p === "height" || p === "width" ) && this.style ) {
+					// Store display property
+					opt.display = jQuery.css(this, "display");
+
+					// Make sure that nothing sneaks out
+					opt.overflow = this.style.overflow;
+				}
+
+				if ( jQuery.isArray( prop[p] ) ) {
+					// Create (if needed) and add to specialEasing
+					(opt.specialEasing = opt.specialEasing || {})[p] = prop[p][1];
+					prop[p] = prop[p][0];
+				}
+			}
+
+			if ( opt.overflow != null ) {
+				this.style.overflow = "hidden";
+			}
+
+			opt.curAnim = jQuery.extend({}, prop);
+
+			jQuery.each( prop, function( name, val ) {
+				var e = new jQuery.fx( self, opt, name );
+
+				if ( rfxtypes.test(val) ) {
+					e[ val === "toggle" ? hidden ? "show" : "hide" : val ]( prop );
+
+				} else {
+					var parts = rfxnum.exec(val),
+						start = e.cur(true) || 0;
+
+					if ( parts ) {
+						var end = parseFloat( parts[2] ),
+							unit = parts[3] || "px";
+
+						// We need to compute starting value
+						if ( unit !== "px" ) {
+							self.style[ name ] = (end || 1) + unit;
+							start = ((end || 1) / e.cur(true)) * start;
+							self.style[ name ] = start + unit;
+						}
+
+						// If a +=/-= token was provided, we're doing a relative animation
+						if ( parts[1] ) {
+							end = ((parts[1] === "-=" ? -1 : 1) * end) + start;
+						}
+
+						e.custom( start, end, unit );
+
+					} else {
+						e.custom( start, val, "" );
+					}
+				}
+			});
+
+			// For JS strict compliance
+			return true;
+		});
+	},
+
+	stop: function( clearQueue, gotoEnd ) {
+		var timers = jQuery.timers;
+
+		if ( clearQueue ) {
+			this.queue([]);
+		}
+
+		this.each(function() {
+			// go in reverse order so anything added to the queue during the loop is ignored
+			for ( var i = timers.length - 1; i >= 0; i-- ) {
+				if ( timers[i].elem === this ) {
+					if (gotoEnd) {
+						// force the next step to be the last
+						timers[i](true);
+					}
+
+					timers.splice(i, 1);
+				}
+			}
+		});
+
+		// start the next in the queue if the last step wasn't forced
+		if ( !gotoEnd ) {
+			this.dequeue();
+		}
+
+		return this;
+	}
+
+});
+
+// Generate shortcuts for custom animations
+jQuery.each({
+	slideDown: genFx("show", 1),
+	slideUp: genFx("hide", 1),
+	slideToggle: genFx("toggle", 1),
+	fadeIn: { opacity: "show" },
+	fadeOut: { opacity: "hide" }
+}, function( name, props ) {
+	jQuery.fn[ name ] = function( speed, callback ) {
+		return this.animate( props, speed, callback );
+	};
+});
+
+jQuery.extend({
+	speed: function( speed, easing, fn ) {
+		var opt = speed && typeof speed === "object" ? speed : {
+			complete: fn || !fn && easing ||
+				jQuery.isFunction( speed ) && speed,
+			duration: speed,
+			easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
+		};
+
+		opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+			jQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;
+
+		// Queueing
+		opt.old = opt.complete;
+		opt.complete = function() {
+			if ( opt.queue !== false ) {
+				jQuery(this).dequeue();
+			}
+			if ( jQuery.isFunction( opt.old ) ) {
+				opt.old.call( this );
+			}
+		};
+
+		return opt;
+	},
+
+	easing: {
+		linear: function( p, n, firstNum, diff ) {
+			return firstNum + diff * p;
+		},
+		swing: function( p, n, firstNum, diff ) {
+			return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
+		}
+	},
+
+	timers: [],
+
+	fx: function( elem, options, prop ) {
+		this.options = options;
+		this.elem = elem;
+		this.prop = prop;
+
+		if ( !options.orig ) {
+			options.orig = {};
+		}
+	}
+
+});
+
+jQuery.fx.prototype = {
+	// Simple function for setting a style value
+	update: function() {
+		if ( this.options.step ) {
+			this.options.step.call( this.elem, this.now, this );
+		}
+
+		(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
+
+		// Set display property to block for height/width animations
+		if ( ( this.prop === "height" || this.prop === "width" ) && this.elem.style ) {
+			this.elem.style.display = "block";
+		}
+	},
+
+	// Get the current size
+	cur: function( force ) {
+		if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
+			return this.elem[ this.prop ];
+		}
+
+		var r = parseFloat(jQuery.css(this.elem, this.prop, force));
+		return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
+	},
+
+	// Start an animation from one number to another
+	custom: function( from, to, unit ) {
+		this.startTime = now();
+		this.start = from;
+		this.end = to;
+		this.unit = unit || this.unit || "px";
+		this.now = this.start;
+		this.pos = this.state = 0;
+
+		var self = this;
+		function t( gotoEnd ) {
+			return self.step(gotoEnd);
+		}
+
+		t.elem = this.elem;
+
+		if ( t() && jQuery.timers.push(t) && !timerId ) {
+			timerId = setInterval(jQuery.fx.tick, 13);
+		}
+	},
+
+	// Simple 'show' function
+	show: function() {
+		// Remember where we started, so that we can go back to it later
+		this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+		this.options.show = true;
+
+		// Begin the animation
+		// Make sure that we start at a small width/height to avoid any
+		// flash of content
+		this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());
+
+		// Start by showing the element
+		jQuery( this.elem ).show();
+	},
+
+	// Simple 'hide' function
+	hide: function() {
+		// Remember where we started, so that we can go back to it later
+		this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+		this.options.hide = true;
+
+		// Begin the animation
+		this.custom(this.cur(), 0);
+	},
+
+	// Each step of an animation
+	step: function( gotoEnd ) {
+		var t = now(), done = true;
+
+		if ( gotoEnd || t >= this.options.duration + this.startTime ) {
+			this.now = this.end;
+			this.pos = this.state = 1;
+			this.update();
+
+			this.options.curAnim[ this.prop ] = true;
+
+			for ( var i in this.options.curAnim ) {
+				if ( this.options.curAnim[i] !== true ) {
+					done = false;
+				}
+			}
+
+			if ( done ) {
+				if ( this.options.display != null ) {
+					// Reset the overflow
+					this.elem.style.overflow = this.options.overflow;
+
+					// Reset the display
+					var old = jQuery.data(this.elem, "olddisplay");
+					this.elem.style.display = old ? old : this.options.display;
+
+					if ( jQuery.css(this.elem, "display") === "none" ) {
+						this.elem.style.display = "block";
+					}
+				}
+
+				// Hide the element if the "hide" operation was done
+				if ( this.options.hide ) {
+					jQuery(this.elem).hide();
+				}
+
+				// Reset the properties, if the item has been hidden or shown
+				if ( this.options.hide || this.options.show ) {
+					for ( var p in this.options.curAnim ) {
+						jQuery.style(this.elem, p, this.options.orig[p]);
+					}
+				}
+
+				// Execute the complete function
+				this.options.complete.call( this.elem );
+			}
+
+			return false;
+
+		} else {
+			var n = t - this.startTime;
+			this.state = n / this.options.duration;
+
+			// Perform the easing function, defaults to swing
+			var specialEasing = this.options.specialEasing && this.options.specialEasing[this.prop];
+			var defaultEasing = this.options.easing || (jQuery.easing.swing ? "swing" : "linear");
+			this.pos = jQuery.easing[specialEasing || defaultEasing](this.state, n, 0, 1, this.options.duration);
+			this.now = this.start + ((this.end - this.start) * this.pos);
+
+			// Perform the next step of the animation
+			this.update();
+		}
+
+		return true;
+	}
+};
+
+jQuery.extend( jQuery.fx, {
+	tick: function() {
+		var timers = jQuery.timers;
+
+		for ( var i = 0; i < timers.length; i++ ) {
+			if ( !timers[i]() ) {
+				timers.splice(i--, 1);
+			}
+		}
+
+		if ( !timers.length ) {
+			jQuery.fx.stop();
+		}
+	},
+		
+	stop: function() {
+		clearInterval( timerId );
+		timerId = null;
+	},
+	
+	speeds: {
+		slow: 600,
+ 		fast: 200,
+ 		// Default speed
+ 		_default: 400
+	},
+
+	step: {
+		opacity: function( fx ) {
+			jQuery.style(fx.elem, "opacity", fx.now);
+		},
+
+		_default: function( fx ) {
+			if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
+				fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;
+			} else {
+				fx.elem[ fx.prop ] = fx.now;
+			}
+		}
+	}
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+	jQuery.expr.filters.animated = function( elem ) {
+		return jQuery.grep(jQuery.timers, function( fn ) {
+			return elem === fn.elem;
+		}).length;
+	};
+}
+
+function genFx( type, num ) {
+	var obj = {};
+
+	jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
+		obj[ this ] = type;
+	});
+
+	return obj;
+}
+if ( "getBoundingClientRect" in document.documentElement ) {
+	jQuery.fn.offset = function( options ) {
+		var elem = this[0];
+
+		if ( options ) { 
+			return this.each(function( i ) {
+				jQuery.offset.setOffset( this, options, i );
+			});
+		}
+
+		if ( !elem || !elem.ownerDocument ) {
+			return null;
+		}
+
+		if ( elem === elem.ownerDocument.body ) {
+			return jQuery.offset.bodyOffset( elem );
+		}
+
+		var box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement,
+			clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
+			top  = box.top  + (self.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop ) - clientTop,
+			left = box.left + (self.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;
+
+		return { top: top, left: left };
+	};
+
+} else {
+	jQuery.fn.offset = function( options ) {
+		var elem = this[0];
+
+		if ( options ) { 
+			return this.each(function( i ) {
+				jQuery.offset.setOffset( this, options, i );
+			});
+		}
+
+		if ( !elem || !elem.ownerDocument ) {
+			return null;
+		}
+
+		if ( elem === elem.ownerDocument.body ) {
+			return jQuery.offset.bodyOffset( elem );
+		}
+
+		jQuery.offset.initialize();
+
+		var offsetParent = elem.offsetParent, prevOffsetParent = elem,
+			doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,
+			body = doc.body, defaultView = doc.defaultView,
+			prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
+			top = elem.offsetTop, left = elem.offsetLeft;
+
+		while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
+			if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
+				break;
+			}
+
+			computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
+			top  -= elem.scrollTop;
+			left -= elem.scrollLeft;
+
+			if ( elem === offsetParent ) {
+				top  += elem.offsetTop;
+				left += elem.offsetLeft;
+
+				if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.nodeName)) ) {
+					top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
+					left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+				}
+
+				prevOffsetParent = offsetParent, offsetParent = elem.offsetParent;
+			}
+
+			if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
+				top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
+				left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+			}
+
+			prevComputedStyle = computedStyle;
+		}
+
+		if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
+			top  += body.offsetTop;
+			left += body.offsetLeft;
+		}
+
+		if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
+			top  += Math.max( docElem.scrollTop, body.scrollTop );
+			left += Math.max( docElem.scrollLeft, body.scrollLeft );
+		}
+
+		return { top: top, left: left };
+	};
+}
+
+jQuery.offset = {
+	initialize: function() {
+		var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.curCSS(body, "marginTop", true) ) || 0,
+			html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
+
+		jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );
+
+		container.innerHTML = html;
+		body.insertBefore( container, body.firstChild );
+		innerDiv = container.firstChild;
+		checkDiv = innerDiv.firstChild;
+		td = innerDiv.nextSibling.firstChild.firstChild;
+
+		this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
+		this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
+
+		checkDiv.style.position = "fixed", checkDiv.style.top = "20px";
+		// safari subtracts parent border width here which is 5px
+		this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
+		checkDiv.style.position = checkDiv.style.top = "";
+
+		innerDiv.style.overflow = "hidden", innerDiv.style.position = "relative";
+		this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
+
+		this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
+
+		body.removeChild( container );
+		body = container = innerDiv = checkDiv = table = td = null;
+		jQuery.offset.initialize = jQuery.noop;
+	},
+
+	bodyOffset: function( body ) {
+		var top = body.offsetTop, left = body.offsetLeft;
+
+		jQuery.offset.initialize();
+
+		if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
+			top  += parseFloat( jQuery.curCSS(body, "marginTop",  true) ) || 0;
+			left += parseFloat( jQuery.curCSS(body, "marginLeft", true) ) || 0;
+		}
+
+		return { top: top, left: left };
+	},
+	
+	setOffset: function( elem, options, i ) {
+		// set position first, in-case top/left are set even on static elem
+		if ( /static/.test( jQuery.curCSS( elem, "position" ) ) ) {
+			elem.style.position = "relative";
+		}
+		var curElem   = jQuery( elem ),
+			curOffset = curElem.offset(),
+			curTop    = parseInt( jQuery.curCSS( elem, "top",  true ), 10 ) || 0,
+			curLeft   = parseInt( jQuery.curCSS( elem, "left", true ), 10 ) || 0;
+
+		if ( jQuery.isFunction( options ) ) {
+			options = options.call( elem, i, curOffset );
+		}
+
+		var props = {
+			top:  (options.top  - curOffset.top)  + curTop,
+			left: (options.left - curOffset.left) + curLeft
+		};
+		
+		if ( "using" in options ) {
+			options.using.call( elem, props );
+		} else {
+			curElem.css( props );
+		}
+	}
+};
+
+
+jQuery.fn.extend({
+	position: function() {
+		if ( !this[0] ) {
+			return null;
+		}
+
+		var elem = this[0],
+
+		// Get *real* offsetParent
+		offsetParent = this.offsetParent(),
+
+		// Get correct offsets
+		offset       = this.offset(),
+		parentOffset = /^body|html$/i.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+		// Subtract element margins
+		// note: when an element has margin: auto the offsetLeft and marginLeft
+		// are the same in Safari causing offset.left to incorrectly be 0
+		offset.top  -= parseFloat( jQuery.curCSS(elem, "marginTop",  true) ) || 0;
+		offset.left -= parseFloat( jQuery.curCSS(elem, "marginLeft", true) ) || 0;
+
+		// Add offsetParent borders
+		parentOffset.top  += parseFloat( jQuery.curCSS(offsetParent[0], "borderTopWidth",  true) ) || 0;
+		parentOffset.left += parseFloat( jQuery.curCSS(offsetParent[0], "borderLeftWidth", true) ) || 0;
+
+		// Subtract the two offsets
+		return {
+			top:  offset.top  - parentOffset.top,
+			left: offset.left - parentOffset.left
+		};
+	},
+
+	offsetParent: function() {
+		return this.map(function() {
+			var offsetParent = this.offsetParent || document.body;
+			while ( offsetParent && (!/^body|html$/i.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
+				offsetParent = offsetParent.offsetParent;
+			}
+			return offsetParent;
+		});
+	}
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( ["Left", "Top"], function( i, name ) {
+	var method = "scroll" + name;
+
+	jQuery.fn[ method ] = function(val) {
+		var elem = this[0], win;
+		
+		if ( !elem ) {
+			return null;
+		}
+
+		if ( val !== undefined ) {
+			// Set the scroll offset
+			return this.each(function() {
+				win = getWindow( this );
+
+				if ( win ) {
+					win.scrollTo(
+						!i ? val : jQuery(win).scrollLeft(),
+						 i ? val : jQuery(win).scrollTop()
+					);
+
+				} else {
+					this[ method ] = val;
+				}
+			});
+		} else {
+			win = getWindow( elem );
+
+			// Return the scroll offset
+			return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
+				jQuery.support.boxModel && win.document.documentElement[ method ] ||
+					win.document.body[ method ] :
+				elem[ method ];
+		}
+	};
+});
+
+function getWindow( elem ) {
+	return ("scrollTo" in elem && elem.document) ?
+		elem :
+		elem.nodeType === 9 ?
+			elem.defaultView || elem.parentWindow :
+			false;
+}
+// Create innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each([ "Height", "Width" ], function( i, name ) {
+
+	var type = name.toLowerCase();
+
+	// innerHeight and innerWidth
+	jQuery.fn["inner" + name] = function() {
+		return this[0] ?
+			jQuery.css( this[0], type, false, "padding" ) :
+			null;
+	};
+
+	// outerHeight and outerWidth
+	jQuery.fn["outer" + name] = function( margin ) {
+		return this[0] ?
+			jQuery.css( this[0], type, false, margin ? "margin" : "border" ) :
+			null;
+	};
+
+	jQuery.fn[ type ] = function( size ) {
+		// Get window width or height
+		var elem = this[0];
+		if ( !elem ) {
+			return size == null ? null : this;
+		}
+		
+		if ( jQuery.isFunction( size ) ) {
+			return this.each(function( i ) {
+				var self = jQuery( this );
+				self[ type ]( size.call( this, i, self[ type ]() ) );
+			});
+		}
+
+		return ("scrollTo" in elem && elem.document) ? // does it walk and quack like a window?
+			// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
+			elem.document.compatMode === "CSS1Compat" && elem.document.documentElement[ "client" + name ] ||
+			elem.document.body[ "client" + name ] :
+
+			// Get document width or height
+			(elem.nodeType === 9) ? // is it a document
+				// Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+				Math.max(
+					elem.documentElement["client" + name],
+					elem.body["scroll" + name], elem.documentElement["scroll" + name],
+					elem.body["offset" + name], elem.documentElement["offset" + name]
+				) :
+
+				// Get or set width or height on the element
+				size === undefined ?
+					// Get width or height on the element
+					jQuery.css( elem, type ) :
+
+					// Set the width or height on the element (default to pixels if value is unitless)
+					this.css( type, typeof size === "string" ? size : size + "px" );
+	};
+
+});
+// Expose jQuery to the global object
+window.jQuery = window.$ = jQuery;
+
+})(window);

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/jquery.jstree.js
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/jquery.jstree.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/jquery.jstree.js	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,3091 @@
+/*
+ * jsTree 1.0-rc1
+ * http://jstree.com/
+ *
+ * Copyright (c) 2010 Ivan Bozhanov (vakata.com)
+ *
+ * Dual licensed under the MIT and GPL licenses (same as jQuery):
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ * Date: 2010-05-25
+ */
+
+/*global window : false, clearInterval: false, clearTimeout: false, document: false, setInterval: false, setTimeout: false, jQuery: false, navigator: false, XSLTProcessor: false, DOMParser: false, XMLSerializer: false*/
+
+"use strict";
+// Common functions not related to jsTree 
+// decided to move them to a `vakata` "namespace"
+(function ($) {
+	$.vakata = {};
+	// CSS related functions
+	$.vakata.css = {
+		get_css : function(rule_name, delete_flag, sheet) {
+			rule_name = rule_name.toLowerCase();
+			var css_rules = sheet.cssRules || sheet.rules,
+				j = 0;
+			do {
+				if(css_rules.length && j > css_rules.length + 5) { return false; }
+				if(css_rules[j].selectorText && css_rules[j].selectorText.toLowerCase() == rule_name) {
+					if(delete_flag === true) {
+						if(sheet.removeRule) { sheet.removeRule(j); }
+						if(sheet.deleteRule) { sheet.deleteRule(j); }
+						return true;
+					}
+					else { return css_rules[j]; }
+				}
+			}
+			while (css_rules[++j]);
+			return false;
+		},
+		add_css : function(rule_name, sheet) {
+			if($.jstree.css.get_css(rule_name, false, sheet)) { return false; }
+			if(sheet.insertRule) { sheet.insertRule(rule_name + ' { }', 0); } else { sheet.addRule(rule_name, null, 0); }
+			return $.vakata.css.get_css(rule_name);
+		},
+		remove_css : function(rule_name, sheet) { 
+			return $.vakata.css.get_css(rule_name, true, sheet); 
+		},
+		add_sheet : function(opts) {
+			var tmp;
+			if(opts.str) {
+				tmp = document.createElement("style");
+				tmp.setAttribute('type',"text/css");
+				if(tmp.styleSheet) {
+					document.getElementsByTagName("head")[0].appendChild(tmp);
+					tmp.styleSheet.cssText = opts.str;
+				}
+				else {
+					tmp.appendChild(document.createTextNode(opts.str));
+					document.getElementsByTagName("head")[0].appendChild(tmp);
+				}
+				return tmp.sheet || tmp.styleSheet;
+			}
+			if(opts.url) {
+				if(document.createStyleSheet) {
+					try { tmp = document.createStyleSheet(opts.url); } catch (e) { }
+				}
+				else {
+					tmp			= document.createElement('link');
+					tmp.rel		= 'stylesheet';
+					tmp.type	= 'text/css';
+					tmp.media	= "all";
+					tmp.href	= opts.url;
+					document.getElementsByTagName("head")[0].appendChild(tmp);
+					return tmp.styleSheet;
+				}
+			}
+		}
+	};
+})(jQuery);
+
+/* 
+ * jsTree core 1.0
+ */
+(function ($) {
+	// private variables 
+	var instances = [],			// instance array (used by $.jstree.reference/create/focused)
+		focused_instance = -1,	// the index in the instance array of the currently focused instance
+		plugins = {},			// list of included plugins
+		prepared_move = {};		// for the move plugin
+
+	// jQuery plugin wrapper (thanks to jquery UI widget function)
+	$.fn.jstree = function (settings) {
+		var isMethodCall = (typeof settings == 'string'), // is this a method call like $().jstree("open_node")
+			args = Array.prototype.slice.call(arguments, 1), 
+			returnValue = this;
+
+		// extend settings and allow for multiple hashes and metadata
+		if(!isMethodCall && $.meta) { args.push($.metadata.get(this).jstree); }
+		settings = !isMethodCall && args.length ? $.extend.apply(null, [true, settings].concat(args)) : settings;
+		// block calls to "private" methods
+		if(isMethodCall && settings.substring(0, 1) == '_') { return returnValue; }
+
+		// if a method call execute the method on all selected instances
+		if(isMethodCall) {
+			this.each(function() {
+				var instance = instances[$.data(this, "jstree-instance-id")],
+					methodValue = (instance && $.isFunction(instance[settings])) ? instance[settings].apply(instance, args) : instance;
+					if(typeof methodValue !== "undefined" && methodValue !== true && methodValue !== false) { returnValue = methodValue; return false; }
+			});
+		}
+		else {
+			this.each(function() {
+				var instance_id = $.data(this, "jstree-instance-id"),
+					s = false;
+				// if an instance already exists, destroy it first
+				if(instance_id && instances[instance_id]) { instances[instance_id].destroy(); }
+				// push a new empty object to the instances array
+				instance_id = parseInt(instances.push({}),10) - 1;
+				// store the jstree instance id to the container element
+				$.data(this, "jstree-instance-id", instance_id);
+				// clean up all plugins
+				settings.plugins = $.isArray(settings.plugins) ? settings.plugins : $.jstree.defaults.plugins;
+				if($.inArray("core", settings.plugins) === -1) { settings.plugins.unshift("core"); }
+				
+				// only unique plugins (NOT WORKING)
+				// settings.plugins = settings.plugins.sort().join(",,").replace(/(,|^)([^,]+)(,,\2)+(,|$)/g,"$1$2$4").replace(/,,+/g,",").replace(/,$/,"").split(",");
+
+				// extend defaults with passed data
+				s = $.extend(true, {}, $.jstree.defaults, settings);
+				s.plugins = settings.plugins;
+				// push the new object to the instances array (at the same time set the default classes to the container) and init
+				instances[instance_id] = new $.jstree._instance(instance_id, $(this).addClass("jstree jstree-" + instance_id), s); 
+				// init all activated plugins for this instance
+				$.each(instances[instance_id].get_settings().plugins, function (i, val) { instances[instance_id].data[val] = {}; });
+				$.each(instances[instance_id].get_settings().plugins, function (i, val) { if(plugins[val]) { plugins[val].__init.apply(instances[instance_id]); } });
+				// initialize the instance
+				instances[instance_id].init();
+			});
+		}
+		// return the jquery selection (or if it was a method call that returned a value - the returned value)
+		return returnValue;
+	};
+	// object to store exposed functions and objects
+	$.jstree = {
+		defaults : {
+			plugins : []
+		},
+		_focused : function () { return instances[focused_instance] || null; },
+		_reference : function (needle) { 
+			// get by instance id
+			if(instances[needle]) { return instances[needle]; }
+			// get by DOM (if still no luck - return null
+			var o = $(needle); 
+			if(!o.length && typeof needle === "string") { o = $("#" + needle); }
+			if(!o.length) { return null; }
+			return instances[o.closest(".jstree").data("jstree-instance-id")] || null; 
+		},
+		_instance : function (index, container, settings) { 
+			// for plugins to store data in
+			this.data = { core : {} };
+			this.get_settings	= function () { return $.extend(true, {}, settings); };
+			this.get_index		= function () { return index; };
+			this.get_container	= function () { return container; };
+			this._set_settings	= function (s) { 
+				settings = $.extend(true, {}, settings, s);
+			};
+		},
+		_fn : { },
+		plugin : function (pname, pdata) {
+			pdata = $.extend({}, {
+				__init		: $.noop, 
+				__destroy	: $.noop,
+				_fn			: {},
+				defaults	: false
+			}, pdata);
+			plugins[pname] = pdata;
+
+			$.jstree.defaults[pname] = pdata.defaults;
+			$.each(pdata._fn, function (i, val) {
+				val.plugin		= pname;
+				val.old			= $.jstree._fn[i];
+				$.jstree._fn[i] = function () {
+					var rslt,
+						func = val,
+						args = Array.prototype.slice.call(arguments),
+						stgs = this.get_settings(),
+						evnt = new $.Event("before.jstree"),
+						rlbk = false;
+
+					// Check if function belongs to the included plugins of this instance
+					do {
+						if(func && func.plugin && $.inArray(func.plugin, stgs.plugins) !== -1) { break; }
+						func = func.old;
+					} while(func);
+					if(!func) { return; }
+
+					// a chance to stop execution (or change arguments): 
+					// * just bind to jstree.before
+					// * check the additional data object (func property)
+					// * call event.stopImmediatePropagation()
+					// * return false (or an array of arguments)
+					rslt = this.get_container().triggerHandler(evnt, { "func" : i, "inst" : this, "args" : args });
+					if(rslt === false) { return; }
+					if(typeof rslt !== "undefined") { args = rslt; }
+
+					// context and function to trigger events, then finally call the function
+					rslt = func.apply(
+						$.extend({}, this, { 
+							__callback : function (data) { 
+								this.get_container().triggerHandler( i + '.jstree', { "inst" : this, "args" : args, "rslt" : data, "rlbk" : rlbk });
+							},
+							__rollback : function () { 
+								rlbk = this.get_rollback();
+								return rlbk;
+							},
+							__call_old : function (replace_arguments) {
+								return func.old.apply(this, (replace_arguments ? Array.prototype.slice.call(arguments, 1) : args ) );
+							}
+						}), args);
+
+					// return the result
+					return rslt;
+				};
+				$.jstree._fn[i].old = val.old;
+				$.jstree._fn[i].plugin = pname;
+			});
+		},
+		rollback : function (rb) {
+			if(rb) {
+				if(!$.isArray(rb)) { rb = [ rb ]; }
+				$.each(rb, function (i, val) {
+					instances[val.i].set_rollback(val.h, val.d);
+				});
+			}
+		}
+	};
+	// set the prototype for all instances
+	$.jstree._fn = $.jstree._instance.prototype = {};
+
+	// css functions - used internally
+
+	// load the css when DOM is ready
+	$(function() {
+		// code is copied form jQuery ($.browser is deprecated + there is a bug in IE)
+		var u = navigator.userAgent.toLowerCase(),
+			v = (u.match( /.+?(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],
+			css_string = '' + 
+				'.jstree ul, .jstree li { display:block; margin:0 0 0 0; padding:0 0 0 0; list-style-type:none; } ' + 
+				'.jstree li { display:block; min-height:18px; line-height:18px; white-space:nowrap; margin-left:18px; } ' + 
+				'.jstree > ul > li { margin-left:0px; } ' + 
+				'.jstree ins { display:inline-block; text-decoration:none; width:18px; height:18px; margin:0 0 0 0; padding:0; } ' + 
+				'.jstree a { display:inline-block; line-height:16px; height:16px; color:black; white-space:nowrap; text-decoration:none; padding:1px 2px; margin:0; } ' + 
+				'.jstree a:focus { outline: none; } ' + 
+				'.jstree a > ins { height:16px; width:16px; } ' + 
+				'.jstree a > .jstree-icon { margin-right:3px; } ' + 
+				'li.jstree-open > ul { display:block; } ' + 
+				'li.jstree-closed > ul { display:none; } ';
+		// Correct IE 6 (does not support the > CSS selector
+		if(/msie/.test(u) && parseInt(v, 10) == 6) { 
+			css_string += '' + 
+				'.jstree li { height:18px; margin-left:0; } ' + 
+				'.jstree li li { margin-left:18px; } ' + 
+				'li.jstree-open ul { display:block; } ' + 
+				'li.jstree-closed ul { display:none !important; } ' + 
+				'.jstree li a { display:inline; } ' + 
+				'.jstree li a ins { height:16px; width:16px; margin-right:3px; } ';
+		}
+		$.vakata.css.add_sheet({ str : css_string });
+	});
+
+	// core functions (open, close, create, update, delete)
+	$.jstree.plugin("core", {
+		__init : function () {
+			this.data.core.to_open = $.map($.makeArray(this.get_settings().core.initially_open), function (n) { return "#" + n.toString().replace(/^#/,"").replace('\\/','/').replace('/','\\/'); });
+		},
+		defaults : { 
+			html_titles	: false,
+			animation	: 500,
+			initially_open : []
+		},
+		_fn : { 
+			init	: function () { 
+				this.set_focus(); 
+				this.get_container().html("<ul><li class='jstree-last jstree-leaf'><ins>&#160;</ins><a class='jstree-loading' href='#'><ins class='jstree-icon'>&#160;</ins>Loading ...</a></li></ul>");
+				this.data.core.li_height = this.get_container().find("ul li.jstree-closed, ul li.jstree-leaf").eq(0).height() || 18;
+
+				this.get_container()
+					.delegate("li > ins", "click.jstree", $.proxy(function (event) {
+							var trgt = $(event.target);
+							if(trgt.is("ins") && event.pageY - trgt.offset().top < this.data.core.li_height) { this.toggle_node(trgt); }
+						}, this))
+					.bind("mousedown.jstree", $.proxy(function () { 
+							this.set_focus(); // This used to be setTimeout(set_focus,0) - why?
+						}, this))
+					.bind("dblclick.jstree", function (event) { 
+						var sel;
+						if(document.selection && document.selection.empty) { document.selection.empty(); }
+						else {
+							if(window.getSelection) {
+								sel = window.getSelection();
+								try { 
+									sel.removeAllRanges();
+									sel.collapse();
+								} catch (err) { }
+							}
+						}
+					});
+				this.__callback();
+				this.load_node(-1, function () { this.loaded(); this.reopen(); });
+			},
+			destroy	: function () { 
+				var i,
+					n = this.get_index(),
+					s = this.get_settings(),
+					_this = this;
+
+				$.each(s.plugins, function (i, val) {
+					plugins[val].__destroy.apply(_this);
+				});
+				this.__callback();
+				// set focus to another instance if this one is focused
+				if(this.is_focused()) { 
+					for(i in instances) { 
+						if(instances.hasOwnProperty(i) && i != n) { 
+							instances[i].set_focus(); 
+							break; 
+						} 
+					}
+				}
+				// if no other instance found
+				if(n === focused_instance) { focused_instance = -1; }
+				// remove all traces of jstree in the DOM (only the ones set using jstree*) and cleans all events
+				this.get_container()
+					.unbind(".jstree")
+					.undelegate(".jstree")
+					.removeData("jstree-instance-id")
+					.find("[class^='jstree']")
+						.andSelf()
+						.attr("class", function () { return this.className.replace(/jstree[^ ]*|$/ig,''); });
+				// remove the actual data
+				instances[n] = null;
+				delete instances[n];
+			},
+			save_opened : function () {
+				var _this = this;
+				this.data.core.to_open = [];
+				this.get_container().find(".jstree-open").each(function () { 
+					_this.data.core.to_open.push("#" + this.id.toString().replace(/^#/,"").replace('\\/','/').replace('/','\\/')); 
+				});
+				this.__callback(_this.data.core.to_open);
+			},
+			reopen : function (is_callback) {
+				var _this = this,
+					done = true,
+					current = [],
+					remaining = [];
+				if(!is_callback) { this.data.core.reopen = false; this.data.core.refreshing = true; }
+				if(this.data.core.to_open.length) {
+					$.each(this.data.core.to_open, function (i, val) {
+						if(val == "#") { return true; }
+						if($(val).length && $(val).is(".jstree-closed")) { current.push(val); }
+						else { remaining.push(val); }
+					});
+					if(current.length) {
+						this.data.core.to_open = remaining;
+						$.each(current, function (i, val) { 
+							_this.open_node(val, function () { _this.reopen(true); }, true); 
+						});
+						done = false;
+					}
+				}
+				if(done) { 
+					// TODO: find a more elegant approach to syncronizing returning requests
+					if(this.data.core.reopen) { clearTimeout(this.data.core.reopen); }
+					this.data.core.reopen = setTimeout(function () { _this.__callback({}, _this); }, 50);
+					this.data.core.refreshing = false;
+				}
+			},
+			refresh : function (obj) {
+				var _this = this;
+				this.save_opened();
+				if(!obj) { obj = -1; }
+				this.load_node(obj, function () { _this.__callback({}); _this.reopen(); });
+			},
+			// Dummy function to fire after the first load (so that there is a jstree.loaded event)
+			loaded	: function () { 
+				this.__callback(); 
+			},
+			// deal with focus
+			set_focus	: function () { 
+				var f = $.jstree._focused();
+				if(f && f !== this) {
+					f.get_container().removeClass("jstree-focused"); 
+				}
+				if(f !== this) {
+					this.get_container().addClass("jstree-focused"); 
+					focused_instance = this.get_index(); 
+				}
+				this.__callback();
+			},
+			is_focused	: function () { 
+				return focused_instance == this.get_index(); 
+			},
+
+			// traverse
+			_get_node		: function (obj) { 
+				var $obj = $(obj, this.get_container()); 
+				if($obj.is(".jstree") || obj == -1) { return -1; } 
+				$obj = $obj.closest("li", this.get_container()); 
+				return $obj.length ? $obj : false; 
+			},
+			_get_next		: function (obj, strict) {
+				obj = this._get_node(obj);
+				if(obj === -1) { return this.get_container().find("> ul > li:first-child"); }
+				if(!obj.length) { return false; }
+				if(strict) { return (obj.nextAll("li").size() > 0) ? obj.nextAll("li:eq(0)") : false; }
+
+				if(obj.hasClass("jstree-open")) { return obj.find("li:eq(0)"); }
+				else if(obj.nextAll("li").size() > 0) { return obj.nextAll("li:eq(0)"); }
+				else { return obj.parentsUntil(this.get_container(),"li").next("li").eq(0); }
+			},
+			_get_prev		: function (obj, strict) {
+				obj = this._get_node(obj);
+				if(obj === -1) { return this.get_container().find("> ul > li:last-child"); }
+				if(!obj.length) { return false; }
+				if(strict) { return (obj.prevAll("li").length > 0) ? obj.prevAll("li:eq(0)") : false; }
+
+				if(obj.prev("li").length) {
+					obj = obj.prev("li").eq(0);
+					while(obj.hasClass("jstree-open")) { obj = obj.children("ul:eq(0)").children("li:last"); }
+					return obj;
+				}
+				else { var o = obj.parentsUntil(this.get_container(),"li:eq(0)"); return o.length ? o : false; }
+			},
+			_get_parent		: function (obj) {
+				obj = this._get_node(obj);
+				if(obj == -1 || !obj.length) { return false; }
+				var o = obj.parentsUntil(this.get_container(), "li:eq(0)");
+				return o.length ? o : -1;
+			},
+			_get_children	: function (obj) {
+				obj = this._get_node(obj);
+				if(obj === -1) { return this.get_container().children("ul:eq(0)").children("li"); }
+				if(!obj.length) { return false; }
+				return obj.children("ul:eq(0)").children("li");
+			},
+			get_path		: function (obj, id_mode) {
+				var p = [],
+					_this = this;
+				obj = this._get_node(obj);
+				if(obj === -1 || !obj || !obj.length) { return false; }
+				obj.parentsUntil(this.get_container(), "li").each(function () {
+					p.push( id_mode ? this.id : _this.get_text(this) );
+				});
+				p.reverse();
+				p.push( id_mode ? obj.attr("id") : this.get_text(obj) );
+				return p;
+			},
+
+			// open/close
+			open_node	: function (obj, callback, skip_animation) {
+				obj = this._get_node(obj);
+				if(!obj.length) { return false; }
+				var s = skip_animation ? 0 : this.get_settings().core.animation,
+					t = this;
+				if(!this._is_loaded(obj)) {
+					obj.children("a").addClass("jstree-loading");
+					this.load_node(obj, function () { t.open_node(obj, callback, skip_animation); }, callback);
+				}
+				else {
+					if(s) { obj.children("ul").css("display","none"); }
+					obj.removeClass("jstree-closed").addClass("jstree-open").children("a").removeClass("jstree-loading");
+					if(s) { obj.children("ul").slideDown(s, function () { this.style.display = ""; }); }
+					this.__callback({ "obj" : obj });
+					if(callback) { callback.call(); }
+				}
+			},
+			close_node	: function (obj, skip_animation) {
+				obj = this._get_node(obj);
+				var s = skip_animation ? 0 : this.get_settings().core.animation;
+				if(!obj.length) { return false; }
+				if(s) { obj.children("ul").attr("style","display:block !important"); }
+				obj.removeClass("jstree-open").addClass("jstree-closed");
+				if(s) { obj.children("ul").slideUp(s, function () { this.style.display = ""; }); }
+				this.__callback({ "obj" : obj });
+			},
+			toggle_node	: function (obj) {
+				obj = this._get_node(obj);
+				if(obj.hasClass("jstree-closed")) { return this.open_node(obj); }
+				if(obj.hasClass("jstree-open")) { return this.close_node(obj); }
+			},
+			open_all	: function (obj, original_obj) {
+				obj = obj ? this._get_node(obj) : this.get_container();
+				if(original_obj) { 
+					obj = obj.find("li.jstree-closed");
+				}
+				else {
+					original_obj = obj;
+					if(obj.is(".jstree-closed")) { obj = obj.find("li.jstree-closed").andSelf(); }
+					else { obj = obj.find("li.jstree-closed"); }
+				}
+				var _this = this;
+				obj.each(function () { 
+					var __this = this; 
+					if(!_this._is_loaded(this)) { _this.open_node(this, function() { _this.open_all(__this, original_obj); }, true); }
+					else { _this.open_node(this, false, true); }
+				});
+				// so that callback is fired AFTER all nodes are open
+				if(original_obj.find('li.jstree-closed').length === 0) { this.__callback({ "obj" : original_obj }); }
+			},
+			close_all	: function (obj) {
+				var _this = this;
+				obj = obj ? this._get_node(obj) : this.get_container();
+				obj.find("li.jstree-open").andSelf().each(function () { _this.close_node(this); });
+				this.__callback({ "obj" : obj });
+			},
+			clean_node	: function (obj) {
+				obj = obj && obj != -1 ? $(obj) : this.get_container();
+				obj = obj.is("li") ? obj.find("li").andSelf() : obj.find("li");
+				obj.removeClass("jstree-last")
+					.filter("li:last-child").addClass("jstree-last").end()
+					.filter(":has(ul)")
+						.not(".jstree-open").removeClass("jstree-leaf").addClass("jstree-closed");
+				obj.not(".jstree-open, .jstree-closed").addClass("jstree-leaf");
+				this.__callback({ "obj" : obj });
+			},
+			// rollback
+			get_rollback : function () { 
+				this.__callback();
+				return { i : this.get_index(), h : this.get_container().children("ul").clone(true), d : this.data }; 
+			},
+			set_rollback : function (html, data) {
+				this.get_container().empty().append(html);
+				this.data = data;
+				this.__callback();
+			},
+			// Dummy functions to be overwritten by any datastore plugin included
+			load_node	: function (obj, s_call, e_call) { this.__callback({ "obj" : obj }); },
+			_is_loaded	: function (obj) { return true; },
+
+			// Basic operations: create
+			create_node	: function (obj, position, js, callback, is_loaded) {
+				obj = this._get_node(obj);
+				position = typeof position === "undefined" ? "last" : position;
+				var d = $("<li>"),
+					s = this.get_settings().core.html_titles,
+					tmp;
+
+				if(obj !== -1 && !obj.length) { return false; }
+				if(!is_loaded && !this._is_loaded(obj)) { this.load_node(obj, function () { this.create_node(obj, position, js, callback, true); }); return false; }
+
+				this.__rollback();
+
+				if(typeof js === "string") { js = { "data" : js }; }
+				if(!js) { js = {}; }
+				if(js.attr) { d.attr(js.attr); }
+				if(js.state) { d.addClass("jstree-" + js.state); }
+				if(!js.data) { js.data = "New node"; }
+				if(!$.isArray(js.data)) { tmp = js.data; js.data = []; js.data.push(tmp); }
+				$.each(js.data, function (i, m) {
+					tmp = $("<a>");
+					if($.isFunction(m)) { m = m.call(this, js); }
+					if(typeof m == "string") { tmp.attr('href','#')[ s ? "html" : "text" ](m); }
+					else {
+						if(!m.attr) { m.attr = {}; }
+						if(!m.attr.href) { m.attr.href = '#'; }
+						tmp.attr(m.attr)[ s ? "html" : "text" ](m.title);
+						if(m.language) { tmp.addClass(m.language); }
+					}
+					tmp.prepend("<ins class='jstree-icon'>&#160;</ins>");
+					if(m.icon) { 
+						if(m.icon.indexOf("/") === -1) { tmp.children("ins").addClass(m.icon); }
+						else { tmp.children("ins").css("background","url('" + m.icon + "') center center no-repeat;"); }
+					}
+					d.append(tmp);
+				});
+				d.prepend("<ins class='jstree-icon'>&#160;</ins>");
+				if(obj === -1) {
+					obj = this.get_container();
+					if(position === "before") { position = "first"; }
+					if(position === "after") { position = "last"; }
+				}
+				switch(position) {
+					case "before": obj.before(d); tmp = this._get_parent(obj); break;
+					case "after" : obj.after(d);  tmp = this._get_parent(obj); break;
+					case "inside":
+					case "first" :
+						if(!obj.children("ul").length) { obj.append("<ul>"); }
+						obj.children("ul").prepend(d);
+						tmp = obj;
+						break;
+					case "last":
+						if(!obj.children("ul").length) { obj.append("<ul>"); }
+						obj.children("ul").append(d);
+						tmp = obj;
+						break;
+					default:
+						if(!obj.children("ul").length) { obj.append("<ul>"); }
+						if(!position) { position = 0; }
+						tmp = obj.children("ul").children("li").eq(position);
+						if(tmp.length) { tmp.before(d); }
+						else { obj.children("ul").append(d); }
+						tmp = obj;
+						break;
+				}
+				if(tmp === -1 || tmp.get(0) === this.get_container().get(0)) { tmp = -1; }
+				this.clean_node(tmp);
+				this.__callback({ "obj" : d, "parent" : tmp });
+				if(callback) { callback.call(this, d); }
+				return d;
+			},
+			// Basic operations: rename (deal with text)
+			get_text	: function (obj) {
+				obj = this._get_node(obj);
+				if(!obj.length) { return false; }
+				var s = this.get_settings().core.html_titles;
+				obj = obj.children("a:eq(0)");
+				if(s) {
+					obj = obj.clone();
+					obj.children("INS").remove();
+					return obj.html();
+				}
+				else {
+					obj = obj.contents().filter(function() { return this.nodeType == 3; })[0];
+					return obj.nodeValue;
+				}
+			},
+			set_text	: function (obj, val) {
+				obj = this._get_node(obj);
+				if(!obj.length) { return false; }
+				obj = obj.children("a:eq(0)");
+				if(this.get_settings().core.html_titles) {
+					var tmp = obj.children("INS").clone();
+					obj.html(val).prepend(tmp);
+					this.__callback({ "obj" : obj, "name" : val });
+					return true;
+				}
+				else {
+					obj = obj.contents().filter(function() { return this.nodeType == 3; })[0];
+					this.__callback({ "obj" : obj, "name" : val });
+					return (obj.nodeValue = val);
+				}
+			},
+			rename_node : function (obj, val) {
+				obj = this._get_node(obj);
+				this.__rollback();
+				if(obj && obj.length && this.set_text.apply(this, Array.prototype.slice.call(arguments))) { this.__callback({ "obj" : obj, "name" : val }); }
+			},
+			// Basic operations: deleting nodes
+			delete_node : function (obj) {
+				obj = this._get_node(obj);
+				if(!obj.length) { return false; }
+				this.__rollback();
+				var p = this._get_parent(obj);
+				this.deselect_node(obj);
+				obj = obj.remove();
+				if(p !== -1 && p.find("> ul > li").length === 0) {
+					p.removeClass("jstree-open, jstree-closed").addClass("jstree-leaf");
+				}
+				this.clean_node(p);
+				this.__callback({ "obj" : obj });
+				return obj;
+			},
+			prepare_move : function (o, r, pos, cb, is_cb) {
+				var p = {};
+
+				p.ot = $.jstree._reference(p.o) || this;
+				p.o = p.ot._get_node(o);
+				p.r = r === - 1 ? -1 : this._get_node(r);
+				p.p = (typeof p === "undefined") ? "last" : pos; // TODO: move to a setting
+				if(!is_cb && prepared_move.o && prepared_move.o[0] === p.o[0] && prepared_move.r[0] === p.r[0] && prepared_move.p === p.p) {
+					this.__callback(prepared_move);
+					if(cb) { cb.call(this, prepared_move); }
+					return;
+				}
+				p.ot = $.jstree._reference(p.o) || this;
+				p.rt = r === -1 ? p.ot : $.jstree._reference(p.r) || this;
+				if(p.r === -1) {
+					p.cr = -1;
+					switch(p.p) {
+						case "first":
+						case "before":
+						case "inside":
+							p.cp = 0; 
+							break;
+						case "after":
+						case "last":
+							p.cp = p.rt.get_container().find(" > ul > li").length; 
+							break;
+						default:
+							p.cp = p.p;
+							break;
+					}
+				}
+				else {
+					if(!/^(before|after)$/.test(p.p) && !this._is_loaded(p.r)) {
+						return this.load_node(p.r, function () { this.prepare_move(o, r, p, cb, true); });
+					}
+					switch(p.p) {
+						case "before":
+							p.cp = p.r.index();
+							p.cr = p.rt._get_parent(p.r);
+							break;
+						case "after":
+							p.cp = p.r.index() + 1;
+							p.cr = p.rt._get_parent(p.r);
+							break;
+						case "inside":
+						case "first":
+							p.cp = 0;
+							p.cr = p.r;
+							break;
+						case "last":
+							p.cp = p.r.find(" > ul > li").length; 
+							p.cr = p.r;
+							break;
+						default: 
+							p.cp = p.p;
+							p.cr = p.r;
+							break;
+					}
+				}
+				p.np = p.cr == -1 ? p.rt.get_container() : p.cr;
+				p.op = p.ot._get_parent(p.o);
+				p.or = p.np.find(" > ul > li:nth-child(" + (p.cp + 1) + ")");
+
+				prepared_move = p;
+				this.__callback(prepared_move);
+				if(cb) { cb.call(this, prepared_move); }
+			},
+			check_move : function () {
+				var obj = prepared_move;
+				if(obj.or[0] === obj.o[0] || obj.r.parentsUntil(".jstree").andSelf().filter("li").index(obj.o) !== -1) { return false; }
+				return true;
+			},
+			move_node : function (obj, ref, position, is_copy, is_prepared, skip_check) {
+				if(!is_prepared) { 
+					return this.prepare_move(obj, ref, position, function (p) {
+						this.move_node(p, false, false, is_copy, true, skip_check);
+					});
+				}
+				if(!skip_check && !this.check_move()) { return false; }
+
+				this.__rollback();
+				var o = false;
+				if(is_copy) {
+					o = obj.o.clone();
+					o.find("*[id]").andSelf().each(function () {
+						if(this.id) { this.id = "copy_" + this.id; }
+					});
+				}
+				else { o = obj.o; }
+
+				if(obj.or.length) { obj.or.before(o); }
+				else { 
+					if(!obj.np.children("ul").length) { $("<ul>").appendTo(obj.np); }
+					obj.np.children("ul:eq(0)").append(o); 
+				}
+
+				try { 
+					obj.ot.clean_node(obj.op);
+					obj.rt.clean_node(obj.np);
+					if(!obj.op.find("> ul > li").length) {
+						obj.op.removeClass("jstree-open jstree-closed").addClass("jstree-leaf").children("ul").remove();
+					}
+				} catch (e) { }
+
+				if(is_copy) { 
+					prepared_move.cy = true;
+					prepared_move.oc = o; 
+				}
+				this.__callback(prepared_move);
+				return prepared_move;
+			},
+			_get_move : function () { return prepared_move; }
+		}
+	});
+})(jQuery);
+//*/
+
+/* 
+ * jsTree ui plugin 1.0
+ * This plugins handles selecting/deselecting/hovering/dehovering nodes
+ */
+(function ($) {
+	$.jstree.plugin("ui", {
+		__init : function () { 
+			this.data.ui.selected = $(); 
+			this.data.ui.last_selected = false; 
+			this.data.ui.hovered = null;
+			this.data.ui.to_select = this.get_settings().ui.initially_select;
+
+			this.get_container()
+				.delegate("a", "click.jstree", $.proxy(function (event) {
+						event.preventDefault();
+						this.select_node(event.currentTarget, true, event);
+					}, this))
+				.delegate("a", "mouseenter.jstree", $.proxy(function (event) {
+						this.hover_node(event.target);
+					}, this))
+				.delegate("a", "mouseleave.jstree", $.proxy(function (event) {
+						this.dehover_node(event.target);
+					}, this))
+				.bind("reopen.jstree", $.proxy(function () { 
+						this.reselect();
+					}, this))
+				.bind("get_rollback.jstree", $.proxy(function () { 
+						this.dehover_node();
+						this.save_selected();
+					}, this))
+				.bind("set_rollback.jstree", $.proxy(function () { 
+						this.reselect();
+					}, this))
+				.bind("close_node.jstree", $.proxy(function (event, data) { 
+						var s = this.get_settings().ui,
+							obj = this._get_node(data.args[0]),
+							clk = (obj && obj.length) ? obj.find(".jstree-clicked") : [],
+							_this = this;
+						if(s.selected_parent_close === false || !clk.length) { return; }
+						clk.each(function () { 
+							_this.deselect_node(this);
+							if(s.selected_parent_close === "select_parent") { _this.select_node(obj); }
+						});
+					}, this))
+				.bind("delete_node.jstree", $.proxy(function (event, data) { 
+						var obj = this._get_node(data.rslt.obj),
+							clk = (obj && obj.length) ? obj.find(".jstree-clicked") : [],
+							_this = this;
+						clk.each(function () { _this.deselect_node(this); });
+					}, this))
+				.bind("move_node.jstree", $.proxy(function (event, data) { 
+						if(data.rslt.cy) { 
+							data.rslt.oc.find(".jstree-clicked").removeClass("jstree-clicked");
+						}
+					}, this));
+		},
+		defaults : {
+			select_limit : -1, // 0, 1, 2 ... or -1 for unlimited
+			select_multiple_modifier : "ctrl", // on, or ctrl, shift, alt
+			selected_parent_close : "select_parent", // false, "deselect", "select_parent"
+			initially_select : []
+		},
+		_fn : { 
+			_get_node : function (obj, allow_multiple) {
+				if(typeof obj === "undefined" || obj === null) { return allow_multiple ? this.data.ui.selected : this.data.ui.last_selected; }
+				return this.__call_old();
+			},
+			save_selected : function () {
+				var _this = this;
+				this.data.ui.to_select = [];
+				this.data.ui.selected.each(function () { _this.data.ui.to_select.push("#" + this.id.toString().replace(/^#/,"").replace('\\/','/').replace('/','\\/')); });
+				this.__callback(this.data.ui.to_select);
+			},
+			reselect : function () {
+				var _this = this,
+					s = this.data.ui.to_select;
+				s = $.map($.makeArray(s), function (n) { return "#" + n.toString().replace(/^#/,"").replace('\\/','/').replace('/','\\/'); });
+				this.deselect_all();
+				$.each(s, function (i, val) { if(val && val !== "#") { _this.select_node(val); } });
+				this.__callback();
+			},
+			refresh : function (obj) {
+				this.save_selected();
+				return this.__call_old();
+			},
+			hover_node : function (obj) {
+				obj = this._get_node(obj);
+				if(!obj.length) { return false; }
+				//if(this.data.ui.hovered && obj.get(0) === this.data.ui.hovered.get(0)) { return; }
+				if(!obj.hasClass("jstree-hovered")) { this.dehover_node(); }
+				this.data.ui.hovered = obj.children("a").addClass("jstree-hovered").parent();
+				this.__callback({ "obj" : obj });
+			},
+			dehover_node : function () {
+				var obj = this.data.ui.hovered, p;
+				if(!obj || !obj.length) { return false; }
+				p = obj.children("a").removeClass("jstree-hovered").parent();
+				if(this.data.ui.hovered[0] === p[0]) { this.data.ui.hovered = null; }
+				this.__callback({ "obj" : obj });
+			},
+			select_node : function (obj, check, e) {
+				obj = this._get_node(obj);
+				if(!obj.length) { return false; }
+				var s = this.get_settings().ui,
+					is_multiple = (s.select_multiple_modifier == "on" || (s.select_multiple_modifier !== false && e && e[s.select_multiple_modifier + "Key"])),
+					is_selected = this.is_selected(obj),
+					proceed = true;
+				if(check) {
+					proceed = false;
+					switch(!0) {
+						case (is_selected && !is_multiple): break;
+						case (!is_selected && !is_multiple): 
+							if(s.select_limit == -1 || s.select_limit > 0) {
+								this.deselect_all();
+								proceed = true;
+							}
+							break;
+						case (is_selected && is_multiple): 
+							this.deselect_node(obj);
+							break;
+						case (!is_selected && is_multiple): 
+							if(s.select_limit == -1 || this.data.ui.selected.length + 1 <= s.select_limit) { 
+								proceed = true;
+							}
+							break;
+					}
+				}
+				if(proceed && !is_selected) {
+					obj.children("a").addClass("jstree-clicked");
+					this.data.ui.selected = this.data.ui.selected.add(obj);
+					this.data.ui.last_selected = obj;
+					this.__callback({ "obj" : obj });
+				}
+			},
+			deselect_node : function (obj) {
+				obj = this._get_node(obj);
+				if(!obj.length) { return false; }
+				if(this.is_selected(obj)) {
+					obj.children("a").removeClass("jstree-clicked");
+					this.data.ui.selected = this.data.ui.selected.not(obj);
+					if(this.data.ui.last_selected.get(0) === obj.get(0)) { this.data.ui.last_selected = this.data.ui.selected.eq(0); }
+					this.__callback({ "obj" : obj });
+				}
+			},
+			toggle_select : function (obj) {
+				obj = this._get_node(obj);
+				if(!obj.length) { return false; }
+				if(this.is_selected(obj)) { this.deselect_node(obj); }
+				else { this.select_node(obj); }
+			},
+			is_selected : function (obj) { return this.data.ui.selected.index(this._get_node(obj)) >= 0; },
+			get_selected : function (context) { 
+				return context ? $(context).find(".jstree-clicked").parent() : this.data.ui.selected; 
+			},
+			deselect_all : function (context) {
+				if(context) { $(context).find(".jstree-clicked").removeClass("jstree-clicked"); } 
+				else { this.get_container().find(".jstree-clicked").removeClass("jstree-clicked"); }
+				this.data.ui.selected = $([]);
+				this.data.ui.last_selected = false;
+				this.__callback();
+			}
+		}
+	});
+	// include the selection plugin by default
+	$.jstree.defaults.plugins.push("ui");
+})(jQuery);
+//*/
+
+/* 
+ * jsTree CRRM plugin 1.0
+ * Handles creating/renaming/removing/moving nodes by user interaction.
+ */
+(function ($) {
+	$.jstree.plugin("crrm", { 
+		__init : function () {
+			this.get_container()
+				.bind("move_node.jstree", $.proxy(function (e, data) {
+					if(this.get_settings().crrm.move.open_onmove) {
+						var t = this;
+						data.rslt.np.parentsUntil(".jstree").andSelf().filter(".jstree-closed").each(function () {
+							t.open_node(this, false, true);
+						});
+					}
+				}, this));
+		},
+		defaults : {
+			input_width_limit : 200,
+			move : {
+				always_copy			: false, // false, true or "multitree"
+				open_onmove			: true,
+				default_position	: "last",
+				check_move			: function (m) { return true; }
+			}
+		},
+		_fn : {
+			_show_input : function (obj, callback) {
+				obj = this._get_node(obj);
+				var w = this.get_settings().crrm.input_width_limit,
+					w1 = obj.children("ins").width(),
+					w2 = obj.find("> a:visible > ins").width() * obj.find("> a:visible > ins").length,
+					t = this.get_text(obj),
+					h1 = $("<div>", { css : { "position" : "absolute", "top" : "-200px", "left" : "-1000px", "visibility" : "hidden" } }).appendTo("body"),
+					h2 = obj.css("position","relative").append(
+					$("<input>", { 
+						"value" : t,
+						// "size" : t.length,
+						"css" : {
+							"padding" : "0",
+							"border" : "1px solid silver",
+							"position" : "absolute",
+							"left" : (w1 + w2 + 4) + "px",
+							"top" : "0px",
+							"height" : (this.data.core.li_height - 2) + "px",
+							"lineHeight" : (this.data.core.li_height - 2) + "px",
+							"width" : "150px" // will be set a bit further down
+						},
+						"blur" : $.proxy(function () {
+							var i = obj.children("input"),
+								v = i.val();
+							if(v === "") { v = t; }
+							this.rename_node(obj, v);
+							callback.call(this, obj, v, t);
+							i.remove();
+							obj.css("position","");
+						}, this),
+						"keyup" : function (event) {
+							var key = event.keyCode || event.which;
+							if(key == 27) { this.value = t; this.blur(); return; }
+							else if(key == 13) { this.blur(); return; }
+							else {
+								h2.width(Math.min(h1.text("pW" + this.value).width(),w));
+							}
+						}
+					})
+				).children("input"); 
+				this.set_text(obj, "");
+				h1.css({
+						fontFamily		: h2.css('fontFamily')		|| '',
+						fontSize		: h2.css('fontSize')		|| '',
+						fontWeight		: h2.css('fontWeight')		|| '',
+						fontStyle		: h2.css('fontStyle')		|| '',
+						fontStretch		: h2.css('fontStretch')		|| '',
+						fontVariant		: h2.css('fontVariant')		|| '',
+						letterSpacing	: h2.css('letterSpacing')	|| '',
+						wordSpacing		: h2.css('wordSpacing')		|| ''
+				});
+				h2.width(Math.min(h1.text("pW" + h2[0].value).width(),w))[0].select();
+			},
+			rename : function (obj) {
+				obj = this._get_node(obj);
+				this.__rollback();
+				var f = this.__callback;
+				this._show_input(obj, function (obj, new_name, old_name) { 
+					f.call(this, { "obj" : obj, "new_name" : new_name, "old_name" : old_name });
+				});
+			},
+			create : function (obj, position, js, callback, skip_rename) {
+				var t, _this = this;
+				obj = this._get_node(obj);
+				if(!obj) { obj = -1; }
+				this.__rollback();
+				t = this.create_node(obj, position, js, function (t) {
+					var p = this._get_parent(t),
+						pos = $(t).index();
+					if(callback) { callback.call(this, t); }
+					if(p.length && p.hasClass("jstree-closed")) { this.open_node(p, false, true); }
+					if(!skip_rename) { 
+						this._show_input(t, function (obj, new_name, old_name) { 
+							_this.__callback({ "obj" : obj, "name" : new_name, "parent" : p, "position" : pos });
+						});
+					}
+					else { _this.__callback({ "obj" : t, "name" : this.get_text(t), "parent" : p, "position" : pos }); }
+				});
+				return t;
+			},
+			remove : function (obj) {
+				obj = this._get_node(obj, true);
+				this.__rollback();
+				this.delete_node(obj);
+				this.__callback({ "obj" : obj });
+			},
+			check_move : function () {
+				if(!this.__call_old()) { return false; }
+				var s = this.get_settings().crrm.move;
+				if(!s.check_move.call(this, this._get_move())) { return false; }
+				return true;
+			},
+			move_node : function (obj, ref, position, is_copy, is_prepared, skip_check) {
+				var s = this.get_settings().crrm.move;
+				if(!is_prepared) { 
+					if(!position) { position = s.default_position; }
+					return this.__call_old(true, obj, ref, position, is_copy, false, skip_check);
+				}
+				// if the move is already prepared
+				if(s.always_copy === true || (s.always_copy === "multitree" && obj.rt.get_index() === obj.ot.get_index() )) {
+					is_copy = true;
+				}
+				this.__call_old(true, obj, ref, position, is_copy, true, skip_check);
+			},
+
+			cut : function (obj) {
+				obj = this._get_node(obj);
+				this.data.crrm.cp_nodes = false;
+				this.data.crrm.ct_nodes = false;
+				if(!obj || !obj.length) { return false; }
+				this.data.crrm.ct_nodes = obj;
+			},
+			copy : function (obj) {
+				obj = this._get_node(obj);
+				this.data.crrm.cp_nodes = false;
+				this.data.crrm.ct_nodes = false;
+				if(!obj || !obj.length) { return false; }
+				this.data.crrm.cp_nodes = obj;
+			},
+			paste : function (obj) { 
+				obj = this._get_node(obj);
+				if(!obj || !obj.length) { return false; }
+				if(!this.data.crrm.ct_nodes && !this.data.crrm.cp_nodes) { return false; }
+				if(this.data.crrm.ct_nodes) { this.move_node(this.data.crrm.ct_nodes, obj); }
+				if(this.data.crrm.cp_nodes) { this.move_node(this.data.crrm.cp_nodes, obj, false, true); }
+			}
+		}
+	});
+	// include the crr plugin by default
+	$.jstree.defaults.plugins.push("crrm");
+})(jQuery);
+
+/* 
+ * jsTree themes plugin 1.0
+ * Handles loading and setting themes, as well as detecting path to themes, etc.
+ */
+(function ($) {
+	var themes_loaded = [];
+	// this variable stores the path to the themes folder - if left as false - it will be autodetected
+	$.jstree._themes = false;
+	$.jstree.plugin("themes", {
+		__init : function () { 
+			this.get_container()
+				.bind("init.jstree", $.proxy(function () {
+						var s = this.get_settings().themes;
+						this.data.themes.dots = s.dots; 
+						this.data.themes.icons = s.icons; 
+						//alert(s.dots);
+						this.set_theme(s.theme, s.url);
+					}, this))
+				.bind("loaded.jstree", $.proxy(function () {
+						// bound here too, as simple HTML tree's won't honor dots & icons otherwise
+						if(!this.data.themes.dots) { this.hide_dots(); }
+						else { this.show_dots(); }
+						if(!this.data.themes.icons) { this.hide_icons(); }
+						else { this.show_icons(); }
+					}, this));
+		},
+		defaults : { 
+			theme : "default", 
+			url : false,
+			dots : true,
+			icons : true
+		},
+		_fn : {
+			set_theme : function (theme_name, theme_url) {
+				if(!theme_name) { return false; }
+				if(!theme_url) { theme_url = $.jstree._themes + theme_name + '/style.css'; }
+				if($.inArray(theme_url, themes_loaded) == -1) {
+					$.vakata.css.add_sheet({ "url" : theme_url, "rel" : "jstree" });
+					themes_loaded.push(theme_url);
+				}
+				if(this.data.theme != theme_name) {
+					this.get_container().removeClass('jstree-' + this.data.theme);
+					this.data.themes.theme = theme_name;
+				}
+				this.get_container().addClass('jstree-' + theme_name);
+				if(!this.data.themes.dots) { this.hide_dots(); }
+				else { this.show_dots(); }
+				if(!this.data.themes.icons) { this.hide_icons(); }
+				else { this.show_icons(); }
+				this.__callback();
+			},
+			get_theme	: function () { return this.data.themes.theme; },
+
+			show_dots	: function () { this.data.themes.dots = true; this.get_container().children("ul").removeClass("jstree-no-dots"); },
+			hide_dots	: function () { this.data.themes.dots = false; this.get_container().children("ul").addClass("jstree-no-dots"); },
+			toggle_dots	: function () { if(this.data.themes.dots) { this.hide_dots(); } else { this.show_dots(); } },
+
+			show_icons	: function () { this.data.themes.icons = true; this.get_container().children("ul").removeClass("jstree-no-icons"); },
+			hide_icons	: function () { this.data.themes.icons = false; this.get_container().children("ul").addClass("jstree-no-icons"); },
+			toggle_icons: function () { if(this.data.themes.icons) { this.hide_icons(); } else { this.show_icons(); } }
+		}
+	});
+	// autodetect themes path
+	$(function () {
+		if($.jstree._themes === false) {
+			$("script").each(function () { 
+				if(this.src.toString().match(/jquery\.jstree[^\/]*?\.js(\?.*)?$/)) { 
+					$.jstree._themes = this.src.toString().replace(/jquery\.jstree[^\/]*?\.js(\?.*)?$/, "") + 'themes/'; 
+					return false; 
+				}
+			});
+		}
+		if($.jstree._themes === false) { $.jstree._themes = "themes/"; }
+	});
+	// include the themes plugin by default
+	$.jstree.defaults.plugins.push("themes");
+})(jQuery);
+//*/
+
+/* 
+ * jsTree HTML data 1.0
+ * The HTML data store. Datastores are build by replacing the `load_node` and `_is_loaded` functions.
+ */
+(function ($) {
+	$.jstree.plugin("html_data", {
+		__init : function () { 
+			this.data.html_data.original_container_html = this.get_container().html().replace(/<\/([^>]+)>\s+</ig,"</$1><").replace(/>\s+<([a-z]{1})/ig,"><$1");
+		},
+		defaults : { 
+			data : false,
+			ajax : false,
+			correct_state : false
+		},
+		_fn : {
+			load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_html(obj, function () { _this.__callback({ "obj" : obj }); s_call.call(this); }, e_call); },
+			_is_loaded : function (obj) { 
+				obj = this._get_node(obj); 
+				return obj == -1 || !obj || !this.get_settings().html_data.ajax || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").size() > 0;
+			},
+			load_node_html : function (obj, s_call, e_call) {
+				var d,
+					s = this.get_settings().html_data,
+					error_func = function () {},
+					success_func = function () {};
+				switch(!0) {
+					case (!s.data && !s.ajax):
+						if(!obj || obj == -1) {
+							this.get_container()
+								.html(this.data.html_data.original_container_html)
+								.find("li, a").filter(function () { return this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree-icon'>&#160;</ins>");
+							this.clean_node();
+						}
+						if(s_call) { s_call.call(this); }
+						break;
+					case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)):
+						if(!obj || obj == -1) {
+							d = $(s.data);
+							if(!d.is("ul")) { d = $("<ul>").append(d); }
+							this.get_container()
+								.children("ul").empty().append(d.children())
+								.find("li, a").filter(function () { return this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree-icon'>&#160;</ins>");
+							this.clean_node();
+						}
+						if(s_call) { s_call.call(this); }
+						break;
+					case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1):
+						obj = this._get_node(obj);
+						error_func = function (x, t, e) {
+							var ef = this.get_settings().html_data.ajax.error; 
+							if(ef) { ef.call(this, x, t, e); }
+							if(obj != -1 && obj.length) {
+								obj.children(".jstree-loading").removeClass("jstree-loading");
+								if(s.correct_state) { obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf"); }
+							}
+							if(e_call) { e_call.call(this); }
+						};
+						success_func = function (d, t, x) {
+							if(x.responseText == "") {
+								return error_func.call(this, x, t, "");
+							}
+							var sf = this.get_settings().html_data.ajax.success; 
+							if(sf) { d = sf.call(this,d,t,x) || d; }
+							if(d) {
+								d = $(d);
+								if(!d.is("ul")) { d = $("<ul>").append(d); }
+								if(obj == -1 || !obj) { this.get_container().children("ul").empty().append(d.children()).find("li, a").filter(function () { return this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree-icon'>&#160;</ins>"); }
+								else { obj.children(".jstree-loading").removeClass("jstree-loading"); obj.append(d).find("li, a").filter(function () { return this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree-icon'>&#160;</ins>"); }
+								this.clean_node(obj);
+								if(s_call) { s_call.call(this); }
+							}
+							else {
+								obj.children(".jstree-loading").removeClass("jstree-loading");
+								if(s.correct_state) { obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf"); }
+							}
+						};
+						s.ajax.context = this;
+						s.ajax.error = error_func;
+						s.ajax.success = success_func;
+						if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, obj); }
+						$.ajax(s.ajax);
+						break;
+				}
+			}
+		}
+	});
+	// include the HTML data plugin by default
+	$.jstree.defaults.plugins.push("html_data");
+})(jQuery);
+//*/
+
+/*
+ * jsTree hotkeys plugin 1.0
+ * Enables keyboard navigation for all tree instances
+ * Depends on the jstree ui & jquery hotkeys plugins
+ */
+(function ($) {
+	var bound = [];
+	function exec(i, event) {
+		var f = $.jstree._focused();
+		if(f && f.data && f.data.hotkeys && f.data.hotkeys.enabled) { 
+			var tmp = f.get_settings().hotkeys[i];
+			if(tmp) { return f.get_settings().hotkeys[i].call(f, event); }
+		}
+	}
+	$.jstree.plugin("hotkeys", {
+		__init : function () {
+			if(typeof $.hotkeys === "undefined") { throw "jsTree hotkeys: jQuery hotkeys plugin not included."; }
+			if(!this.data.ui) { throw "jsTree hotkeys: jsTree UI plugin not included."; }
+			$.each(this.get_settings().hotkeys, function (i, val) {
+				if($.inArray(i, bound) == -1) {
+					$(document).bind("keydown", i, function (event) { return exec(i, event); });
+					bound.push(i);
+				}
+			});
+			this.enable_hotkeys();
+		},
+		defaults : {
+			"up" : function () { 
+				var o = this.data.ui.hovered || this.data.ui.last_selected || -1;
+				this.hover_node(this._get_prev(o));
+				return false; 
+			},
+			"down" : function () { 
+				var o = this.data.ui.hovered || this.data.ui.last_selected || -1;
+				this.hover_node(this._get_next(o));
+				return false;
+			},
+			"left" : function () { 
+				var o = this.data.ui.hovered || this.data.ui.last_selected;
+				if(o) {
+					if(o.hasClass("jstree-open")) { this.close_node(o); }
+					else { this.hover_node(this._get_prev(o)); }
+				}
+				return false;
+			},
+			"right" : function () { 
+				var o = this.data.ui.hovered || this.data.ui.last_selected;
+				if(o && o.length) {
+					if(o.hasClass("jstree-closed")) { this.open_node(o); }
+					else { this.hover_node(this._get_next(o)); }
+				}
+				return false;
+			},
+			"space" : function () { 
+				if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").click(); } 
+				return false; 
+			},
+			"ctrl+space" : function (event) { 
+				event.type = "click";
+				if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").trigger(event); } 
+				return false; 
+			},
+			"f2" : function () { this.rename(this.data.ui.hovered || this.data.ui.last_selected); },
+			"del" : function () { this.remove(this.data.ui.hovered || this._get_node(null)); }
+		},
+		_fn : {
+			enable_hotkeys : function () {
+				this.data.hotkeys.enabled = true;
+			},
+			disable_hotkeys : function () {
+				this.data.hotkeys.enabled = false;
+			}
+		}
+	});
+})(jQuery);
+//*/
+
+/* 
+ * jsTree JSON 1.0
+ * The JSON data store. Datastores are build by overriding the `load_node` and `_is_loaded` functions.
+ */
+(function ($) {
+	$.jstree.plugin("json_data", {
+		defaults : { 
+			data : false,
+			ajax : false,
+			correct_state : false,
+			progressive_render : false
+		},
+		_fn : {
+			load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_json(obj, function () { _this.__callback({ "obj" : obj }); s_call.call(this); }, e_call); },
+			_is_loaded : function (obj) { 
+				var s = this.get_settings().json_data;
+				obj = this._get_node(obj); 
+				if(obj && obj !== -1 && s.progressive_render) {
+					obj.append(this.parse_json(obj.data("jstree-children")));
+					$.removeData(obj, "jstree-children");
+					this.clean_node(obj);
+				}
+				return obj == -1 || !obj || !s.ajax || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").size() > 0;
+			},
+			load_node_json : function (obj, s_call, e_call) {
+				var s = this.get_settings().json_data,
+					error_func = function () {},
+					success_func = function () {};
+				switch(!0) {
+					case (!s.data && !s.ajax): throw "Neither data nor ajax settings supplied.";
+					case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)):
+						if(!obj || obj == -1) {
+							this.get_container().children("ul").empty().append(this.parse_json(s.data).children());
+							this.clean_node();
+						}
+						if(s_call) { s_call.call(this); }
+						break;
+					case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1):
+						obj = this._get_node(obj);
+						error_func = function (x, t, e) {
+							var ef = this.get_settings().json_data.ajax.error; 
+							if(ef) { ef.call(this, x, t, e); }
+							if(obj != -1 && obj.length) {
+								obj.children(".jstree-loading").removeClass("jstree-loading");
+								if(s.correct_state) { obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf"); }
+							}
+							if(e_call) { e_call.call(this); }
+						};
+						success_func = function (d, t, x) {
+							if(x.responseText == "" || (!$.isArray(d) && !$.isPlainObject(d))) {
+								return error_func.call(this, x, t, "");
+							}
+							var sf = this.get_settings().json_data.ajax.success; 
+							if(sf) { d = sf.call(this,d,t,x) || d; }
+							d = this.parse_json(d);
+							if(d) {
+								if(obj == -1 || !obj) { this.get_container().children("ul").empty().append(d.children()); }
+								else { obj.append(d).children(".jstree-loading").removeClass("jstree-loading"); }
+								this.clean_node(obj);
+								if(s_call) { s_call.call(this); }
+							}
+							else {
+								obj.children(".jstree-loading").removeClass("jstree-loading");
+								if(s.correct_state) { obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf"); }
+							}
+						};
+						s.ajax.context = this;
+						s.ajax.error = error_func;
+						s.ajax.success = success_func;
+						if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, obj); }
+						$.ajax(s.ajax);
+						break;
+				}
+			},
+			parse_json : function (js, is_callback) {
+				var d = $(), tmp, i, j, s = this.get_settings().json_data, ul1, ul2, t = this.get_settings().core.html_titles;
+				if(!js) { return d; }
+				if($.isFunction(js)) { 
+					js = js.call(this);
+				}
+				if($.isArray(js)) {
+					if(!js.length) { return false; }
+					for(i = 0, j = js.length; i < j; i++) {
+						tmp = this.parse_json(js[i], true);
+						if(tmp.length) { d = d.add(tmp); }
+					}
+				}
+				else {
+					if(typeof js == "string") { js = { data : js }; }
+					if(!js.data && js.data !== "") { return d; }
+					d = $("<li>");
+					if(js.attr) { d.attr(js.attr); }
+					if(js.metadata) { d.data("jstree", js.metadata); }
+					if(js.state) { d.addClass("jstree-" + js.state); }
+					if(!$.isArray(js.data)) { tmp = js.data; js.data = []; js.data.push(tmp); }
+					$.each(js.data, function (i, m) {
+						tmp = $("<a>");
+						if($.isFunction(m)) { m = m.call(this, js); }
+						if(typeof m == "string") { tmp.attr('href','#')[ t ? "html" : "text" ](m); }
+						else {
+							if(!m.attr) { m.attr = {}; }
+							if(!m.attr.href) { m.attr.href = '#'; }
+							tmp.attr(m.attr)[ t ? "html" : "text" ](m.title);
+							if(m.language) { tmp.addClass(m.language); }
+						}
+						tmp.prepend("<ins class='jstree-icon'>&#160;</ins>");
+						if(m.icon) { 
+							if(m.icon.indexOf("/") === -1) { tmp.children("ins").addClass(m.icon); }
+							else { tmp.children("ins").css("background","url('" + m.icon + "') center center no-repeat;"); }
+						}
+						d.append(tmp);
+					});
+					d.prepend("<ins class='jstree-icon'>&#160;</ins>");
+					if(js.children) { 
+						if(s.progressive_render && js.state !== "open") {
+							d.addClass("jstree-closed").data("jstree-children", js.children);
+						}
+						else {
+							if($.isFunction(js.children)) {
+								js.children = js.children.call(this, js);
+							}
+							if($.isArray(js.children) && js.children.length) {
+								tmp = this.parse_json(js.children, true);
+								if(tmp.length) {
+									ul2 = $("<ul>");
+									ul2.append(tmp);
+									d.append(ul2);
+								}
+							}
+						}
+					}
+				}
+				if(!is_callback) {
+					ul1 = $("<ul>");
+					ul1.append(d);
+					d = ul1;
+				}
+				return d;
+			},
+			get_json : function (obj, li_attr, a_attr) {
+				var result = [], 
+					s = this.get_settings(), 
+					_this = this,
+					tmp1, tmp2, li, a, t, lang;
+				obj = this._get_node(obj);
+				if(!obj || obj === -1) { obj = this.get_container().find("> ul > li"); }
+				li_attr = $.isArray(li_attr) ? li_attr : [ "id", "class" ];
+				if(this.data.types) { li_attr.push(s.types.type_attr); }
+				a_attr = $.isArray(a_attr) ? a_attr : [ ];
+
+				obj.each(function () {
+					li = $(this);
+					tmp1 = { data : [] };
+					if(li_attr.length) { tmp1.attr = { }; }
+					$.each(li_attr, function (i, v) { 
+						tmp2 = li.attr(v); 
+						if(tmp2 && tmp2.length && tmp2.replace(/jstree[^ ]*|$/ig,'').length) {
+							tmp1.attr[v] = tmp2.replace(/jstree[^ ]*|$/ig,''); 
+						}
+					});
+					if(li.hasClass("jstree-open")) { tmp1.state = "open"; }
+					if(li.hasClass("jstree-closed")) { tmp1.state = "closed"; }
+					a = li.children("a");
+					a.each(function () {
+						t = $(this);
+						if(
+							a_attr.length || 
+							$.inArray("languages", s.plugins) !== -1 || 
+							t.children("ins").get(0).style.backgroundImage.length || 
+							(t.children("ins").get(0).className && t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').length)
+						) { 
+							lang = false;
+							if($.inArray("languages", s.plugins) !== -1 && $.isArray(s.languages) && s.languages.length) {
+								$.each(s.languages, function (l, lv) {
+									if(t.hasClass(lv)) {
+										lang = lv;
+										return false;
+									}
+								});
+							}
+							tmp2 = { attr : { }, title : _this.get_text(t, lang) }; 
+							$.each(a_attr, function (k, z) {
+								tmp1.attr[z] = li.attr(z).replace(/jstree[^ ]*|$/ig,'');
+							});
+							$.each(s.languages, function (k, z) {
+								if(t.hasClass(z)) { tmp2.language = z; return true; }
+							});
+							if(t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"").length) {
+								tmp2.icon = t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"");
+							}
+							if(t.children("ins").get(0).style.backgroundImage.length) {
+								tmp2.icon = t.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")","");
+							}
+						}
+						else {
+							tmp2 = _this.get_text(t);
+						}
+						if(a.length > 1) { tmp1.data.push(tmp2); }
+						else { tmp1.data = tmp2; }
+					});
+					li = li.find("> ul > li");
+					if(li.length) { tmp1.children = _this.get_json(li, li_attr, a_attr); }
+					result.push(tmp1);
+				});
+				return result;
+			}
+		}
+	});
+})(jQuery);
+//*/
+
+/* 
+ * jsTree languages plugin 1.0
+ * Adds support for multiple language versions in one tree
+ * This basically allows for many titles coexisting in one node, but only one of them being visible at any given time
+ * This is useful for maintaining the same structure in many languages (hence the name of the plugin)
+ */
+(function ($) {
+	$.jstree.plugin("languages", {
+		__init : function () { this._load_css();  },
+		defaults : [],
+		_fn : {
+			set_lang : function (i) { 
+				var langs = this.get_settings().languages,
+					st = false,
+					selector = ".jstree-" + this.get_index() + ' a';
+				if(!$.isArray(langs) || langs.length === 0) { return false; }
+				if($.inArray(i,langs) == -1) {
+					if(!!langs[i]) { i = langs[i]; }
+					else { return false; }
+				}
+				if(i == this.data.languages.current_language) { return true; }
+				st = $.vakata.css.get_css(selector + "." + this.data.languages.current_language, false, this.data.languages.language_css);
+				if(st !== false) { st.style.display = "none"; }
+				st = $.vakata.css.get_css(selector + "." + i, false, this.data.languages.language_css);
+				if(st !== false) { st.style.display = ""; }
+				this.data.languages.current_language = i;
+				this.__callback(i);
+				return true;
+			},
+			get_lang : function () {
+				return this.data.languages.current_language;
+			},
+			get_text : function (obj, lang) {
+				obj = this._get_node(obj) || this.data.ui.last_selected;
+				if(!obj.size()) { return false; }
+				var langs = this.get_settings().languages,
+					s = this.get_settings().core.html_titles;
+				if($.isArray(langs) && langs.length) {
+					lang = (lang && $.inArray(lang,langs) != -1) ? lang : this.data.languages.current_language;
+					obj = obj.children("a." + lang);
+				}
+				else { obj = obj.children("a:eq(0)"); }
+				if(s) {
+					obj = obj.clone();
+					obj.children("INS").remove();
+					return obj.html();
+				}
+				else {
+					obj = obj.contents().filter(function() { return this.nodeType == 3; })[0];
+					return obj.nodeValue;
+				}
+			},
+			set_text : function (obj, val, lang) {
+				obj = this._get_node(obj) || this.data.ui.last_selected;
+				if(!obj.size()) { return false; }
+				var langs = this.get_settings().languages,
+					s = this.get_settings().core.html_titles,
+					tmp;
+				if($.isArray(langs) && langs.length) {
+					lang = (lang && $.inArray(lang,langs) != -1) ? lang : this.data.languages.current_language;
+					obj = obj.children("a." + lang);
+				}
+				else { obj = obj.children("a:eq(0)"); }
+				if(s) {
+					tmp = obj.children("INS").clone();
+					obj.html(val).prepend(tmp);
+					this.__callback({ "obj" : obj, "name" : val, "lang" : lang });
+					return true;
+				}
+				else {
+					obj = obj.contents().filter(function() { return this.nodeType == 3; })[0];
+					this.__callback({ "obj" : obj, "name" : val, "lang" : lang });
+					return (obj.nodeValue = val);
+				}
+			},
+			_load_css : function () {
+				var langs = this.get_settings().languages,
+					str = "/* languages css */",
+					selector = ".jstree-" + this.get_index() + ' a',
+					ln;
+				if($.isArray(langs) && langs.length) {
+					this.data.languages.current_language = langs[0];
+					for(ln = 0; ln < langs.length; ln++) {
+						str += selector + "." + langs[ln] + " {";
+						if(langs[ln] != this.data.languages.current_language) { str += " display:none; "; }
+						str += " } ";
+					}
+					this.data.languages.language_css = $.vakata.css.add_sheet({ 'str' : str });
+				}
+			},
+			create_node : function (obj, position, js, callback) {
+				var t = this.__call_old(true, obj, position, js, function (t) {
+					var langs = this.get_settings().languages,
+						a = t.children("a"),
+						ln;
+					if($.isArray(langs) && langs.length) {
+						for(ln = 0; ln < langs.length; ln++) {
+							if(!a.is("." + langs[ln])) {
+								t.append(a.eq(0).clone().removeClass(langs.join(" ")).addClass(langs[ln]));
+							}
+						}
+						a.not("." + langs.join(", .")).remove();
+					}
+					if(callback) { callback.call(this, t); }
+				});
+				return t;
+			}
+		}
+	});
+})(jQuery);
+//*/
+
+/*
+ * jsTree cookies plugin 1.0
+ * Stores the currently opened/selected nodes in a cookie and then restores them
+ * Depends on the jquery.cookie plugin
+ */
+(function ($) {
+	$.jstree.plugin("cookies", {
+		__init : function () {
+			if(typeof $.cookie === "undefined") { throw "jsTree cookie: jQuery cookie plugin not included."; }
+
+			var s = this.get_settings().cookies,
+				tmp;
+			if(!!s.save_opened) {
+				tmp = $.cookie(s.save_opened);
+				if(tmp && tmp.length) { this.data.core.to_open = tmp.split(","); }
+			}
+			if(!!s.save_selected) {
+				tmp = $.cookie(s.save_selected);
+				if(tmp && tmp.length) { this.data.ui.to_select = tmp.split(","); }
+			}
+			this.get_container()
+				.one( ( this.data.ui ? "reselect" : "reopen" ) + ".jstree", $.proxy(function () {
+					this.get_container()
+						.bind("open_node.jstree close_node.jstree select_node.jstree deselect_node.jstree", $.proxy(function (e) { 
+								if(this.get_settings().cookies.auto_save) { this.save_cookie((e.handleObj.namespace + e.handleObj.type).replace("jstree","")); }
+							}, this));
+				}, this));
+		},
+		defaults : {
+			save_opened		: "jstree_open",
+			save_selected	: "jstree_select",
+			auto_save		: true,
+			cookie_options	: {}
+		},
+		_fn : {
+			save_cookie : function (c) {
+				if(this.data.core.refreshing) { return; }
+				var s = this.get_settings().cookies;
+				if(!c) { // if called manually and not by event
+					if(s.save_opened) {
+						this.save_opened();
+						$.cookie(s.save_opened, this.data.core.to_open.join(","), s.cookie_options);
+					}
+					if(s.save_selected && this.data.ui) {
+						this.save_selected();
+						$.cookie(s.save_selected, this.data.ui.to_select.join(","), s.cookie_options);
+					}
+					return;
+				}
+				switch(c) {
+					case "open_node":
+					case "close_node":
+						if(!!s.save_opened) { 
+							this.save_opened(); 
+							$.cookie(s.save_opened, this.data.core.to_open.join(","), s.cookie_options); 
+						}
+						break;
+					case "select_node":
+					case "deselect_node":
+						if(!!s.save_selected && this.data.ui) { 
+							this.save_selected(); 
+							$.cookie(s.save_selected, this.data.ui.to_select.join(","), s.cookie_options); 
+						}
+						break;
+				}
+			}
+		}
+	});
+	// include cookies by default
+	$.jstree.defaults.plugins.push("cookies");
+})(jQuery);
+//*/
+
+/*
+ * jsTree sort plugin 1.0
+ * Sorts items alphabetically (or using any other function)
+ */
+(function ($) {
+	$.jstree.plugin("sort", {
+		__init : function () {
+			this.get_container()
+				.bind("load_node.jstree", $.proxy(function (e, data) {
+						var obj = this._get_node(data.rslt.obj);
+						obj = obj === -1 ? this.get_container().children("ul") : obj.children("ul");
+						this.sort(obj);
+					}, this))
+				.bind("rename_node.jstree", $.proxy(function (e, data) {
+						this.sort(data.rslt.obj.parent());
+					}, this))
+				.bind("move_node.jstree", $.proxy(function (e, data) {
+						var m = data.rslt.np == -1 ? this.get_container() : data.rslt.np;
+						this.sort(m.children("ul"));
+					}, this));
+		},
+		defaults : function (a, b) { return this.get_text(a) > this.get_text(b) ? 1 : -1; },
+		_fn : {
+			sort : function (obj) {
+				var s = this.get_settings().sort,
+					t = this;
+				obj.append($.makeArray(obj.children("li")).sort($.proxy(s, t)));
+				obj.find("> li > ul").each(function() { t.sort($(this)); });
+				this.clean_node(obj);
+			}
+		}
+	});
+})(jQuery);
+//*/
+
+/*
+ * jsTree DND plugin 1.0
+ * Drag and drop plugin for moving/copying nodes
+ */
+(function ($) {
+	var o = false,
+		r = false,
+		m = false;
+	$.vakata.dnd = {
+		is_down : false,
+		is_drag : false,
+		helper : false,
+		init_x : 0,
+		init_y : 0,
+		threshold : 5,
+		user_data : {},
+
+		drag_start : function (e, data, html) { 
+			if($.vakata.dnd.is_drag) { $.vakata.drag_stop({}); }
+			try {
+				e.currentTarget.unselectable = "on";
+				e.currentTarget.onselectstart = function() { return false; };
+				if(e.currentTarget.style) { e.currentTarget.style.MozUserSelect = "none"; }
+			} catch(err) { }
+			$.vakata.dnd.init_x = e.pageX;
+			$.vakata.dnd.init_y = e.pageY;
+			$.vakata.dnd.user_data = data;
+			$.vakata.dnd.is_down = true;
+			$.vakata.dnd.helper = $("<div id='vakata-dragged'>").html(html).css("opacity", "0.75");
+			$(document).bind("mousemove", $.vakata.dnd.drag);
+			$(document).bind("mouseup", $.vakata.dnd.drag_stop);
+			return false;
+		},
+		drag : function (e) { 
+			if(!$.vakata.dnd.is_down) { return; }
+			if(!$.vakata.dnd.is_drag) {
+				if(Math.abs(e.pageX - $.vakata.dnd.init_x) > 5 || Math.abs(e.pageY - $.vakata.dnd.init_y) > 5) { 
+					$.vakata.dnd.helper.appendTo("body");
+					$.vakata.dnd.is_drag = true;
+					$(document).triggerHandler("vakata.drag_start", { "event" : e, "data" : $.vakata.dnd.user_data });
+				}
+				else { return; }
+			}
+			$.vakata.dnd.helper.css({ left : (e.pageX + 5) + "px", top : (e.pageY + 10) + "px" });
+			$(document).triggerHandler("vakata.drag", { "event" : e, "data" : $.vakata.dnd.user_data });
+		},
+		drag_stop : function (e) {
+			$(document).unbind("mousemove", $.vakata.dnd.drag);
+			$(document).unbind("mouseup", $.vakata.dnd.drag_stop);
+			$(document).triggerHandler("vakata.drag_stop", { "event" : e, "data" : $.vakata.dnd.user_data });
+			$.vakata.dnd.helper.remove();
+			$.vakata.dnd.init_x = 0;
+			$.vakata.dnd.init_y = 0;
+			$.vakata.dnd.user_data = {};
+			$.vakata.dnd.is_down = false;
+			$.vakata.dnd.is_drag = false;
+		}
+	};
+	$(function() {
+		var css_string = '#vakata-dragged { display:block; margin:0 0 0 0; padding:4px 4px 4px 24px; position:absolute; left:-2000px; top:-2000px; line-height:16px; } ';
+		$.vakata.css.add_sheet({ str : css_string });
+	});
+
+	$.jstree.plugin("dnd", {
+		__init : function () {
+			this.data.dnd = {
+				active : false,
+				after : false,
+				inside : false,
+				before : false,
+				off : false,
+				prepared : false,
+				w : 0,
+				to1 : false,
+				to2 : false,
+				cof : false,
+				cw : false,
+				ch : false,
+				i1 : false,
+				i2 : false
+			};
+			this.get_container()
+				.bind("mouseenter.jstree", $.proxy(function () {
+						if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree && this.data.themes) {
+							m.attr("class", "jstree-" + this.data.themes.theme); 
+							$.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme);
+						}
+					}, this))
+				.bind("mouseleave.jstree", $.proxy(function () {
+						if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
+							if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); }
+							if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); }
+						}
+					}, this))
+				.bind("mousemove.jstree", $.proxy(function (e) {
+						if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
+							var cnt = this.get_container()[0];
+
+							// Horizontal scroll
+							if(e.pageX + 20 > this.data.dnd.cof.left + this.data.dnd.cw) {
+								if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); }
+								this.data.dnd.i1 = setInterval($.proxy(function () { this.scrollLeft += 5; }, cnt), 100);
+							}
+							else if(e.pageX - 20 < this.data.dnd.cof.left) {
+								if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); }
+								this.data.dnd.i1 = setInterval($.proxy(function () { this.scrollLeft -= 5; }, cnt), 100);
+							}
+							else {
+								if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); }
+							}
+
+							// Vertical scroll
+							if(e.pageY + 20 > this.data.dnd.cof.top + this.data.dnd.ch) {
+								if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); }
+								this.data.dnd.i2 = setInterval($.proxy(function () { this.scrollTop += 5; }, cnt), 100);
+							}
+							else if(e.pageY - 20 < this.data.dnd.cof.top) {
+								if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); }
+								this.data.dnd.i2 = setInterval($.proxy(function () { this.scrollTop -= 5; }, cnt), 100);
+							}
+							else {
+								if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); }
+							}
+
+						}
+					}, this))
+				.delegate("a", "mousedown.jstree", $.proxy(function (e) { 
+						this.start_drag(e.currentTarget, e);
+						return false;
+					}, this))
+				.delegate("a", "mouseenter.jstree", $.proxy(function (e) { 
+						if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
+							this.dnd_enter(e.currentTarget);
+						}
+					}, this))
+				.delegate("a", "mousemove.jstree", $.proxy(function (e) { 
+						if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
+							if(typeof this.data.dnd.off.top === "undefined") { this.data.dnd.off = $(e.target).offset(); }
+							this.data.dnd.w = (e.pageY - (this.data.dnd.off.top || 0)) % this.data.core.li_height;
+							if(this.data.dnd.w < 0) { this.data.dnd.w += this.data.core.li_height; }
+							this.dnd_show();
+						}
+					}, this))
+				.delegate("a", "mouseleave.jstree", $.proxy(function (e) { 
+						if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
+							this.data.dnd.after		= false;
+							this.data.dnd.before	= false;
+							this.data.dnd.inside	= false;
+							$.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");
+							m.hide();
+							if(r && r[0] === e.target.parentNode) {
+								if(this.data.dnd.to1) {
+									clearTimeout(this.data.dnd.to1);
+									this.data.dnd.to1 = false;
+								}
+								if(this.data.dnd.to2) {
+									clearTimeout(this.data.dnd.to2);
+									this.data.dnd.to2 = false;
+								}
+							}
+						}
+					}, this))
+				.delegate("a", "mouseup.jstree", $.proxy(function (e) { 
+						if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
+							this.dnd_finish(e);
+						}
+					}, this));
+
+			$(document)
+				.bind("vakata.drag_stop", $.proxy(function () {
+						this.data.dnd.after		= false;
+						this.data.dnd.before	= false;
+						this.data.dnd.inside	= false;
+						this.data.dnd.off		= false;
+						this.data.dnd.prepared	= false;
+						this.data.dnd.w			= false;
+						this.data.dnd.to1		= false;
+						this.data.dnd.to2		= false;
+						this.data.dnd.active	= false;
+						this.data.dnd.foreign	= false;
+						if(m) { m.css({ "left" : "-2000px", "top" : "-2000px" }); }
+					}, this))
+				.bind("vakata.drag_start", $.proxy(function (e, data) {
+						if(data.data.jstree) { 
+							var et = $(data.event.target);
+							if(et.closest(".jstree").hasClass("jstree-" + this.get_index())) {
+								this.dnd_enter(et);
+							}
+						}
+					}, this));
+
+			var s = this.get_settings().dnd;
+			if(s.drag_target) {
+				$(document)
+					.delegate(s.drag_target, "mousedown.jstree", $.proxy(function (e) {
+						o = e.target;
+						$.vakata.dnd.drag_start(e, { jstree : true, obj : e.target }, "<ins class='jstree-icon'></ins>" + $(e.target).text() );
+						if(this.data.themes) { 
+							m.attr("class", "jstree-" + this.data.themes.theme); 
+							$.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme); 
+						}
+						$.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");
+						var cnt = this.get_container();
+						this.data.dnd.cof = cnt.children("ul").offset();
+						this.data.dnd.cw = parseInt(cnt.width(),10);
+						this.data.dnd.ch = parseInt(cnt.height(),10);
+						this.data.dnd.foreign = true;
+						return false;
+					}, this));
+			}
+			if(s.drop_target) {
+				$(document)
+					.delegate(s.drop_target, "mouseenter.jstree", $.proxy(function (e) {
+							if(this.data.dnd.active && this.get_settings().dnd.drop_check.call(this, { "o" : o, "r" : $(e.target) })) {
+								$.vakata.dnd.helper.children("ins").attr("class","jstree-ok");
+							}
+						}, this))
+					.delegate(s.drop_target, "mouseleave.jstree", $.proxy(function (e) {
+							if(this.data.dnd.active) {
+								$.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");
+							}
+						}, this))
+					.delegate(s.drop_target, "mouseup.jstree", $.proxy(function (e) {
+							if(this.data.dnd.active && $.vakata.dnd.helper.children("ins").hasClass("jstree-ok")) {
+								this.get_settings().dnd.drop_finish.call(this, { "o" : o, "r" : $(e.target) });
+							}
+						}, this));
+			}
+		},
+		defaults : {
+			copy_modifier	: "ctrl",
+			check_timeout	: 200,
+			open_timeout	: 500,
+			drop_target		: ".jstree-drop",
+			drop_check		: function (data) { return true; },
+			drop_finish		: $.noop,
+			drag_target		: ".jstree-draggable",
+			drag_finish		: $.noop,
+			drag_check		: function (data) { return { after : false, before : false, inside : true }; }
+		},
+		_fn : {
+			dnd_prepare : function () {
+				this.data.dnd.off = r.offset();
+				if(this.data.dnd.foreign) {
+					var a = this.get_settings().dnd.drag_check.call(this, { "o" : o, "r" : r });
+					this.data.dnd.after = a.after;
+					this.data.dnd.before = a.before;
+					this.data.dnd.inside = a.inside;
+					this.data.dnd.prepared = true;
+					return this.dnd_show();
+				}
+				this.prepare_move(o, r, "before");
+				this.data.dnd.before = this.check_move();
+				this.prepare_move(o, r, "after");
+				this.data.dnd.after = this.check_move();
+				if(this._is_loaded(r)) {
+					this.prepare_move(o, r, "inside");
+					this.data.dnd.inside = this.check_move();
+				}
+				else {
+					this.data.dnd.inside = false;
+				}
+				this.data.dnd.prepared = true;
+				return this.dnd_show();
+			},
+			dnd_show : function () {
+				if(!this.data.dnd.prepared) { return; }
+				var o = ["before","inside","after"],
+					r = false;
+				if(this.data.dnd.w < this.data.core.li_height/3) { o = ["before","inside","after"]; }
+				else if(this.data.dnd.w <= this.data.core.li_height*2/3) {
+					o = this.data.dnd.w < this.data.core.li_height/2 ? ["inside","before","after"] : ["inside","after","before"];
+				}
+				else { o = ["after","inside","before"]; }
+				$.each(o, $.proxy(function (i, val) { 
+					if(this.data.dnd[val]) {
+						$.vakata.dnd.helper.children("ins").attr("class","jstree-ok");
+						r = val;
+						return false;
+					}
+				}, this));
+				if(r === false) { $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid"); }
+				switch(r) {
+					case "before":
+						m.css({ "left" : (this.data.dnd.off.left + 10) + "px", "top" : (this.data.dnd.off.top - 6) + "px" }).show();
+						break;
+					case "after":
+						m.css({ "left" : (this.data.dnd.off.left + 10) + "px", "top" : (this.data.dnd.off.top + this.data.core.li_height - 7) + "px" }).show();
+						break;
+					case "inside":
+						m.css({ "left" : (this.data.dnd.off.left + 14) + "px", "top" : (this.data.dnd.off.top + this.data.core.li_height/2 - 5) + "px" }).show();
+						break;
+					default:
+						m.hide();
+						break;
+				}
+				return r;
+			},
+			dnd_open : function () {
+				this.data.dnd.to2 = false;
+				this.open_node(r, $.proxy(this.dnd_prepare,this), true);
+			},
+			dnd_finish : function (e) {
+				if(this.data.dnd.foreign) {
+					if(this.data.dnd.after || this.data.dnd.before || this.data.dnd.inside) {
+						this.get_settings().dnd.drag_finish.call(this, { "o" : o, "r" : r });
+					}
+				}
+				else {
+					this.dnd_prepare();
+					this.move_node(o, r, this.dnd_show(), e[this.get_settings().dnd.copy_modifier + "Key"]);
+				}
+				o = false;
+				r = false;
+				m.hide();
+			},
+			dnd_enter : function (obj) {
+				var s = this.get_settings().dnd;
+				this.data.dnd.prepared = false;
+				r = this._get_node(obj);
+				if(s.check_timeout) { 
+					// do the calculations after a minimal timeout (users tend to drag quickly to the desired location)
+					if(this.data.dnd.to1) { clearTimeout(this.data.dnd.to1); }
+					this.data.dnd.to1 = setTimeout($.proxy(this.dnd_prepare, this), s.check_timeout); 
+				}
+				else { 
+					this.dnd_prepare(); 
+				}
+				if(s.open_timeout) { 
+					if(this.data.dnd.to2) { clearTimeout(this.data.dnd.to2); }
+					if(r.hasClass("jstree-closed")) { 
+						// if the node is closed - open it, then recalculate
+						this.data.dnd.to2 = setTimeout($.proxy(this.dnd_open, this), s.open_timeout);
+					}
+				}
+				else {
+					if(r.hasClass("jstree-closed")) { 
+						this.dnd_open();
+					}
+				}
+			},
+			start_drag : function (obj, e) {
+				o = this._get_node(obj);
+				if(this.data.ui && this.is_selected(o)) { o = this._get_node(null, true); }
+				$.vakata.dnd.drag_start(e, { jstree : true, obj : o }, "<ins class='jstree-icon'></ins>" + (o.length > 1 ? "Multiple selection" : this.get_text(o)) );
+				if(this.data.themes) { 
+					m.attr("class", "jstree-" + this.data.themes.theme); 
+					$.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme); 
+				}
+				var cnt = this.get_container();
+				this.data.dnd.cof = cnt.children("ul").offset();
+				this.data.dnd.cw = parseInt(cnt.width(),10);
+				this.data.dnd.ch = parseInt(cnt.height(),10);
+				this.data.dnd.active = true;
+			}
+		}
+	});
+	$(function() {
+		var css_string = '' + 
+			'#vakata-dragged ins { display:block; text-decoration:none; width:16px; height:16px; margin:0 0 0 0; padding:0; position:absolute; top:4px; left:4px; } ' + 
+			'#vakata-dragged .jstree-ok { background:green; } ' + 
+			'#vakata-dragged .jstree-invalid { background:red; } ' + 
+			'#jstree-marker { padding:0; margin:0; line-height:12px; font-size:1px; overflow:hidden; height:12px; width:8px; position:absolute; left:-45px; top:-30px; z-index:1000; background-repeat:no-repeat; display:none; background-color:silver; } ';
+		$.vakata.css.add_sheet({ str : css_string });
+		m = $("<div>").attr({ id : "jstree-marker" }).hide().appendTo("body");
+		$(document).bind("vakata.drag_start", function (e, data) {
+			if(data.data.jstree) { 
+				m.show(); 
+			}
+		});
+		$(document).bind("vakata.drag_stop", function (e, data) {
+			if(data.data.jstree) { m.hide(); }
+		});
+	});
+})(jQuery);
+//*/
+
+/*
+ * jsTree checkbox plugin 1.0
+ * Inserts checkboxes in front of every node
+ * Depends on the ui plugin
+ * DOES NOT WORK NICELY WITH MULTITREE DRAG'N'DROP
+ */
+(function ($) {
+	$.jstree.plugin("checkbox", {
+		__init : function () {
+			if(!this.data.ui) { throw("jsTree checkboxes: jsTree UI plugin not included"); }
+			this.select_node = this.deselect_node = this.deselect_all = $.noop;
+			this.get_selected = this.get_checked;
+
+			this.get_container()
+				.bind("open_node.jstree create_node.jstree", $.proxy(function (e, data) { 
+						this._prepare_checkboxes(data.rslt.obj);
+					}, this))
+				.bind("loaded.jstree", $.proxy(function (e) {
+						this._prepare_checkboxes();
+					}, this))
+				.bind("clean_node.jstree", $.proxy(function (e, data) {
+						this._repair_state(data.args[0]);
+					}, this))
+				.delegate("a", "click.jstree", $.proxy(function (e) {
+						this.change_state(e.target);
+						this.save_selected();
+						if(this.data.cookies) { this.save_cookie("select_node"); }
+						e.preventDefault();
+					}, this));
+		},
+		_fn : {
+			_prepare_checkboxes : function (obj) {
+				obj = !obj || obj == -1 ? this.get_container() : this._get_node(obj);
+				var c = obj.is("li") && obj.hasClass("jstree-checked") ? "jstree-checked" : "jstree-unchecked";
+				obj.find("a").not(":has(.checkbox)").prepend("<ins class='checkbox'>&#160;</ins>").parent().addClass(c);
+			},
+			change_state : function (obj, state) {
+				obj = this._get_node(obj);
+				state = (state === false || state === true) ? state : obj.hasClass("jstree-checked");
+				if(state) { obj.find("li").andSelf().removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked"); }
+				else { obj.find("li").andSelf().removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked"); this.data.ui.last_selected = obj; }
+
+				var _this = this;
+				obj.parentsUntil(this.get_container(), "li").each(function () {
+					var $this = $(this);
+					if(state) {
+						if($this.children("ul").children(".jstree-checked, .jstree-undetermined").length) {
+							$this.parentsUntil(_this.get_container(), "li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");
+							return false;
+						}
+						else {
+							$this.removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked");
+						}
+					}
+					else {
+						if($this.children("ul").children(".jstree-unchecked, .jstree-undetermined").length) {
+							$this.parentsUntil(_this.get_container(), "li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");
+							return false;
+						}
+						else {
+							$this.removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked");
+						}
+					}
+				});
+				this.data.ui.selected = this.get_checked();
+				this.__callback(obj);
+			},
+			check_node : function (obj) {
+				this.change_state(obj, false);
+			},
+			uncheck_node : function (obj) {
+				this.change_state(obj, true);
+			},
+			check_all : function () {
+				var _this = this;
+				this.get_container().children("ul").children("li").each(function () {
+					_this.check_node(this, false);
+				});
+			},
+			uncheck_all : function () {
+				var _this = this;
+				this.get_container().children("ul").children("li").each(function () {
+					_this.change_state(this, true);
+				});
+			},
+
+			is_checked : function(obj) {
+				obj = this._get_node(obj);
+				return obj.length ? obj.is(".jstree-checked") : false;
+			},
+			get_checked : function (obj) {
+				obj = !obj || obj === -1 ? this.get_container() : this._get_node(obj);
+				return obj.find("> ul > .jstree-checked, .jstree-undetermined > ul > .jstree-checked");
+			},
+			get_unchecked : function (obj) { 
+				obj = !obj || obj === -1 ? this.get_container() : this._get_node(obj);
+				return obj.find("> ul > .jstree-unchecked, .jstree-undetermined > ul > .jstree-unchecked");
+			},
+
+			show_checkboxes : function () { this.get_container().children("ul").removeClass("jstree-no-checkboxes"); },
+			hide_checkboxes : function () { this.get_container().children("ul").addClass("jstree-no-checkboxes"); },
+
+			_repair_state : function (obj) {
+				obj = this._get_node(obj);
+				if(!obj.length) { return; }
+				var a = obj.find("> ul > .jstree-checked").length,
+					b = obj.find("> ul > .jstree-undetermined").length,
+					c = obj.find("> ul > li").length;
+
+				if(c === 0) { if(obj.hasClass("jstree-undetermined")) { this.check_node(obj); } }
+				else if(a === 0 && b === 0) { this.uncheck_node(obj); }
+				else if(a === c) { this.check_node(obj); }
+				else { 
+					obj.parentsUntil(this.get_container(),"li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");
+				}
+			},
+			reselect : function () {
+				var _this = this,
+					s = this.data.ui.to_select;
+				s = $.map($.makeArray(s), function (n) { return "#" + n.toString().replace(/^#/,"").replace('\\/','/').replace('/','\\/'); });
+				this.deselect_all();
+				$.each(s, function (i, val) { _this.check_node(val); });
+				this.__callback();
+			}
+		}
+	});
+})(jQuery);
+//*/
+
+/* 
+ * jsTree XML 1.0
+ * The XML data store. Datastores are build by overriding the `load_node` and `_is_loaded` functions.
+ */
+(function ($) {
+	$.vakata.xslt = function (xml, xsl) {
+		var rs = "", xm, xs, processor, support;
+		if(document.recalc) {
+			xm = document.createElement('xml');
+			xs = document.createElement('xml');
+			xm.innerHTML = xml;
+			xs.innerHTML = xsl;
+			$("body").append(xm).append(xs);
+			rs = xm.transformNode(xs.XMLDocument);
+			$("body").remove(xm).remove(xs);
+			return rs;
+		}
+		if(typeof window.DOMParser !== "undefined" && typeof window.XMLHttpRequest !== "undefined" && typeof window.XSLTProcessor !== "undefined") {
+			processor = new XSLTProcessor();
+			support = $.isFunction(processor.transformDocument) ? (typeof window.XMLSerializer !== "undefined") : true;
+			if(!support) { return false; }
+			xml = new DOMParser().parseFromString(xml, "text/xml");
+			xsl = new DOMParser().parseFromString(xsl, "text/xml");
+			if($.isFunction(processor.transformDocument)) {
+				rs = document.implementation.createDocument("", "", null);
+				processor.transformDocument(xml, xsl, rs, null);
+				return new XMLSerializer().serializeToString(rs);
+			}
+			else {
+				processor.importStylesheet(xsl);
+				rs = processor.transformToFragment(xml, document);
+				return $("<div>").append(rs).html();
+			}
+		}
+		return false;
+	};
+	var xsl = {
+		'nest' : '<?xml version="1.0" encoding="utf-8" ?>' + 
+			'<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >' + 
+			'<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/html" />' + 
+			'<xsl:template match="/">' + 
+			'	<xsl:call-template name="nodes">' + 
+			'		<xsl:with-param name="node" select="/root" />' + 
+			'	</xsl:call-template>' + 
+			'</xsl:template>' + 
+			'<xsl:template name="nodes">' + 
+			'	<xsl:param name="node" />' + 
+			'	<ul>' + 
+			'	<xsl:for-each select="$node/item">' + 
+			'		<xsl:variable name="children" select="count(./item) &gt; 0" />' + 
+			'		<li>' + 
+			'			<xsl:attribute name="class">' + 
+			'				<xsl:if test="position() = last()">jstree-last </xsl:if>' + 
+			'				<xsl:choose>' + 
+			'					<xsl:when test="@state = \'open\'">jstree-open </xsl:when>' + 
+			'					<xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>' + 
+			'					<xsl:otherwise>jstree-leaf </xsl:otherwise>' + 
+			'				</xsl:choose>' + 
+			'				<xsl:value-of select="@class" />' + 
+			'			</xsl:attribute>' + 
+			'			<xsl:for-each select="@*">' + 
+			'				<xsl:if test="name() != \'class\' and name() != \'state\' and name() != \'hasChildren\'">' + 
+			'					<xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + 
+			'				</xsl:if>' + 
+			'			</xsl:for-each>' + 
+			'	<ins class="jstree-icon"><xsl:text>&#xa0;</xsl:text></ins>' + 
+			'			<xsl:for-each select="content/name">' + 
+			'				<a>' + 
+			'				<xsl:attribute name="href">' + 
+			'					<xsl:choose>' + 
+			'					<xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>' + 
+			'					<xsl:otherwise>#</xsl:otherwise>' + 
+			'					</xsl:choose>' + 
+			'				</xsl:attribute>' + 
+			'				<xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>' + 
+			'				<xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>' + 
+			'				<xsl:for-each select="@*">' + 
+			'					<xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">' + 
+			'						<xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + 
+			'					</xsl:if>' + 
+			'				</xsl:for-each>' + 
+			'					<ins>' + 
+			'						<xsl:attribute name="class">jstree-icon ' + 
+			'							<xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>' + 
+			'						</xsl:attribute>' + 
+			'						<xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if>' + 
+			'						<xsl:text>&#xa0;</xsl:text>' + 
+			'					</ins>' + 
+			'					<xsl:value-of select="current()" />' + 
+			'				</a>' + 
+			'			</xsl:for-each>' + 
+			'			<xsl:if test="$children or @hasChildren"><xsl:call-template name="nodes"><xsl:with-param name="node" select="current()" /></xsl:call-template></xsl:if>' + 
+			'		</li>' + 
+			'	</xsl:for-each>' + 
+			'	</ul>' + 
+			'</xsl:template>' + 
+			'</xsl:stylesheet>',
+
+		'flat' : '<?xml version="1.0" encoding="utf-8" ?>' + 
+			'<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >' + 
+			'<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/xml" />' + 
+			'<xsl:template match="/">' + 
+			'	<ul>' + 
+			'	<xsl:for-each select="//item[not(@parent_id) or @parent_id=0]">' + 
+			'		<xsl:call-template name="nodes">' + 
+			'			<xsl:with-param name="node" select="." />' + 
+			'			<xsl:with-param name="is_last" select="number(position() = last())" />' + 
+			'		</xsl:call-template>' + 
+			'	</xsl:for-each>' + 
+			'	</ul>' + 
+			'</xsl:template>' + 
+			'<xsl:template name="nodes">' + 
+			'	<xsl:param name="node" />' + 
+			'	<xsl:param name="is_last" />' + 
+			'	<xsl:variable name="children" select="count(//item[@parent_id=$node/attribute::id]) &gt; 0" />' + 
+			'	<li>' + 
+			'	<xsl:attribute name="class">' + 
+			'		<xsl:if test="$is_last = true()">jstree-last </xsl:if>' + 
+			'		<xsl:choose>' + 
+			'			<xsl:when test="@state = \'open\'">jstree-open </xsl:when>' + 
+			'			<xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>' + 
+			'			<xsl:otherwise>jstree-leaf </xsl:otherwise>' + 
+			'		</xsl:choose>' + 
+			'		<xsl:value-of select="@class" />' + 
+			'	</xsl:attribute>' + 
+			'	<xsl:for-each select="@*">' + 
+			'		<xsl:if test="name() != \'parent_id\' and name() != \'hasChildren\' and name() != \'class\' and name() != \'state\'">' + 
+			'		<xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + 
+			'		</xsl:if>' + 
+			'	</xsl:for-each>' + 
+			'	<ins class="jstree-icon"><xsl:text>&#xa0;</xsl:text></ins>' + 
+			'	<xsl:for-each select="content/name">' + 
+			'		<a>' + 
+			'		<xsl:attribute name="href">' + 
+			'			<xsl:choose>' + 
+			'			<xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>' + 
+			'			<xsl:otherwise>#</xsl:otherwise>' + 
+			'			</xsl:choose>' + 
+			'		</xsl:attribute>' + 
+			'		<xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>' + 
+			'		<xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>' + 
+			'		<xsl:for-each select="@*">' + 
+			'			<xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">' + 
+			'				<xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + 
+			'			</xsl:if>' + 
+			'		</xsl:for-each>' + 
+			'			<ins>' + 
+			'				<xsl:attribute name="class">jstree-icon ' + 
+			'					<xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>' + 
+			'				</xsl:attribute>' + 
+			'				<xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if>' + 
+			'				<xsl:text>&#xa0;</xsl:text>' + 
+			'			</ins>' + 
+			'			<xsl:value-of select="current()" />' + 
+			'		</a>' + 
+			'	</xsl:for-each>' + 
+			'	<xsl:if test="$children">' + 
+			'		<ul>' + 
+			'		<xsl:for-each select="//item[@parent_id=$node/attribute::id]">' + 
+			'			<xsl:call-template name="nodes">' + 
+			'				<xsl:with-param name="node" select="." />' + 
+			'				<xsl:with-param name="is_last" select="number(position() = last())" />' + 
+			'			</xsl:call-template>' + 
+			'		</xsl:for-each>' + 
+			'		</ul>' + 
+			'	</xsl:if>' + 
+			'	</li>' + 
+			'</xsl:template>' + 
+			'</xsl:stylesheet>'
+	};
+	$.jstree.plugin("xml_data", {
+		defaults : { 
+			data : false,
+			ajax : false,
+			xsl : "flat",
+			clean_node : false
+		},
+		_fn : {
+			load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_xml(obj, function () { _this.__callback({ "obj" : obj }); s_call.call(this); }, e_call); },
+			_is_loaded : function (obj) { 
+				var s = this.get_settings().xml_data;
+				return obj == -1 || !obj || !s.ajax || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").size() > 0;
+			},
+			load_node_xml : function (obj, s_call, e_call) {
+				var s = this.get_settings().xml_data,
+					error_func = function () {},
+					success_func = function () {};
+				switch(!0) {
+					case (!s.data && !s.ajax): throw "Neither data nor ajax settings supplied.";
+					case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)):
+						if(!obj || obj == -1) {
+							this.get_container().children("ul").empty().append(this.parse_xml(s.data).children());
+							if(s.clean_node) { this.clean_node(obj); }
+						}
+						if(s_call) { s_call.call(this); }
+						break;
+					case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1):
+						obj = this._get_node(obj);
+						error_func = function (x, t, e) {
+							var ef = this.get_settings().xml_data.ajax.error; 
+							if(ef) { ef.call(this, x, t, e); }
+							if(obj !== -1 && obj.length) {
+								obj.children(".jstree-loading").removeClass("jstree-loading");
+								if(s.correct_state) { obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf"); }
+							}
+							if(e_call) { e_call.call(this); }
+						};
+						success_func = function (d, t, x) {
+							if(x.responseText == "") {
+								return error_func.call(this, x, t, "");
+							}
+							d = x.responseText;
+							var sf = this.get_settings().xml_data.ajax.success; 
+							if(sf) { d = sf.call(this,d,t,x) || d; }
+							d = this.parse_xml(d);
+							if(d) {
+								if(obj === -1 || !obj) { this.get_container().children("ul").empty().append(this.parse_xml(x.responseText).children()); }
+								else { obj.append(this.parse_xml(x.responseText)).children(".jstree-loading").removeClass("jstree-loading"); }
+								if(s.clean_node) { this.clean_node(obj); }
+								if(s_call) { s_call.call(this); }
+							}
+							else {
+								obj.children(".jstree-loading").removeClass("jstree-loading");
+								if(s.correct_state) { obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf"); }
+							}
+						};
+						s.ajax.context = this;
+						s.ajax.error = error_func;
+						s.ajax.success = success_func;
+						if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(null, obj); }
+						$.ajax(s.ajax);
+						break;
+				}
+			},
+			parse_xml : function (xml) {
+				var s = this.get_settings().xml_data,
+					result = $.vakata.xslt(xml, xsl[s.xsl]);
+				if(result !== false) { result = $(result); }
+				return result;
+			},
+			get_xml : function (tp, obj, li_attr, a_attr, is_callback) {
+				var result = "", 
+					s = this.get_settings(), 
+					_this = this,
+					tmp1, tmp2, li, a, lang;
+				if(!tp) { tp = "flat"; }
+				if(!is_callback) { is_callback = 0; }
+				obj = this._get_node(obj);
+				if(!obj || obj === -1) { obj = this.get_container().find("> ul > li"); }
+				li_attr = $.isArray(li_attr) ? li_attr : [ "id", "class" ];
+				if(this.data.types) { li_attr.push(s.types.type_attr); }
+				a_attr = $.isArray(a_attr) ? a_attr : [ ];
+
+				if(!is_callback) { result += "<root>"; }
+				obj.each(function () {
+					result += "<item";
+					li = $(this);
+					$.each(li_attr, function (i, v) { result += " " + v + "=\"" + li.attr(v).replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"") + "\""; });
+					if(li.hasClass("jstree-open")) { result += " state=\"open\""; }
+					if(li.hasClass("jstree-closed")) { result += " state=\"closed\""; }
+					if(tp === "flat") { result += " parent_id=\"" + is_callback + "\""; }
+					result += ">";
+					result += "<content>";
+					a = li.children("a");
+					a.each(function () {
+						tmp1 = $(this);
+						lang = false;
+						result += "<name";
+						if($.inArray("languages", s.plugins) !== -1) {
+							$.each(s.languages, function (k, z) {
+								if(tmp1.hasClass(z)) { result += " lang=\"" + z + "\""; lang = z; return false; }
+							});
+						}
+						if(a_attr.length) { 
+							$.each(a_attr, function (k, z) {
+								result += " " + z + "=\"" + li.attr(z).replace(/jstree[^ ]*|$/ig,'') + "\"";
+							});
+						}
+						if(tmp1.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"").length) {
+							result += ' icon="' + tmp1.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"") + '"';
+						}
+						if(tmp1.children("ins").get(0).style.backgroundImage.length) {
+							result += ' icon="' + tmp1.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")","") + '"';
+						}
+						result += ">";
+						result += "<![CDATA[" + _this.get_text(tmp1, lang) + "]]>";
+						result += "</name>";
+					});
+					result += "</content>";
+					tmp2 = li[0].id;
+					li = li.find("> ul > li");
+					if(li.length) { tmp2 = _this.get_xml(tp, li, li_attr, a_attr, tmp2); }
+					if(tp == "nest") { result += tmp2; }
+					result += "</item>";
+					if(tp == "flat") { result += tmp2; }
+				});
+				if(!is_callback) { result += "</root>"; }
+				return result;
+			}
+		}
+	});
+})(jQuery);
+//*/
+
+/*
+ * jsTree search plugin 1.0
+ * Enables both sync and async search on the tree
+ * DOES NOT WORK WITH JSON PROGRESSIVE RENDER
+ */
+(function ($) {
+	$.expr[':'].jstree_contains = function(a,i,m){
+		return (a.textContent || a.innerText || "").toLowerCase().indexOf(m[3].toLowerCase())>=0;
+	};
+	$.jstree.plugin("search", {
+		__init : function () {
+			this.data.search.str = "";
+			this.data.search.result = $();
+		},
+		defaults : {
+			ajax : false, // OR ajax object
+			case_insensitive : false
+		},
+		_fn : {
+			search : function (str, skip_async) {
+				var s = this.get_settings().search, 
+					t = this,
+					error_func = function () { },
+					success_func = function () { };
+				this.data.search.str = str;
+
+				if(!skip_async && s.ajax !== false && this.get_container().find(".jstree-closed:eq(0)").length > 0) {
+					this.search.supress_callback = true;
+					error_func = function () { };
+					success_func = function (d, t, x) {
+						var sf = this.get_settings().search.ajax.success; 
+						if(sf) { d = sf.call(this,d,t,x) || d; }
+						this.data.search.to_open = d;
+						this._search_open();
+					};
+					s.ajax.context = this;
+					s.ajax.error = error_func;
+					s.ajax.success = success_func;
+					if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, str); }
+					if(!s.ajax.data) { s.ajax.data = { "search_string" : str }; }
+					if(!s.ajax.dataType || /^json/.exec(s.ajax.dataType)) { s.ajax.dataType = "json"; }
+					$.ajax(s.ajax);
+					return;
+				}
+				if(this.data.search.result.length) { this.clear_search(); }
+				this.data.search.result = this.get_container().find("a" + (this.data.languages ? "." + this.get_lang() : "" ) + ":" + (s.case_insensitive ? "jstree_contains" : "contains") + "(" + this.data.search.str + ")");
+				this.data.search.result.addClass("jstree-search").parents(".jstree-closed").each(function () {
+					t.open_node(this, false, true);
+				});
+				this.__callback({ nodes : this.data.search.result, str : str });
+			},
+			clear_search : function (str) {
+				this.data.search.result.removeClass("jstree-search");
+				this.__callback(this.data.search.result);
+				this.data.search.result = $();
+			},
+			_search_open : function (is_callback) {
+				var _this = this,
+					done = true,
+					current = [],
+					remaining = [];
+				if(this.data.search.to_open.length) {
+					$.each(this.data.search.to_open, function (i, val) {
+						if(val == "#") { return true; }
+						if($(val).length && $(val).is(".jstree-closed")) { current.push(val); }
+						else { remaining.push(val); }
+					});
+					if(current.length) {
+						this.data.search.to_open = remaining;
+						$.each(current, function (i, val) { 
+							_this.open_node(val, function () { _this._search_open(true); }); 
+						});
+						done = false;
+					}
+				}
+				if(done) { this.search(this.data.search.str, true); }
+			}
+		}
+	});
+})(jQuery);
+//*/
+
+/*
+ * jsTree contextmenu plugin 1.0
+ */
+(function ($) {
+	$.vakata.context = {
+		cnt		: $("<div id='vakata-contextmenu'>"),
+		vis		: false,
+		tgt		: false,
+		func	: false,
+		data	: false,
+		show	: function (s, t, x, y, d) {
+			var html = $.vakata.context.parse(s), h, w;
+			if(!html) { return; }
+			$.vakata.context.vis = true;
+			$.vakata.context.tgt = t;
+			$.vakata.context.data = d || null;
+			$.vakata.context.cnt
+				.html(html)
+				.css({ "visibility" : "hidden", "display" : "block", "left" : 0, "top" : 0 });
+			h = $.vakata.context.cnt.height();
+			w = $.vakata.context.cnt.width();
+			if(x + w > $(document).width()) { 
+				x = $(document).width() - (w + 5); 
+				$.vakata.context.cnt.find("li > ul").addClass("right"); 
+			}
+			if(y + h > $(document).height()) { 
+				y = y - (h + t[0].offsetHeight); 
+				$.vakata.context.cnt.find("li > ul").addClass("bottom"); 
+			}
+
+			$.vakata.context.cnt
+				.css({ "left" : x, "top" : y })
+				.find("li:has(ul)")
+					.bind("mouseenter", function (e) { 
+						var w = $(document).width(),
+							h = $(document).height(),
+							ul = $(this).children("ul").show(); 
+						if(w !== $(document).width()) { ul.toggleClass("right"); }
+						if(h !== $(document).height()) { ul.toggleClass("bottom"); }
+					})
+					.bind("mouseleave", function (e) { 
+						$(this).children("ul").hide(); 
+					})
+					.end()
+				.css({ "visibility" : "visible" })
+				.show();
+			$(document).triggerHandler("vakata.context_show");
+		},
+		hide	: function () {
+			$.vakata.context.vis = false;
+			$.vakata.context.cnt.attr("class","").hide();
+			$(document).triggerHandler("vakata.context_hide");
+		},
+		parse	: function (s, is_callback) {
+			var str = "",
+				tmp = false;
+			if(!is_callback) { $.vakata.context.func = {}; }
+			str += "<ul>";
+			$.each(s, function (i, val) {
+				if(!val) { return true; }
+				$.vakata.context.func[i] = val.action;
+				if(val.separator_before) {
+					str += "<li class='vakata-separator vakata-separator-before'></li>";
+				}
+				str += "<li><ins ";
+				if(val.icon && val.icon.indexOf("/") === -1) { str += " class='" + val.icon + "' "; }
+				if(val.icon && val.icon.indexOf("/") !== -1) { str += " style='background:url(" + val.icon + ") center center no-repeat;' "; }
+				str += ">&#160;</ins><a href='#' rel='" + i + "'>" + val.label;
+				if(val.submenu) {
+					str += "<span style='float:right;'>&raquo;</span>";
+				}
+				str += "</a>";
+				if(val.submenu) {
+					tmp = $.vakata.context.parse(val.submenu, true);
+					if(tmp) { str += tmp; }
+				}
+				str += "</li>";
+				if(val.separator_after) {
+					str += "<li class='vakata-separator vakata-separator-after'></li>";
+				}
+			});
+			str += "</ul>";
+			return str.length > 10 ? str : false;
+		},
+		exec	: function (i) {
+			if($.isFunction($.vakata.context.func[i])) {
+				$.vakata.context.func[i].call($.vakata.context.data, $.vakata.context.tgt);
+				return true;
+			}
+			else { return false; }
+		}
+	};
+	$(function () {
+		var css_string = '' + 
+			'#vakata-contextmenu { display:none; position:absolute; margin:0; padding:0; min-width:180px; background:#ebebeb; border:1px solid silver; } ' + 
+			'#vakata-contextmenu ul { min-width:180px; } ' + 
+			'#vakata-contextmenu ul, #vakata-contextmenu li { margin:0; padding:0; list-style-type:none; display:block; } ' + 
+			'#vakata-contextmenu li { line-height:20px; min-height:20px; position:relative; padding:0px; } ' + 
+			'#vakata-contextmenu li a { padding:1px 6px; line-height:17px; display:block; text-decoration:none; margin:1px 1px 0 1px; } ' + 
+			'#vakata-contextmenu li ins { float:left; width:16px; height:16px; text-decoration:none; margin-right:2px; } ' + 
+			'#vakata-contextmenu li a:hover, #vakata-contextmenu li.vakata-hover > a { background:gray; color:white; } ' + 
+			'#vakata-contextmenu li ul { display:none; position:absolute; top:-2px; left:100%; background:#ebebeb; border:1px solid gray; } ' + 
+			'#vakata-contextmenu .right { right:100%; left:auto; } ' + 
+			'#vakata-contextmenu .bottom { bottom:-1px; top:auto; } ' + 
+			'#vakata-contextmenu li.vakata-separator { min-height:0; height:1px; line-height:1px; font-size:1px; overflow:hidden; margin:0 2px; background:silver; /* border-top:1px solid #fefefe; */ padding:0; } ';
+		$.vakata.css.add_sheet({ str : css_string });
+		$.vakata.context.cnt
+			.delegate("a","click", function (e) { e.preventDefault(); })
+			.delegate("a","mouseup", function (e) {
+				if($.vakata.context.exec($(this).attr("rel"))) {
+					$.vakata.context.hide();
+				}
+			})
+			.delegate("a","mouseover", function () {
+				$.vakata.context.cnt.find(".vakata-hover").removeClass("vakata-hover");
+			})
+			.appendTo("body");
+		$(document).bind("mousedown", function (e) { if($.vakata.context.vis && !$.contains($.vakata.context.cnt[0], e.target)) { $.vakata.context.hide(); } });
+		if(typeof $.hotkeys !== "undefined") {
+			$(document)
+				.bind("keydown", "up", function (e) { 
+					if($.vakata.context.vis) { 
+						var o = $.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").prevAll("li:not(.vakata-separator)").first();
+						if(!o.length) { o = $.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").last(); }
+						o.addClass("vakata-hover");
+						e.stopImmediatePropagation(); 
+						e.preventDefault();
+					} 
+				})
+				.bind("keydown", "down", function (e) { 
+					if($.vakata.context.vis) { 
+						var o = $.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").nextAll("li:not(.vakata-separator)").first();
+						if(!o.length) { o = $.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").first(); }
+						o.addClass("vakata-hover");
+						e.stopImmediatePropagation(); 
+						e.preventDefault();
+					} 
+				})
+				.bind("keydown", "right", function (e) { 
+					if($.vakata.context.vis) { 
+						$.vakata.context.cnt.find(".vakata-hover").children("ul").show().children("li:not(.vakata-separator)").removeClass("vakata-hover").first().addClass("vakata-hover");
+						e.stopImmediatePropagation(); 
+						e.preventDefault();
+					} 
+				})
+				.bind("keydown", "left", function (e) { 
+					if($.vakata.context.vis) { 
+						$.vakata.context.cnt.find(".vakata-hover").children("ul").hide().children(".vakata-separator").removeClass("vakata-hover");
+						e.stopImmediatePropagation(); 
+						e.preventDefault();
+					} 
+				})
+				.bind("keydown", "esc", function (e) { 
+					$.vakata.context.hide(); 
+					e.preventDefault();
+				})
+				.bind("keydown", "space", function (e) { 
+					$.vakata.context.cnt.find(".vakata-hover").last().children("a").click();
+					e.preventDefault();
+				});
+		}
+	});
+
+	$.jstree.plugin("contextmenu", {
+		__init : function () {
+			this.get_container()
+				.delegate("a", "contextmenu.jstree", $.proxy(function (e) {
+						e.preventDefault();
+						this.show_contextmenu(e.currentTarget, e.pageX, e.pageY);
+					}, this));
+		},
+		defaults : { 
+			show_at_node : true,
+			items : { // Could be a function that should return an object like this one
+				"create" : {
+					"separator_before"	: false,
+					"separator_after"	: true,
+					"label"				: "Create",
+					"action"			: function (obj) { this.create(obj); }
+				},
+				"rename" : {
+					"separator_before"	: false,
+					"separator_after"	: false,
+					"label"				: "Rename",
+					"action"			: function (obj) { this.rename(obj); }
+				},
+				"remove" : {
+					"separator_before"	: false,
+					"icon"				: false,
+					"separator_after"	: false,
+					"label"				: "Delete",
+					"action"			: function (obj) { this.remove(obj); }
+				},
+				"ccp" : {
+					"separator_before"	: true,
+					"icon"				: false,
+					"separator_after"	: false,
+					"label"				: "Edit",
+					"action"			: function (obj) { this.remove(obj); },
+					"submenu" : { 
+						"cut" : {
+							"separator_before"	: false,
+							"separator_after"	: false,
+							"label"				: "Cut",
+							"action"			: function (obj) { this.cut(obj); }
+						},
+						"copy" : {
+							"separator_before"	: false,
+							"icon"				: false,
+							"separator_after"	: false,
+							"label"				: "Copy",
+							"action"			: function (obj) { this.copy(obj); }
+						},
+						"paste" : {
+							"separator_before"	: false,
+							"icon"				: false,
+							"separator_after"	: false,
+							"label"				: "Paste",
+							"action"			: function (obj) { this.paste(obj); }
+						}
+					}
+				}
+			}
+		},
+		_fn : {
+			show_contextmenu : function (obj, x, y) {
+				obj = this._get_node(obj);
+				var s = this.get_settings().contextmenu,
+					a = obj.children("a:visible:eq(0)"),
+					o = false;
+				if(s.show_at_node || typeof x === "undefined" || typeof y === "undefined") {
+					o = a.offset();
+					x = o.left;
+					y = o.top + this.data.core.li_height;
+				}
+				if($.isFunction(s.items)) { s.items = s.items.call(this, obj); }
+				$.vakata.context.show(s.items, a, x, y, this);
+				if(this.data.themes) { $.vakata.context.cnt.attr("class", "jstree-" + this.data.themes.theme + "-context"); }
+			}
+		}
+	});
+})(jQuery);
+//*/
+
+/* 
+ * jsTree types plugin 1.0
+ * Adds support types of nodes
+ * You can set an attribute on each li node, that represents its type.
+ * According to the type setting the node may get custom icon/validation rules
+ */
+(function ($) {
+	$.jstree.plugin("types", {
+		__init : function () {
+			var s = this.get_settings().types;
+			this.data.types.attach_to = [];
+			this.get_container()
+				.bind("init.jstree", $.proxy(function () { 
+						var types = s.types, 
+							attr  = s.type_attr, 
+							icons_css = "", 
+							_this = this;
+
+						$.each(types, function (i, tp) {
+							$.each(tp, function (k, v) { 
+								if(!/^(max_depth|max_children|icon|valid_children)$/.test(k)) { _this.data.types.attach_to.push(k); }
+							});
+							if(!tp.icon) { return true; }
+							if( tp.icon.image || tp.icon.position) {
+								if(i == "default")	{ icons_css += '.jstree-' + _this.get_index() + ' a > .jstree-icon { '; }
+								else				{ icons_css += '.jstree-' + _this.get_index() + ' li[' + attr + '=' + i + '] > a > .jstree-icon { '; }
+								if(tp.icon.image)	{ icons_css += ' background-image:url(' + tp.icon.image + '); '; }
+								if(tp.icon.position){ icons_css += ' background-position:' + tp.icon.position + '; '; }
+								else				{ icons_css += ' background-position:0 0; '; }
+								icons_css += '} ';
+							}
+						});
+						if(icons_css != "") { $.vakata.css.add_sheet({ 'str' : icons_css }); }
+					}, this))
+				.bind("before.jstree", $.proxy(function (e, data) { 
+						if($.inArray(data.func, this.data.types.attach_to) !== -1) {
+							var s = this.get_settings().types.types,
+								t = this._get_type(data.args[0]);
+							if(s[t] && typeof s[t][data.func] !== "undefined" && !this._check(data.func, data.args[0])) {
+								e.stopImmediatePropagation();
+								return false;
+							}
+						}
+					}, this));
+		},
+		defaults : {
+			// defines maximum number of root nodes (-1 means unlimited, -2 means disable max_children checking)
+			max_children		: -1,
+			// defines the maximum depth of the tree (-1 means unlimited, -2 means disable max_depth checking)
+			max_depth			: -1,
+			// defines valid node types for the root nodes
+			valid_children		: "all",
+
+			// where is the type stores (the rel attribute of the LI element)
+			type_attr : "rel",
+			// a list of types
+			types : {
+				// the default type
+				"default" : {
+					"max_children"	: -1,
+					"max_depth"		: -1,
+					"valid_children": "all"
+
+					// Bound functions - you can bind any other function here (using boolean or function)
+					//"select_node"	: true,
+					//"open_node"	: true,
+					//"close_node"	: true,
+					//"create_node"	: true,
+					//"delete_node"	: true
+				}
+			}
+		},
+		_fn : {
+			_get_type : function (obj) {
+				obj = this._get_node(obj);
+				return (!obj || !obj.length) ? false : obj.attr(this.get_settings().types.type_attr) || "default";
+			},
+			set_type : function (str, obj) {
+				obj = this._get_node(obj);
+				return (!obj.length || !str) ? false : obj.attr(this.get_settings().types.type_attr, str);
+			},
+			_check : function (rule, obj, opts) {
+				var v = false, t = this._get_type(obj), d = 0, _this = this, s = this.get_settings().types;
+				if(obj === -1) { 
+					if(!!s[rule]) { v = s[rule]; }
+					else { return; }
+				}
+				else {
+					if(t === false) { return; }
+					if(!!s.types[t] && !!s.types[t][rule]) { v = s.types[t][rule]; }
+					else if(!!s.types["default"] && !!s.types["default"][rule]) { v = s.types["default"][rule]; }
+				}
+				if($.isFunction(v)) { v = v.call(this, obj); }
+				if(rule === "max_depth" && obj !== -1 && opts !== false && s.max_depth !== -2 && v !== 0) {
+					this._get_node(obj).parentsUntil(this.get_container(),"li").each(function (i) {
+						d = _this._check(rule, this, false);
+						if(d !== -1 && d - (i + 1) <= 0) { v = 0; return false; }
+						if(d >= 0 && (d - (i + 1) < v || v < 0) ) { v = d - (i + 1); }
+					});
+				}
+				return v;
+			},
+			check_move : function () {
+				if(!this.__call_old()) { return false; }
+				var m  = this._get_move(),
+					s  = m.rt.get_settings().types,
+					mc = m.rt._check("max_children", m.cr),
+					md = m.rt._check("max_depth", m.cr),
+					vc = m.rt._check("valid_children", m.cr),
+					ch = 0, d = 1, t;
+
+				if(vc === "none") { return false; } 
+				if($.isArray(vc) && m.ot && m.ot._get_type) {
+					m.o.each(function () {
+						if($.inArray(m.ot._get_type(this), vc) === -1) { d = false; return false; }
+					});
+					if(d === false) { return false; }
+				}
+				if(s.max_children !== -2 && mc !== -1) {
+					ch = m.cr === -1 ? this.get_container().children("> ul > li").not(m.o).length : m.cr.children("> ul > li").not(m.o).length;
+					if(ch + m.o.length > mc) { return false; }
+				}
+				if(s.max_depth !== -2 && md !== -1) {
+					d = 0;
+					if(md === 0) { return false; }
+					if(typeof m.o.d === "undefined") {
+						// TODO: deal with progressive rendering and async when checking max_depth (how to know the depth of the moved node)
+						t = m.o;
+						while(t.length > 0) {
+							t = t.find("> ul > li");
+							d ++;
+						}
+						m.o.d = d;
+					}
+					if(md - m.o.d < 0) { return false; }
+				}
+				return true;
+			},
+			create_node : function (obj, position, js, callback, is_loaded, skip_check) {
+				if(!skip_check && (is_loaded || this._is_loaded(obj))) {
+					var p  = (position && position.match(/^before|after$/i)) ? this._get_parent(obj) : this._get_node(obj),
+						s  = this.get_settings().types,
+						mc = this._check("max_children", p),
+						md = this._check("max_depth", p),
+						vc = this._check("valid_children", p),
+						ch;
+					if(!js) { js = {}; }
+					if(vc === "none") { return false; } 
+					if($.isArray(vc)) {
+						if(!js.attr || !js.attr[s.type_attr]) { 
+							if(!js.attr) { js.attr = {}; }
+							js.attr[s.type_attr] = vc[0]; 
+						}
+						else {
+							if($.inArray(js.attr[s.type_attr], vc) === -1) { return false; }
+						}
+					}
+					if(s.max_children !== -2 && mc !== -1) {
+						ch = p === -1 ? this.get_container().children("> ul > li").length : p.children("> ul > li").length;
+						if(ch + 1 > mc) { return false; }
+					}
+					if(s.max_depth !== -2 && md !== -1 && (md - 1) <= 0) { return false; }
+				}
+				return this.__call_old(true, obj, position, js, callback, is_loaded, skip_check);
+			}
+		}
+	});
+})(jQuery);
+//*/
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/jquery.jstree.min.js
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/jquery.jstree.min.js	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/jquery.jstree.min.js	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,142 @@
+(function(c){c.vakata={};c.vakata.css={get_css:function(a,d,g){a=a.toLowerCase();var f=g.cssRules||g.rules,b=0;do{if(f.length&&b>f.length+5)return false;if(f[b].selectorText&&f[b].selectorText.toLowerCase()==a)if(d===true){g.removeRule&&g.removeRule(b);g.deleteRule&&g.deleteRule(b);return true}else return f[b]}while(f[++b]);return false},add_css:function(a,d){if(c.jstree.css.get_css(a,false,d))return false;d.insertRule?d.insertRule(a+" { }",0):d.addRule(a,null,0);return c.vakata.css.get_css(a)},remove_css:function(a,
+d){return c.vakata.css.get_css(a,true,d)},add_sheet:function(a){var d;if(a.str){d=document.createElement("style");d.setAttribute("type","text/css");if(d.styleSheet){document.getElementsByTagName("head")[0].appendChild(d);d.styleSheet.cssText=a.str}else{d.appendChild(document.createTextNode(a.str));document.getElementsByTagName("head")[0].appendChild(d)}return d.sheet||d.styleSheet}if(a.url)if(document.createStyleSheet)try{document.createStyleSheet(a.url)}catch(g){}else{d=document.createElement("link");
+d.rel="stylesheet";d.type="text/css";d.media="all";d.href=a.url;document.getElementsByTagName("head")[0].appendChild(d);return d.styleSheet}}}})(jQuery);
+(function(c){var a=[],d=-1,g={},f={};c.fn.jstree=function(b){var e=typeof b=="string",h=Array.prototype.slice.call(arguments,1),k=this;!e&&c.meta&&h.push(c.metadata.get(this).jstree);b=!e&&h.length?c.extend.apply(null,[true,b].concat(h)):b;if(e&&b.substring(0,1)=="_")return k;e?this.each(function(){var j=a[c.data(this,"jstree-instance-id")];j=j&&c.isFunction(j[b])?j[b].apply(j,h):j;if(typeof j!=="undefined"&&j!==true&&j!==false){k=j;return false}}):this.each(function(){var j=c.data(this,"jstree-instance-id"),
+i=false;j&&a[j]&&a[j].destroy();j=parseInt(a.push({}),10)-1;c.data(this,"jstree-instance-id",j);b.plugins=c.isArray(b.plugins)?b.plugins:c.jstree.defaults.plugins;c.inArray("core",b.plugins)===-1&&b.plugins.unshift("core");i=c.extend(true,{},c.jstree.defaults,b);i.plugins=b.plugins;a[j]=new c.jstree._instance(j,c(this).addClass("jstree jstree-"+j),i);c.each(a[j].get_settings().plugins,function(m,l){a[j].data[l]={}});c.each(a[j].get_settings().plugins,function(m,l){g[l]&&g[l].__init.apply(a[j])});
+a[j].init()});return k};c.jstree={defaults:{plugins:[]},_focused:function(){return a[d]||null},_reference:function(b){if(a[b])return a[b];var e=c(b);if(!e.length&&typeof b==="string")e=c("#"+b);if(!e.length)return null;return a[e.closest(".jstree").data("jstree-instance-id")]||null},_instance:function(b,e,h){this.data={core:{}};this.get_settings=function(){return c.extend(true,{},h)};this.get_index=function(){return b};this.get_container=function(){return e};this._set_settings=function(k){h=c.extend(true,
+{},h,k)}},_fn:{},plugin:function(b,e){e=c.extend({},{__init:c.noop,__destroy:c.noop,_fn:{},defaults:false},e);g[b]=e;c.jstree.defaults[b]=e.defaults;c.each(e._fn,function(h,k){k.plugin=b;k.old=c.jstree._fn[h];c.jstree._fn[h]=function(){var j,i=k,m=Array.prototype.slice.call(arguments);j=this.get_settings();var l=new c.Event("before.jstree"),o=false;do{if(i&&i.plugin&&c.inArray(i.plugin,j.plugins)!==-1)break;i=i.old}while(i);if(i){j=this.get_container().triggerHandler(l,{func:h,inst:this,args:m});
+if(j!==false){if(typeof j!=="undefined")m=j;return j=i.apply(c.extend({},this,{__callback:function(n){this.get_container().triggerHandler(h+".jstree",{inst:this,args:m,rslt:n,rlbk:o})},__rollback:function(){return o=this.get_rollback()},__call_old:function(n){return i.old.apply(this,n?Array.prototype.slice.call(arguments,1):m)}}),m)}}};c.jstree._fn[h].old=k.old;c.jstree._fn[h].plugin=b})},rollback:function(b){if(b){c.isArray(b)||(b=[b]);c.each(b,function(e,h){a[h.i].set_rollback(h.h,h.d)})}}};c.jstree._fn=
+c.jstree._instance.prototype={};c(function(){var b=navigator.userAgent.toLowerCase(),e=(b.match(/.+?(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],h=".jstree ul, .jstree li { display:block; margin:0 0 0 0; padding:0 0 0 0; list-style-type:none; } .jstree li { display:block; min-height:18px; line-height:18px; white-space:nowrap; margin-left:18px; } .jstree > ul > li { margin-left:0px; } .jstree ins { display:inline-block; text-decoration:none; width:18px; height:18px; margin:0 0 0 0; padding:0; } .jstree a { display:inline-block; line-height:16px; height:16px; color:black; white-space:nowrap; text-decoration:none; padding:1px 2px; margin:0; } .jstree a:focus { outline: none; } .jstree a > ins { height:16px; width:16px; } .jstree a > .jstree-icon { margin-right:3px; } li.jstree-open > ul { display:block; } li.jstree-closed > ul { display:none; } ";
+if(/msie/.test(b)&&parseInt(e,10)==6)h+=".jstree li { height:18px; margin-left:0; } .jstree li li { margin-left:18px; } li.jstree-open ul { display:block; } li.jstree-closed ul { display:none !important; } .jstree li a { display:inline; } .jstree li a ins { height:16px; width:16px; margin-right:3px; } ";c.vakata.css.add_sheet({str:h})});c.jstree.plugin("core",{__init:function(){this.data.core.to_open=c.map(c.makeArray(this.get_settings().core.initially_open),function(b){return"#"+b.toString().replace(/^#/,
+"").replace("\\/","/").replace("/","\\/")})},defaults:{html_titles:false,animation:500,initially_open:[]},_fn:{init:function(){this.set_focus();this.get_container().html("<ul><li class='jstree-last jstree-leaf'><ins>&#160;</ins><a class='jstree-loading' href='#'><ins class='jstree-icon'>&#160;</ins>Loading ...</a></li></ul>");this.data.core.li_height=this.get_container().find("ul li.jstree-closed, ul li.jstree-leaf").eq(0).height()||18;this.get_container().delegate("li > ins","click.jstree",c.proxy(function(b){var e=
+c(b.target);e.is("ins")&&b.pageY-e.offset().top<this.data.core.li_height&&this.toggle_node(e)},this)).bind("mousedown.jstree",c.proxy(function(){this.set_focus()},this)).bind("dblclick.jstree",function(){var b;if(document.selection&&document.selection.empty)document.selection.empty();else if(window.getSelection){b=window.getSelection();try{b.removeAllRanges();b.collapse()}catch(e){}}});this.__callback();this.load_node(-1,function(){this.loaded();this.reopen()})},destroy:function(){var b,e=this.get_index(),
+h=this.get_settings(),k=this;c.each(h.plugins,function(j,i){g[i].__destroy.apply(k)});this.__callback();if(this.is_focused())for(b in a)if(a.hasOwnProperty(b)&&b!=e){a[b].set_focus();break}if(e===d)d=-1;this.get_container().unbind(".jstree").undelegate(".jstree").removeData("jstree-instance-id").find("[class^='jstree']").andSelf().attr("class",function(){return this.className.replace(/jstree[^ ]*|$/ig,"")});a[e]=null;delete a[e]},save_opened:function(){var b=this;this.data.core.to_open=[];this.get_container().find(".jstree-open").each(function(){b.data.core.to_open.push("#"+
+this.id.toString().replace(/^#/,"").replace("\\/","/").replace("/","\\/"))});this.__callback(b.data.core.to_open)},reopen:function(b){var e=this,h=true,k=[],j=[];if(!b){this.data.core.reopen=false;this.data.core.refreshing=true}if(this.data.core.to_open.length){c.each(this.data.core.to_open,function(i,m){if(m=="#")return true;c(m).length&&c(m).is(".jstree-closed")?k.push(m):j.push(m)});if(k.length){this.data.core.to_open=j;c.each(k,function(i,m){e.open_node(m,function(){e.reopen(true)},true)});h=
+false}}if(h){this.data.core.reopen&&clearTimeout(this.data.core.reopen);this.data.core.reopen=setTimeout(function(){e.__callback({},e)},50);this.data.core.refreshing=false}},refresh:function(b){var e=this;this.save_opened();b||(b=-1);this.load_node(b,function(){e.__callback({});e.reopen()})},loaded:function(){this.__callback()},set_focus:function(){var b=c.jstree._focused();b&&b!==this&&b.get_container().removeClass("jstree-focused");if(b!==this){this.get_container().addClass("jstree-focused");d=
+this.get_index()}this.__callback()},is_focused:function(){return d==this.get_index()},_get_node:function(b){var e=c(b,this.get_container());if(e.is(".jstree")||b==-1)return-1;e=e.closest("li",this.get_container());return e.length?e:false},_get_next:function(b,e){b=this._get_node(b);if(b===-1)return this.get_container().find("> ul > li:first-child");if(!b.length)return false;if(e)return b.nextAll("li").size()>0?b.nextAll("li:eq(0)"):false;return b.hasClass("jstree-open")?b.find("li:eq(0)"):b.nextAll("li").size()>
+0?b.nextAll("li:eq(0)"):b.parentsUntil(this.get_container(),"li").next("li").eq(0)},_get_prev:function(b,e){b=this._get_node(b);if(b===-1)return this.get_container().find("> ul > li:last-child");if(!b.length)return false;if(e)return b.prevAll("li").length>0?b.prevAll("li:eq(0)"):false;if(b.prev("li").length){for(b=b.prev("li").eq(0);b.hasClass("jstree-open");)b=b.children("ul:eq(0)").children("li:last");return b}else{var h=b.parentsUntil(this.get_container(),"li:eq(0)");return h.length?h:false}},
+_get_parent:function(b){b=this._get_node(b);if(b==-1||!b.length)return false;b=b.parentsUntil(this.get_container(),"li:eq(0)");return b.length?b:-1},_get_children:function(b){b=this._get_node(b);if(b===-1)return this.get_container().children("ul:eq(0)").children("li");if(!b.length)return false;return b.children("ul:eq(0)").children("li")},get_path:function(b,e){var h=[],k=this;b=this._get_node(b);if(b===-1||!b||!b.length)return false;b.parentsUntil(this.get_container(),"li").each(function(){h.push(e?
+this.id:k.get_text(this))});h.reverse();h.push(e?b.attr("id"):this.get_text(b));return h},open_node:function(b,e,h){b=this._get_node(b);if(!b.length)return false;var k=h?0:this.get_settings().core.animation,j=this;if(this._is_loaded(b)){k&&b.children("ul").css("display","none");b.removeClass("jstree-closed").addClass("jstree-open").children("a").removeClass("jstree-loading");k&&b.children("ul").slideDown(k,function(){this.style.display=""});this.__callback({obj:b});e&&e.call()}else{b.children("a").addClass("jstree-loading");
+this.load_node(b,function(){j.open_node(b,e,h)},e)}},close_node:function(b,e){b=this._get_node(b);var h=e?0:this.get_settings().core.animation;if(!b.length)return false;h&&b.children("ul").attr("style","display:block !important");b.removeClass("jstree-open").addClass("jstree-closed");h&&b.children("ul").slideUp(h,function(){this.style.display=""});this.__callback({obj:b})},toggle_node:function(b){b=this._get_node(b);if(b.hasClass("jstree-closed"))return this.open_node(b);if(b.hasClass("jstree-open"))return this.close_node(b)},
+open_all:function(b,e){b=b?this._get_node(b):this.get_container();if(e)b=b.find("li.jstree-closed");else{e=b;b=b.is(".jstree-closed")?b.find("li.jstree-closed").andSelf():b.find("li.jstree-closed")}var h=this;b.each(function(){var k=this;h._is_loaded(this)?h.open_node(this,false,true):h.open_node(this,function(){h.open_all(k,e)},true)});e.find("li.jstree-closed").length===0&&this.__callback({obj:e})},close_all:function(b){var e=this;b=b?this._get_node(b):this.get_container();b.find("li.jstree-open").andSelf().each(function(){e.close_node(this)});
+this.__callback({obj:b})},clean_node:function(b){b=b&&b!=-1?c(b):this.get_container();b=b.is("li")?b.find("li").andSelf():b.find("li");b.removeClass("jstree-last").filter("li:last-child").addClass("jstree-last").end().filter(":has(ul)").not(".jstree-open").removeClass("jstree-leaf").addClass("jstree-closed");b.not(".jstree-open, .jstree-closed").addClass("jstree-leaf");this.__callback({obj:b})},get_rollback:function(){this.__callback();return{i:this.get_index(),h:this.get_container().children("ul").clone(true),
+d:this.data}},set_rollback:function(b,e){this.get_container().empty().append(b);this.data=e;this.__callback()},load_node:function(b){this.__callback({obj:b})},_is_loaded:function(){return true},create_node:function(b,e,h,k,j){b=this._get_node(b);e=typeof e==="undefined"?"last":e;var i=c("<li>"),m=this.get_settings().core.html_titles,l;if(b!==-1&&!b.length)return false;if(!j&&!this._is_loaded(b)){this.load_node(b,function(){this.create_node(b,e,h,k,true)});return false}this.__rollback();if(typeof h===
+"string")h={data:h};h||(h={});h.attr&&i.attr(h.attr);h.state&&i.addClass("jstree-"+h.state);if(!h.data)h.data="New node";if(!c.isArray(h.data)){l=h.data;h.data=[];h.data.push(l)}c.each(h.data,function(o,n){l=c("<a>");if(c.isFunction(n))n=n.call(this,h);if(typeof n=="string")l.attr("href","#")[m?"html":"text"](n);else{if(!n.attr)n.attr={};if(!n.attr.href)n.attr.href="#";l.attr(n.attr)[m?"html":"text"](n.title);n.language&&l.addClass(n.language)}l.prepend("<ins class='jstree-icon'>&#160;</ins>");if(n.icon)n.icon.indexOf("/")===
+-1?l.children("ins").addClass(n.icon):l.children("ins").css("background","url('"+n.icon+"') center center no-repeat;");i.append(l)});i.prepend("<ins class='jstree-icon'>&#160;</ins>");if(b===-1){b=this.get_container();if(e==="before")e="first";if(e==="after")e="last"}switch(e){case "before":b.before(i);l=this._get_parent(b);break;case "after":b.after(i);l=this._get_parent(b);break;case "inside":case "first":b.children("ul").length||b.append("<ul>");b.children("ul").prepend(i);l=b;break;case "last":b.children("ul").length||
+b.append("<ul>");b.children("ul").append(i);l=b;break;default:b.children("ul").length||b.append("<ul>");e||(e=0);l=b.children("ul").children("li").eq(e);l.length?l.before(i):b.children("ul").append(i);l=b;break}if(l===-1||l.get(0)===this.get_container().get(0))l=-1;this.clean_node(l);this.__callback({obj:i,parent:l});k&&k.call(this,i);return i},get_text:function(b){b=this._get_node(b);if(!b.length)return false;var e=this.get_settings().core.html_titles;b=b.children("a:eq(0)");if(e){b=b.clone();b.children("INS").remove();
+return b.html()}else{b=b.contents().filter(function(){return this.nodeType==3})[0];return b.nodeValue}},set_text:function(b,e){b=this._get_node(b);if(!b.length)return false;b=b.children("a:eq(0)");if(this.get_settings().core.html_titles){var h=b.children("INS").clone();b.html(e).prepend(h);this.__callback({obj:b,name:e});return true}else{b=b.contents().filter(function(){return this.nodeType==3})[0];this.__callback({obj:b,name:e});return b.nodeValue=e}},rename_node:function(b,e){b=this._get_node(b);
+this.__rollback();b&&b.length&&this.set_text.apply(this,Array.prototype.slice.call(arguments))&&this.__callback({obj:b,name:e})},delete_node:function(b){b=this._get_node(b);if(!b.length)return false;this.__rollback();var e=this._get_parent(b);this.deselect_node(b);b=b.remove();e!==-1&&e.find("> ul > li").length===0&&e.removeClass("jstree-open, jstree-closed").addClass("jstree-leaf");this.clean_node(e);this.__callback({obj:b});return b},prepare_move:function(b,e,h,k,j){var i={};i.ot=c.jstree._reference(i.o)||
+this;i.o=i.ot._get_node(b);i.r=e===-1?-1:this._get_node(e);i.p=typeof i==="undefined"?"last":h;if(!(!j&&f.o&&f.o[0]===i.o[0]&&f.r[0]===i.r[0]&&f.p===i.p)){i.ot=c.jstree._reference(i.o)||this;i.rt=e===-1?i.ot:c.jstree._reference(i.r)||this;if(i.r===-1){i.cr=-1;switch(i.p){case "first":case "before":case "inside":i.cp=0;break;case "after":case "last":i.cp=i.rt.get_container().find(" > ul > li").length;break;default:i.cp=i.p;break}}else{if(!/^(before|after)$/.test(i.p)&&!this._is_loaded(i.r))return this.load_node(i.r,
+function(){this.prepare_move(b,e,i,k,true)});switch(i.p){case "before":i.cp=i.r.index();i.cr=i.rt._get_parent(i.r);break;case "after":i.cp=i.r.index()+1;i.cr=i.rt._get_parent(i.r);break;case "inside":case "first":i.cp=0;i.cr=i.r;break;case "last":i.cp=i.r.find(" > ul > li").length;i.cr=i.r;break;default:i.cp=i.p;i.cr=i.r;break}}i.np=i.cr==-1?i.rt.get_container():i.cr;i.op=i.ot._get_parent(i.o);i.or=i.np.find(" > ul > li:nth-child("+(i.cp+1)+")");f=i}this.__callback(f);k&&k.call(this,f)},check_move:function(){var b=
+f;if(b.or[0]===b.o[0]||b.r.parentsUntil(".jstree").andSelf().filter("li").index(b.o)!==-1)return false;return true},move_node:function(b,e,h,k,j,i){if(!j)return this.prepare_move(b,e,h,function(l){this.move_node(l,false,false,k,true,i)});if(!i&&!this.check_move())return false;this.__rollback();e=false;if(k){e=b.o.clone();e.find("*[id]").andSelf().each(function(){if(this.id)this.id="copy_"+this.id})}else e=b.o;if(b.or.length)b.or.before(e);else{b.np.children("ul").length||c("<ul>").appendTo(b.np);
+b.np.children("ul:eq(0)").append(e)}try{b.ot.clean_node(b.op);b.rt.clean_node(b.np);b.op.find("> ul > li").length||b.op.removeClass("jstree-open jstree-closed").addClass("jstree-leaf").children("ul").remove()}catch(m){}if(k){f.cy=true;f.oc=e}this.__callback(f);return f},_get_move:function(){return f}}})})(jQuery);
+(function(c){c.jstree.plugin("ui",{__init:function(){this.data.ui.selected=c();this.data.ui.last_selected=false;this.data.ui.hovered=null;this.data.ui.to_select=this.get_settings().ui.initially_select;this.get_container().delegate("a","click.jstree",c.proxy(function(a){a.preventDefault();this.select_node(a.currentTarget,true,a)},this)).delegate("a","mouseenter.jstree",c.proxy(function(a){this.hover_node(a.target)},this)).delegate("a","mouseleave.jstree",c.proxy(function(a){this.dehover_node(a.target)},
+this)).bind("reopen.jstree",c.proxy(function(){this.reselect()},this)).bind("get_rollback.jstree",c.proxy(function(){this.dehover_node();this.save_selected()},this)).bind("set_rollback.jstree",c.proxy(function(){this.reselect()},this)).bind("close_node.jstree",c.proxy(function(a,d){var g=this.get_settings().ui,f=this._get_node(d.args[0]),b=f&&f.length?f.find(".jstree-clicked"):[],e=this;g.selected_parent_close===false||!b.length||b.each(function(){e.deselect_node(this);g.selected_parent_close==="select_parent"&&
+e.select_node(f)})},this)).bind("delete_node.jstree",c.proxy(function(a,d){var g=this._get_node(d.rslt.obj),f=this;(g&&g.length?g.find(".jstree-clicked"):[]).each(function(){f.deselect_node(this)})},this)).bind("move_node.jstree",c.proxy(function(a,d){d.rslt.cy&&d.rslt.oc.find(".jstree-clicked").removeClass("jstree-clicked")},this))},defaults:{select_limit:-1,select_multiple_modifier:"ctrl",selected_parent_close:"select_parent",initially_select:[]},_fn:{_get_node:function(a,d){if(typeof a==="undefined"||
+a===null)return d?this.data.ui.selected:this.data.ui.last_selected;return this.__call_old()},save_selected:function(){var a=this;this.data.ui.to_select=[];this.data.ui.selected.each(function(){a.data.ui.to_select.push("#"+this.id.toString().replace(/^#/,"").replace("\\/","/").replace("/","\\/"))});this.__callback(this.data.ui.to_select)},reselect:function(){var a=this,d=this.data.ui.to_select;d=c.map(c.makeArray(d),function(g){return"#"+g.toString().replace(/^#/,"").replace("\\/","/").replace("/",
+"\\/")});this.deselect_all();c.each(d,function(g,f){f&&f!=="#"&&a.select_node(f)});this.__callback()},refresh:function(){this.save_selected();return this.__call_old()},hover_node:function(a){a=this._get_node(a);if(!a.length)return false;a.hasClass("jstree-hovered")||this.dehover_node();this.data.ui.hovered=a.children("a").addClass("jstree-hovered").parent();this.__callback({obj:a})},dehover_node:function(){var a=this.data.ui.hovered;if(!a||!a.length)return false;if(this.data.ui.hovered[0]===a.children("a").removeClass("jstree-hovered").parent()[0])this.data.ui.hovered=
+null;this.__callback({obj:a})},select_node:function(a,d,g){a=this._get_node(a);if(!a.length)return false;var f=this.get_settings().ui;g=f.select_multiple_modifier=="on"||f.select_multiple_modifier!==false&&g&&g[f.select_multiple_modifier+"Key"];var b=this.is_selected(a),e=true;if(d){e=false;switch(true){case b&&!g:break;case !b&&!g:if(f.select_limit==-1||f.select_limit>0){this.deselect_all();e=true}break;case b&&g:this.deselect_node(a);break;case !b&&g:if(f.select_limit==-1||this.data.ui.selected.length+
+1<=f.select_limit)e=true;break}}if(e&&!b){a.children("a").addClass("jstree-clicked");this.data.ui.selected=this.data.ui.selected.add(a);this.data.ui.last_selected=a;this.__callback({obj:a})}},deselect_node:function(a){a=this._get_node(a);if(!a.length)return false;if(this.is_selected(a)){a.children("a").removeClass("jstree-clicked");this.data.ui.selected=this.data.ui.selected.not(a);if(this.data.ui.last_selected.get(0)===a.get(0))this.data.ui.last_selected=this.data.ui.selected.eq(0);this.__callback({obj:a})}},
+toggle_select:function(a){a=this._get_node(a);if(!a.length)return false;this.is_selected(a)?this.deselect_node(a):this.select_node(a)},is_selected:function(a){return this.data.ui.selected.index(this._get_node(a))>=0},get_selected:function(a){return a?c(a).find(".jstree-clicked").parent():this.data.ui.selected},deselect_all:function(a){a?c(a).find(".jstree-clicked").removeClass("jstree-clicked"):this.get_container().find(".jstree-clicked").removeClass("jstree-clicked");this.data.ui.selected=c([]);
+this.data.ui.last_selected=false;this.__callback()}}});c.jstree.defaults.plugins.push("ui")})(jQuery);
+(function(c){c.jstree.plugin("crrm",{__init:function(){this.get_container().bind("move_node.jstree",c.proxy(function(a,d){if(this.get_settings().crrm.move.open_onmove){var g=this;d.rslt.np.parentsUntil(".jstree").andSelf().filter(".jstree-closed").each(function(){g.open_node(this,false,true)})}},this))},defaults:{input_width_limit:200,move:{always_copy:false,open_onmove:true,default_position:"last",check_move:function(){return true}}},_fn:{_show_input:function(a,d){a=this._get_node(a);var g=this.get_settings().crrm.input_width_limit,
+f=a.children("ins").width(),b=a.find("> a:visible > ins").width()*a.find("> a:visible > ins").length,e=this.get_text(a),h=c("<div>",{css:{position:"absolute",top:"-200px",left:"-1000px",visibility:"hidden"}}).appendTo("body"),k=a.css("position","relative").append(c("<input>",{value:e,css:{padding:"0",border:"1px solid silver",position:"absolute",left:f+b+4+"px",top:"0px",height:this.data.core.li_height-2+"px",lineHeight:this.data.core.li_height-2+"px",width:"150px"},blur:c.proxy(function(){var j=
+a.children("input"),i=j.val();if(i==="")i=e;this.rename_node(a,i);d.call(this,a,i,e);j.remove();a.css("position","")},this),keyup:function(j){j=j.keyCode||j.which;if(j==27){this.value=e;this.blur()}else j==13?this.blur():k.width(Math.min(h.text("pW"+this.value).width(),g))}})).children("input");this.set_text(a,"");h.css({fontFamily:k.css("fontFamily")||"",fontSize:k.css("fontSize")||"",fontWeight:k.css("fontWeight")||"",fontStyle:k.css("fontStyle")||"",fontStretch:k.css("fontStretch")||"",fontVariant:k.css("fontVariant")||
+"",letterSpacing:k.css("letterSpacing")||"",wordSpacing:k.css("wordSpacing")||""});k.width(Math.min(h.text("pW"+k[0].value).width(),g))[0].select()},rename:function(a){a=this._get_node(a);this.__rollback();var d=this.__callback;this._show_input(a,function(g,f,b){d.call(this,{obj:g,new_name:f,old_name:b})})},create:function(a,d,g,f,b){var e=this;(a=this._get_node(a))||(a=-1);this.__rollback();return this.create_node(a,d,g,function(h){var k=this._get_parent(h),j=c(h).index();f&&f.call(this,h);k.length&&
+k.hasClass("jstree-closed")&&this.open_node(k,false,true);b?e.__callback({obj:h,name:this.get_text(h),parent:k,position:j}):this._show_input(h,function(i,m){e.__callback({obj:i,name:m,parent:k,position:j})})})},remove:function(a){a=this._get_node(a,true);this.__rollback();this.delete_node(a);this.__callback({obj:a})},check_move:function(){if(!this.__call_old())return false;if(!this.get_settings().crrm.move.check_move.call(this,this._get_move()))return false;return true},move_node:function(a,d,g,f,
+b,e){var h=this.get_settings().crrm.move;if(!b){if(!g)g=h.default_position;return this.__call_old(true,a,d,g,f,false,e)}if(h.always_copy===true||h.always_copy==="multitree"&&a.rt.get_index()===a.ot.get_index())f=true;this.__call_old(true,a,d,g,f,true,e)},cut:function(a){a=this._get_node(a);this.data.crrm.cp_nodes=false;this.data.crrm.ct_nodes=false;if(!a||!a.length)return false;this.data.crrm.ct_nodes=a},copy:function(a){a=this._get_node(a);this.data.crrm.cp_nodes=false;this.data.crrm.ct_nodes=false;
+if(!a||!a.length)return false;this.data.crrm.cp_nodes=a},paste:function(a){a=this._get_node(a);if(!a||!a.length)return false;if(!this.data.crrm.ct_nodes&&!this.data.crrm.cp_nodes)return false;this.data.crrm.ct_nodes&&this.move_node(this.data.crrm.ct_nodes,a);this.data.crrm.cp_nodes&&this.move_node(this.data.crrm.cp_nodes,a,false,true)}}});c.jstree.defaults.plugins.push("crrm")})(jQuery);
+(function(c){var a=[];c.jstree._themes=false;c.jstree.plugin("themes",{__init:function(){this.get_container().bind("init.jstree",c.proxy(function(){var d=this.get_settings().themes;this.data.themes.dots=d.dots;this.data.themes.icons=d.icons;this.set_theme(d.theme,d.url)},this)).bind("loaded.jstree",c.proxy(function(){this.data.themes.dots?this.show_dots():this.hide_dots();this.data.themes.icons?this.show_icons():this.hide_icons()},this))},defaults:{theme:"default",url:false,dots:true,icons:true},
+_fn:{set_theme:function(d,g){if(!d)return false;g||(g=c.jstree._themes+d+"/style.css");if(c.inArray(g,a)==-1){c.vakata.css.add_sheet({url:g,rel:"jstree"});a.push(g)}if(this.data.theme!=d){this.get_container().removeClass("jstree-"+this.data.theme);this.data.themes.theme=d}this.get_container().addClass("jstree-"+d);this.data.themes.dots?this.show_dots():this.hide_dots();this.data.themes.icons?this.show_icons():this.hide_icons();this.__callback()},get_theme:function(){return this.data.themes.theme},
+show_dots:function(){this.data.themes.dots=true;this.get_container().children("ul").removeClass("jstree-no-dots")},hide_dots:function(){this.data.themes.dots=false;this.get_container().children("ul").addClass("jstree-no-dots")},toggle_dots:function(){this.data.themes.dots?this.hide_dots():this.show_dots()},show_icons:function(){this.data.themes.icons=true;this.get_container().children("ul").removeClass("jstree-no-icons")},hide_icons:function(){this.data.themes.icons=false;this.get_container().children("ul").addClass("jstree-no-icons")},
+toggle_icons:function(){this.data.themes.icons?this.hide_icons():this.show_icons()}}});c(function(){c.jstree._themes===false&&c("script").each(function(){if(this.src.toString().match(/jquery\.jstree[^\/]*?\.js(\?.*)?$/)){c.jstree._themes=this.src.toString().replace(/jquery\.jstree[^\/]*?\.js(\?.*)?$/,"")+"themes/";return false}});if(c.jstree._themes===false)c.jstree._themes="themes/"});c.jstree.defaults.plugins.push("themes")})(jQuery);
+(function(c){c.jstree.plugin("html_data",{__init:function(){this.data.html_data.original_container_html=this.get_container().html().replace(/<\/([^>]+)>\s+</ig,"</$1><").replace(/>\s+<([a-z]{1})/ig,"><$1")},defaults:{data:false,ajax:false,correct_state:false},_fn:{load_node:function(a,d,g){var f=this;this.load_node_html(a,function(){f.__callback({obj:a});d.call(this)},g)},_is_loaded:function(a){a=this._get_node(a);return a==-1||!a||!this.get_settings().html_data.ajax||a.is(".jstree-open, .jstree-leaf")||
+a.children("ul").children("li").size()>0},load_node_html:function(a,d,g){var f,b=this.get_settings().html_data,e=function(){};switch(true){case !b.data&&!b.ajax:if(!a||a==-1){this.get_container().html(this.data.html_data.original_container_html).find("li, a").filter(function(){return this.firstChild.tagName!=="INS"}).prepend("<ins class='jstree-icon'>&#160;</ins>");this.clean_node()}d&&d.call(this);break;case !!b.data&&!b.ajax||!!b.data&&!!b.ajax&&(!a||a===-1):if(!a||a==-1){f=c(b.data);f.is("ul")||
+(f=c("<ul>").append(f));this.get_container().children("ul").empty().append(f.children()).find("li, a").filter(function(){return this.firstChild.tagName!=="INS"}).prepend("<ins class='jstree-icon'>&#160;</ins>");this.clean_node()}d&&d.call(this);break;case !b.data&&!!b.ajax||!!b.data&&!!b.ajax&&a&&a!==-1:a=this._get_node(a);e=function(h,k,j){var i=this.get_settings().html_data.ajax.error;i&&i.call(this,h,k,j);if(a!=-1&&a.length){a.children(".jstree-loading").removeClass("jstree-loading");b.correct_state&&
+a.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}g&&g.call(this)};b.ajax.context=this;b.ajax.error=e;b.ajax.success=function(h,k,j){if(j.responseText=="")return e.call(this,j,k,"");var i=this.get_settings().html_data.ajax.success;if(i)h=i.call(this,h,k,j)||h;if(h){h=c(h);h.is("ul")||(h=c("<ul>").append(h));if(a==-1||!a)this.get_container().children("ul").empty().append(h.children()).find("li, a").filter(function(){return this.firstChild.tagName!=="INS"}).prepend("<ins class='jstree-icon'>&#160;</ins>");
+else{a.children(".jstree-loading").removeClass("jstree-loading");a.append(h).find("li, a").filter(function(){return this.firstChild.tagName!=="INS"}).prepend("<ins class='jstree-icon'>&#160;</ins>")}this.clean_node(a);d&&d.call(this)}else{a.children(".jstree-loading").removeClass("jstree-loading");b.correct_state&&a.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}};if(c.isFunction(b.ajax.data))b.ajax.data=b.ajax.data.call(this,a);c.ajax(b.ajax);break}}}});c.jstree.defaults.plugins.push("html_data")})(jQuery);
+(function(c){var a=[];c.jstree.plugin("hotkeys",{__init:function(){if(typeof c.hotkeys==="undefined")throw"jsTree hotkeys: jQuery hotkeys plugin not included.";if(!this.data.ui)throw"jsTree hotkeys: jsTree UI plugin not included.";c.each(this.get_settings().hotkeys,function(d){if(c.inArray(d,a)==-1){c(document).bind("keydown",d,function(g){var f;var b=c.jstree._focused();if(b&&b.data&&b.data.hotkeys&&b.data.hotkeys.enabled)if(b.get_settings().hotkeys[d])f=b.get_settings().hotkeys[d].call(b,g);return f});
+a.push(d)}});this.enable_hotkeys()},defaults:{up:function(){this.hover_node(this._get_prev(this.data.ui.hovered||this.data.ui.last_selected||-1));return false},down:function(){this.hover_node(this._get_next(this.data.ui.hovered||this.data.ui.last_selected||-1));return false},left:function(){var d=this.data.ui.hovered||this.data.ui.last_selected;if(d)d.hasClass("jstree-open")?this.close_node(d):this.hover_node(this._get_prev(d));return false},right:function(){var d=this.data.ui.hovered||this.data.ui.last_selected;
+if(d&&d.length)d.hasClass("jstree-closed")?this.open_node(d):this.hover_node(this._get_next(d));return false},space:function(){this.data.ui.hovered&&this.data.ui.hovered.children("a:eq(0)").click();return false},"ctrl+space":function(d){d.type="click";this.data.ui.hovered&&this.data.ui.hovered.children("a:eq(0)").trigger(d);return false},f2:function(){this.rename(this.data.ui.hovered||this.data.ui.last_selected)},del:function(){this.remove(this.data.ui.hovered||this._get_node(null))}},_fn:{enable_hotkeys:function(){this.data.hotkeys.enabled=
+true},disable_hotkeys:function(){this.data.hotkeys.enabled=false}}})})(jQuery);
+(function(c){c.jstree.plugin("json_data",{defaults:{data:false,ajax:false,correct_state:false,progressive_render:false},_fn:{load_node:function(a,d,g){var f=this;this.load_node_json(a,function(){f.__callback({obj:a});d.call(this)},g)},_is_loaded:function(a){var d=this.get_settings().json_data;if((a=this._get_node(a))&&a!==-1&&d.progressive_render){a.append(this.parse_json(a.data("jstree-children")));c.removeData(a,"jstree-children");this.clean_node(a)}return a==-1||!a||!d.ajax||a.is(".jstree-open, .jstree-leaf")||
+a.children("ul").children("li").size()>0},load_node_json:function(a,d,g){var f=this.get_settings().json_data,b=function(){};switch(true){case !f.data&&!f.ajax:throw"Neither data nor ajax settings supplied.";case !!f.data&&!f.ajax||!!f.data&&!!f.ajax&&(!a||a===-1):if(!a||a==-1){this.get_container().children("ul").empty().append(this.parse_json(f.data).children());this.clean_node()}d&&d.call(this);break;case !f.data&&!!f.ajax||!!f.data&&!!f.ajax&&a&&a!==-1:a=this._get_node(a);b=function(e,h,k){var j=
+this.get_settings().json_data.ajax.error;j&&j.call(this,e,h,k);if(a!=-1&&a.length){a.children(".jstree-loading").removeClass("jstree-loading");f.correct_state&&a.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}g&&g.call(this)};f.ajax.context=this;f.ajax.error=b;f.ajax.success=function(e,h,k){if(k.responseText==""||!c.isArray(e)&&!c.isPlainObject(e))return b.call(this,k,h,"");var j=this.get_settings().json_data.ajax.success;if(j)e=j.call(this,e,h,k)||e;if(e=this.parse_json(e)){a==
+-1||!a?this.get_container().children("ul").empty().append(e.children()):a.append(e).children(".jstree-loading").removeClass("jstree-loading");this.clean_node(a);d&&d.call(this)}else{a.children(".jstree-loading").removeClass("jstree-loading");f.correct_state&&a.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}};if(c.isFunction(f.ajax.data))f.ajax.data=f.ajax.data.call(this,a);c.ajax(f.ajax);break}},parse_json:function(a,d){var g=c(),f,b,e;b=this.get_settings().json_data;var h=this.get_settings().core.html_titles;
+if(!a)return g;if(c.isFunction(a))a=a.call(this);if(c.isArray(a)){if(!a.length)return false;b=0;for(e=a.length;b<e;b++){f=this.parse_json(a[b],true);if(f.length)g=g.add(f)}}else{if(typeof a=="string")a={data:a};if(!a.data&&a.data!=="")return g;g=c("<li>");a.attr&&g.attr(a.attr);a.metadata&&g.data("jstree",a.metadata);a.state&&g.addClass("jstree-"+a.state);if(!c.isArray(a.data)){f=a.data;a.data=[];a.data.push(f)}c.each(a.data,function(k,j){f=c("<a>");if(c.isFunction(j))j=j.call(this,a);if(typeof j==
+"string")f.attr("href","#")[h?"html":"text"](j);else{if(!j.attr)j.attr={};if(!j.attr.href)j.attr.href="#";f.attr(j.attr)[h?"html":"text"](j.title);j.language&&f.addClass(j.language)}f.prepend("<ins class='jstree-icon'>&#160;</ins>");if(j.icon)j.icon.indexOf("/")===-1?f.children("ins").addClass(j.icon):f.children("ins").css("background","url('"+j.icon+"') center center no-repeat;");g.append(f)});g.prepend("<ins class='jstree-icon'>&#160;</ins>");if(a.children)if(b.progressive_render&&a.state!=="open")g.addClass("jstree-closed").data("jstree-children",
+a.children);else{if(c.isFunction(a.children))a.children=a.children.call(this,a);if(c.isArray(a.children)&&a.children.length){f=this.parse_json(a.children,true);if(f.length){b=c("<ul>");b.append(f);g.append(b)}}}}if(!d){b=c("<ul>");b.append(g);g=b}return g},get_json:function(a,d,g){var f=[],b=this.get_settings(),e=this,h,k,j,i,m,l;a=this._get_node(a);if(!a||a===-1)a=this.get_container().find("> ul > li");d=c.isArray(d)?d:["id","class"];this.data.types&&d.push(b.types.type_attr);g=c.isArray(g)?g:[];
+a.each(function(){j=c(this);h={data:[]};if(d.length)h.attr={};c.each(d,function(o,n){if((k=j.attr(n))&&k.length&&k.replace(/jstree[^ ]*|$/ig,"").length)h.attr[n]=k.replace(/jstree[^ ]*|$/ig,"")});if(j.hasClass("jstree-open"))h.state="open";if(j.hasClass("jstree-closed"))h.state="closed";i=j.children("a");i.each(function(){m=c(this);if(g.length||c.inArray("languages",b.plugins)!==-1||m.children("ins").get(0).style.backgroundImage.length||m.children("ins").get(0).className&&m.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,
+"").length){l=false;c.inArray("languages",b.plugins)!==-1&&c.isArray(b.languages)&&b.languages.length&&c.each(b.languages,function(o,n){if(m.hasClass(n)){l=n;return false}});k={attr:{},title:e.get_text(m,l)};c.each(g,function(o,n){h.attr[n]=j.attr(n).replace(/jstree[^ ]*|$/ig,"")});c.each(b.languages,function(o,n){if(m.hasClass(n)){k.language=n;return true}});if(m.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,"").replace(/^\s+$/ig,"").length)k.icon=m.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,
+"").replace(/^\s+$/ig,"");if(m.children("ins").get(0).style.backgroundImage.length)k.icon=m.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")","")}else k=e.get_text(m);if(i.length>1)h.data.push(k);else h.data=k});j=j.find("> ul > li");if(j.length)h.children=e.get_json(j,d,g);f.push(h)});return f}}})})(jQuery);
+(function(c){c.jstree.plugin("languages",{__init:function(){this._load_css()},defaults:[],_fn:{set_lang:function(a){var d=this.get_settings().languages,g=false,f=".jstree-"+this.get_index()+" a";if(!c.isArray(d)||d.length===0)return false;if(c.inArray(a,d)==-1)if(d[a])a=d[a];else return false;if(a==this.data.languages.current_language)return true;g=c.vakata.css.get_css(f+"."+this.data.languages.current_language,false,this.data.languages.language_css);if(g!==false)g.style.display="none";g=c.vakata.css.get_css(f+
+"."+a,false,this.data.languages.language_css);if(g!==false)g.style.display="";this.data.languages.current_language=a;this.__callback(a);return true},get_lang:function(){return this.data.languages.current_language},get_text:function(a,d){a=this._get_node(a)||this.data.ui.last_selected;if(!a.size())return false;var g=this.get_settings().languages,f=this.get_settings().core.html_titles;if(c.isArray(g)&&g.length){d=d&&c.inArray(d,g)!=-1?d:this.data.languages.current_language;a=a.children("a."+d)}else a=
+a.children("a:eq(0)");if(f){a=a.clone();a.children("INS").remove();return a.html()}else{a=a.contents().filter(function(){return this.nodeType==3})[0];return a.nodeValue}},set_text:function(a,d,g){a=this._get_node(a)||this.data.ui.last_selected;if(!a.size())return false;var f=this.get_settings().languages,b=this.get_settings().core.html_titles;if(c.isArray(f)&&f.length){g=g&&c.inArray(g,f)!=-1?g:this.data.languages.current_language;a=a.children("a."+g)}else a=a.children("a:eq(0)");if(b){f=a.children("INS").clone();
+a.html(d).prepend(f);this.__callback({obj:a,name:d,lang:g});return true}else{a=a.contents().filter(function(){return this.nodeType==3})[0];this.__callback({obj:a,name:d,lang:g});return a.nodeValue=d}},_load_css:function(){var a=this.get_settings().languages,d="/* languages css */",g=".jstree-"+this.get_index()+" a",f;if(c.isArray(a)&&a.length){this.data.languages.current_language=a[0];for(f=0;f<a.length;f++){d+=g+"."+a[f]+" {";if(a[f]!=this.data.languages.current_language)d+=" display:none; ";d+=
+" } "}this.data.languages.language_css=c.vakata.css.add_sheet({str:d})}},create_node:function(a,d,g,f){return this.__call_old(true,a,d,g,function(b){var e=this.get_settings().languages,h=b.children("a"),k;if(c.isArray(e)&&e.length){for(k=0;k<e.length;k++)h.is("."+e[k])||b.append(h.eq(0).clone().removeClass(e.join(" ")).addClass(e[k]));h.not("."+e.join(", .")).remove()}f&&f.call(this,b)})}}})})(jQuery);
+(function(c){c.jstree.plugin("cookies",{__init:function(){if(typeof c.cookie==="undefined")throw"jsTree cookie: jQuery cookie plugin not included.";var a=this.get_settings().cookies,d;if(a.save_opened)if((d=c.cookie(a.save_opened))&&d.length)this.data.core.to_open=d.split(",");if(a.save_selected)if((d=c.cookie(a.save_selected))&&d.length)this.data.ui.to_select=d.split(",");this.get_container().one((this.data.ui?"reselect":"reopen")+".jstree",c.proxy(function(){this.get_container().bind("open_node.jstree close_node.jstree select_node.jstree deselect_node.jstree",
+c.proxy(function(g){this.get_settings().cookies.auto_save&&this.save_cookie((g.handleObj.namespace+g.handleObj.type).replace("jstree",""))},this))},this))},defaults:{save_opened:"jstree_open",save_selected:"jstree_select",auto_save:true,cookie_options:{}},_fn:{save_cookie:function(a){if(!this.data.core.refreshing){var d=this.get_settings().cookies;if(a)switch(a){case "open_node":case "close_node":if(d.save_opened){this.save_opened();c.cookie(d.save_opened,this.data.core.to_open.join(","),d.cookie_options)}break;
+case "select_node":case "deselect_node":if(d.save_selected&&this.data.ui){this.save_selected();c.cookie(d.save_selected,this.data.ui.to_select.join(","),d.cookie_options)}break}else{if(d.save_opened){this.save_opened();c.cookie(d.save_opened,this.data.core.to_open.join(","),d.cookie_options)}if(d.save_selected&&this.data.ui){this.save_selected();c.cookie(d.save_selected,this.data.ui.to_select.join(","),d.cookie_options)}}}}}});c.jstree.defaults.plugins.push("cookies")})(jQuery);
+(function(c){c.jstree.plugin("sort",{__init:function(){this.get_container().bind("load_node.jstree",c.proxy(function(a,d){var g=this._get_node(d.rslt.obj);g=g===-1?this.get_container().children("ul"):g.children("ul");this.sort(g)},this)).bind("rename_node.jstree",c.proxy(function(a,d){this.sort(d.rslt.obj.parent())},this)).bind("move_node.jstree",c.proxy(function(a,d){this.sort((d.rslt.np==-1?this.get_container():d.rslt.np).children("ul"))},this))},defaults:function(a,d){return this.get_text(a)>this.get_text(d)?
+1:-1},_fn:{sort:function(a){var d=this.get_settings().sort,g=this;a.append(c.makeArray(a.children("li")).sort(c.proxy(d,g)));a.find("> li > ul").each(function(){g.sort(c(this))});this.clean_node(a)}}})})(jQuery);
+(function(c){var a=false,d=false,g=false;c.vakata.dnd={is_down:false,is_drag:false,helper:false,init_x:0,init_y:0,threshold:5,user_data:{},drag_start:function(f,b,e){c.vakata.dnd.is_drag&&c.vakata.drag_stop({});try{f.currentTarget.unselectable="on";f.currentTarget.onselectstart=function(){return false};if(f.currentTarget.style)f.currentTarget.style.MozUserSelect="none"}catch(h){}c.vakata.dnd.init_x=f.pageX;c.vakata.dnd.init_y=f.pageY;c.vakata.dnd.user_data=b;c.vakata.dnd.is_down=true;c.vakata.dnd.helper=
+c("<div id='vakata-dragged'>").html(e).css("opacity","0.75");c(document).bind("mousemove",c.vakata.dnd.drag);c(document).bind("mouseup",c.vakata.dnd.drag_stop);return false},drag:function(f){if(c.vakata.dnd.is_down){if(!c.vakata.dnd.is_drag)if(Math.abs(f.pageX-c.vakata.dnd.init_x)>5||Math.abs(f.pageY-c.vakata.dnd.init_y)>5){c.vakata.dnd.helper.appendTo("body");c.vakata.dnd.is_drag=true;c(document).triggerHandler("vakata.drag_start",{event:f,data:c.vakata.dnd.user_data})}else return;c.vakata.dnd.helper.css({left:f.pageX+
+5+"px",top:f.pageY+10+"px"});c(document).triggerHandler("vakata.drag",{event:f,data:c.vakata.dnd.user_data})}},drag_stop:function(f){c(document).unbind("mousemove",c.vakata.dnd.drag);c(document).unbind("mouseup",c.vakata.dnd.drag_stop);c(document).triggerHandler("vakata.drag_stop",{event:f,data:c.vakata.dnd.user_data});c.vakata.dnd.helper.remove();c.vakata.dnd.init_x=0;c.vakata.dnd.init_y=0;c.vakata.dnd.user_data={};c.vakata.dnd.is_down=false;c.vakata.dnd.is_drag=false}};c(function(){c.vakata.css.add_sheet({str:"#vakata-dragged { display:block; margin:0 0 0 0; padding:4px 4px 4px 24px; position:absolute; left:-2000px; top:-2000px; line-height:16px; } "})});
+c.jstree.plugin("dnd",{__init:function(){this.data.dnd={active:false,after:false,inside:false,before:false,off:false,prepared:false,w:0,to1:false,to2:false,cof:false,cw:false,ch:false,i1:false,i2:false};this.get_container().bind("mouseenter.jstree",c.proxy(function(){if(c.vakata.dnd.is_drag&&c.vakata.dnd.user_data.jstree&&this.data.themes){g.attr("class","jstree-"+this.data.themes.theme);c.vakata.dnd.helper.attr("class","jstree-dnd-helper jstree-"+this.data.themes.theme)}},this)).bind("mouseleave.jstree",
+c.proxy(function(){if(c.vakata.dnd.is_drag&&c.vakata.dnd.user_data.jstree){this.data.dnd.i1&&clearInterval(this.data.dnd.i1);this.data.dnd.i2&&clearInterval(this.data.dnd.i2)}},this)).bind("mousemove.jstree",c.proxy(function(b){if(c.vakata.dnd.is_drag&&c.vakata.dnd.user_data.jstree){var e=this.get_container()[0];if(b.pageX+20>this.data.dnd.cof.left+this.data.dnd.cw){this.data.dnd.i1&&clearInterval(this.data.dnd.i1);this.data.dnd.i1=setInterval(c.proxy(function(){this.scrollLeft+=5},e),100)}else if(b.pageX-
+20<this.data.dnd.cof.left){this.data.dnd.i1&&clearInterval(this.data.dnd.i1);this.data.dnd.i1=setInterval(c.proxy(function(){this.scrollLeft-=5},e),100)}else this.data.dnd.i1&&clearInterval(this.data.dnd.i1);if(b.pageY+20>this.data.dnd.cof.top+this.data.dnd.ch){this.data.dnd.i2&&clearInterval(this.data.dnd.i2);this.data.dnd.i2=setInterval(c.proxy(function(){this.scrollTop+=5},e),100)}else if(b.pageY-20<this.data.dnd.cof.top){this.data.dnd.i2&&clearInterval(this.data.dnd.i2);this.data.dnd.i2=setInterval(c.proxy(function(){this.scrollTop-=
+5},e),100)}else this.data.dnd.i2&&clearInterval(this.data.dnd.i2)}},this)).delegate("a","mousedown.jstree",c.proxy(function(b){this.start_drag(b.currentTarget,b);return false},this)).delegate("a","mouseenter.jstree",c.proxy(function(b){c.vakata.dnd.is_drag&&c.vakata.dnd.user_data.jstree&&this.dnd_enter(b.currentTarget)},this)).delegate("a","mousemove.jstree",c.proxy(function(b){if(c.vakata.dnd.is_drag&&c.vakata.dnd.user_data.jstree){if(typeof this.data.dnd.off.top==="undefined")this.data.dnd.off=
+c(b.target).offset();this.data.dnd.w=(b.pageY-(this.data.dnd.off.top||0))%this.data.core.li_height;if(this.data.dnd.w<0)this.data.dnd.w+=this.data.core.li_height;this.dnd_show()}},this)).delegate("a","mouseleave.jstree",c.proxy(function(b){if(c.vakata.dnd.is_drag&&c.vakata.dnd.user_data.jstree){this.data.dnd.after=false;this.data.dnd.before=false;this.data.dnd.inside=false;c.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");g.hide();if(d&&d[0]===b.target.parentNode){if(this.data.dnd.to1){clearTimeout(this.data.dnd.to1);
+this.data.dnd.to1=false}if(this.data.dnd.to2){clearTimeout(this.data.dnd.to2);this.data.dnd.to2=false}}}},this)).delegate("a","mouseup.jstree",c.proxy(function(b){c.vakata.dnd.is_drag&&c.vakata.dnd.user_data.jstree&&this.dnd_finish(b)},this));c(document).bind("vakata.drag_stop",c.proxy(function(){this.data.dnd.after=false;this.data.dnd.before=false;this.data.dnd.inside=false;this.data.dnd.off=false;this.data.dnd.prepared=false;this.data.dnd.w=false;this.data.dnd.to1=false;this.data.dnd.to2=false;
+this.data.dnd.active=false;this.data.dnd.foreign=false;g&&g.css({left:"-2000px",top:"-2000px"})},this)).bind("vakata.drag_start",c.proxy(function(b,e){if(e.data.jstree){var h=c(e.event.target);h.closest(".jstree").hasClass("jstree-"+this.get_index())&&this.dnd_enter(h)}},this));var f=this.get_settings().dnd;f.drag_target&&c(document).delegate(f.drag_target,"mousedown.jstree",c.proxy(function(b){a=b.target;c.vakata.dnd.drag_start(b,{jstree:true,obj:b.target},"<ins class='jstree-icon'></ins>"+c(b.target).text());
+if(this.data.themes){g.attr("class","jstree-"+this.data.themes.theme);c.vakata.dnd.helper.attr("class","jstree-dnd-helper jstree-"+this.data.themes.theme)}c.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");b=this.get_container();this.data.dnd.cof=b.children("ul").offset();this.data.dnd.cw=parseInt(b.width(),10);this.data.dnd.ch=parseInt(b.height(),10);this.data.dnd.foreign=true;return false},this));f.drop_target&&c(document).delegate(f.drop_target,"mouseenter.jstree",c.proxy(function(b){this.data.dnd.active&&
+this.get_settings().dnd.drop_check.call(this,{o:a,r:c(b.target)})&&c.vakata.dnd.helper.children("ins").attr("class","jstree-ok")},this)).delegate(f.drop_target,"mouseleave.jstree",c.proxy(function(){this.data.dnd.active&&c.vakata.dnd.helper.children("ins").attr("class","jstree-invalid")},this)).delegate(f.drop_target,"mouseup.jstree",c.proxy(function(b){this.data.dnd.active&&c.vakata.dnd.helper.children("ins").hasClass("jstree-ok")&&this.get_settings().dnd.drop_finish.call(this,{o:a,r:c(b.target)})},
+this))},defaults:{copy_modifier:"ctrl",check_timeout:200,open_timeout:500,drop_target:".jstree-drop",drop_check:function(){return true},drop_finish:c.noop,drag_target:".jstree-draggable",drag_finish:c.noop,drag_check:function(){return{after:false,before:false,inside:true}}},_fn:{dnd_prepare:function(){this.data.dnd.off=d.offset();if(this.data.dnd.foreign){var f=this.get_settings().dnd.drag_check.call(this,{o:a,r:d});this.data.dnd.after=f.after;this.data.dnd.before=f.before;this.data.dnd.inside=f.inside;
+this.data.dnd.prepared=true;return this.dnd_show()}this.prepare_move(a,d,"before");this.data.dnd.before=this.check_move();this.prepare_move(a,d,"after");this.data.dnd.after=this.check_move();if(this._is_loaded(d)){this.prepare_move(a,d,"inside");this.data.dnd.inside=this.check_move()}else this.data.dnd.inside=false;this.data.dnd.prepared=true;return this.dnd_show()},dnd_show:function(){if(this.data.dnd.prepared){var f=["before","inside","after"],b=false;f=this.data.dnd.w<this.data.core.li_height/
+3?["before","inside","after"]:this.data.dnd.w<=this.data.core.li_height*2/3?this.data.dnd.w<this.data.core.li_height/2?["inside","before","after"]:["inside","after","before"]:["after","inside","before"];c.each(f,c.proxy(function(e,h){if(this.data.dnd[h]){c.vakata.dnd.helper.children("ins").attr("class","jstree-ok");b=h;return false}},this));b===false&&c.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");switch(b){case "before":g.css({left:this.data.dnd.off.left+10+"px",top:this.data.dnd.off.top-
+6+"px"}).show();break;case "after":g.css({left:this.data.dnd.off.left+10+"px",top:this.data.dnd.off.top+this.data.core.li_height-7+"px"}).show();break;case "inside":g.css({left:this.data.dnd.off.left+14+"px",top:this.data.dnd.off.top+this.data.core.li_height/2-5+"px"}).show();break;default:g.hide();break}return b}},dnd_open:function(){this.data.dnd.to2=false;this.open_node(d,c.proxy(this.dnd_prepare,this),true)},dnd_finish:function(f){if(this.data.dnd.foreign){if(this.data.dnd.after||this.data.dnd.before||
+this.data.dnd.inside)this.get_settings().dnd.drag_finish.call(this,{o:a,r:d})}else{this.dnd_prepare();this.move_node(a,d,this.dnd_show(),f[this.get_settings().dnd.copy_modifier+"Key"])}d=a=false;g.hide()},dnd_enter:function(f){var b=this.get_settings().dnd;this.data.dnd.prepared=false;d=this._get_node(f);if(b.check_timeout){this.data.dnd.to1&&clearTimeout(this.data.dnd.to1);this.data.dnd.to1=setTimeout(c.proxy(this.dnd_prepare,this),b.check_timeout)}else this.dnd_prepare();if(b.open_timeout){this.data.dnd.to2&&
+clearTimeout(this.data.dnd.to2);if(d.hasClass("jstree-closed"))this.data.dnd.to2=setTimeout(c.proxy(this.dnd_open,this),b.open_timeout)}else d.hasClass("jstree-closed")&&this.dnd_open()},start_drag:function(f,b){a=this._get_node(f);if(this.data.ui&&this.is_selected(a))a=this._get_node(null,true);c.vakata.dnd.drag_start(b,{jstree:true,obj:a},"<ins class='jstree-icon'></ins>"+(a.length>1?"Multiple selection":this.get_text(a)));if(this.data.themes){g.attr("class","jstree-"+this.data.themes.theme);c.vakata.dnd.helper.attr("class",
+"jstree-dnd-helper jstree-"+this.data.themes.theme)}var e=this.get_container();this.data.dnd.cof=e.children("ul").offset();this.data.dnd.cw=parseInt(e.width(),10);this.data.dnd.ch=parseInt(e.height(),10);this.data.dnd.active=true}}});c(function(){c.vakata.css.add_sheet({str:"#vakata-dragged ins { display:block; text-decoration:none; width:16px; height:16px; margin:0 0 0 0; padding:0; position:absolute; top:4px; left:4px; } #vakata-dragged .jstree-ok { background:green; } #vakata-dragged .jstree-invalid { background:red; } #jstree-marker { padding:0; margin:0; line-height:12px; font-size:1px; overflow:hidden; height:12px; width:8px; position:absolute; left:-45px; top:-30px; z-index:1000; background-repeat:no-repeat; display:none; background-color:silver; } "});
+g=c("<div>").attr({id:"jstree-marker"}).hide().appendTo("body");c(document).bind("vakata.drag_start",function(f,b){b.data.jstree&&g.show()});c(document).bind("vakata.drag_stop",function(f,b){b.data.jstree&&g.hide()})})})(jQuery);
+(function(c){c.jstree.plugin("checkbox",{__init:function(){if(!this.data.ui)throw"jsTree checkboxes: jsTree UI plugin not included";this.select_node=this.deselect_node=this.deselect_all=c.noop;this.get_selected=this.get_checked;this.get_container().bind("open_node.jstree create_node.jstree",c.proxy(function(a,d){this._prepare_checkboxes(d.rslt.obj)},this)).bind("loaded.jstree",c.proxy(function(){this._prepare_checkboxes()},this)).bind("clean_node.jstree",c.proxy(function(a,d){this._repair_state(d.args[0])},
+this)).delegate("a","click.jstree",c.proxy(function(a){this.change_state(a.target);this.save_selected();this.data.cookies&&this.save_cookie("select_node");a.preventDefault()},this))},_fn:{_prepare_checkboxes:function(a){a=!a||a==-1?this.get_container():this._get_node(a);var d=a.is("li")&&a.hasClass("jstree-checked")?"jstree-checked":"jstree-unchecked";a.find("a").not(":has(.checkbox)").prepend("<ins class='checkbox'>&#160;</ins>").parent().addClass(d)},change_state:function(a,d){a=this._get_node(a);
+if(d=d===false||d===true?d:a.hasClass("jstree-checked"))a.find("li").andSelf().removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked");else{a.find("li").andSelf().removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked");this.data.ui.last_selected=a}var g=this;a.parentsUntil(this.get_container(),"li").each(function(){var f=c(this);if(d)if(f.children("ul").children(".jstree-checked, .jstree-undetermined").length){f.parentsUntil(g.get_container(),"li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");
+return false}else f.removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked");else if(f.children("ul").children(".jstree-unchecked, .jstree-undetermined").length){f.parentsUntil(g.get_container(),"li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");return false}else f.removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked")});this.data.ui.selected=this.get_checked();this.__callback(a)},check_node:function(a){this.change_state(a,
+false)},uncheck_node:function(a){this.change_state(a,true)},check_all:function(){var a=this;this.get_container().children("ul").children("li").each(function(){a.check_node(this,false)})},uncheck_all:function(){var a=this;this.get_container().children("ul").children("li").each(function(){a.change_state(this,true)})},is_checked:function(a){a=this._get_node(a);return a.length?a.is(".jstree-checked"):false},get_checked:function(a){a=!a||a===-1?this.get_container():this._get_node(a);return a.find("> ul > .jstree-checked, .jstree-undetermined > ul > .jstree-checked")},
+get_unchecked:function(a){a=!a||a===-1?this.get_container():this._get_node(a);return a.find("> ul > .jstree-unchecked, .jstree-undetermined > ul > .jstree-unchecked")},show_checkboxes:function(){this.get_container().children("ul").removeClass("jstree-no-checkboxes")},hide_checkboxes:function(){this.get_container().children("ul").addClass("jstree-no-checkboxes")},_repair_state:function(a){a=this._get_node(a);if(a.length){var d=a.find("> ul > .jstree-checked").length,g=a.find("> ul > .jstree-undetermined").length,
+f=a.find("> ul > li").length;if(f===0)a.hasClass("jstree-undetermined")&&this.check_node(a);else if(d===0&&g===0)this.uncheck_node(a);else d===f?this.check_node(a):a.parentsUntil(this.get_container(),"li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined")}},reselect:function(){var a=this,d=this.data.ui.to_select;d=c.map(c.makeArray(d),function(g){return"#"+g.toString().replace(/^#/,"").replace("\\/","/").replace("/","\\/")});this.deselect_all();c.each(d,function(g,
+f){a.check_node(f)});this.__callback()}}})})(jQuery);
+(function(c){c.vakata.xslt=function(d,g){var f="",b,e;if(document.recalc){b=document.createElement("xml");e=document.createElement("xml");b.innerHTML=d;e.innerHTML=g;c("body").append(b).append(e);f=b.transformNode(e.XMLDocument);c("body").remove(b).remove(e);return f}if(typeof window.DOMParser!=="undefined"&&typeof window.XMLHttpRequest!=="undefined"&&typeof window.XSLTProcessor!=="undefined"){b=new XSLTProcessor;f=c.isFunction(b.transformDocument)?typeof window.XMLSerializer!=="undefined":true;if(!f)return false;
+d=(new DOMParser).parseFromString(d,"text/xml");g=(new DOMParser).parseFromString(g,"text/xml");if(c.isFunction(b.transformDocument)){f=document.implementation.createDocument("","",null);b.transformDocument(d,g,f,null);return(new XMLSerializer).serializeToString(f)}else{b.importStylesheet(g);f=b.transformToFragment(d,document);return c("<div>").append(f).html()}}return false};var a={nest:'<?xml version="1.0" encoding="utf-8" ?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" ><xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/html" /><xsl:template match="/">\t<xsl:call-template name="nodes">\t\t<xsl:with-param name="node" select="/root" />\t</xsl:call-template></xsl:template><xsl:template name="nodes">\t<xsl:param name="node" />\t<ul>\t<xsl:for-each select="$node/item">\t\t<xsl:variable name="children" select="count(./item) &gt; 0" />\t\t<li>\t\t\t<xsl:attribute name="class">\t\t\t\t<xsl:if test="position() = last()">jstree-last </xsl:if>\t\t\t\t<xsl:choose>\t\t\t\t\t<xsl:when test="@state = \'open\'">jstree-open </xsl:when>\t\t\t\t\t<xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>\t\t\t\t\t<xsl:otherwise>jstree-leaf </xsl:otherwise>\t\t\t\t</xsl:choose>\t\t\t\t<xsl:value-of select="@class" />\t\t\t</xsl:attribute>\t\t\t<xsl:for-each select="@*">\t\t\t\t<xsl:if test="name() != \'class\' and name() != \'state\' and name() != \'hasChildren\'">\t\t\t\t\t<xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>\t\t\t\t</xsl:if>\t\t\t</xsl:for-each>\t<ins class="jstree-icon"><xsl:text>&#xa0;</xsl:text></ins>\t\t\t<xsl:for-each select="content/name">\t\t\t\t<a>\t\t\t\t<xsl:attribute name="href">\t\t\t\t\t<xsl:choose>\t\t\t\t\t<xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>\t\t\t\t\t<xsl:otherwise>#</xsl:otherwise>\t\t\t\t\t</xsl:choose>\t\t\t\t</xsl:attribute>\t\t\t\t<xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>\t\t\t\t<xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>\t\t\t\t<xsl:for-each select="@*">\t\t\t\t\t<xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">\t\t\t\t\t\t<xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>\t\t\t\t\t</xsl:if>\t\t\t\t</xsl:for-each>\t\t\t\t\t<ins>\t\t\t\t\t\t<xsl:attribute name="class">jstree-icon \t\t\t\t\t\t\t<xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>\t\t\t\t\t\t</xsl:attribute>\t\t\t\t\t\t<xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if>\t\t\t\t\t\t<xsl:text>&#xa0;</xsl:text>\t\t\t\t\t</ins>\t\t\t\t\t<xsl:value-of select="current()" />\t\t\t\t</a>\t\t\t</xsl:for-each>\t\t\t<xsl:if test="$children or @hasChildren"><xsl:call-template name="nodes"><xsl:with-param name="node" select="current()" /></xsl:call-template></xsl:if>\t\t</li>\t</xsl:for-each>\t</ul></xsl:template></xsl:stylesheet>',
+flat:'<?xml version="1.0" encoding="utf-8" ?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" ><xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/xml" /><xsl:template match="/">\t<ul>\t<xsl:for-each select="//item[not(@parent_id) or @parent_id=0]">\t\t<xsl:call-template name="nodes">\t\t\t<xsl:with-param name="node" select="." />\t\t\t<xsl:with-param name="is_last" select="number(position() = last())" />\t\t</xsl:call-template>\t</xsl:for-each>\t</ul></xsl:template><xsl:template name="nodes">\t<xsl:param name="node" />\t<xsl:param name="is_last" />\t<xsl:variable name="children" select="count(//item[@parent_id=$node/attribute::id]) &gt; 0" />\t<li>\t<xsl:attribute name="class">\t\t<xsl:if test="$is_last = true()">jstree-last </xsl:if>\t\t<xsl:choose>\t\t\t<xsl:when test="@state = \'open\'">jstree-open </xsl:when>\t\t\t<xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>\t\t\t<xsl:otherwise>jstree-leaf </xsl:otherwise>\t\t</xsl:choose>\t\t<xsl:value-of select="@class" />\t</xsl:attribute>\t<xsl:for-each select="@*">\t\t<xsl:if test="name() != \'parent_id\' and name() != \'hasChildren\' and name() != \'class\' and name() != \'state\'">\t\t<xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>\t\t</xsl:if>\t</xsl:for-each>\t<ins class="jstree-icon"><xsl:text>&#xa0;</xsl:text></ins>\t<xsl:for-each select="content/name">\t\t<a>\t\t<xsl:attribute name="href">\t\t\t<xsl:choose>\t\t\t<xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>\t\t\t<xsl:otherwise>#</xsl:otherwise>\t\t\t</xsl:choose>\t\t</xsl:attribute>\t\t<xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>\t\t<xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>\t\t<xsl:for-each select="@*">\t\t\t<xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">\t\t\t\t<xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>\t\t\t</xsl:if>\t\t</xsl:for-each>\t\t\t<ins>\t\t\t\t<xsl:attribute name="class">jstree-icon \t\t\t\t\t<xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>\t\t\t\t</xsl:attribute>\t\t\t\t<xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if>\t\t\t\t<xsl:text>&#xa0;</xsl:text>\t\t\t</ins>\t\t\t<xsl:value-of select="current()" />\t\t</a>\t</xsl:for-each>\t<xsl:if test="$children">\t\t<ul>\t\t<xsl:for-each select="//item[@parent_id=$node/attribute::id]">\t\t\t<xsl:call-template name="nodes">\t\t\t\t<xsl:with-param name="node" select="." />\t\t\t\t<xsl:with-param name="is_last" select="number(position() = last())" />\t\t\t</xsl:call-template>\t\t</xsl:for-each>\t\t</ul>\t</xsl:if>\t</li></xsl:template></xsl:stylesheet>'};
+c.jstree.plugin("xml_data",{defaults:{data:false,ajax:false,xsl:"flat",clean_node:false},_fn:{load_node:function(d,g,f){var b=this;this.load_node_xml(d,function(){b.__callback({obj:d});g.call(this)},f)},_is_loaded:function(d){var g=this.get_settings().xml_data;return d==-1||!d||!g.ajax||d.is(".jstree-open, .jstree-leaf")||d.children("ul").children("li").size()>0},load_node_xml:function(d,g,f){var b=this.get_settings().xml_data,e=function(){};switch(true){case !b.data&&!b.ajax:throw"Neither data nor ajax settings supplied.";
+case !!b.data&&!b.ajax||!!b.data&&!!b.ajax&&(!d||d===-1):if(!d||d==-1){this.get_container().children("ul").empty().append(this.parse_xml(b.data).children());b.clean_node&&this.clean_node(d)}g&&g.call(this);break;case !b.data&&!!b.ajax||!!b.data&&!!b.ajax&&d&&d!==-1:d=this._get_node(d);e=function(h,k,j){var i=this.get_settings().xml_data.ajax.error;i&&i.call(this,h,k,j);if(d!==-1&&d.length){d.children(".jstree-loading").removeClass("jstree-loading");b.correct_state&&d.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}f&&
+f.call(this)};b.ajax.context=this;b.ajax.error=e;b.ajax.success=function(h,k,j){if(j.responseText=="")return e.call(this,j,k,"");h=j.responseText;var i=this.get_settings().xml_data.ajax.success;if(i)h=i.call(this,h,k,j)||h;if(h=this.parse_xml(h)){d===-1||!d?this.get_container().children("ul").empty().append(this.parse_xml(j.responseText).children()):d.append(this.parse_xml(j.responseText)).children(".jstree-loading").removeClass("jstree-loading");b.clean_node&&this.clean_node(d);g&&g.call(this)}else{d.children(".jstree-loading").removeClass("jstree-loading");
+b.correct_state&&d.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}};if(c.isFunction(b.ajax.data))b.ajax.data=b.ajax.data.call(null,d);c.ajax(b.ajax);break}},parse_xml:function(d){var g=this.get_settings().xml_data;d=c.vakata.xslt(d,a[g.xsl]);if(d!==false)d=c(d);return d},get_xml:function(d,g,f,b,e){var h="",k=this.get_settings(),j=this,i,m,l,o,n;d||(d="flat");e||(e=0);g=this._get_node(g);if(!g||g===-1)g=this.get_container().find("> ul > li");f=c.isArray(f)?f:["id","class"];this.data.types&&
+f.push(k.types.type_attr);b=c.isArray(b)?b:[];e||(h+="<root>");g.each(function(){h+="<item";l=c(this);c.each(f,function(q,p){h+=" "+p+'="'+l.attr(p).replace(/jstree[^ ]*|$/ig,"").replace(/^\s+$/ig,"")+'"'});if(l.hasClass("jstree-open"))h+=' state="open"';if(l.hasClass("jstree-closed"))h+=' state="closed"';if(d==="flat")h+=' parent_id="'+e+'"';h+=">";h+="<content>";o=l.children("a");o.each(function(){i=c(this);n=false;h+="<name";c.inArray("languages",k.plugins)!==-1&&c.each(k.languages,function(q,
+p){if(i.hasClass(p)){h+=' lang="'+p+'"';n=p;return false}});b.length&&c.each(b,function(q,p){h+=" "+p+'="'+l.attr(p).replace(/jstree[^ ]*|$/ig,"")+'"'});if(i.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,"").replace(/^\s+$/ig,"").length)h+=' icon="'+i.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,"").replace(/^\s+$/ig,"")+'"';if(i.children("ins").get(0).style.backgroundImage.length)h+=' icon="'+i.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")",
+"")+'"';h+=">";h+="<![CDATA["+j.get_text(i,n)+"]]\>";h+="</name>"});h+="</content>";m=l[0].id;l=l.find("> ul > li");if(l.length)m=j.get_xml(d,l,f,b,m);if(d=="nest")h+=m;h+="</item>";if(d=="flat")h+=m});e||(h+="</root>");return h}}})})(jQuery);
+(function(c){c.expr[":"].jstree_contains=function(a,d,g){return(a.textContent||a.innerText||"").toLowerCase().indexOf(g[3].toLowerCase())>=0};c.jstree.plugin("search",{__init:function(){this.data.search.str="";this.data.search.result=c()},defaults:{ajax:false,case_insensitive:false},_fn:{search:function(a,d){var g=this.get_settings().search,f=this;this.data.search.str=a;if(!d&&g.ajax!==false&&this.get_container().find(".jstree-closed:eq(0)").length>0){this.search.supress_callback=true;g.ajax.context=
+this;g.ajax.error=function(){};g.ajax.success=function(b,e,h){var k=this.get_settings().search.ajax.success;if(k)b=k.call(this,b,e,h)||b;this.data.search.to_open=b;this._search_open()};if(c.isFunction(g.ajax.data))g.ajax.data=g.ajax.data.call(this,a);if(!g.ajax.data)g.ajax.data={search_string:a};if(!g.ajax.dataType||/^json/.exec(g.ajax.dataType))g.ajax.dataType="json";c.ajax(g.ajax)}else{this.data.search.result.length&&this.clear_search();this.data.search.result=this.get_container().find("a"+(this.data.languages?
+"."+this.get_lang():"")+":"+(g.case_insensitive?"jstree_contains":"contains")+"("+this.data.search.str+")");this.data.search.result.addClass("jstree-search").parents(".jstree-closed").each(function(){f.open_node(this,false,true)});this.__callback({nodes:this.data.search.result,str:a})}},clear_search:function(){this.data.search.result.removeClass("jstree-search");this.__callback(this.data.search.result);this.data.search.result=c()},_search_open:function(){var a=this,d=true,g=[],f=[];if(this.data.search.to_open.length){c.each(this.data.search.to_open,
+function(b,e){if(e=="#")return true;c(e).length&&c(e).is(".jstree-closed")?g.push(e):f.push(e)});if(g.length){this.data.search.to_open=f;c.each(g,function(b,e){a.open_node(e,function(){a._search_open(true)})});d=false}}d&&this.search(this.data.search.str,true)}}})})(jQuery);
+(function(c){c.vakata.context={cnt:c("<div id='vakata-contextmenu'>"),vis:false,tgt:false,func:false,data:false,show:function(a,d,g,f,b){if(a=c.vakata.context.parse(a)){c.vakata.context.vis=true;c.vakata.context.tgt=d;c.vakata.context.data=b||null;c.vakata.context.cnt.html(a).css({visibility:"hidden",display:"block",left:0,top:0});b=c.vakata.context.cnt.height();a=c.vakata.context.cnt.width();if(g+a>c(document).width()){g=c(document).width()-(a+5);c.vakata.context.cnt.find("li > ul").addClass("right")}if(f+
+b>c(document).height()){f-=b+d[0].offsetHeight;c.vakata.context.cnt.find("li > ul").addClass("bottom")}c.vakata.context.cnt.css({left:g,top:f}).find("li:has(ul)").bind("mouseenter",function(){var e=c(document).width(),h=c(document).height(),k=c(this).children("ul").show();e!==c(document).width()&&k.toggleClass("right");h!==c(document).height()&&k.toggleClass("bottom")}).bind("mouseleave",function(){c(this).children("ul").hide()}).end().css({visibility:"visible"}).show();c(document).triggerHandler("vakata.context_show")}},
+hide:function(){c.vakata.context.vis=false;c.vakata.context.cnt.attr("class","").hide();c(document).triggerHandler("vakata.context_hide")},parse:function(a,d){var g="",f=false;if(!d)c.vakata.context.func={};g+="<ul>";c.each(a,function(b,e){if(!e)return true;c.vakata.context.func[b]=e.action;if(e.separator_before)g+="<li class='vakata-separator vakata-separator-before'></li>";g+="<li><ins ";if(e.icon&&e.icon.indexOf("/")===-1)g+=" class='"+e.icon+"' ";if(e.icon&&e.icon.indexOf("/")!==-1)g+=" style='background:url("+
+e.icon+") center center no-repeat;' ";g+=">&#160;</ins><a href='#' rel='"+b+"'>"+e.label;if(e.submenu)g+="<span style='float:right;'>&raquo;</span>";g+="</a>";if(e.submenu)if(f=c.vakata.context.parse(e.submenu,true))g+=f;g+="</li>";if(e.separator_after)g+="<li class='vakata-separator vakata-separator-after'></li>"});g+="</ul>";return g.length>10?g:false},exec:function(a){if(c.isFunction(c.vakata.context.func[a])){c.vakata.context.func[a].call(c.vakata.context.data,c.vakata.context.tgt);return true}else return false}};
+c(function(){c.vakata.css.add_sheet({str:"#vakata-contextmenu { display:none; position:absolute; margin:0; padding:0; min-width:180px; background:#ebebeb; border:1px solid silver; } #vakata-contextmenu ul { min-width:180px; } #vakata-contextmenu ul, #vakata-contextmenu li { margin:0; padding:0; list-style-type:none; display:block; } #vakata-contextmenu li { line-height:20px; min-height:20px; position:relative; padding:0px; } #vakata-contextmenu li a { padding:1px 6px; line-height:17px; display:block; text-decoration:none; margin:1px 1px 0 1px; } #vakata-contextmenu li ins { float:left; width:16px; height:16px; text-decoration:none; margin-right:2px; } #vakata-contextmenu li a:hover, #vakata-contextmenu li.vakata-hover > a { background:gray; color:white; } #vakata-contextmenu li ul { display:none; position:absolute; top:-2px; left:100%; background:#ebebeb; border:1px solid gray; } #vakata-contextmenu .right { right:100%; left:auto; } #vakata-contextmenu .bottom { bottom:-1px; top:auto; } #vakata-contextmenu li.vakata-separator { min-height:0; height:1px; line-height:1px; font-size:1px; overflow:hidden; margin:0 2px; background:silver; /* border-top:1px solid #fefefe; */ padding:0; } "});
+c.vakata.context.cnt.delegate("a","click",function(a){a.preventDefault()}).delegate("a","mouseup",function(){c.vakata.context.exec(c(this).attr("rel"))&&c.vakata.context.hide()}).delegate("a","mouseover",function(){c.vakata.context.cnt.find(".vakata-hover").removeClass("vakata-hover")}).appendTo("body");c(document).bind("mousedown",function(a){c.vakata.context.vis&&!c.contains(c.vakata.context.cnt[0],a.target)&&c.vakata.context.hide()});typeof c.hotkeys!=="undefined"&&c(document).bind("keydown","up",
+function(a){if(c.vakata.context.vis){var d=c.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").prevAll("li:not(.vakata-separator)").first();d.length||(d=c.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").last());d.addClass("vakata-hover");a.stopImmediatePropagation();a.preventDefault()}}).bind("keydown","down",function(a){if(c.vakata.context.vis){var d=c.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").nextAll("li:not(.vakata-separator)").first();
+d.length||(d=c.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").first());d.addClass("vakata-hover");a.stopImmediatePropagation();a.preventDefault()}}).bind("keydown","right",function(a){if(c.vakata.context.vis){c.vakata.context.cnt.find(".vakata-hover").children("ul").show().children("li:not(.vakata-separator)").removeClass("vakata-hover").first().addClass("vakata-hover");a.stopImmediatePropagation();a.preventDefault()}}).bind("keydown","left",function(a){if(c.vakata.context.vis){c.vakata.context.cnt.find(".vakata-hover").children("ul").hide().children(".vakata-separator").removeClass("vakata-hover");
+a.stopImmediatePropagation();a.preventDefault()}}).bind("keydown","esc",function(a){c.vakata.context.hide();a.preventDefault()}).bind("keydown","space",function(a){c.vakata.context.cnt.find(".vakata-hover").last().children("a").click();a.preventDefault()})});c.jstree.plugin("contextmenu",{__init:function(){this.get_container().delegate("a","contextmenu.jstree",c.proxy(function(a){a.preventDefault();this.show_contextmenu(a.currentTarget,a.pageX,a.pageY)},this))},defaults:{show_at_node:true,items:{create:{separator_before:false,
+separator_after:true,label:"Create",action:function(a){this.create(a)}},rename:{separator_before:false,separator_after:false,label:"Rename",action:function(a){this.rename(a)}},remove:{separator_before:false,icon:false,separator_after:false,label:"Delete",action:function(a){this.remove(a)}},ccp:{separator_before:true,icon:false,separator_after:false,label:"Edit",action:function(a){this.remove(a)},submenu:{cut:{separator_before:false,separator_after:false,label:"Cut",action:function(a){this.cut(a)}},
+copy:{separator_before:false,icon:false,separator_after:false,label:"Copy",action:function(a){this.copy(a)}},paste:{separator_before:false,icon:false,separator_after:false,label:"Paste",action:function(a){this.paste(a)}}}}}},_fn:{show_contextmenu:function(a,d,g){a=this._get_node(a);var f=this.get_settings().contextmenu,b=a.children("a:visible:eq(0)"),e=false;if(f.show_at_node||typeof d==="undefined"||typeof g==="undefined"){e=b.offset();d=e.left;g=e.top+this.data.core.li_height}if(c.isFunction(f.items))f.items=
+f.items.call(this,a);c.vakata.context.show(f.items,b,d,g,this);this.data.themes&&c.vakata.context.cnt.attr("class","jstree-"+this.data.themes.theme+"-context")}}})})(jQuery);
+(function(c){c.jstree.plugin("types",{__init:function(){var a=this.get_settings().types;this.data.types.attach_to=[];this.get_container().bind("init.jstree",c.proxy(function(){var d=a.type_attr,g="",f=this;c.each(a.types,function(b,e){c.each(e,function(h){/^(max_depth|max_children|icon|valid_children)$/.test(h)||f.data.types.attach_to.push(h)});if(!e.icon)return true;if(e.icon.image||e.icon.position){g+=b=="default"?".jstree-"+f.get_index()+" a > .jstree-icon { ":".jstree-"+f.get_index()+" li["+d+
+"="+b+"] > a > .jstree-icon { ";if(e.icon.image)g+=" background-image:url("+e.icon.image+"); ";g+=e.icon.position?" background-position:"+e.icon.position+"; ":" background-position:0 0; ";g+="} "}});g!=""&&c.vakata.css.add_sheet({str:g})},this)).bind("before.jstree",c.proxy(function(d,g){if(c.inArray(g.func,this.data.types.attach_to)!==-1){var f=this.get_settings().types.types,b=this._get_type(g.args[0]);if(f[b]&&typeof f[b][g.func]!=="undefined"&&!this._check(g.func,g.args[0])){d.stopImmediatePropagation();
+return false}}},this))},defaults:{max_children:-1,max_depth:-1,valid_children:"all",type_attr:"rel",types:{"default":{max_children:-1,max_depth:-1,valid_children:"all"}}},_fn:{_get_type:function(a){a=this._get_node(a);return!a||!a.length?false:a.attr(this.get_settings().types.type_attr)||"default"},set_type:function(a,d){d=this._get_node(d);return!d.length||!a?false:d.attr(this.get_settings().types.type_attr,a)},_check:function(a,d,g){var f=false,b=this._get_type(d),e=0,h=this,k=this.get_settings().types;
+if(d===-1)if(k[a])f=k[a];else return;else{if(b===false)return;if(k.types[b]&&k.types[b][a])f=k.types[b][a];else if(k.types["default"]&&k.types["default"][a])f=k.types["default"][a]}if(c.isFunction(f))f=f.call(this,d);a==="max_depth"&&d!==-1&&g!==false&&k.max_depth!==-2&&f!==0&&this._get_node(d).parentsUntil(this.get_container(),"li").each(function(j){e=h._check(a,this,false);if(e!==-1&&e-(j+1)<=0){f=0;return false}if(e>=0&&(e-(j+1)<f||f<0))f=e-(j+1)});return f},check_move:function(){if(!this.__call_old())return false;
+var a=this._get_move(),d=a.rt.get_settings().types,g=a.rt._check("max_children",a.cr),f=a.rt._check("max_depth",a.cr),b=a.rt._check("valid_children",a.cr),e=0,h=1;if(b==="none")return false;if(c.isArray(b)&&a.ot&&a.ot._get_type){a.o.each(function(){if(c.inArray(a.ot._get_type(this),b)===-1)return h=false});if(h===false)return false}if(d.max_children!==-2&&g!==-1){e=a.cr===-1?this.get_container().children("> ul > li").not(a.o).length:a.cr.children("> ul > li").not(a.o).length;if(e+a.o.length>g)return false}if(d.max_depth!==
+-2&&f!==-1){h=0;if(f===0)return false;if(typeof a.o.d==="undefined"){for(d=a.o;d.length>0;){d=d.find("> ul > li");h++}a.o.d=h}if(f-a.o.d<0)return false}return true},create_node:function(a,d,g,f,b,e){if(!e&&(b||this._is_loaded(a))){var h=d&&d.match(/^before|after$/i)?this._get_parent(a):this._get_node(a),k=this.get_settings().types,j=this._check("max_children",h),i=this._check("max_depth",h),m=this._check("valid_children",h);g||(g={});if(m==="none")return false;if(c.isArray(m))if(!g.attr||!g.attr[k.type_attr]){if(!g.attr)g.attr=
+{};g.attr[k.type_attr]=m[0]}else if(c.inArray(g.attr[k.type_attr],m)===-1)return false;if(k.max_children!==-2&&j!==-1){h=h===-1?this.get_container().children("> ul > li").length:h.children("> ul > li").length;if(h+1>j)return false}if(k.max_depth!==-2&&i!==-1&&i-1<=0)return false}return this.__call_old(true,a,d,g,f,b,e)}}})})(jQuery);
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/d.png
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/d.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/dot_for_ie.gif
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/dot_for_ie.gif
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/style.css
===================================================================
--- trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/style.css	                        (rev 0)
+++ trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/style.css	2010-06-02 15:20:17 UTC (rev 6243)
@@ -0,0 +1,56 @@
+/*
+ * jsTree default theme 1.0
+ * Supported features: dots/no-dots, icons/no-icons, focused, loading
+ * Supported plugins: ui (hovered, clicked), checkbox, contextmenu, search
+ */
+
+.jstree-default li, 
+.jstree-default ins { background-image:url("d.png"); background-repeat:no-repeat; background-color:transparent; }
+.jstree-default li { background-position:-90px 0; background-repeat:repeat-y;  }
+.jstree-default li.jstree-last { background:transparent; }
+.jstree-default .jstree-open > ins { background-position:-72px 0; }
+.jstree-default .jstree-closed > ins { background-position:-54px 0; }
+.jstree-default .jstree-leaf > ins { background-position:-36px 0; }
+
+.jstree-default .jstree-hovered { background:#e7f4f9; border:1px solid #d8f0fa; padding:0 2px 0 1px; }
+.jstree-default .jstree-clicked { background:#beebff; border:1px solid #99defd; padding:0 2px 0 1px; }
+.jstree-default a .jstree-icon { background-position:-56px -19px; }
+.jstree-default a.jstree-loading .jstree-icon { background:url("throbber.gif") center center no-repeat !important; }
+
+.jstree-default.jstree-focused { background:#ffffff; }
+
+.jstree-default .jstree-no-dots li, 
+.jstree-default .jstree-no-dots .jstree-leaf > ins { background:transparent; }
+.jstree-default .jstree-no-dots .jstree-open > ins { background-position:-18px 0; }
+.jstree-default .jstree-no-dots .jstree-closed > ins { background-position:0 0; }
+
+.jstree-default .jstree-no-icons a .jstree-icon { display:none; }
+
+.jstree-default .jstree-search { font-style:italic; }
+
+.jstree-default .jstree-no-icons .checkbox { display:inline-block; }
+.jstree-default .jstree-no-checkboxes .checkbox { display:none !important; }
+.jstree-default .jstree-checked > a > .checkbox { background-position:-38px -19px; }
+.jstree-default .jstree-unchecked > a > .checkbox { background-position:-2px -19px; }
+.jstree-default .jstree-undetermined > a > .checkbox { background-position:-20px -19px; }
+.jstree-default .jstree-checked > a > .checkbox:hover { background-position:-38px -37px; }
+.jstree-default .jstree-unchecked > a > .checkbox:hover { background-position:-2px -37px; }
+.jstree-default .jstree-undetermined > a > .checkbox:hover { background-position:-20px -37px; }
+
+#vakata-dragged.jstree-default ins { background:transparent !important; }
+#vakata-dragged.jstree-default .jstree-ok { background:url("d.png") -2px -53px no-repeat !important; }
+#vakata-dragged.jstree-default .jstree-invalid { background:url("d.png") -18px -53px no-repeat !important; }
+#jstree-marker.jstree-default { background:url("d.png") -41px -57px no-repeat !important; }
+
+.jstree-default a.jstree-search { color:aqua; }
+
+#vakata-contextmenu.jstree-default-context, 
+#vakata-contextmenu.jstree-default-context li ul { background:#f0f0f0; border:1px solid #979797; -moz-box-shadow: 1px 1px 2px #999; -webkit-box-shadow: 1px 1px 2px #999; box-shadow: 1px 1px 2px #999; }
+#vakata-contextmenu.jstree-default-context li { }
+#vakata-contextmenu.jstree-default-context a { color:black; }
+#vakata-contextmenu.jstree-default-context a:hover, 
+#vakata-contextmenu.jstree-default-context .vakata-hover > a { padding:0 5px; background:#e8eff7; border:1px solid #aecff7; color:black; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; }
+#vakata-contextmenu.jstree-default-context li.vakata-separator { background:white; border-top:1px solid #e0e0e0; margin:0; }
+#vakata-contextmenu.jstree-default-context li ul { margin-left:-4px; }
+
+/* TODO: IE6 support - the `>` selectors */
\ No newline at end of file

Added: trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/throbber.gif
===================================================================
(Binary files differ)


Property changes on: trunk/mapbender/http/extensions/jsTree.v.1.0rc/themes/default/throbber.gif
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Modified: trunk/mapbender/http/plugins/mb_metadata_edit.js
===================================================================
--- trunk/mapbender/http/plugins/mb_metadata_edit.js	2010-06-02 12:00:36 UTC (rev 6242)
+++ trunk/mapbender/http/plugins/mb_metadata_edit.js	2010-06-02 15:20:17 UTC (rev 6243)
@@ -100,6 +100,10 @@
 	
 		wmsId = obj;
 		
+		if (!wmsId) {
+			return;
+		}
+				
 		var formData = arguments.length >= 2 ? arguments[1] : undefined;
 		
 		if (!formReady) {

Modified: trunk/mapbender/http/plugins/mb_metadata_layer.js
===================================================================
--- trunk/mapbender/http/plugins/mb_metadata_layer.js	2010-06-02 12:00:36 UTC (rev 6242)
+++ trunk/mapbender/http/plugins/mb_metadata_layer.js	2010-06-02 15:20:17 UTC (rev 6243)
@@ -113,6 +113,10 @@
 
 		wmsId = obj;
 		
+		if (!wmsId) {
+			return;
+		}
+		
 		var formData = arguments.length >= 2 ? arguments[1] : undefined;
 
 		if (!formReady) {

Modified: trunk/mapbender/http/plugins/mb_metadata_layerTree.js
===================================================================
--- trunk/mapbender/http/plugins/mb_metadata_layerTree.js	2010-06-02 12:00:36 UTC (rev 6242)
+++ trunk/mapbender/http/plugins/mb_metadata_layerTree.js	2010-06-02 15:20:17 UTC (rev 6243)
@@ -28,10 +28,10 @@
 
 	var createFolder = function (set) {
 		return {
-			attributes: {
+			data: set.attr.layer_title,
+			attr: {
 				data: $.toJSON(set.attr)
 			},
-			data: set.attr.layer_title,
 			state: "closed",
 			children: []
 		};
@@ -39,7 +39,7 @@
 	
 	var createLeaf = function (set) {
 		return {
-			attributes: {
+			attr: {
 				data: $.toJSON(set.attr)
 			},
 			data: {
@@ -86,47 +86,75 @@
 		return children;
 	};
 
+	var checkLayer = function () {
+		$("#" + instanceId).find("li").each(function () {
+			var metadata = $(this).metadata({
+				type: "attr",
+				name: "data"
+			});
+			if (metadata && metadata.layer_searchable) {
+				$("#" + instanceId).jstree("check_node", this);
+			}
+		});
+	};
+
 	var initTree = function (nestedSets) {
 		var jsTreeData = toJsTreeJson(nestedSets);
+		
 		jsTreeData[0].state = "open";
 		
-		var jsTree = $.tree.reference(instanceId);
-		if (jsTree !== null) {
-			jsTree.destroy();
-		}
+		$("#" + instanceId).jstree("destroy");
 		
-		$("#" + instanceId).tree({
-			ui: {
-//				theme_path: "../extensions/jsTree.v.0.9.9a2/themes/checkbox/style.css",
-//				theme_name: "checkbox"
-				theme_path: "../extensions/jsTree.v.0.9.9a2/themes/default/style.css",
-				theme_name: "default"
+		$.jstree._themes = "../extensions/jsTree.v.1.0rc/themes/";
+		
+		$("#" + instanceId).empty().jstree({ 
+			"json_data" : {
+				"data" : jsTreeData
 			},
-			plugins: {
-//				checkbox: {			
-//				}
-			},
-			data : { 
-				type : "json",
-				opts : {
-					static : jsTreeData
-				}
-			},
-			callback: {
-				onselect: function (node, treeObj) {
-					var data = $(node).metadata({
-						type: "attr",
-						name: "data"
-					});
-					that.events.selected.trigger({
-						"layer": data
-					});
-				}
+			"plugins" : [ "themes", "json_data", "ui", "checkbox" ]
+		});
+		
+		$("#" + instanceId).bind("before.jstree", function (evt, data) {
+			if (data.func === "change_state" && data.args[0].tagName.toUpperCase() === "A") {
+				$("#" + instanceId).find("a").removeClass("jstree-clicked");
+				$(data.args[0]).parent().children("a").addClass("jstree-clicked");
+				var metadata = $(data.args[0]).parent().metadata({
+					type: "attr",
+					name: "data"
+				});
+				that.events.selected.trigger({
+					"layer": metadata
+				});
+									
+				evt.stopImmediatePropagation();
+				return false;
 			}
 		});
+		checkLayer();
 	};
 
+	this.serialize = function (callback) {
+		var data = {
+			wms: {
+				"layer_searchable": []
+			}
+		};
 
+		var $checked = $("#" + instanceId).jstree("get_checked");
+		$checked.each(function () {
+			var metadata = $(this).metadata({
+				type: "attr",
+				name: "data"
+			});
+			data.wms.layer_searchable.push(metadata.layer_id);
+		});
+		
+		if ($.isFunction(callback)) {
+			callback(data);
+		}
+		return data;
+	};	
+
 	this.events = {
 		selected: new Mapbender.Event()
 	};

Modified: trunk/mapbender/http/plugins/mb_metadata_select.js
===================================================================
--- trunk/mapbender/http/plugins/mb_metadata_select.js	2010-06-02 12:00:36 UTC (rev 6242)
+++ trunk/mapbender/http/plugins/mb_metadata_select.js	2010-06-02 15:20:17 UTC (rev 6243)
@@ -61,8 +61,7 @@
 				// initialize datatables
 				table = $metadataSelect.find("table").dataTable({
 					"aoColumns": aoColumns,
-					"bJQueryUI": true,
-					"bAutoWidth": false
+					"bJQueryUI": true
 				});
 				
 				// add rows

Modified: trunk/mapbender/http/plugins/mb_metadata_server.php
===================================================================
--- trunk/mapbender/http/plugins/mb_metadata_server.php	2010-06-02 12:00:36 UTC (rev 6242)
+++ trunk/mapbender/http/plugins/mb_metadata_server.php	2010-06-02 15:20:17 UTC (rev 6243)
@@ -76,33 +76,51 @@
 		$wmsId = $ajaxResponse->getParameter("id");
 		getWms($wmsId);
 
-		$sql = <<<SQL
-	
-SELECT wms_id, wms_abstract, wms_title, fees, accessconstraints, 
-contactperson, contactposition, contactvoicetelephone, 
-contactfacsimiletelephone, contactorganization, address, city, 
-stateorprovince, postcode, country, contactelectronicmailaddress,
-wms_timestamp, wms_timestamp_create 
-FROM wms WHERE wms_id = $wmsId;
+		$wms = new wms();
+		$wms->createObjFromDBNoGui($wmsId);
 
-SQL;
+		$fields = array(
+			"wms_id", 
+			"wms_abstract", 
+			"wms_title", 
+			"fees", 
+			"accessconstraints", 
+			"contactperson", 
+			"contactposition", 
+			"contactvoicetelephone", 
+			"contactfacsimiletelephone", 
+			"contactorganization", 
+			"address", 
+			"city", 
+			"stateorprovince", 
+			"postcode", 
+			"country", 
+			"contactelectronicmailaddress",
+			"wms_timestamp", 
+			"wms_timestamp_create"
+		);
 
-		$res = db_query($sql);
-
 		$resultObj = array();
-		$row = db_fetch_assoc($res);
-
-		foreach ($row as $key => $value) {
-			if(($key == "wms_timestamp" || $key == "wms_timestamp_create") && 
-				$value != "") {
-				$value = date('d.m.Y', $value);
-				$resultObj[$key] = $value;
+		foreach ($fields as $field) {
+			if ($field == "wms_timestamp" || $field == "wms_timestamp_create") {
+				if ($wms->$field != "") {
+					$resultObj[$field] = date('d.m.Y', $wms->$field);
+					
+				}
 			}
 			else {
-				$resultObj[$key] = $value;	
+				$resultObj[$field] = $wms->$field;	
 			}
 		}
 		
+		// layer searchable
+		$resultObj["layer_searchable"] = array();
+		foreach ($wms->objLayer as $layer) {
+			if (intval($layer->layer_searchable) === 1) {
+				$resultObj["layer_searchable"][] = intval($layer->layer_uid);
+			}
+		}
+		
 		$keywordSql = <<<SQL
 	
 SELECT DISTINCT keyword FROM keyword, layer_keyword 
@@ -209,7 +227,7 @@
 
 		$sql = <<<SQL
 	
-SELECT layer_id, layer_pos, layer_parent, layer_name, layer_title, layer_abstract 
+SELECT layer_id, layer_pos, layer_parent, layer_name, layer_title, layer_abstract, layer_searchable 
 FROM layer WHERE fkey_wms_id = $wmsId ORDER BY layer_pos;
 
 SQL;
@@ -231,7 +249,8 @@
 					"layer_id" => intval($row["layer_id"]),
 					"layer_name" => $row["layer_name"],
 					"layer_title" => $row["layer_title"],
-					"layer_abstract" => $row["layer_abstract"]
+					"layer_abstract" => $row["layer_abstract"],
+					"layer_searchable" => intval($row["layer_searchable"])
 				)
 			);
 		}
@@ -330,6 +349,21 @@
 			}
 		}
 
+		if (is_array($data->wms->layer_searchable)) {
+			foreach ($wms->objLayer as &$layer) {
+				$layer->layer_searchable = 0;
+				for ($i = 0; $i < count($data->wms->layer_searchable); $i++) {
+					$id = $data->wms->layer_searchable[$i];
+					if ($id !== intval($layer->layer_uid)) {
+						continue;						
+					}
+					$layer->layer_searchable = 1;
+					break;
+				}
+				unset($id);
+			}
+		}
+
 		try {
 			$layerId = intval($data->layer->layer_id);
 		}

Modified: trunk/mapbender/http/plugins/mb_metadata_submit.js
===================================================================
--- trunk/mapbender/http/plugins/mb_metadata_submit.js	2010-06-02 12:00:36 UTC (rev 6242)
+++ trunk/mapbender/http/plugins/mb_metadata_submit.js	2010-06-02 15:20:17 UTC (rev 6243)
@@ -6,11 +6,21 @@
 	
 	var serializeCallback = function (data) {
 		if (data === null) {
+			// if data is null, the form didn't validate!
+			// formData is set to null, which will prevent server interaction
 			formData = null;
 			return;
 		}
 		if (formData !== null) {
-			formData = $.extend(formData, data);
+			if (formData.wms && data.wms) {
+				formDatawms = $.extend(formData.wms, data.wms);
+			}
+			else if (formData.layer && data.layer) {
+				formData.layer = $.extend(formData.layer, data.layer);
+			}
+			else {
+				formData = $.extend(formData, data);
+			}
 		}
 	};
 	
@@ -20,11 +30,14 @@
 	
 	this.submit = function () {
 		formData = {};
+		console.log(serializeCallback);
 		this.events.submit.trigger({
 			callback: serializeCallback
 		});
 
+		// The form didn't validate
 		if (formData === null) {
+			alert("Please complete or correct the data in the form.");
 			return;
 		}
 



More information about the Mapbender_commits mailing list