[Pkg-mozext-commits] [firexpath] 01/18: Initial commit (version 0.9.1)

David Prévot taffit at moszumanska.debian.org
Sat Mar 26 19:35:46 UTC 2016


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to tag FirePath-0.9.5
in repository firexpath.

commit 6850cc28240512daf7f5154614560d9bd033576c
Author: pierre.tholence <pierre.tholence at dfa30af4-1965-11df-8728-136f2c2ca76e>
Date:   Sun Feb 14 12:52:52 2010 +0000

    Initial commit (version 0.9.1)
---
 build.xml                             |   46 +
 chrome.manifest                       |    4 +
 content/FireXPath.png                 |  Bin 0 -> 2753 bytes
 content/XPathPanel.js                 | 1858 +++++++++++++++++++++++++++++++++
 content/bindings.xml                  |  690 ++++++++++++
 content/firebugOverlay.xul            |   31 +
 defaults/preferences/FireXPathPref.js |    3 +
 install.rdf                           |   23 +
 license.txt                           |  674 ++++++++++++
 locale/en-US/FireXPath.dtd            |    7 +
 locale/en-US/FireXPath.properties     |   27 +
 skin/classic/FireXPath.css            |   75 ++
 skin/classic/xPathPanel.css           |   43 +
 13 files changed, 3481 insertions(+)

diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..8a05d33
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ====================================================================== 
+	 5 mai 2009 16:19:23														
+
+	 FireXPath	
+	 Firebug extension to generate, edit and inspect XPath expressions
+				   
+	 Pierre Tholence																
+	 ====================================================================== -->
+<project name="FireXPath" default="xpi">
+	<description>
+		Firebug extension to generate, edit and inspect XPath expressions
+	</description>
+	
+
+	<property name="filename" value="FireXPath.xpi"/>
+	<property name="builddir" value="build"/>
+	<property name="tempdir" value="temp"/>
+
+	<!-- ================================= 
+		  target: xpi			  
+		 ================================= -->
+	<target name="xpi" depends="clean" description="create the xpi file">
+		<mkdir dir="${tempdir}"/>
+		<copy todir="${tempdir}">
+			<fileset dir="." >
+				<exclude name="${tempdir}"/>
+				<exclude name="build.xml"/>
+				<exclude name=".project"/>
+				<exclude name="**/.svn"/>
+			</fileset>
+		</copy>
+		<mkdir dir="${builddir}"/>
+		<zip destfile="${builddir}/${filename}" basedir="${tempdir}"/>
+		<delete dir="${tempdir}"/>
+	</target>
+
+	<!-- - - - - - - - - - - - - - - - - - 
+		  target: copyFiles					  
+		 - - - - - - - - - - - - - - - - - -->
+	<target name="clean">
+		<delete dir="${builddir}"/>
+		<delete dir="${tempdir}"/>
+	</target>
+
+</project>
diff --git a/chrome.manifest b/chrome.manifest
new file mode 100644
index 0000000..4c87b40
--- /dev/null
+++ b/chrome.manifest
@@ -0,0 +1,4 @@
+content firexpath content/
+locale firexpath en-US locale/en-US/
+skin firexpath classic/1.0 skin/classic/
+overlay chrome://firebug/content/firebugOverlay.xul chrome://firexpath/content/firebugOverlay.xul
diff --git a/content/FireXPath.png b/content/FireXPath.png
new file mode 100644
index 0000000..cfd609a
Binary files /dev/null and b/content/FireXPath.png differ
diff --git a/content/XPathPanel.js b/content/XPathPanel.js
new file mode 100644
index 0000000..7f094e3
--- /dev/null
+++ b/content/XPathPanel.js
@@ -0,0 +1,1858 @@
+/* 
+ * Copyright (C) 2009  Pierre Tholence, DB4ALL
+ *
+ * This file is part of FireXPath
+ *
+ * FireXPath is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FireXPath 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 FireXPath.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+FBL.ns(function() { with (FBL) {
+
+// ************************************************************************************************
+// Constants
+
+const panelName = "xpath";
+
+const prefRegExp = new RegExp(panelName + "\.(.*)");
+
+const defaultTimePeriod = 100;
+
+// ************************************************************************************************
+// XPath Tokens from XPath V1 W3C Recommendation on http://www.w3.org/TR/xpath
+
+var BaseChar = "[\u0041-\u005A]|[\u0061-\u007A]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u00FF]|[\u0100-\u0131]|" +
+		"[\u0134-\u013E]|[\u0141-\u0148]|[\u014A-\u017E]|[\u0180-\u01C3]|[\u01CD-\u01F0]|[\u01F4-\u01F5]|[\u01FA-\u0217]|" +
+		"[\u0250-\u02A8]|[\u02BB-\u02C1]|\u0386|[\u0388-\u038A]|\u038C|[\u038E-\u03A1]|[\u03A3-\u03CE]|[\u03D0-\u03D6]|" +
+		"\u03DA|\u03DC|\u03DE|\u03E0|[\u03E2-\u03F3]|[\u0401-\u040C]|[\u040E-\u044F]|[\u0451-\u045C]|[\u045E-\u0481]|" +
+		"[\u0490-\u04C4]|[\u04C7-\u04C8]|[\u04CB-\u04CC]|[\u04D0-\u04EB]|[\u04EE-\u04F5]|[\u04F8-\u04F9]|[\u0531-\u0556]|" +
+		"\u0559|[\u0561-\u0586]|[\u05D0-\u05EA]|[\u05F0-\u05F2]|[\u0621-\u063A]|[\u0641-\u064A]|[\u0671-\u06B7]|" +
+		"[\u06BA-\u06BE]|[\u06C0-\u06CE]|[\u06D0-\u06D3]|\u06D5|[\u06E5-\u06E6]|[\u0905-\u0939]|\u093D|[\u0958-\u0961]|" +
+		"[\u0985-\u098C]|[\u098F-\u0990]|[\u0993-\u09A8]|[\u09AA-\u09B0]|\u09B2|[\u09B6-\u09B9]|[\u09DC-\u09DD]|" +
+		"[\u09DF-\u09E1]|[\u09F0-\u09F1]|[\u0A05-\u0A0A]|[\u0A0F-\u0A10]|[\u0A13-\u0A28]|[\u0A2A-\u0A30]|[\u0A32-\u0A33]|" +
+		"[\u0A35-\u0A36]|[\u0A38-\u0A39]|[\u0A59-\u0A5C]|\u0A5E|[\u0A72-\u0A74]|[\u0A85-\u0A8B]|\u0A8D|[\u0A8F-\u0A91]|" +
+		"[\u0A93-\u0AA8]|[\u0AAA-\u0AB0]|[\u0AB2-\u0AB3]|[\u0AB5-\u0AB9]|\u0ABD|\u0AE0|[\u0B05-\u0B0C]|[\u0B0F-\u0B10]|" +
+		"[\u0B13-\u0B28]|[\u0B2A-\u0B30]|[\u0B32-\u0B33]|[\u0B36-\u0B39]|\u0B3D|[\u0B5C-\u0B5D]|[\u0B5F-\u0B61]|" +
+		"[\u0B85-\u0B8A]|[\u0B8E-\u0B90]|[\u0B92-\u0B95]|[\u0B99-\u0B9A]|\u0B9C|[\u0B9E-\u0B9F]|[\u0BA3-\u0BA4]|" +
+		"[\u0BA8-\u0BAA]|[\u0BAE-\u0BB5]|[\u0BB7-\u0BB9]|[\u0C05-\u0C0C]|[\u0C0E-\u0C10]|[\u0C12-\u0C28]|[\u0C2A-\u0C33]|" +
+		"[\u0C35-\u0C39]|[\u0C60-\u0C61]|[\u0C85-\u0C8C]|[\u0C8E-\u0C90]|[\u0C92-\u0CA8]|[\u0CAA-\u0CB3]|[\u0CB5-\u0CB9]|" +
+		"\u0CDE|[\u0CE0-\u0CE1]|[\u0D05-\u0D0C]|[\u0D0E-\u0D10]|[\u0D12-\u0D28]|[\u0D2A-\u0D39]|[\u0D60-\u0D61]|" +
+		"[\u0E01-\u0E2E]|\u0E30|[\u0E32-\u0E33]|[\u0E40-\u0E45]|[\u0E81-\u0E82]|\u0E84|[\u0E87-\u0E88]|\u0E8A|\u0E8D|" +
+		"[\u0E94-\u0E97]|[\u0E99-\u0E9F]|[\u0EA1-\u0EA3]|\u0EA5|\u0EA7|[\u0EAA-\u0EAB]|[\u0EAD-\u0EAE]|\u0EB0|" +
+		"[\u0EB2-\u0EB3]|\u0EBD|[\u0EC0-\u0EC4]|[\u0F40-\u0F47]|[\u0F49-\u0F69]|[\u10A0-\u10C5]|[\u10D0-\u10F6]|\u1100|" +
+		"[\u1102-\u1103]|[\u1105-\u1107]|\u1109|[\u110B-\u110C]|[\u110E-\u1112]|\u113C|\u113E|\u1140|\u114C|\u114E|\u1150|" +
+		"[\u1154-\u1155]|\u1159|[\u115F-\u1161]|\u1163|\u1165|\u1167|\u1169|[\u116D-\u116E]|[\u1172-\u1173]|\u1175|\u119E|" +
+		"\u11A8|\u11AB|[\u11AE-\u11AF]|[\u11B7-\u11B8]|\u11BA|[\u11BC-\u11C2]|\u11EB|\u11F0|\u11F9|[\u1E00-\u1E9B]|" +
+		"[\u1EA0-\u1EF9]|[\u1F00-\u1F15]|[\u1F18-\u1F1D]|[\u1F20-\u1F45]|[\u1F48-\u1F4D]|[\u1F50-\u1F57]|\u1F59|\u1F5B|\u1F5D|" +
+		"[\u1F5F-\u1F7D]|[\u1F80-\u1FB4]|[\u1FB6-\u1FBC]|\u1FBE|[\u1FC2-\u1FC4]|[\u1FC6-\u1FCC]|[\u1FD0-\u1FD3]|[\u1FD6-\u1FDB]|" +
+		"[\u1FE0-\u1FEC]|[\u1FF2-\u1FF4]|[\u1FF6-\u1FFC]|\u2126|[\u212A-\u212B]|\u212E|[\u2180-\u2182]|[\u3041-\u3094]|" +
+		"[\u30A1-\u30FA]|[\u3105-\u312C]|[\uAC00-\uD7A3]";
+		
+var Ideographic = "[\u4E00-\u9FA5]|\u3007|[\u3021-\u3029]";
+
+var Letter = BaseChar + "|" + Ideographic;
+
+var NCNameStartChar = Letter + "|_";
+
+var NCNameChar = "[A-Z]|_|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|" +
+		"[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|" +
+		"-|\\.|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040]";
+		
+var NCName = "(?:(?:" +  NCNameStartChar + ")(?:" +  NCNameChar + ")*)";
+
+var QName = NCName + ":" + NCName + "|" + NCName;
+
+var NameTest = "\\*|" + NCName + ":\\*|" + QName;
+
+var NodeType = "comment|text|processing-instruction|node";
+
+var NameOperator = "and|or|mod|div";
+
+var Operator = NameOperator + "|\\*|//|/|\\||\\+|-|!=|<=|<|>=|>|=";
+
+var FunctionName = QName;
+
+var AxisName = "ancestor|ancestor-or-self|attribute|child|descendant|descendant-or-self|following|following-sibling|parent|preceding|" +
+		"preceding-sibling|self";
+
+var Literal = "\"[^\"]*\"|'[^']*'";
+
+var Numbers = "\\d+(?:\\.\\d?)?|\\.\\d+";
+
+var ExprToken = "\\(|\\)|\\[|\\]|\\.\\.|@|,|::|" + NameTest + "|" + NodeType + "|" + Operator + "|" + FunctionName + "|" + 
+AxisName + "|" + Literal + "|" + Numbers + "|\\.";
+
+var xPathToken = new RegExp(ExprToken, "g");
+
+var selectedToken = new RegExp(NCName + ":(?!:)|" + ExprToken + "|\\s", "g");
+
+var nameTestToken = new RegExp(NameTest);
+// Function supported by Firefox
+var functionNameToken = new RegExp("concat|substring|substring-after|substring-before|string|local-name|name|namespace-uri|normalize-space" +
+		"translate|ceiling|count|floor|last|number|position|round|sum|boolean|contains|false|lang|not|starts-with|string-length|true");
+
+var expressionToken = new RegExp("\\]|\\)|\\*" + NameTest + "|" + Literal + "|" + Numbers + "|\\.");
+
+var getNamespace = new RegExp("([^:]+:).*");
+
+// ************************************************************************************************
+// XPathPanel
+
+Firebug.XPathPanel = function() {}
+Firebug.XPathPanel.prototype = extend(Firebug.Panel,
+{
+	
+	// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	// extends Panel ()
+	
+	name: panelName,
+	title: "XPath",
+
+	initialize: function() {
+		Firebug.Panel.initialize.apply(this, arguments);
+		this.addStyleSheet(this.document);
+		this.location = this.getDefaultLocation(this.context);
+		this.xPathBar = (this.context.chrome?this.context.chrome.$("FireXPathBar"): $("FireXPathBar"));
+		this.xPathStatusBar = (this.context.chrome?this.context.chrome.$("FireXPathStatusBar"): $("FireXPathStatusBar"));
+		
+		this.ioBoxContainer = this.document.createElement("div");
+		setClass(this.ioBoxContainer, "io-box-container");
+		this.panelNode.appendChild(this.ioBoxContainer);
+		
+		this.onMouseDown = bind(this.onMouseDown, this);
+		
+		this.inspecting = false;
+	},
+	
+	destroy: function(state) {
+		state.persistedLocation = this.persisteLocation();
+		this.xPathBar.persiste(state);
+		this.stopLoading();
+		
+		if (this.ioBox) {
+			this.ioBox.destroy();
+			delete this.ioBox;
+		}
+		Firebug.Panel.destroy.apply(this, arguments);
+	},
+	
+	initializeNode: function(oldPanelNode) {
+		this.panelNode.addEventListener("mousedown", this.onMouseDown, false);
+	},
+
+	destroyNode: function() {
+		this.panelNode.removeEventListener("mousedown", this.onMouseDown, false);
+	},
+	
+	show: function(state) {
+		if (this.context.loaded) {
+			this.showModules(true);
+			
+			if(!this.ioBox) {
+				this.ioBox = new InsideOutBox(this, this.ioBoxContainer);
+				if(state) {
+					this.restoreLocation(state.persistedLocation);
+					this.xPathBar.restore(state);
+					this.xPathBar.evaluate(true);
+				} else {
+					this.ioBox.createObjectBox(this.rootElement || this.location.document);
+				}
+			}
+		}
+	},
+	
+	hide: function() {
+		this.showModules(false);
+	},
+	
+	showModules: function(show) {
+		this.xPathBar.show(this.context, show);
+		this.xPathStatusBar.show(this.context, show);
+		
+		var $ = FBL.$;
+		if(this.context.chrome)
+			$ = this.context.chrome.$;
+		
+		// when there is a visibility: hidden style the collapsed attribute doesn't work correctly
+		$("fbPanelStatus").removeAttribute("style");
+		collapse($("fbSearchBox"), show);
+		collapse($("fbPanelStatus"), show);
+	},
+	
+	detach: function(oldChrome, newChrome) {
+		Firebug.Panel.detach.apply(this, arguments);
+		if(this.context == FirebugContext) {
+			this.xPathBar.persiste(this.context);
+		}
+		this.xPathBar = newChrome.$("FireXPathBar");
+		this.xPathStatusBar = newChrome.$("FireXPathStatusBar");
+		if(this.context == FirebugContext) {
+			this.xPathBar.restore(this.context);
+			this.xPathBar.currentContext = this.context;
+		}
+		if(this.context.browser.detached || (newChrome != Firebug.originalChrome && this.context == FirebugContext)) {
+			Firebug.XPathPanel.LocationHighlightModule.addLocationListener(newChrome);
+		} else {
+			Firebug.XPathPanel.LocationHighlightModule.removeLocationListener(oldChrome);
+		}
+	},
+	
+	reattach: function(doc) {
+		Firebug.Panel.reattach.apply(this, arguments);
+		this.addStyleSheet(doc);
+	},
+	
+	supportsObject: function(object) {
+		if(object instanceof Window)
+			return 2;
+		else if (object instanceof Element ||
+				object instanceof Text ||
+				object instanceof Attr ||
+				object instanceof Comment ||
+				object instanceof Document ||
+				object instanceof SourceText )
+			return 1;
+		else
+			return 0;
+	},
+	
+	updateSelection: function(object) {
+		var location;
+		if(object instanceof Document)
+			location =  object.defaultView;
+		else
+			location = object.ownerDocument.defaultView;
+		
+		this.navigate(location);
+		this.xPathBar.setNode(object, this.inspecting);
+	},
+	
+	// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	// extends Panel (location menu for iframes)
+	
+	getLocationList: function() {
+		var locations = [];
+		var win = this.context.window;
+		
+		locations.push(this.context.window);
+		
+		for(var i=0; i<win.frames.length; i++) {
+			locations.push(win.frames[i].window);
+		}
+		return locations;
+	},
+	
+	updateLocation: function() {
+		this.xPathBar.updateLocation(this.location);
+		this.xPathStatusBar.reset(this.context);
+		this.setResult(null, null);
+	},
+	
+	getDefaultLocation: function(context) {
+		return context.window;
+	},
+	
+	getObjectDescription: function(object) {
+		var win = this.context.window;
+		
+		var path;
+		try{
+			path = object.location.host + object.location.pathname;
+		} catch(e) {
+			path = "" + object.location;
+		}
+
+		var name = "";
+
+		if(object == win) name = $STR_XP("topWindow");
+		else {
+			for(var i=0; i<win.frames.length; i++)
+				if(win.frames[i].window== object) {
+					name = getElementCSSSelector(object.frameElement); //+ "["+i+"]";
+					break;
+				}
+		}
+		
+		return {name: name, path: path};
+	},
+	
+	persisteLocation: function() {
+		var win = this.context.window;
+		for(var i = 0; i < win.frames.length; i++)
+			if(win.frames[i].window == this.location) 
+				return i;
+		return "top";
+	},
+	
+	restoreLocation: function(location) {
+		var win =this.context.window;
+		
+		if(location != "top" && location < win.frames.length)
+			this.navigate(this.context.window.frames[location]);
+		else
+			this.navigate(win);
+	},
+	
+	// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	// extends Panel (option menu)
+	
+	getOptionsMenuItems: function()
+	{
+		return [
+			getOptionMenu("showXPathContextMenu", "showXPathContext"),
+			getOptionMenu("generateAbsoluteXPathMenu", "generateAbsoluteXPath"),
+			getOptionMenu("showDOMMenu", "showDOM")
+		];
+	},
+	
+	updateOption: function(name, value) {
+		if(prefRegExp.test(name)) {
+			var option = prefRegExp.exec(name)[1];
+			if(option == "showDOM") {
+				this.displayResult();
+			} else if (option == "showXPathContext") {
+				this.xPathBar.showXPathContext(value);
+			}
+		}
+	},
+
+	// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	// Style sheet management method
+		
+	addStyleSheet: function(doc) {
+		// Make sure the stylesheet isn't appended twice.
+		if ($("xPathStyles", doc))
+			return;
+
+		var styleSheet = createStyleSheet(doc,
+			"chrome://firexpath/skin/xPathPanel.css");
+		styleSheet.setAttribute("id", "xPathStyles");
+		addStyleSheet(doc, styleSheet);
+	},
+	
+	// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	// Result management methods
+	
+	setResult: function(xPathContext, result) {
+		this.rootElement = xPathContext;
+		this.evaluationResult = result;
+		this.displayResult();
+		Firebug.XPathPanel.ResultHighlightModule.refreshHighlight(this);
+	},
+	
+	displayResult: function() {
+		this.stopLoading();
+		
+		this.setResultInfo();
+		
+		clearNode(this.ioBoxContainer);
+		delete this.ioBox.rootObjectBox;
+		
+		var showDOM = Firebug.getPref(Firebug.prefDomain, "xpath.showDOM")
+		
+		if(this.evaluationResult != null && !this.evaluationResult.message) {
+			if(isArray(this.evaluationResult)) {
+				if(showDOM) {
+					this.ioBox.createObjectBox(this.rootElement || this.location.document);
+					this.ioBox.selectMultiple(this.evaluationResult);
+				} else
+					this.ioBox.addObjects(this.evaluationResult);
+			} else {
+				var type = typeof(this.evaluationResult);
+				type = type.charAt(0).toUpperCase() + type.substring(1);
+				this.ioBoxContainer.textContent = type + ": " + this.evaluationResult;
+			}
+		} else if(showDOM){
+			this.ioBox.createObjectBox(this.rootElement || this.location.document);
+		}
+	},
+	
+	setResultInfo: function() {
+		var result = this.evaluationResult;
+		if(result == null) {
+			this.xPathStatusBar.clearResultInfo(this.context);
+		} else if(result.message) {
+			this.xPathStatusBar.setResultInfo(this.context, "error", $STR_XP(result.message));
+		} else {
+			if(FBL.isArray(result)) {
+				var whiteSpace = 0;
+				result.forEach(function(object) {if(isWhitespaceText(object)) whiteSpace++;})
+				switch(result.length) {
+					case 0:
+						this.xPathStatusBar.setResultInfo(this.context, "warning", $STR_XP("noResultError"));
+					break;
+					case 1:
+						this.xPathStatusBar.setResultInfo(this.context, "ok", $STR_XP("oneResultMessage"));
+					break;
+					default:
+						this.xPathStatusBar.setResultInfo(this.context, "ok", 
+							$STR_XP("manyResultMessage", result.length) + 
+							(whiteSpace > 0? 
+								" (" + (whiteSpace == 1? 
+									$STR_XP("oneWhiteSpaceMessage"): 
+									$STR_XP("manyWhiteSpaceMessage", whiteSpace)
+								) + ")":
+							"") );
+					break;
+				}
+			} else {
+				switch(typeof(result)) {
+					case "string":
+						this.xPathStatusBar.setResultInfo(this.context, "ok", $STR_XP("stringResultMessage"));
+					break;
+					case "number":
+						this.xPathStatusBar.setResultInfo(this.context, "ok", $STR_XP("numberResultMessage"));
+					break;
+					case "boolean":
+						this.xPathStatusBar.setResultInfo(this.context, "ok", $STR_XP("booleanResultMessage"));
+					break;
+				}
+			}
+		}
+	},
+
+	// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	// SourceBox proxy
+
+	createObjectBox: function(object, isRoot) {
+		var tag = getNodeTag(object);
+		if (tag)
+			return tag.replace({object: object}, this.document);
+	},
+
+	getParentObject: function(node) {
+		if (node instanceof SourceText)
+			return node.owner;
+
+		if (this.rootElement && node == this.rootElement)
+			return null;
+
+		var parentNode = node ? node.parentNode : null;
+		return parentNode;
+	},
+
+	getChildObject: function(node, index, previousSibling)
+	{
+		if(node instanceof Document) {
+			if(index == 0)
+				return node.documentElement;
+		}
+		else if (previousSibling) {
+			return findNextSibling(previousSibling);
+		}
+		else {
+			var childIndex = 0;
+			for (var child = node.firstChild; child; child = child.nextSibling) {
+				if (!isWhitespaceText(child) && childIndex++ == index)
+					return child;
+			}
+		}
+
+		return null;
+	},
+	
+	// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	// Result display loading management methods
+	
+	startLoading: function(objects, task) {
+		var step = bind(function(object) {task(object); this.increaseLoading()}, this);
+		var end = bind(this.finishLoading, this);
+ 
+ 		this.stepper = new Stepper(arrayIterator(objects), step, end);
+		
+		//this.panelNode.removeChild(this.ioBoxContainer);
+		
+		this.xPathStatusBar.startLoading(this.context, objects.length);
+		this.stepper.start();
+	},
+	
+	stopLoading: function() {
+		if(this.stepper) {
+			this.stepper.stop();
+			this.finishLoading();
+		}
+	},
+	
+	increaseLoading: function() {
+		this.xPathStatusBar.increaseLoading(this.context);
+	},
+	
+	finishLoading: function() {
+		this.xPathStatusBar.stopLoading(this.context);
+		
+		//this.panelNode.appendChild(this.ioBoxContainer);
+		
+		delete this.stepper;
+	},
+	
+	// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	// Inspector management methods
+	
+	startInspecting: function() {
+		this.inspecting = true;
+		this.previousLocation = this.location;
+		this.previousXPath = this.xPathBar.xPath;
+		this.setResult(null, null);
+	},
+	
+	stopInspecting: function(cancelled) {
+		this.inspecting = false;
+		if(cancelled) {
+			this.navigate(this.previousLocation);
+			this.xPathBar.xPath = this.previousXPath;
+			delete this.previousLocation;
+			delete this.previousXPath;
+		}
+		this.xPathBar.evaluate();
+	},
+	
+	// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	// Event handlers
+	
+	onMouseDown: function(event) {
+		if (!isLeftClick(event))
+			return;
+
+		if (getAncestorByClass(event.target, "nodeTag")) {
+			var element = Firebug.getRepObject(event.target);
+			
+			Firebug.Inspector.highlightObject(null);
+			element.scrollIntoView();
+			Firebug.Inspector.highlightObject(element, FirebugContext);
+		}
+	},
+	
+});
+
+// ************************************************************************************************
+// Special Reps
+
+Firebug.XPathPanel.Attr = domplate(Firebug.Rep,
+{
+	tag:
+		SPAN({"class": "nodeAttr", _repObject:"$attr"}, " ",
+			SPAN({"class": "nodeName"}, "$attr.nodeName"), "="",
+			SPAN({"class": "nodeValue"}, "$attr.nodeValue|filterFireXPathClassValue"), """
+		),
+	
+	className: "attrNode",
+
+	supportsObject: function(object) {
+		return object instanceof Attr;
+	},
+	
+	getRealObject: function(attribute) {
+		return attribute.ownerElement;
+	},
+	
+	getContextMenuItems: function(attribute, target, context) {
+		return getNodeContextMenu(attribute, target, context);
+	},
+	
+	getTooltip: function(attribute) {
+		return getXPathFromNode(attribute);
+	}
+});
+
+Firebug.XPathPanel.Comment = domplate(Firebug.Rep,
+{
+	tag:
+		DIV({"class": "nodeBox", _repObject: "$object"},
+			DIV({"class": "nodeComment"},
+				"<!--$object.nodeValue-->"
+			)
+		),
+	
+	className: "commentNode",
+
+	supportsObject: function(object) {
+		return object instanceof Comment;
+	},
+	
+	getContextMenuItems: function(node, target, context) {
+		return getNodeContextMenu(node, target, context);
+	},
+	
+	getTooltip: function(node) {
+		return getXPathFromNode(node);
+	}
+});
+
+Firebug.XPathPanel.CDATASection = domplate(Firebug.Rep,
+{
+	tag:
+		DIV({"class": "nodeBox", _repObject: "$object"},
+			"<![CDATA[",
+			SPAN({"class": "nodeText"}, "$object.nodeValue"),
+			"]]>"
+		),
+		
+	className: "cdataNode",
+
+	supportsObject: function(object) {
+		return object instanceof CDATASection;
+	},
+	
+	getContextMenuItems: function(node, target, context) {
+		return getNodeContextMenu(node, target, context);
+	},
+	
+	getTooltip: function(node) {
+		return getXPathFromNode(node);
+	}
+});
+
+Firebug.registerRep(
+	Firebug.XPathPanel.Attr,
+	Firebug.XPathPanel.Comment,
+	Firebug.XPathPanel.CDATASection
+);
+
+// ************************************************************************************************
+// Extension of FirebugReps.Element and FirebugReps.TextNode to modify the context menu 
+// and tooltip when the xPath tab is selected
+
+function overwriteMethodForPanel(object, methodName, panelName, newMethod ) {
+	if(object[methodName] && object[methodName] instanceof Function)
+		object["default" + methodName] = object[methodName];
+	object[methodName] = function () {
+		var selectedPanelName = FirebugContext.panelName;
+
+		if(selectedPanelName != panelName) {
+			if(object["default" + methodName])
+				return object["default" + methodName].apply(object, arguments);
+		} else {
+			return newMethod.apply(object, arguments);
+		}
+	}
+}
+
+FirebugReps.Element.getTagName = function(node) {
+	return getTagName(node);
+}
+
+// Overwrite FirebugReps.Element.getContextMenuItems
+overwriteMethodForPanel(
+	FirebugReps.Element,
+	"getContextMenuItems",
+	Firebug.XPathPanel.prototype.name,
+	function(node, target, context) {
+		return getNodeContextMenu(node, target, context);
+	}
+);
+
+// Overwrite FirebugReps.Element.getTooltip
+overwriteMethodForPanel(
+	FirebugReps.Element,
+	"getTooltip",
+	Firebug.XPathPanel.prototype.name,
+	function(node) {
+		return getXPathFromNode(node);
+	}
+);
+
+// Overwrite FirebugReps.TextNode.getContextMenuItem
+overwriteMethodForPanel(
+	FirebugReps.TextNode,
+	"getContextMenuItems",
+	Firebug.XPathPanel.prototype.name,
+	function(node, target, context) {
+		return getNodeContextMenu(node, target, context);
+	}
+);
+
+// Overwrite FirebugReps.TextNode.getTooltip
+overwriteMethodForPanel(
+	FirebugReps.TextNode,
+	"getTooltip",
+	Firebug.XPathPanel.prototype.name,
+	function(node) {
+		return getXPathFromNode(node);
+	}
+);
+
+// Overwrite FirebugReps.TextNode.getRealObject
+overwriteMethodForPanel(
+	FirebugReps.TextNode,
+	"getRealObject",
+	Firebug.XPathPanel.prototype.name,
+	function(object) {
+		return object.parentNode;
+	}
+);
+
+// ************************************************************************************************
+// Tree definition
+
+//TODO improve this (add the url, ns...)
+Firebug.XPathPanel.Document = domplate(FirebugReps.Document,
+{
+	tag:
+		DIV({"class": "nodeBox containerNodeBox repIgnore", _repObject: "$object"},
+			DIV({"class": "nodeLabel"},
+				IMG({"class": "twisty"}),
+				SPAN({"class": "nodeLabelBox repTarget"},
+					"<",
+					SPAN({"class": "nodeTag"}, "document"),
+					SPAN({"class": "nodeBracket insertBefore"}, ">")
+				)
+			),
+			DIV({"class": "nodeChildBox"}),
+			DIV({"class": "nodeCloseLabel"},
+				SPAN({"class": "nodeCloseLabelBox repTarget"},
+					"</",
+					SPAN({"class": "nodeTag"}, "document"),
+					">"
+				)
+			 )
+		)
+});
+
+FirebugReps.Element.filterFireXPathClass = function(attrs) {
+	for (var i=0; i<attrs.length; i++) {
+		var attr = attrs[i];
+		if(attr.localName == "class" && attr.nodeValue == "firexpath-matching-node") {
+			attrs.splice(i, 1);
+			break;
+		}
+	}
+	return attrs;
+}
+
+FirebugReps.Element.filterFireXPathClassValue = function(value) {
+	return value.replace(" firexpath-matching-node", "");
+},
+
+Firebug.XPathPanel.Element = domplate(FirebugReps.Element,
+{
+	tag:
+		DIV({"class": "nodeBox containerNodeBox repIgnore", _repObject: "$object"},
+			DIV({"class": "nodeLabel"},
+				IMG({"class": "twisty"}),
+				SPAN({"class": "nodeLabelBox repTarget"},
+					"<",
+					SPAN({"class": "nodeTag"}, "$object|getTagName"),
+					FOR("attr", "$object|attrIterator|filterFireXPathClass", Firebug.XPathPanel.Attr.tag),
+					SPAN({"class": "nodeBracket insertBefore"}, ">")
+				)
+			),
+			DIV({"class": "nodeChildBox"}),
+			DIV({"class": "nodeCloseLabel"},
+				SPAN({"class": "nodeCloseLabelBox repTarget"},
+					"</",
+					SPAN({"class": "nodeTag"}, "$object.localName|toLowerCase"),
+					">"
+				)
+			 )
+		)
+});
+
+Firebug.XPathPanel.TextElement = domplate(FirebugReps.Element,
+{
+	tag:
+		DIV({"class": "nodeBox textNodeBox repIgnore", _repObject: "$object"},
+			DIV({"class": "nodeLabel"},
+				SPAN({"class": "nodeLabelBox repTarget"},
+					"<",
+					SPAN({"class": "nodeTag"}, "$object|getTagName"),
+					FOR("attr", "$object|attrIterator|filterFireXPathClass", Firebug.XPathPanel.Attr.tag),
+					SPAN({"class": "nodeBracket insertBefore"}, ">"),
+					SPAN({"class": "nodeText", _repObject: "$object.firstChild"}, "$object.firstChild.nodeValue"),
+					"</",
+					SPAN({"class": "nodeTag"}, "$object.localName|toLowerCase"),
+					">"
+				)
+			)
+		)
+});
+
+Firebug.XPathPanel.EmptyElement = domplate(FirebugReps.Element,
+{
+	tag:
+		DIV({"class": "nodeBox emptyNodeBox repIgnore", _repObject: "$object"},
+			DIV({"class": "nodeLabel"},
+				SPAN({"class": "nodeLabelBox repTarget"},
+					"<",
+					SPAN({"class": "nodeTag"}, "$object|getTagName"),
+					FOR("attr", "$object|attrIterator|filterFireXPathClass", Firebug.XPathPanel.Attr.tag),
+					SPAN({"class": "nodeBracket insertBefore"}, "/>")
+				)
+			)
+		)
+});
+
+Firebug.XPathPanel.TextNode = domplate(FirebugReps.Element,
+{
+	tag:
+		DIV({"class": "nodeBox", _repObject: "$object"},
+			SPAN({"class": "nodeText"}, "$object.nodeValue")
+		)
+});
+
+// ************************************************************************************************
+// Local Helpers
+
+function getNodeTag(node) {
+	if (node instanceof Element) {
+		if (node instanceof HTMLAppletElement)
+			return Firebug.XPathPanel.EmptyElement.tag;
+		else if (node.firebugIgnore || node.id == "_firebugConsole")
+			return null;
+		else if (isEmptyElement(node))
+			return Firebug.XPathPanel.EmptyElement.tag;
+		else if (isPureText(node))
+			return Firebug.XPathPanel.TextElement.tag;
+		else
+			return Firebug.XPathPanel.Element.tag;
+	}
+	else if(node instanceof Document)
+		return Firebug.XPathPanel.Document.tag;
+	else if (node instanceof Text)
+		return Firebug.XPathPanel.TextNode.tag;
+	else if (node instanceof CDATASection)
+		return Firebug.XPathPanel.CDATASection.tag;
+	else if (node instanceof Comment)
+		return Firebug.XPathPanel.Comment.tag;
+	else
+		return FirebugReps.Nada.tag;
+}
+
+function isWhitespaceText(node) {
+	if (node instanceof HTMLAppletElement)
+		return false;
+	return node.nodeType == 3 && isWhitespace(node.nodeValue);
+}
+
+function findNextSibling(node) {
+	for (var child = node.nextSibling; child; child = child.nextSibling) {
+		if (!isWhitespaceText(child))
+			return child;
+	}
+}
+
+function isPureText(element) {
+	if(element.firstChild.nodeType == 3
+			&& element.childNodes.length == 1
+			&& !isWhitespaceText(element.firstChild))
+		return true;
+	else
+		return false;
+}
+
+function isEmptyElement(element) {
+	for(var child = element.firstChild; child; child = child.nextSibling) {
+		if(!isWhitespaceText(child)) return false;
+	}
+	return true;
+}
+
+function getOptionMenu(label, option) {
+	var key = Firebug.XPathPanel.prototype.name + "." + option;
+	var value = Firebug.getPref(Firebug.prefDomain, key);
+	
+	return {label: $STR_XP(label),
+		nol10n: true,
+		type: "checkbox",
+		checked: value,
+		command: bindFixed(Firebug.setPref, Firebug, Firebug.prefDomain, key, !value) };
+}
+
+function getNodeContextMenu(node, target, context) {
+
+	// This to make sure the context menu is added to the right object
+	if(node != Firebug.getRepObject(target)) return;
+	
+	var xPathBar = context.getPanel(panelName).xPathBar;
+	
+	var contextMenu = [
+		{label: $STR_XP("copyXPath"),
+		nol10n: true,
+		command: bindFixed(copyXPath, FBL, node)}
+	];
+	
+	if(Firebug.getPref(Firebug.prefDomain, "xpath.showXPathContext")) {
+		var panel = context.getPanel(Firebug.XPathPanel.prototype.name);
+		if(panel.rootElement && panel.rootElement != panel.location.document)
+			contextMenu.push(
+				{label: $STR_XP("copyXPathFromContext"),
+				nol10n: true,
+				command: bindFixed(copyXPath, FBL, node, panel.rootElement) }
+			)
+	}
+	
+	contextMenu.push(
+		{label: $STR_XP("setXPath"),
+			nol10n: true,
+			command: bindFixed(xPathBar.setNode, xPathBar, node)}
+	)
+		
+	var element = null;
+	if(node instanceof Element) {
+		element = node;
+		if(Firebug.getPref(Firebug.prefDomain, "xpath.showXPathContext"))
+			contextMenu.push(
+				{label: $STR_XP("setXPathContext"),
+					nol10n: true,
+					command: bindFixed(xPathBar.setContextNode, xPathBar, node)}
+			);
+	}
+	else if(node instanceof Attr)
+		element = node.ownerElement;
+	else if(node instanceof Text)
+		element = node.parentNode;
+		
+	if(element) {
+		contextMenu.push("-");
+		contextMenu.push({label: "ScrollIntoView", command: bindFixed(element.scrollIntoView, element) });
+	}
+	
+	return contextMenu;
+}
+
+function copyXPath(node, context) {
+	var xpath = getXPathFromNode(node, context);
+	copyToClipboard(xpath);
+}
+
+// Generator that create an iterator over an array
+function arrayIterator(array) {
+	for(var i = 0, length = array.length; i < length; i++) {
+		yield array[i];
+	}
+}
+
+// ************************************************************************************************
+// Global Helpers
+
+FBL.$STR_XP = function() {
+	var args = cloneArray(arguments);
+	var key = args.shift();
+	var bundle = document.getElementById("FireXpath_strings");
+	try{
+		if(args.length > 0)
+			return bundle.getFormattedString(key, args);
+		else
+			return bundle.getString(key);
+	} catch(e) {
+		return key;
+	}
+}
+
+FBL.isArray = function (object) {
+		return FirebugReps.Arr.isArray(object);
+}
+
+FBL.getTagName = function(node) {
+	var ns = node.namespaceURI;
+	var prefix = node.lookupPrefix(ns);
+	
+	//if an element has a namespace it needs a prefix
+	if(ns != null && !prefix) {
+		prefix = getPrefixFromNS(ns);
+	}
+	
+	return (prefix?prefix + ":":"") + node.localName.toLowerCase();	
+}
+
+FBL.getPrefixFromNS = function(ns) {
+	return ns.replace(/.*[^\w](\w+)[^\w]*$/, "$1");
+}
+
+FBL.getXPathFromNode = function(node, context) {
+	var result = "";
+	var stop = false;
+	var absolute = Firebug.getPref(Firebug.prefDomain, "xpath.generateAbsoluteXPath");
+
+	var parent = context || node.ownerDocument;
+	while (node && node != parent && !stop) {
+		var str = "";
+		var position = getNodePosition(node);
+		switch (node.nodeType) {
+			case Node.DOCUMENT_NODE:
+			break;
+			case Node.ATTRIBUTE_NODE:
+				str = "@" + node.name;
+			break;
+			case Node.COMMENT_NODE:
+				str = "comment()";
+			break;
+			case Node.TEXT_NODE:
+				str = "text()";
+			break;
+			case Node.ELEMENT_NODE:
+
+				var name = getTagName(node);
+
+				if(!absolute && node.id && node.id != "") {
+					str = ".//*[@id='" + node.id + "']";
+					position = null;
+					stop = true;
+				} else {
+					str = name;
+				}
+				
+			break;
+		}
+		
+		result = str + (position ? "[" + position + "]" : "") + (result? "/": "") + result;
+		
+		if(node instanceof Attr) node = node.ownerElement;
+		else node = node.parentNode;
+
+	}
+
+	return result;
+}
+
+function getNodePosition(node) {
+	if (!node.parentNode)
+		return null;
+	
+	var siblings = node.parentNode.childNodes;
+	var count = 0;
+	var position;
+	
+	for (var i = 0; i < siblings.length; i++) {
+		var object = siblings[i];
+		if(object.nodeType == node.nodeType && object.nodeName == node.nodeName) {
+			count++;
+			if(object == node) position = count;
+		}
+	}
+
+	if (count > 1)
+		return position;
+	else
+		return null;
+}
+
+// ************************************************************************************************
+// Extension of InsideOutBox to support multiple selection
+
+InsideOutBox.prototype = extend(InsideOutBox.prototype, {
+	
+	selectMultiple: function(objects) {
+		var filteredObjects =  objects.filter(function(object){return !isWhitespaceText(object);});
+		
+		this.firstSelection = true;
+		this.view.startLoading(filteredObjects, bind(this.selectObject, this));
+	},
+	
+	selectObject: function(object) {
+		
+		// Get correct object to find or create the objectBox
+		var correctObject = object;
+		if(object instanceof Attr)
+			correctObject = object.ownerElement;
+		else if(object instanceof Text)
+			correctObject = object.parentNode;
+		
+		// Find the objectBox (node in the ioBox)
+		var objectBox = this.findObjectBox(correctObject);
+		
+		// Create it if it doesn't exist yet
+		if(!objectBox)
+			objectBox = this.createObjectBox(correctObject);
+		
+		// objectBox can be null for object that have the firebugIgnore attribute
+		if(objectBox != null) {
+			
+			// Get the correct node in the ioBox to set its class to selected
+			var nodeToSelect = objectBox;
+			
+			if(object instanceof Attr) {
+				// Get the nodes that contains the attributes
+				var attributeNodes = getElementsByClass(objectBox, "nodeAttr");
+				
+				// This get the node that contains the attribute we are looking for
+				nodeToSelect = Array.filter(attributeNodes, function(attributeNode) {
+					return attributeNode.childNodes[1].textContent == object.name;
+				})[0];
+			}
+			else if(object instanceof Text) {
+				// Get the nodes that contains the text
+				var textNodes = getElementsByClass(objectBox, "nodeText");
+				
+				if(textNodes.length == 0) {
+					this.expandObjectBox(objectBox);
+					textNodes = getElementsByClass(objectBox, "nodeText");
+				}
+		
+				// This get the node that contains the text we are looking for
+				nodeToSelect = Array.filter(textNodes, function(textNode) {
+					return textNode.textContent == object.nodeValue;
+				})[0];
+			}
+			
+			// Set the correct node's class to selected
+			setClass(nodeToSelect, "selected");
+			
+			// Make the objectBox visible 
+			this.openObjectBox(objectBox);
+			
+			// Scroll into the first element selected in the tree
+			if(this.firstSelection) {
+				this.firstSelection = false;
+				scrollIntoCenterView(nodeToSelect, this.view.ioBoxContainer);
+			}
+		}
+	},
+	
+	addObjects: function(objects) {
+		this.view.startLoading(objects, bind(this.addObject, this));
+	},
+	
+	addObject: function(object) {
+		var objectBox;
+			
+		if(object instanceof Attr) {
+			objectBox = this.view.createObjectBox(object.ownerElement);
+			
+			// get the nodes that contains the attributes
+			var attributeNodes = getElementsByClass(objectBox, "nodeAttr");
+			
+			// return the node that contains the attribute we are looking for
+			var attr = Array.filter(attributeNodes, function(attributeNode) {
+				// the node containing the attribute name
+				return attributeNode.childNodes[1].textContent == object.name;
+			})[0];
+			if(attr) setClass(attr, "selected");
+		} else {
+			objectBox = this.view.createObjectBox(object);
+		}
+		
+		this.box.appendChild(objectBox);
+	}
+});
+
+// ************************************************************************************************
+// Auto Completion
+	
+Firebug.XPathPanel.xPathAutoCompleter = function(evaluator) {
+	this.autoCompleter = new Firebug.AutoCompleter(
+			null,
+			bind(this.getAutoCompleteRange, this),
+			bind(this.getAutoCompleteList, this),
+			true, true);
+	
+	this.evaluator = evaluator;
+}
+
+Firebug.XPathPanel.xPathAutoCompleter.prototype = {
+	
+	reset: function() {
+		this.autoCompleter.reset();
+	},
+	
+	complete: function(context, textbox, cycle, reverse) {
+		this.autoCompleter.complete(context, textbox, cycle, reverse);
+	},
+	
+	getAutoCompleteRange: function(value, offset, context) {
+		
+		var preSelection = value.substring(0, offset);
+		var result;
+		var tokens = [];
+
+		while ((result = selectedToken.exec(preSelection)) != null) {
+			tokens.unshift(result[0]);
+		}
+
+		var start;
+		var end;
+		if(tokens.length == 0) {
+			start = 0;
+			end =  value.length;
+		} else if(nameTestToken.test(tokens[0])) {
+			start = preSelection.lastIndexOf(tokens[0]);
+			end = start + tokens[0].length
+		} else {
+			start = preSelection.lastIndexOf(tokens[0]) + tokens[0].length;
+			var postSelection = value.substring(start);
+			var firstTokenIndex = postSelection.search(selectedToken);
+			end = (firstTokenIndex == -1? value.length : start + firstTokenIndex);
+		}
+		
+		return{start: start, end: end - 1};
+	},
+	
+	getAutoCompleteList: function(preExpr, expr, postExpr, context) {
+		var result;
+		var token;
+		var previousToken = ""
+		var tokens = [];
+		var stack = [];
+		while ((result = xPathToken.exec(preExpr)) != null) {
+			token = result[0];
+			if(token == "[") {
+				stack.unshift({type: "predicate", name: tokens[0] || ""});
+			} else if(token == "(") {
+				if(functionNameToken.test(previousToken))
+					stack.unshift({type: "function", name: tokens[0] || ""});
+				else
+					stack.unshift({type: "bracket", name: tokens[0] || ""});
+			} else if(token == "]" || token == ")") {
+				stack.shift();
+			}
+			tokens.unshift(token);
+			previousToken = token
+		}
+		
+		var returning = [];
+		
+		var inside = (stack.length > 0? stack[0].type: null);
+		
+		if (!tokens.length) {
+			// At the begining
+			returning = extendArrays(["/"], this.getNodeList(expr, inside, tokens, true) || [], this.Functions);
+		} else if(tokens[0] == "|") {
+			// After union operator
+			returning = this.getNodeList(expr, inside, tokens, true) || [];
+		} else if(tokens[0] == "::" || tokens[0] == "@") {
+			// After an Axis
+			returning = this.getNodeList(expr, inside, tokens, false) || [];
+		} else if(include(["/", "//"], tokens[0])) {
+			// After a separator or the root
+			returning = this.getNodeList(expr, inside, tokens, true) || [];
+		} else if(include(["(", ",", "["], tokens[0]) ||
+				// If the token is * or  name operator, we make sure it's actually an operator
+				(tokens[0] != "*" && !include(this.NameOperators, tokens[0]) && include(this.Operators, tokens[0])) ||
+				((tokens[0] == "*" || include(this.NameOperators, tokens[0]))
+					 && tokens[1] != undefined && !include(extendArrays(["@", "::", "(", "["], this.Operators), tokens[1]))
+			) {
+			// After "(", "," "[" or an operator
+			var nodeList = this.getNodeList(expr, inside, tokens, true);
+			if(nodeList)
+				returning =  extendArrays(["/"], nodeList, this.Functions);
+		} else if(expressionToken.test(tokens[0])) {
+			// After an expression
+			returning =  this.getOperators(tokens[0], inside);
+		} else{
+			return [];
+		}
+		if(tokens[0] == "." && returning.length > 0 && !include(returning, ".")) returning.unshift(".");
+		if(tokens[0] == "/" && returning.length > 0 && !include(returning, "/")) returning.unshift("/");
+
+		return returning;
+	},
+	
+	getNodeList: function(expr, inside, tokens, addAxes) {
+		var flattenedExpr = this.flattenExpression(tokens);
+		var returning = [];
+		
+		var result = this.evaluator.evaluateExpression(flattenedExpr + "*");
+		var attribute = false;
+		if(!result) return null;
+		
+		if(endsWith(flattenedExpr, "@") || endsWith(flattenedExpr, "attribute::")) {
+			result.forEach(function(attribute) {
+				add(returning, attribute.name);
+			});
+			attribute = true;
+			this.addNamespacesAndSort(returning);
+			if(returning.length > 0) returning.unshift("*");
+		} else {
+			result.forEach(function(node) {
+				add(returning, getTagName(node));
+			});
+			this.addNamespacesAndSort(returning);
+			if(this.evaluator.hasResult(flattenedExpr + "comment()")) returning.push("comment()");
+			if(this.evaluator.hasResult(flattenedExpr + "node()")) returning.push("node()");
+			if(this.evaluator.hasResult(flattenedExpr + "text()")) returning.push("text()");
+			if(addAxes) {
+				var parentExpression = flattenedExpr.replace(/\/$/, "");
+				parentExpression += (endsWith(parentExpression, "/")?"descendant-or-self::node()":"");
+				parentExpression = parentExpression || "/";
+				result = this.evaluator.evaluateExpression(parentExpression);
+				if(result) {
+					var hasSelf =  result.some(function(node) {return node.nodeType == 1;});
+					var hasAttribute = result.some(function(node) {return node.hasAttributes();});
+					var hasAncestor = result.some(function(node) {return node.parentNode && node.parentNode.nodeType==1;});
+					var hasDescendant = result.some(function(node) {return node.hasChildNodes();});
+					var hasFollowingSibling = result.some(function(node) {return hasNextSibling(node);});
+					var hasFollowing = hasFollowingSibling || result.some(function(node) {return hasFollowingNode(node);});
+					var hasPrecedingSibling = result.some(function(node) {return hasPreviousSibling(node);});
+					var hasPreceding = hasPrecedingSibling || result.some(function(node) {return hasPrecedingNode(node);});
+					returning.push(".");
+					if(hasAttribute) returning.push("@");
+					if(hasAncestor) returning.push("..");
+					if(hasAncestor) returning.push("ancestor::");
+					if(hasSelf || hasAncestor)returning.push("ancestor-or-self::");
+					if(hasDescendant) returning.push("descendant::");
+					if(hasSelf || hasDescendant)returning.push("descendant-or-self::");
+					if(hasFollowing) returning.push("following::");
+					if(hasFollowingSibling) returning.push("following-sibling::");
+					if(hasAncestor) returning.push("parent::");
+					if(hasPreceding) returning.push("preceding::");
+					if(hasPrecedingSibling) returning.push("preceding-sibling::");
+					if(hasDescendant) returning.push("child::");
+					if(hasSelf)returning.push("self::");
+					if(hasAttribute) returning.push("attribute::");
+					
+					if(hasDescendant) returning.unshift("*");
+				}
+			} else {
+				if(returning.length > 0) returning.unshift("*");
+			}
+		}
+		
+		if(returning.indexOf(expr) != -1) {
+			returning.unshift(expr + " ");
+			if(!attribute) returning.unshift(expr + "/", expr+"[");
+			if(inside == "function") returning.unshift(expr + ",", expr + ")");
+			if(inside == "bracket") returning.unshift(expr + ")");
+			if(inside == "predicate") returning.unshift(expr + "]");
+			if(!attribute) returning.unshift(expr+"|");
+		}
+		return returning;
+	},
+	
+	addNamespacesAndSort: function(returning) {
+		var namespaces = [];
+		for each(var node in returning) {
+			if(getNamespace.test(node)) {
+				add(namespaces, getNamespace.exec(node)[1] + "*");
+			}
+		}
+		returning.push.apply(returning, namespaces);
+		returning.sort();
+	},
+	
+	getOperators: function(token, inside) {
+		var returning;
+		if((/\)|"[^"]*"|'[^']*'|\d+(?:\.\d?)?|\.\d+/).test(token))
+			returning = cloneArray(this.NumberAndBooleanOperators);
+		else
+			returning = extendArrays(this.NodeSetOperators, this.NumberAndBooleanOperators);
+		
+		if(inside == "function") returning.unshift(",", ")");
+		if(inside == "bracket") returning.unshift(")");
+		if(inside == "predicate") returning.unshift("]");
+		
+		return returning;
+	},
+	
+	flattenExpression: function(tokens) {
+		var inPredicate = 0;
+		var inFunctionOrBracket = 0;
+		var clone = cloneArray(tokens);
+		var token;
+		var flattenedExpression = [];
+		
+		// Piece of code used twice in the method
+		function inPF() {
+				if(token =="]") inPredicate++;
+				else if(token =="[") inPredicate--;
+				else if(token ==")") inFunctionOrBracket++;
+				else if(token =="(") inFunctionOrBracket--;
+		}
+		
+		while(token = clone.shift()) {
+			// If we are in a function or predicate
+			if(inPredicate == 0 && inFunctionOrBracket == 0 && (
+					include(["(", ",", "["], token) ||
+					// If the token is * or  name operator, we make sure it's actually an operator
+					(token != "*" && !include(this.NameOperators, token) && include(this.NumberAndBooleanOperators, token)) ||
+					((token == "*" || include(this.NameOperators, token))
+						 && clone[0] != undefined && !include(extendArrays(["@", "::", "(", "["], this.Operators), clone[0]))
+				)
+			) 
+			{
+				//if the last token is the root
+				if(include(["/", "//"], flattenedExpression[0]))
+					break;
+				
+				// Find the end of the function or predicate
+				do {
+					inPF();
+					if(inPredicate < 0 || inFunctionOrBracket < 0) break;
+				} while(token = clone.shift());
+				
+				// Remove the function name (if in a function)
+				if(inFunctionOrBracket < 0) {
+					if(functionNameToken.test(clone[0]))
+						token = clone.shift();
+					else {
+						inFunctionOrBracket = 0;
+						inPredicate = 0;
+						continue;
+					}
+				}
+				
+				// Reset inFunction and inPredicate
+				inFunctionOrBracket = 0;
+				inPredicate = 0;
+				
+				flattenedExpression.unshift("/");
+			} else {
+				inPF();
+				if(token =="|") break;
+				flattenedExpression.unshift(token);
+			}
+		}
+		return flattenedExpression.join(" ");
+	},
+
+	NodeSetOperators: [
+		"/",
+		"//",
+		"|",
+		"["
+	],
+	
+	NumberAndBooleanOperators: [
+		"and ",
+		"or ",
+		"< ",
+		"<= ",
+		"> ",
+		">= ",
+		"= ",
+		"+ ",
+		"- ",
+		"* ",
+		"div ",
+		"mod "
+	],
+
+	Operators: [
+		"and",
+		"or",
+		"<",
+		"<=",
+		">",
+		">=",
+		"=",
+		"+",
+		"-",
+		"*",
+		"div",
+		"mod",
+		"/",
+		"//",
+		"|"
+	],
+	
+	NameOperators: [
+		"and",
+		"or",
+		"div",
+		"mod"
+	],
+
+	Functions: [
+		"concat(",
+		"substring(",
+		"substring-after(",
+		"substring-before(",
+		"string(",
+		"local-name(",
+		"name(",
+		"namespace-uri(",
+		"normalize-space(",
+		"translate(",
+		"ceiling(",
+		"count(",
+		"floor(",
+		"last()",
+		"number(",
+		"position()",
+		"round(",
+		"sum(",
+		"boolean(",
+		"contains(",
+		"false()",
+		"lang(",
+		"not(",
+		"starts-with(",
+		"string-length(",
+		"true()",
+	]
+}
+
+// ************************************************************************************************
+// Auto Completion Helpers
+
+function extendArrays(){
+	var newArray = [];
+	for (var i = 0; i < arguments.length; i++) {
+		newArray.push.apply(newArray, arguments[i]);
+	}
+	return newArray;
+}
+
+function include (arrayOrString, value) {
+	try{
+		return arrayOrString.indexOf(value) != -1;
+	} catch(e) {
+		return false;
+	}
+}
+
+function add(array, value) {
+	if(!include(array, value)) {
+		array.push(value);
+	}
+}
+
+function endsWith(string, end) {
+	return string.search(end+"$") != -1;
+}
+
+function hasNextSibling(node) {
+	return !!getNextElement(node.nextSibling)
+}
+
+function hasPreviousSibling(node) {
+	return !!getPreviousElement(node.previousSibling)
+}
+
+function hasFollowingNode(node) {
+	var parent = node;
+	while(parent = parent.parentNode) {
+		if(hasNextSibling(parent))
+			return true;
+	}
+	return false;
+}
+
+function hasPrecedingNode(node) {
+	var parent = node;
+	while(parent = parent.parentNode) {
+		if(hasPreviousSibling(parent))
+			return true;
+	}
+	return false;
+}
+
+// ************************************************************************************************
+// Stepper use to simulate a thread and prevent the UI from freezing
+
+function Stepper(iterator, step, end, timePeriod){
+	this.iterator = iterator
+	this.step = step;
+	this.timePeriod = Math.max(1, timePeriod || defaultTimePeriod);
+	this.end = end;
+	this.stopped = true;
+	this.execute = bind(this.execute, this);
+}
+
+Stepper.prototype = {
+	start: function() {
+		this.timeoutID = setTimeout(this.execute, 0);
+	},
+	
+	execute: function() {
+		try {
+			for(var i = 0, date = new Date(); i < this.timePeriod; i = Date.now() - date) {
+				this.step(this.iterator.next());
+			}
+			this.timeoutID = setTimeout(this.execute, 0);
+		} catch(e) {
+			setTimeout(this.end, 0);
+		}
+	},
+	
+	stop: function() {
+		clearTimeout(this.timeoutID);
+		this.iterator.close();
+	}
+}
+
+// ************************************************************************************************
+// location highlighting module
+
+Firebug.XPathPanel.LocationHighlightModule = extend(Firebug.Module,
+{
+	// add event listener
+	initializeUI: function(detachArgs) {
+		this.addLocationListener(FirebugChrome);
+	},
+	
+	shutdown: function() {
+		this.removeLocationListener(FirebugChrome);
+	},
+	
+	addLocationListener: function(chrome) {
+		chrome.$("fbLocationList").addEventListener("mouseover", this.onLocationMouseOver, false);
+		chrome.$("fbLocationList").addEventListener("mouseout", this.onLocationMouseOut, false);
+	},
+	
+	removeLocationListener: function(chrome) {
+		chrome.$("fbLocationList").removeEventListener("mouseover", this.onLocationMouseOver, false);
+		chrome.$("fbLocationList").removeEventListener("mouseout", this.onLocationMouseOut, false);
+	},
+	
+	onLocationMouseOver: function(event) {
+		var panel = FirebugContext.browser.chrome.getSelectedPanel();
+	
+		if(panel.name == panelName) {
+			var repObject = event.originalTarget.repObject;
+			if(repObject && repObject.frameElement) {
+				Firebug.Inspector.highlightObject(repObject.frameElement, FirebugContext);
+			}
+		}
+	},
+	
+	onLocationMouseOut: function() {
+		Firebug.Inspector.highlightObject(null);
+	}
+})
+
+// ************************************************************************************************
+// result highlighting module
+
+Firebug.XPathPanel.ResultHighlightModule = extend(Firebug.Module,
+{
+	initialize: function() {
+		this.highlighted = false;
+		this.highlightedElement = [];
+	},
+	
+	destroyContext: function(context, persistedState) {
+		persistedState.persistedXPathResultNotHighlighted = !!context.xPathResultNotHighlighted;
+	},
+	
+	loadedContext: function(context) {
+		if(context.persistedState)
+			context.xPathResultNotHighlighted = context.persistedState.persistedXPathResultNotHighlighted 
+	},
+	
+	reattachContext: function(browser, context) {
+		this.highlightButton = browser.chrome.$("FireXPathBarHighlightButton");
+	},
+	
+	showContext: function(browser, context) {
+		this.highlightButton = browser.chrome.$("FireXPathBarHighlightButton");
+		this.refreshHighlightButton(context.getPanel(panelName));
+	},
+	
+	hideUI: function() {
+		this.clear();
+	},
+	
+	showPanel: function(browser, panel) {
+		if(panel.name == panelName) {
+			this.highlightButton.collapsed = false;
+			if(!panel.context.xPathResultNotHighlighted)
+				this.highlight(panel.context);
+		} else {
+			this.highlightButton.collapsed = true;
+			this.clear();
+		}
+	},
+	
+	refreshHighlightButton: function(panel) {
+		if(panel.evaluationResult != null && isArray(panel.evaluationResult) &&
+			panel.evaluationResult.some(function(e) {return e.nodeType == 1 && e.namespaceURI == null})) 
+		{
+			this.highlightButton.setAttribute("checked", !panel.context.xPathResultNotHighlighted);
+			this.highlightButton.setAttribute("disabled", false);
+		} else {
+			this.highlightButton.setAttribute("checked", false);
+			this.highlightButton.setAttribute("disabled", true);
+		}
+	},
+	
+	// call when the result has changed
+	refreshHighlight: function(panel) {
+		this.refreshHighlightButton(panel);
+		if(!panel.context.xPathResultNotHighlighted) {
+			this.clear();
+			this.highlight(panel.context);
+		}
+	},
+	
+	toggleHighlight: function(context) {
+		if(!context.xPathResultNotHighlighted) {
+			this.clear();
+		} else {
+			this.highlight(context);
+		}
+		context.xPathResultNotHighlighted = !context.xPathResultNotHighlighted
+		this.highlightButton.setAttribute("checked", !context.xPathResultNotHighlighted);
+	},
+	
+	highlight: function(context) {
+		var panel = context.getPanel(panelName);
+		var doc = panel.location.document;
+		var resultElement = panel.evaluationResult;
+		
+		var isCSSAttached = doc.getElementById("firexpath-matching-node-style");
+		
+		if(!isCSSAttached) {
+			var head = doc.getElementsByTagName("head")[0]
+			if(head) {
+				if(!context.fireXPathStyleSheet) {
+					var styleSheet = document.createElementNS("http://www.w3.org/1999/xhtml", "style");
+					styleSheet.firebugIgnore = true;
+					styleSheet.setAttribute("type", "text/css");
+					styleSheet.setAttribute("id", "firexpath-matching-node-style");
+					styleSheet.innerHTML = 
+					".firexpath-matching-node {" +
+					"	outline: 2px dashed #00F;" +
+					"}";
+					context.fireXPathStyleSheet = styleSheet;
+				}
+				head.appendChild(context.fireXPathStyleSheet);
+			} else {
+				// if we can't attach the stylesheet there is no need to highlighting the result
+				// for instance in XML documents
+				return;
+			}
+		}
+		
+		var step = bind(function(element) {
+			if(element.nodeType == 1 && isVisible(element)) {
+				setClass(element, "firexpath-matching-node");
+				this.highlightedElement.push(element);
+			}
+		}, this);
+		var end = bind(function() {
+			delete this.stepper;
+		}, this);
+ 
+ 		this.stepper = new Stepper(arrayIterator(resultElement), step, end);
+ 		this.stepper.start();
+	},
+	
+	clear: function(doc) {
+		// clear the stylesheet from the doc before evaluating an XPath expression
+		if(doc) {
+			var styleSheet = doc.getElementById("firexpath-matching-node-style");
+			if(styleSheet) {
+				styleSheet.parentNode.removeChild(styleSheet);
+			}
+		}
+		
+		if(this.stepper) {
+			this.stepper.stop();
+			delete this.stepper;
+		}
+		var element;
+		while(element = this.highlightedElement.pop()) {
+			removeClass(element, "firexpath-matching-node");
+			if (element.className.length === 0) {
+				element.removeAttribute("class");
+			}
+		}
+	}
+})
+
+// ************************************************************************************************
+// Overwrite inspector to make sure it stay on the XPath tab (instead of going to the HTML tab)
+
+overwriteMethodForPanel(
+	Firebug.Inspector, 
+	"startInspecting", 
+	panelName, 
+	function (context) {
+		if (this.inspecting || !context || !context.loaded)
+			return;
+
+		this.inspecting = true;
+		this.inspectingContext = context;
+
+		context.chrome.setGlobalAttribute("cmd_toggleInspecting", "checked", "true");
+		this.attachInspectListeners(context);
+
+		// Remember the previous panel and bar state so we can revert if the user cancels
+		this.previousPanelName = context.panelName;
+		this.previousSidePanelName = context.sidePanelName;
+		this.previouslyCollapsed = $("fbContentBox").collapsed;
+		this.previouslyFocused = context.detached && context.chrome.isFocused();
+
+		var panel;
+		if(this.previouslyCollapsed) {
+			panel = context.chrome.selectPanel("html");
+			this.previousObject = panel.selection;
+		} else {
+			panel = context.getPanel("xpath");
+		}
+
+		if (context.detached)
+			FirebugChrome.focus();
+		else
+			Firebug.showBar(true);
+
+		panel.panelNode.focus();
+		panel.startInspecting();
+
+		if (context.hoverNode)
+			this.inspectNode(context.hoverNode);
+	}
+);
+
+overwriteMethodForPanel(
+	Firebug.Inspector, 
+	"stopInspecting", 
+	panelName, 
+	function(cancelled, waitForClick){
+		if (!this.inspecting) 
+			return;
+		
+		var context = this.inspectingContext;
+		
+		if (this.inspectTimeout) {
+			context.clearTimeout(this.inspectTimeout);
+			delete this.inspectTimeout;
+		}
+		
+		this.detachInspectListeners(context);
+		if (!waitForClick) 
+			this.detachClickInspectListeners(context.window);
+		
+		context.chrome.setGlobalAttribute("cmd_toggleInspecting", "checked", "false");
+		
+		this.inspecting = false;
+		
+		var htmlPanel = context.getPanel("html");
+		var xPathPanel = context.getPanel("xpath");
+		
+		if (this.previouslyFocused) 
+			context.chrome.focus();
+		
+		if (cancelled) {
+			if (this.previouslyCollapsed) 
+				Firebug.showBar(false);
+			
+			if (this.previousPanelName == "html") 
+				context.chrome.select(this.previousObject);
+			else 
+				context.chrome.selectPanel(this.previousPanelName, this.previousSidePanelName);
+		}
+		else {
+			if(this.previouslyCollapsed) {
+				context.chrome.select(htmlPanel.selection);
+				context.chrome.getSelectedPanel().panelNode.focus();
+			}
+		}
+		
+		if(this.previouslyCollapsed)
+			htmlPanel.stopInspecting(htmlPanel.selection, cancelled);
+		else
+			xPathPanel.stopInspecting(cancelled);
+		
+		this.inspectNode(null);
+		
+		delete this.previousObject;
+		delete this.previousPanelName;
+		delete this.previousSidePanelName;
+		delete this.inspectingContext;
+	}
+);
+
+Firebug.registerPanel(Firebug.XPathPanel);
+Firebug.registerModule(Firebug.XPathPanel.LocationHighlightModule, Firebug.XPathPanel.ResultHighlightModule);
+if(Firebug.registerUIListener) Firebug.registerUIListener(Firebug.XPathPanel.ResultHighlightModule);
+}});
\ No newline at end of file
diff --git a/content/bindings.xml b/content/bindings.xml
new file mode 100644
index 0000000..e8f0cca
--- /dev/null
+++ b/content/bindings.xml
@@ -0,0 +1,690 @@
+<?xml version="1.0"?>
+<!DOCTYPE bindings SYSTEM "chrome://firexpath/locale/FireXPath.dtd">
+<!--
+	Copyright (C) 2009  Pierre Tholence, DB4ALL
+	
+	This file is part of FireXPath
+	
+	FireXPath is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+	
+	FireXPath 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 FireXPath.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<bindings xmlns="http://www.mozilla.org/xbl"
+	xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+	
+	<binding id="xPath-textbox" extends="chrome://global/content/bindings/textbox.xml#textbox">
+		<implementation>
+			
+			<field name="_xPathBar">null</field>
+			<property name="xPathBar" readonly="true">
+				<getter><![CDATA[
+					return this._xPathBar ?
+					this._xPathBar : this._xPathBar = document.getBindingParent(this);
+				]]></getter>
+			</property>
+			
+			<method name="setStatus">
+				<parameter name="status"/>
+				<parameter name="info"/>
+				<body><![CDATA[
+					if(status)
+						this.setAttribute("status", status);
+					else
+						this.removeAttribute("status");
+					this.tooltipText = info || "";
+				]]></body>
+			</method>
+			
+			<method name="checkSyntax">
+				<body><![CDATA[
+					if(this.value != "" && this.xPathBar.getXPathExpression(this.value) == null)
+						this.setStatus("error", FBL.$STR_XP("invaliXPathError"));
+					else
+						this.setStatus();
+				]]></body>
+			</method>
+			
+			<method name="setValue">
+				<parameter name="value"/>
+				<body><![CDATA[
+					this.value = value;
+					this.checkSyntax();
+				]]></body>
+			</method>
+		</implementation>
+		<handlers>
+			<handler event="input"><![CDATA[
+				this.checkSyntax();
+				this.xPathBar.autoCompleter.reset();
+			]]></handler>
+			<handler event="keypress"><![CDATA[
+				switch (event.keyCode) {
+					case KeyEvent.DOM_VK_RETURN:
+						this.xPathBar.evaluate();
+						break;
+					case KeyEvent.DOM_VK_UP:
+						this.xPathBar.autoCompleter.complete(FirebugContext, this, true, true);
+						this.checkSyntax();
+						break;
+					case KeyEvent.DOM_VK_TAB:
+						event.preventDefault();
+					case KeyEvent.DOM_VK_DOWN:
+						this.xPathBar.autoCompleter.complete(FirebugContext, this, true, false);
+						this.checkSyntax();
+						break;
+				}
+			]]></handler>
+		</handlers>
+	</binding>
+	
+	<binding id="xPathBar" extends="xul:hbox">
+		<content>
+			<xul:toolbarseparator/>
+			<xul:toolbaritem align="center" flex="6">
+				<xul:label value="&FireXPath.xPath.label;" control="xPathBar-xpath-textbox" accesskey="&FireXPath.xPath.key;"/>
+				<xul:hbox class="xpath-field-container" flex="1">
+					<xul:textbox anonid="xpath-textbox" id="xPathBar-xpath-textbox" class="xpath-textbox" minwidth="100" flex="1"/>
+				</xul:hbox>
+			</xul:toolbaritem>
+			<xul:toolbaritem anonid="xpath-context-toolbar" align="center" flex="1">
+				<xul:label value="&FireXPath.context.label;" control="xPathBar-xpath-context-textbox" accesskey="&FireXPath.context.key;"/>
+				<xul:hbox class="xpath-field-container" flex="1">
+					<xul:textbox anonid="xpath-context-textbox" id="xPathBar-xpath-context-textbox" class="xpath-textbox" flex="1"/>
+				</xul:hbox>
+				<xul:textbox anonid="xpath-context-node-number-textbox"
+					type="number"
+					size="1"
+					min="1"
+					onchange="document.getBindingParent(this).evaluate();"
+					collapsed="true"
+					increment="1"/>
+			</xul:toolbaritem>
+			<xul:toolbarbutton label="&FireXPath.eval.button;" oncommand="document.getBindingParent(this).evaluate();">
+			</xul:toolbarbutton>
+		</content>
+		<implementation>
+			
+			<!--******************************************************************************************************
+				fields and properties
+			-->
+			
+			<field name="NSResolver">null</field>
+			<field name="xPathContextNodes">null</field>
+			<field name="lastXPath">null</field>
+			<field name="lastContext">null</field>
+			<field name="lastXPathContext">null</field>
+			<field name="_evaluator">null</field>
+			
+			<property name="autoCompleter" readonly="true">
+				<getter><![CDATA[
+					return this._autoCompleter ?
+					this._autoCompleter : this._autoCompleter = new Firebug.XPathPanel.xPathAutoCompleter(this);
+				]]></getter>
+			</property>
+			
+			<property name="evaluator" readonly="true">
+				<getter><![CDATA[
+					return this._evaluator ?
+					this._evaluator : this._evaluator = new XPathEvaluator();
+				]]></getter>
+			</property>
+			
+			<property name="xPath">
+				<getter><![CDATA[
+					return this.getElement("xpath-textbox").value;
+				]]></getter>
+				<setter><![CDATA[
+					this.getElement("xpath-textbox").setValue(val);
+					return val;
+				]]></setter>
+			</property>
+			
+			<property name="xPathContext">
+				<getter><![CDATA[
+					var textbox = this.getElement("xpath-context-textbox");
+					if(textbox.value == "")
+						textbox.value = "/";
+					return textbox.value;
+				]]></getter>
+				<setter><![CDATA[
+					this.getElement("xpath-context-textbox").setValue(val);
+					return val;
+				]]></setter>
+			</property>
+			
+			<property name="xPathContextNodeNumber" readonly="true">
+				<getter><![CDATA[
+					return this.getElement("xpath-context-node-number-textbox");
+				]]></getter>
+			</property>
+			
+			<property name="xPathContextToolbar" readonly="true">
+				<getter><![CDATA[
+					return this.getElement("xpath-context-toolbar");
+				]]></getter>
+			</property>
+			
+			<property name="highlightButton" readonly="true">
+				<getter><![CDATA[
+					return this.getElement("highlight-button");
+				]]></getter>
+			</property>
+			
+			<property name="xPathPanel" readonly="true">
+				<getter><![CDATA[	
+					return FirebugContext.getPanel(Firebug.XPathPanel.prototype.name);
+				]]></getter>
+			</property>
+			
+			<!--******************************************************************************************************
+				Constructor
+			-->
+			
+			<constructor><![CDATA[
+				this.xPathContextToolbar.collapsed = !Firebug.getPref(Firebug.prefDomain, "xpath.showXPathContext");
+			]]></constructor>
+			
+			<!--******************************************************************************************************
+				State management method
+			-->
+			
+			<method name="init">
+				<parameter name="context"/>
+				<body><![CDATA[
+					this.NSResolver = this.createNSResolver(context.window.document);
+					this.xPath = "";
+					this.xPathContext = "/";
+					this.xPathContextNodeNumber.collapsed = true;
+					this.xPathContextNodes = null;
+					this.lastXPath = "";
+					this.lastContext = null;
+					context.xPathBarInit = true;
+				]]></body>
+			</method>
+
+			<method name="show">
+				<parameter name="context"/>
+				<parameter name="show"/>
+				<body><![CDATA[
+					this.collapsed = !show;
+					if(show) {
+						this.currentContext = context; 
+						if(!context.xPathBarInit)
+							this.init(context);
+						else
+							this.restore(context);
+						var that = this
+						setTimeout(function() {
+							that.getElement("xpath-textbox").focus();
+						},10)
+					} else {
+						if(context == this.currentContext)
+							this.persiste(context);
+					}
+				]]></body>
+			</method>
+			
+			<method name="persiste">
+				<parameter name="state"/>
+				<body><![CDATA[
+					if(!state.xPathBarState) state.xPathBarState = {};
+					this.copyState(this, state.xPathBarState);
+				]]></body>
+			</method>
+			
+			<method name="restore">
+				<parameter name="state"/>
+				<body><![CDATA[
+					this.copyState(state.xPathBarState, this)
+				]]></body>
+			</method>
+			
+			<method name="copyState">
+				<parameter name="from"/>
+				<parameter name="to"/>
+				<body><![CDATA[
+					to.xPath = from.xPath;
+					to.xPathContext = from.xPathContext;
+					if(!to.xPathContextNodeNumber) to.xPathContextNodeNumber = {};
+					to.xPathContextNodeNumber.value = from.xPathContextNodeNumber.value;
+					to.xPathContextNodeNumber.max = from.xPathContextNodeNumber.max;
+					to.xPathContextNodeNumber.collapsed = from.xPathContextNodeNumber.collapsed;
+					to.xPathContextNodes = from.xPathContextNodes;
+					to.NSResolver = from.NSResolver;
+					to.lastXPath = from.lastXPath;
+					to.lastContext = from.lastContext;
+				]]></body>
+			</method>
+			
+			<!--******************************************************************************************************
+				XPath Evaluation methods
+			-->
+			
+			<method name="evaluate">
+				<parameter name="reevaluate"/>
+				<body><![CDATA[
+					var xPath = this.xPath;
+					if(reevaluate)
+						xPath = this.lastXPath;
+					
+					var context = this.getContextNode(reevaluate);
+					if(xPath != "") {
+						
+						if(!reevaluate && this.lastXPath == xPath && this.lastContext == context)
+							return;
+							
+						var contextTextbox = this.getElement("xpath-context-textbox");
+						if(context) {
+							contextTextbox.setStatus();
+							if(FBL.trimLeft(this.xPath).indexOf("/") == 0 && FBL.trimLeft(this.xPathContext) != "/") {
+								context = null;
+								contextTextbox.setStatus("warning", FBL.$STR_XP("unusedParentNode"));
+							}
+						}
+						
+						var result = this._evaluateExpression(this.xPath, context);
+						this.lastXPath = this.xPath;
+						this.lastContext = context;
+						this.xPathPanel.setResult(context, result);
+					} else {
+						this.lastXPath = "";
+						this.xPathPanel.setResult(context, null);
+					}
+				]]></body>
+			</method>
+			
+			<method name="getXPathExpression">
+				<parameter name="xPath"/>
+				<body><![CDATA[
+					try {
+						return this.evaluator.createExpression(xPath, this.NSResolver);
+					} catch (e) {
+						return null;
+					}
+				]]></body>
+			</method>
+			
+			<method name="_evaluateExpression">
+				<parameter name="xPath"/>
+				<parameter name="contextNode"/>
+				<body><![CDATA[
+					Firebug.XPathPanel.ResultHighlightModule.clear(this.xPathPanel.location.document);
+					var xPathExpression = this.getXPathExpression(xPath);
+					if(!xPathExpression) return new Error("invaliXPathError");
+					
+					var result;
+					try{
+						result = xPathExpression.evaluate(contextNode || this.xPathPanel.location.document, XPathResult.ANY_TYPE, null);
+					} catch(e) {
+						return new Error("invaliXPathError");
+					}
+					return this.processResult(result);
+				]]></body>
+			</method>
+			
+			<method name="createNSResolver">
+				<parameter name="doc"/>
+				<body><![CDATA[
+					var prefixToNS = this.getMappingPrefixNS(doc);
+					return function(prefix) {
+						return prefixToNS[prefix] || null;
+					}
+				]]></body>
+			</method>
+			
+			<method name="getMappingPrefixNS">
+				<parameter name="doc"/>
+				<body><![CDATA[
+					var result = doc.evaluate("//*[namespace-uri() != '']", doc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
+					var nsToPrefix = {};
+					var prefixToNS = {};
+					for ( var i=0, L=result.snapshotLength ; i < L; i++ ) {
+						var node = result.snapshotItem(i);
+						var ns = node.namespaceURI;
+						if(ns) {
+							var prefix = node.lookupPrefix(ns);
+							if(!prefix) {
+								if(!(ns in nsToPrefix)) {
+									nsToPrefix[ns] = FBL.getPrefixFromNS(ns);
+								}
+								prefix = nsToPrefix[ns];
+							}
+							if(!(prefix in prefixToNS))
+								prefixToNS[prefix] = ns;
+						}
+					}
+					return prefixToNS;
+				]]></body>
+			</method>
+			
+			<method name="getContextNode" readonly="true">
+				<parameter name="reevaluate"/>
+				<body><![CDATA[
+					if(this.xPathContextToolbar.collapsed)
+						return null;
+					if(!reevaluate && this.xPathContextNodes && this.lastXPathContext == this.xPathContext)
+						return this.xPathContextNodes[this.xPathContextNodeNumber.value - 1];
+					else {
+						var nodes = this._evaluateExpression(this.xPathContext);
+						
+						this.lastXPathContext = this.xPathContext;
+						
+						if(FBL.isArray(nodes) && nodes.length > 0) {
+							if(!reevaluate) {
+								this.xPathContextNodeNumber.collapsed = (nodes.length == 1);
+								this.xPathContextNodeNumber.max = nodes.length;
+								this.xPathContextNodeNumber.value = 1;
+								this.xPathContextNodes = nodes;
+								this.getElement("xpath-context-textbox").setStatus();
+								return nodes[0];
+							} else {
+								this.xPathContextNodes = nodes;
+								return nodes[this.xPathContextNodeNumber.value - 1];
+							}
+						} else {
+							this.xPathContextNodeNumber.collapsed = true;
+							this.xPathContextNodeNumber.value = 1;
+							this.xPathContextNodes = [null];
+							if(!(nodes instanceof Error))
+								this.getElement("xpath-context-textbox").setStatus("warning", FBL.$STR_XP("noParentNodeSelected"));
+							return null;
+						}
+					}
+				]]></body>
+			</method>
+			
+			<!--******************************************************************************************************
+				public methods, used by the panel
+			-->
+			
+			<method name="setNode">
+				<parameter name="node"/>
+				<parameter name="noEval"/>
+				<body><![CDATA[
+					this.xPath = FBL.getXPathFromNode(node, this.getContextNode());
+					if(!noEval)
+						this.evaluate();
+				]]></body>
+			</method>
+			
+			<method name="setContextNode">
+				<parameter name="node"/>
+				<body><![CDATA[
+					this.xPathContext = FBL.getXPathFromNode(node);
+					this.evaluate();
+				]]></body>
+			</method>
+			
+			<method name="updateLocation">
+				<parameter name="location"/>
+				<body><![CDATA[
+					this.NSResolver = this.createNSResolver(location.document);
+					this.reset();
+				]]></body>
+			</method>
+			
+			<method name="reset">
+				<body><![CDATA[
+					delete this.lastXPath;
+					delete this.lastContext;
+					delete this.lastXPathContext;
+				]]></body>
+			</method>
+			
+			<method name="showXPathContext">
+				<parameter name="show"/>
+				<body><![CDATA[
+					this.xPathContextToolbar.collapsed = !show;
+					this.reset();
+				]]></body>
+			</method>
+			
+			<!--******************************************************************************************************
+				public methods, used by the autoCompleter
+			-->
+			
+			<method name="hasResult">
+				<parameter name="xPath"/>
+				<body><![CDATA[
+					var xPathExpression = this.getXPathExpression(xPath);
+					if(!xPathExpression) return false;
+					
+					var result;
+					try{
+						result = xPathExpression.evaluate(this.getContextNode() || this.xPathPanel.location.document, XPathResult.ANY_UNORDERED_NODE_TYPE, null);
+					} catch(e) {
+						return false;
+					}
+					return result.singleNodeValue != null;
+				]]></body>
+			</method>
+			
+			<method name="evaluateExpression">
+				<parameter name="xPath"/>
+				<body><![CDATA[
+					var xPathExpression = this.getXPathExpression(xPath);
+					if(!xPathExpression) return null;
+					
+					var result;
+					try{
+						result = xPathExpression.evaluate(this.getContextNode() || this.xPathPanel.location.document, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
+					} catch(e) {
+						return null;
+					}
+					return this.processResult(result);
+				]]></body>
+			</method>
+			
+			<!--******************************************************************************************************
+				Helper Methods
+			-->
+				
+			<method name="getElement">
+				<parameter name="aAnonymousID"/>
+				<body><![CDATA[
+					return document.getAnonymousElementByAttribute(this, "anonid", aAnonymousID);
+				]]></body>
+			</method>
+			
+			<method name="processResult">
+				<parameter name="evaluationResult"/>
+				<body><![CDATA[
+				switch(evaluationResult.resultType) {
+					case XPathResult.NUMBER_TYPE:
+						return evaluationResult.numberValue;
+					case XPathResult.STRING_TYPE:
+						return evaluationResult.stringValue;
+					case XPathResult.BOOLEAN_TYPE:
+						return evaluationResult.booleanValue;
+					default:
+						var result = [];
+						var node;
+						while (node = evaluationResult.iterateNext()) {
+							//make sure it is not a node created by firebug
+							if(node.firebugIgnore ||
+								(node.ownerElement && node.ownerElement.firebugIgnore) ||
+								(node.parentNode && node.parentNode.firebugIgnore) ||
+								node.id == "_firebugConsole")
+									continue; 
+							result.push(node);
+						}
+						return result;
+				}
+				]]></body>
+			</method>
+		</implementation>
+	</binding>
+	
+	<binding id="xPathStatusBar" extends="xul:hbox">
+		<content>
+			<xul:statusbarpanel flex="1" align="center" pack="left">
+				<xul:image anonid="xpath-result-icon" class="xpath-result-icon"/>
+				<xul:label  anonid="xpath-result-info" value=""/>
+			</xul:statusbarpanel>
+			<xul:statusbarpanel anonid="xpath-result-progressmeter-container" collapsed="true">
+				<xul:image src="chrome://firebug/skin/errorIcon.png" 
+					onmousedown="document.getBindingParent(this).cancelLoading(FirebugContext)" 
+					class="cancel-xpath-result-loading-button"/>
+				<xul:progressmeter anonid="xpath-result-progressmeter"/>
+			</xul:statusbarpanel>
+		</content>
+		<implementation>
+			
+			<!--******************************************************************************************************
+				fields and properties
+			-->
+			
+			<property name="progressMeter" readonly="true">
+				<getter><![CDATA[
+					return this.getElement("xpath-result-progressmeter");
+				]]></getter>
+			</property>
+			
+			<property name="progressMeterContainer" readonly="true">
+				<getter><![CDATA[
+					return this.getElement("xpath-result-progressmeter-container");
+				]]></getter>
+			</property>
+			
+			<property name="resultInfo">
+				<getter><![CDATA[
+					return this.getElement("xpath-result-info").value;
+				]]></getter>
+				<setter><![CDATA[
+					this.getElement("xpath-result-info").value = val;
+					return val;
+				]]></setter>
+			</property>
+			
+			<property name="resultIcon">
+				<getter><![CDATA[
+					return this.getElement("xpath-result-icon").getAttribute("status");
+				]]></getter>
+				<setter><![CDATA[
+					this.getElement("xpath-result-icon").setAttribute("status", val);
+					return val;
+				]]></setter>
+			</property>
+			
+			<!--******************************************************************************************************
+				ProgressMeter management
+			-->
+			
+			<method name="startLoading">
+				<parameter name="context"/>
+				<parameter name="stepNumber"/>
+				<body><![CDATA[
+					context.xPathStatusBar.loading = true;
+					context.xPathStatusBar.stepNumber = stepNumber;
+					context.xPathStatusBar.currentStep = 0;
+					this.progressMeter.value = 0;
+					this.progressMeterContainer.collapsed = false;
+				]]></body>
+			</method>
+			
+			<method name="increaseLoading">
+				<parameter name="context"/>
+				<body><![CDATA[
+					context.xPathStatusBar.currentStep += 1;
+					if(context.xPathStatusBar.shown)
+						this.progressMeter.value = context.xPathStatusBar.currentStep / context.xPathStatusBar.stepNumber * 100;
+				]]></body>
+			</method>
+			
+			<method name="stopLoading">
+				<parameter name="context"/>
+				<body><![CDATA[
+					delete context.xPathStatusBar.loading;
+					this.progressMeterContainer.collapsed = true;
+				]]></body>
+			</method>
+			
+			<method name="cancelLoading">
+				<parameter name="context"/>
+				<body><![CDATA[
+					var panel = context.getPanel(Firebug.XPathPanel.prototype.name);
+					panel.stopLoading();
+					panel.xPathBar.reset();
+					this.resultInfo = this.resultInfo + " (" + FBL.$STR_XP("nodeSelectedMessage", context.xPathStatusBar.currentStep) + ")";
+					context.xPathStatusBar.resultInfo = this.resultInfo;
+				]]></body>
+			</method>
+			
+			
+			
+			<!--******************************************************************************************************
+				Result info management
+			-->
+			
+			<method name="setResultInfo">
+				<parameter name="context"/>
+				<parameter name="status"/>
+				<parameter name="info"/>
+				<body><![CDATA[
+					context.xPathStatusBar.resultInfo = info;
+					this.resultInfo = info;
+					context.xPathStatusBar.resultIcon = status;
+					this.resultIcon = status;
+				]]></body>
+			</method>
+			
+			<method name="clearResultInfo">
+				<parameter name="context"/>
+				<body><![CDATA[
+					delete context.xPathStatusBar.resultInfo;
+					this.resultInfo = "";
+					delete context.xPathStatusBar.resultIcon;
+					this.resultIcon = "";
+				]]></body>
+			</method>
+			
+			<!--******************************************************************************************************
+				other public methods
+			-->
+
+			<method name="show">
+				<parameter name="context"/>
+				<parameter name="show"/>
+				<body><![CDATA[
+					if(!context.xPathStatusBar)
+						context.xPathStatusBar = {};
+					if(show) {
+						this.resultInfo = context.xPathStatusBar.resultInfo || "";
+						this.resultIcon = context.xPathStatusBar.resultIcon || "";
+						this.progressMeterContainer.collapsed = !context.xPathStatusBar.loading;
+					}
+					context.xPathStatusBar.shown = show;
+					this.collapsed = !show;
+				]]></body>
+			</method>
+			
+			<method name="reset">
+				<parameter name="context"/>
+				<body><![CDATA[
+					this.clearResultInfo(context);
+				]]></body>
+			</method>
+			
+			<!--******************************************************************************************************
+				Helper Methods
+			-->
+				
+			<method name="getElement">
+				<parameter name="aAnonymousID"/>
+				<body><![CDATA[
+					return document.getAnonymousElementByAttribute(this, "anonid", aAnonymousID);
+				]]></body>
+			</method>
+
+		</implementation>
+	</binding>
+</bindings>
\ No newline at end of file
diff --git a/content/firebugOverlay.xul b/content/firebugOverlay.xul
new file mode 100644
index 0000000..89cdce9
--- /dev/null
+++ b/content/firebugOverlay.xul
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE overlay SYSTEM "chrome://firexpath/locale/FireXPath.dtd">
+<?xml-stylesheet href="chrome://firexpath/skin/FireXPath.css" type="text/css"?>
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+	
+	<script src="chrome://firexpath/content/XPathPanel.js" type="application/javascript"/>
+	
+	<stringbundleset id="stringbundleset">
+		<stringbundle id="FireXpath_strings" src="chrome://firexpath/locale/FireXPath.properties"/>
+	</stringbundleset>
+	
+	<popup id="contentAreaContextMenu">
+		<menuitem id="menu_fxpShow" label="&FireXPath.context.show.label;"
+			insertafter="context-viewpartialsource-selection"
+			oncommand="Firebug.toggleBar(true); FirebugChrome.selectPanel('xpath').updateSelection(document.popupNode)"
+			accesskey="X"/>
+	</popup>
+
+	<hbox id="fbToolbarInner">
+		<toolbarbutton id="FireXPathBarHighlightButton" collapsed="true" label="&FireXPath.highlight.button;" class="toolbar-text-button"
+			oncommand="Firebug.XPathPanel.ResultHighlightModule.toggleHighlight(FirebugContext);"
+			checked="false" disabled="true" insertafter="fbLocationList"/>
+		<xpathbar id="FireXPathBar" flex="1"  collapsed="true" insertafter="fbLocationList"/>
+	</hbox>
+	
+	<vbox id="fbContentBox">
+		<xpathstatusbar id="FireXPathStatusBar" insertafter="fbCommandBox" collapsed="true"/>
+	</vbox>
+
+</overlay>
\ No newline at end of file
diff --git a/defaults/preferences/FireXPathPref.js b/defaults/preferences/FireXPathPref.js
new file mode 100644
index 0000000..4d1ffb7
--- /dev/null
+++ b/defaults/preferences/FireXPathPref.js
@@ -0,0 +1,3 @@
+pref("extensions.firebug.xpath.showXPathContext", false);
+pref("extensions.firebug.xpath.generateAbsoluteXPath", false);
+pref("extensions.firebug.xpath.showDOM", true);
\ No newline at end of file
diff --git a/install.rdf b/install.rdf
new file mode 100644
index 0000000..fa776eb
--- /dev/null
+++ b/install.rdf
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>FireXPath at pierre.tholence.com</em:id>
+    <em:version>0.9.1</em:version>
+    <em:type>2</em:type>
+    
+    <!-- Firefox -->
+    <em:targetApplication>
+      <Description>
+        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+        <em:minVersion>3.0</em:minVersion>
+        <em:maxVersion>3.5.*</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+    
+    <em:name>FireXPath</em:name>
+    <em:description>FireXPath is a Firebug extension that adds a development tool to edit, inspect and generate XPath expressions. </em:description>
+    <em:creator>Pierre Tholence</em:creator>
+    <em:iconURL>chrome://firexpath/content/FireXPath.png</em:iconURL>
+  </Description>
+</RDF>
diff --git a/license.txt b/license.txt
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/license.txt
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/locale/en-US/FireXPath.dtd b/locale/en-US/FireXPath.dtd
new file mode 100644
index 0000000..5be5752
--- /dev/null
+++ b/locale/en-US/FireXPath.dtd
@@ -0,0 +1,7 @@
+<!ENTITY FireXPath.context.show.label "Inspect XPath">
+<!ENTITY FireXPath.xPath.label "XPath: ">
+<!ENTITY FireXPath.xPath.key "x">
+<!ENTITY FireXPath.context.label "Parent: ">
+<!ENTITY FireXPath.context.key "t">
+<!ENTITY FireXPath.highlight.button "Highlight">
+<!ENTITY FireXPath.eval.button "Eval">
\ No newline at end of file
diff --git a/locale/en-US/FireXPath.properties b/locale/en-US/FireXPath.properties
new file mode 100644
index 0000000..de8de11
--- /dev/null
+++ b/locale/en-US/FireXPath.properties
@@ -0,0 +1,27 @@
+#result message
+invaliXPathError=Invalid XPath
+noResultError=No matching nodes
+oneResultMessage=1 matching node
+manyResultMessage=%S matching nodes
+oneWhiteSpaceMessage=1 whitespace node
+manyWhiteSpaceMessage=%S whitespace nodes
+nodeSelectedMessage=only %S nodes selected
+stringResultMessage=1 String
+numberResultMessage=1 Number
+booleanResultMessage=1 Boolean
+
+#option menu
+showXPathContextMenu=Show Parent toolbar
+generateAbsoluteXPathMenu=Generate absolute XPath
+showDOMMenu=Show Entire DOM
+
+#context menu
+topWindow=Top Window
+copyXPath=Copy XPath
+copyXPathFromContext=Copy XPath Starting at the Parent
+setXPath=Set as XPath
+setXPathContext=Set as Parent
+
+#input tooltip
+noParentNodeSelected=The expression doesn't match any node
+unusedParentNode=The parent node is not used because the XPath refer to the root (start with "/")
\ No newline at end of file
diff --git a/skin/classic/FireXPath.css b/skin/classic/FireXPath.css
new file mode 100644
index 0000000..f6c190a
--- /dev/null
+++ b/skin/classic/FireXPath.css
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009  Pierre Tholence, DB4ALL
+ *
+ * This file is part of FireXPath
+ *
+ * FireXPath is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FireXPath 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 FireXPath.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+xpathbar {
+	-moz-binding: url("chrome://firexpath/content/bindings.xml#xPathBar");
+}
+
+xpathstatusbar {
+	-moz-binding: url("chrome://firexpath/content/bindings.xml#xPathStatusBar");
+	-moz-appearance: statusbar;
+	min-height:24px;
+}
+
+/**** xPathBar *****/
+.xpath-textbox {
+	-moz-binding: url("chrome://firexpath/content/bindings.xml#xPath-textbox");
+	-moz-appearance: none;
+	border: none;
+	margin: 0;
+}
+
+.xpath-textbox[status = "error"] {
+	background-color: #FF6666;
+	color: #FFFFFF;
+}
+
+.xpath-textbox[status = "warning"] {
+	background-color: yellow;
+}
+
+.xpath-field-container {
+	-moz-appearance: textfield;
+}
+
+/**** xPathStatusBar *****/
+.xpath-result-icon[status = "error"] {
+	list-style-image: url("chrome://firebug/skin/errorIcon.png");
+}
+
+.xpath-result-icon[status = "warning"] {
+	list-style-image: url("chrome://firebug/skin/warningIcon.png");
+}
+
+.xpath-result-icon[status = "ok"] {
+	list-style-image: url("chrome://firebug/skin/okIcon-sm.png");
+}
+
+.cancel-xpath-result-loading-button {
+	height:20px;
+	width:20px;
+	padding:2px;
+	cursor:pointer;
+	border:1px solid transparent;
+	-moz-border-radius : 3px;
+}
+
+.cancel-loading-button:hover {
+	border-color: Gray;
+}
diff --git a/skin/classic/xPathPanel.css b/skin/classic/xPathPanel.css
new file mode 100644
index 0000000..810c02b
--- /dev/null
+++ b/skin/classic/xPathPanel.css
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2009  Pierre Tholence, DB4ALL
+ *
+ * This file is part of FireXPath
+ *
+ * FireXPath is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FireXPath 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 FireXPath.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr.selected,
+.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeText.selected {
+    background-color: blue !important;
+}
+
+.nodeAttr.selected,
+.nodeText.selected,
+.nodeBox.selected > .nodeComment {
+	border-color: Highlight;
+	background-color: Highlight;
+	color: HighlightText !important;
+}
+
+.nodeAttr.selected > .nodeValue {
+	color: inherit !important;
+}
+
+.io-box-container {
+	overflow: auto;
+	width: 100%;
+	height: 100%;
+	background-color: #FFFFFF;
+	color: #000000;
+}
\ No newline at end of file

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/firexpath.git



More information about the Pkg-mozext-commits mailing list