Major update of BidiChecker; consider this version 2.0.

Main changes:
1. New checks added for undeclared opposite-directionality attributes.
2. New GUI with table-based list of errors.
3. New, enhanced bookmarklets.
3. New class-based API with mechanism for selecting a revision of the checks.
4. Expanded, restructured user's guide.
5. New internal GUI architecture.

as well as various minor enhancements and fixes.

Revision created by MOE tool push_codebase.
MOE_MIGRATION=


git-svn-id: http://bidichecker.googlecode.com/svn/trunk@21 b0874413-a7f4-6be4-17d0-addd11b1e57e
diff --git a/README b/README
index 3fd7cdb..e825d0b 100644
--- a/README
+++ b/README
@@ -6,7 +6,7 @@
 in the docs/ subdirectory of this package.
 
 The subdirectories in this package:
-docs/        The user's guide and the API documentation (in docs/jsdoc/).
+docs/        The user's guide and the API documentation.
 lib/         Precompiled JavaScript for easy use in web page tests.
 samples/     A sample application which demonstrates the use of BidiChecker.
 src/         The JavaScript source code and unit tests, if you want to modify
diff --git a/docs/bidichecker_screenshot.png b/docs/bidichecker_screenshot.png
deleted file mode 100644
index 7039ecc..0000000
--- a/docs/bidichecker_screenshot.png
+++ /dev/null
Binary files differ
diff --git a/docs/jsdoc/_01.html b/docs/jsdoc/_01.html
index fe91210..4cd1247 100644
--- a/docs/jsdoc/_01.html
+++ b/docs/jsdoc/_01.html
@@ -18,7 +18,7 @@
 					Overview
 				</div>
 				<div>	
-					<div class="desc">Testing utilities to check a web page for BiDi-related errors.
+					<div class="desc">Class which checks a web page for bidi-related errors.
 This file has the top-level entry points for use as a Javascript API, along
 with JSON-based interface functions meant to be called from an external
 testing framework like WebDriver.</div>
@@ -34,6 +34,145 @@
 			<div class="sectionHead">Constructors</div>
 			
 			
+			<div class="section constructor">
+				<div class="itemTitle">
+					<a name="bidichecker.Revision"></a>
+					
+					
+					bidichecker.Revision(<span class="signature">revision</span>)
+					
+				</div>
+				
+				
+					<div class="desc">A class representing a revision of the BidiChecker checks. Higher revisions
+indicate later releases, which check for more error situations.</div>
+				
+				
+				
+				
+				
+				<div class="detailHead">parameters</div>
+				<table class="params">
+				
+					<tr>
+						<td class="type">
+							number
+						</td>
+						<td>
+							revision
+						</td>
+						<td>
+							The revision number.
+						</td> 
+					</tr>
+				
+				</table>
+				
+				
+				
+				
+				
+				<div class="detailHead">properties</div>
+				
+					<ul class="details">
+						<li><span class="type">number</span> <a href="#bidichecker.Revision.revision">revision</a></li>
+					</ul>
+				
+				
+				
+				
+				
+				
+			</div>
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			<div class="section constructor">
+				<div class="itemTitle">
+					<a name="bidichecker.BidiChecker"></a>
+					
+					
+					bidichecker.BidiChecker(<span class="signature">revision</span>)
+					
+				</div>
+				
+				
+					<div class="desc">Class which checks a web page for bidi-related errors. The preferred way to
+invoke BidiChecker is by constructing an instance of this class. The previous
+API, based on static methods, is no longer recommended and will be
+deprecated.</div>
+				
+				
+				
+				
+				
+				<div class="detailHead">parameters</div>
+				<table class="params">
+				
+					<tr>
+						<td class="type">
+							!bidichecker.Revision
+						</td>
+						<td>
+							revision
+						</td>
+						<td>
+							Revision of BidiChecker checks to
+    run.
+						</td> 
+					</tr>
+				
+				</table>
+				
+				
+				
+				<div class="detailHead">methods</div>
+				
+					<ul class="details">
+						<li><a href="#bidichecker.BidiChecker.checkPage">checkPage</a>(shouldBeRtl, opt_element, opt_filters)</li>
+					</ul>
+				
+					<ul class="details">
+						<li><a href="#bidichecker.BidiChecker.checkPageToJson">checkPageToJson</a>(shouldBeRtl, element, filtersJson)</li>
+					</ul>
+				
+					<ul class="details">
+						<li><a href="#bidichecker.BidiChecker.setGuiAppUrl">setGuiAppUrl</a>(guiAppUrl)</li>
+					</ul>
+				
+					<ul class="details">
+						<li><a href="#bidichecker.BidiChecker.runGui">runGui</a>(opt_noPopup)</li>
+					</ul>
+				
+				
+				
+				
+				
+				
+				
+				
+			</div>
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
 			
 			
 			
@@ -45,20 +184,33 @@
 			<div class="sectionHead">Functions</div>
 			
 			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
 			<div class="section function">
 				<div class="itemTitle">
-					<a name="bidichecker.checkPage"></a>
+					<a name="bidichecker.BidiChecker.checkPage"></a>
 					
+						<i><a href="#bidichecker.BidiChecker" class="type">bidichecker.BidiChecker.</a></i>checkPage(<span class="signature">shouldBeRtl, opt_element, opt_filters</span>)
 					
-					bidichecker.checkPage(<span class="signature">shouldBeRtl, opt_element, opt_filters</span>)
 					
 				</div>
 				
 				
 					<div class="desc">Checks the contents of the current web page, including all nested frames, for
-BiDi-related errors. If <code>opt_element</code> is specified, checks only within
-the given element of the DOM (including any nested frames). This is the main
-entry point for the Javascript API.</div>
+bidi-related errors. If <code>opt_element</code> is specified, checks only within
+the given element of the DOM (including any nested frames).</div>
 				
 				
 				
@@ -131,10 +283,10 @@
 			
 			<div class="section function">
 				<div class="itemTitle">
-					<a name="bidichecker.checkPageToJson"></a>
+					<a name="bidichecker.BidiChecker.checkPageToJson"></a>
 					
+						<i><a href="#bidichecker.BidiChecker" class="type">bidichecker.BidiChecker.</a></i>checkPageToJson(<span class="signature">shouldBeRtl, element, filtersJson</span>)
 					
-					bidichecker.checkPageToJson(<span class="signature">shouldBeRtl, opt_element, opt_filtersJson</span>)
 					
 				</div>
 				
@@ -163,26 +315,27 @@
 				
 					<tr>
 						<td class="type">
-							Element=
+							Element
 						</td>
 						<td>
-							opt_element
+							element
 						</td>
 						<td>
-							The root element of the DOM subtree to be
-    checked; if null, checks the entire current web page.
+							The root element of the DOM subtree to be checked;
+    if null, checks the entire current web page.
 						</td> 
 					</tr>
 				
 					<tr>
 						<td class="type">
-							string=
+							string
 						</td>
 						<td>
-							opt_filtersJson
+							filtersJson
 						</td>
 						<td>
-							Error suppression filters in a JSON string.
+							Error suppression filters in a JSON string,
+    representing a (possibly-empty) array of filter objects.
 						</td> 
 					</tr>
 				
@@ -214,15 +367,15 @@
 			
 			<div class="section function">
 				<div class="itemTitle">
-					<a name="bidichecker.runGui"></a>
+					<a name="bidichecker.BidiChecker.setGuiAppUrl"></a>
 					
+						<i><a href="#bidichecker.BidiChecker" class="type">bidichecker.BidiChecker.</a></i>setGuiAppUrl(<span class="signature">guiAppUrl</span>)
 					
-					bidichecker.runGui(<span class="signature">errors</span>)
 					
 				</div>
 				
 				
-					<div class="desc">Runs the interactive visual error browsing mode.</div>
+					<div class="desc">Sets the location of the GUI files.</div>
 				
 				
 				
@@ -233,14 +386,13 @@
 				
 					<tr>
 						<td class="type">
-							Array.<!bidichecker.Error>
+							string
 						</td>
 						<td>
-							errors
+							guiAppUrl
 						</td>
 						<td>
-							An array of errors to be
-    displayed.
+							Location of the GUI files.
 						</td> 
 					</tr>
 				
@@ -256,15 +408,23 @@
 			
 			<div class="section function">
 				<div class="itemTitle">
-					<a name="bidichecker.runGuiFromJson"></a>
+					<a name="bidichecker.BidiChecker.runGui"></a>
 					
+						<i><a href="#bidichecker.BidiChecker" class="type">bidichecker.BidiChecker.</a></i>runGui(<span class="signature">opt_noPopup</span>)
 					
-					bidichecker.runGuiFromJson(<span class="signature">errorsJson</span>)
 					
 				</div>
 				
 				
-					<div class="desc">JSON interface to <code>runGui</code>.</div>
+					<div class="desc">Runs the interactive visual error browsing GUI, displaying the errors
+reported by the last call to <code>checkPage()</code>. Calling <code>runGui()</code>
+before <code>checkPage()</code> is not supported (and is a no-op). If a GUI opened
+by any prior BidiChecker call in this window is still open, it will be closed
+and then re-opened.
+On IE versions 8 and above, the GUI will always be displayed in an in-page
+dialog box, regardless of the value of opt_noPopup.
+On earlier versions of IE, the GUI will not be displayed. An error message
+will be displayed instead.</div>
 				
 				
 				
@@ -275,14 +435,342 @@
 				
 					<tr>
 						<td class="type">
+							boolean=
+						</td>
+						<td>
+							opt_noPopup
+						</td>
+						<td>
+							Disables opening the error browser in a popup
+    window.
+						</td> 
+					</tr>
+				
+				</table>
+				
+				
+				
+				
+				
+			</div>
+			
+			
+			
+			<div class="section function">
+				<div class="itemTitle">
+					<a name="bidichecker.runBookmarkletGui"></a>
+					
+					
+					bidichecker.runBookmarkletGui(<span class="signature">options, hostWindow, opt_guiAppUrl</span>)
+					
+				</div>
+				
+				
+					<div class="desc">Runs the bookmarklet GUI with a given set of initial options. If a GUI opened
+by any prior BidiChecker call in this window is still open, it will be closed
+and then re-opened.
+On IE the given window is closed, and the GUI is opened in an in-page dialog.
+(This is relevant only for IE versions 9 and up, as the bookmarklet doesn't
+work on earlier versions of IE, due to URL length and other restrictions).</div>
+				
+				
+				
+				
+				
+				<div class="detailHead">parameters</div>
+				<table class="params">
+				
+					<tr>
+						<td class="type">
+							Object.<string, Object>
+						</td>
+						<td>
+							options
+						</td>
+						<td>
+							The initial options.
+    Options are specified as an object with the following (optional) keys:
+    <ul>
+    <li>dir -- string, "rtl" or "ltr" (the default). The expected page
+    directionality.
+    <li>severity -- The severity level from which to suppress error messages,
+    or -1 (for no severity filtering). Default 4.
+    </ul>
+						</td> 
+					</tr>
+				
+					<tr>
+						<td class="type">
+							Window
+						</td>
+						<td>
+							hostWindow
+						</td>
+						<td>
+							The underlying browser window object
+    to be used by the GUI, as returned by window.open, or null to have the
+    function open a new window itself. If non-null, the window should be
+    empty. Do not pass null when calling this function in an onload handler
+    because pop-up blockers will not let it open a window.
+						</td> 
+					</tr>
+				
+					<tr>
+						<td class="type">
+							string=
+						</td>
+						<td>
+							opt_guiAppUrl
+						</td>
+						<td>
+							Location of the GUI files.
+						</td> 
+					</tr>
+				
+				</table>
+				
+				
+				
+				
+				
+			</div>
+			
+			
+			
+			<div class="section function">
+				<div class="itemTitle">
+					<a name="bidichecker.generateBookmarklet"></a>
+					
+					
+					bidichecker.generateBookmarklet(<span class="signature">options, opt_scriptUrl, opt_guiAppUrl</span>)
+					
+				</div>
+				
+				
+					<div class="desc">Generates a BidiChecker bookmarklet. This is a javascript: url that loads the
+BidiChecker package and activates the options page.</div>
+				
+				
+				
+				
+				
+				<div class="detailHead">parameters</div>
+				<table class="params">
+				
+					<tr>
+						<td class="type">
+							!Object.<string, !Object>
+						</td>
+						<td>
+							options
+						</td>
+						<td>
+							The options that the options page
+    will be initially populated with. See OptionsPage constructor
+    documentation for more information.
+						</td> 
+					</tr>
+				
+					<tr>
+						<td class="type">
+							string=
+						</td>
+						<td>
+							opt_scriptUrl
+						</td>
+						<td>
+							Location of the BidiChecker package. Used to
+    install the GUI server. Must not include characters that have special
+    meaning inside JavaScript strings.
+						</td> 
+					</tr>
+				
+					<tr>
+						<td class="type">
+							string=
+						</td>
+						<td>
+							opt_guiAppUrl
+						</td>
+						<td>
+							Location of the GUI application. Must not
+    include characters that have special meaning inside JavaScript strings.
+						</td> 
+					</tr>
+				
+				</table>
+				
+				
+				
+				<div class="detailHead">returns</div>
+				<table class="params">
+				
+					<tr>
+						<td class="type">
 							string
 						</td>
 						<td>
-							errorsJson
+							The generated link.
+						</td> 
+					</tr>
+				
+				</table>
+				
+				
+				
+			</div>
+			
+			
+			
+			<div class="section function">
+				<div class="itemTitle">
+					<a name="bidichecker.checkPage"></a>
+					
+					
+					bidichecker.checkPage(<span class="signature">shouldBeRtl, opt_element, opt_filters</span>)
+					
+				</div>
+				
+				
+					<div class="desc">Checks the contents of the current web page, including all nested frames, for
+bidi-related errors. If <code>opt_element</code> is specified, checks only within
+the given element of the DOM (including any nested frames).
+<p>This used to be the main entry point for the Javascript API. It is now
+deprecated, and is here only for compatibility with any bookmarklets created
+by users before the class-based API was introduced. All other code should
+instead construct an instance of <code>bidichecker.BidiChecker</code> and call its
+<code>checkPage()</code> instance method.</div>
+				
+				
+				
+				
+				
+				<div class="detailHead">parameters</div>
+				<table class="params">
+				
+					<tr>
+						<td class="type">
+							boolean
 						</td>
 						<td>
-							An array of errors to be displayed, in JSON
-    format (similar to that produced by <code>checkPageJson()</code>).
+							shouldBeRtl
+						</td>
+						<td>
+							Is the root expected to be right-to-left?
+						</td> 
+					</tr>
+				
+					<tr>
+						<td class="type">
+							Element=
+						</td>
+						<td>
+							opt_element
+						</td>
+						<td>
+							The root element of the DOM subtree to be
+    checked; if null, checks the entire current web page.
+						</td> 
+					</tr>
+				
+					<tr>
+						<td class="type">
+							Array.<!bidichecker.Filter>=
+						</td>
+						<td>
+							opt_filters
+						</td>
+						<td>
+							Error suppression filters.
+						</td> 
+					</tr>
+				
+				</table>
+				
+				
+				
+				<div class="detailHead">returns</div>
+				<table class="params">
+				
+					<tr>
+						<td class="type">
+							!Array.<!bidichecker.Error>
+						</td>
+						<td>
+							Array of error objects for all failing
+    checks.
+						</td> 
+					</tr>
+				
+				</table>
+				
+				
+				
+			</div>
+			
+			
+			
+			<div class="section function">
+				<div class="itemTitle">
+					<a name="bidichecker.runGui"></a>
+					
+					
+					bidichecker.runGui(<span class="signature">errors, opt_noPopup, opt_guiAppUrl</span>)
+					
+				</div>
+				
+				
+					<div class="desc">Runs the interactive visual error browsing GUI. If a GUI opened by any prior
+BidiChecker call in this window is still open, it will be closed and then
+re-opened.
+<p>This entry point is deprecated, and is here only for compatibility with
+any bookmarklets created by users before the class-based API was introduced.
+All other code should instead construct an instance of
+<code>bidichecker.BidiChecker</code> and call its <code>checkPage()</code> and
+<code>runGui()</code> instance methods.</div>
+				
+				
+				
+				
+				
+				<div class="detailHead">parameters</div>
+				<table class="params">
+				
+					<tr>
+						<td class="type">
+							!Array.<!bidichecker.Error>
+						</td>
+						<td>
+							errors
+						</td>
+						<td>
+							An array of errors to be
+    displayed.
+						</td> 
+					</tr>
+				
+					<tr>
+						<td class="type">
+							boolean=
+						</td>
+						<td>
+							opt_noPopup
+						</td>
+						<td>
+							Disables opening the error browser in a popup
+    window.
+						</td> 
+					</tr>
+				
+					<tr>
+						<td class="type">
+							string=
+						</td>
+						<td>
+							opt_guiAppUrl
+						</td>
+						<td>
+							Location of the GUI files.
 						</td> 
 					</tr>
 				
@@ -302,6 +790,153 @@
 			
 			
 			
+			<div class="section object">
+				<div class="itemTitle">
+					<a name="bidichecker.Revision.revision"></a>
+					
+					<span class="type">number</span>
+					
+					
+						<i><a href="#bidichecker.Revision" class="type">bidichecker.Revision.</a></i>revision
+					
+					
+				</div>
+				
+				
+					<div class="desc"></div>
+				
+				
+				
+				
+				
+			</div>
+			
+			
+			
+			
+			<div class="section object">
+				<div class="itemTitle">
+					<a name="bidichecker.REVISION_1"></a>
+					
+					<span class="type">!bidichecker.Revision</span>
+					
+					
+					
+						bidichecker.REVISION_1
+					
+				</div>
+				
+				
+					<div class="desc">Currently the default revision, for backwards-compatibility with existing
+user tests that did not specify an explicit revision. Includes checks for
+overall page directionality, undeclared opposite-directionality inline text,
+and "spillover" which causes garbling of numbers following declared opposite-
+directionality text.
+<p>This revision is no longer recommended and will be deprecated. Tests
+should use <code>REVISION_2</code>.</div>
+				
+				
+				
+				
+				
+			</div>
+			
+			
+			
+			
+			<div class="section object">
+				<div class="itemTitle">
+					<a name="bidichecker.REVISION_2"></a>
+					
+					<span class="type">!bidichecker.Revision</span>
+					
+					
+					
+						bidichecker.REVISION_2
+					
+				</div>
+				
+				
+					<div class="desc">Currently the latest revision. Adds checks for undeclared opposite-
+directionality text attributes such as input values and tooltip text.</div>
+				
+				
+				
+				
+				
+			</div>
+			
+			
+			
+			
+			<div class="section object">
+				<div class="itemTitle">
+					<a name="bidichecker.LATEST"></a>
+					
+					<span class="type">!bidichecker.Revision</span>
+					
+					
+					
+						bidichecker.LATEST
+					
+				</div>
+				
+				
+					<div class="desc">Always points to the latest revision. Automated tests should avoid using
+this, as it means that newly-added checks will cause the automated tests to
+fail.</div>
+				
+				
+				
+				
+				
+			</div>
+			
+			
+			
+			
+			
+			
+			
+			<div class="section object">
+				<div class="itemTitle">
+					<a name="bidichecker.instance"></a>
+					
+					<span class="type">bidichecker.BidiChecker</span>
+					
+					
+					
+						bidichecker.instance
+					
+				</div>
+				
+				
+					<div class="desc">A static instance of BidiChecker, for use by an external interface.</div>
+				
+				
+				
+				
+				
+			</div>
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
 			
 			
 			
@@ -313,7 +948,7 @@
 		</div>
 	</div>
 	<div class="finePrint">
-	Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> 1.3.3 on Tue, 08 Feb 2011 17:39:01 GMT.
+	Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> 1.3.3 on Thu, 05 Jan 2012 12:29:15 GMT.
 	</div>
 </body>
 </html>
diff --git a/docs/jsdoc/_02.html b/docs/jsdoc/_02.html
index 0554eac..600343d 100644
--- a/docs/jsdoc/_02.html
+++ b/docs/jsdoc/_02.html
@@ -94,7 +94,7 @@
 		</div>
 	</div>
 	<div class="finePrint">
-	Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> 1.3.3 on Tue, 08 Feb 2011 17:39:02 GMT.
+	Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> 1.3.3 on Thu, 05 Jan 2012 12:29:15 GMT.
 	</div>
 </body>
 </html>
diff --git a/docs/jsdoc/_03.html b/docs/jsdoc/_03.html
index 2f150c3..5268c9a 100644
--- a/docs/jsdoc/_03.html
+++ b/docs/jsdoc/_03.html
@@ -2289,7 +2289,7 @@
 		</div>
 	</div>
 	<div class="finePrint">
-	Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> 1.3.3 on Tue, 08 Feb 2011 17:39:02 GMT.
+	Generated by <a href="http://jsdoctoolkit.org/" target="_blank">JsDoc Toolkit</a> 1.3.3 on Thu, 05 Jan 2012 12:29:16 GMT.
 	</div>
 </body>
 </html>
diff --git a/docs/jsdoc/file_list.html b/docs/jsdoc/file_list.html
index 2d66a64..2fdde27 100644
--- a/docs/jsdoc/file_list.html
+++ b/docs/jsdoc/file_list.html
@@ -15,6 +15,10 @@
 		<a href="_01.html" target="main" class="fileHead">bidichecker.js</a>
 		<ul>
 			
+			<li><a href="_01.html#bidichecker.BidiChecker" target="main">bidichecker.BidiChecker</a></li>
+			
+			<li><a href="_01.html#bidichecker.Revision" target="main">bidichecker.Revision</a></li>
+			
 		</ul>
 	</li>
 	
diff --git a/docs/jsdoc/src_01.html b/docs/jsdoc/src_01.html
index de2f1d8..94d829e 100644
--- a/docs/jsdoc/src_01.html
+++ b/docs/jsdoc/src_01.html
@@ -20,7 +20,7 @@
 <span class='linenumber'> 13</span> </span><span class="COMM">// limitations under the License.</span><span class="WHIT">
 <span class='linenumber'> 14</span> 
 <span class='linenumber'> 15</span> </span><span class="COMM">/**
-<span class='linenumber'> 16</span>  * @fileoverview Testing utilities to check a web page for BiDi-related errors.
+<span class='linenumber'> 16</span>  * @fileoverview Class which checks a web page for bidi-related errors.
 <span class='linenumber'> 17</span>  * This file has the top-level entry points for use as a Javascript API, along
 <span class='linenumber'> 18</span>  * with JSON-based interface functions meant to be called from an external
 <span class='linenumber'> 19</span>  * testing framework like WebDriver.
@@ -28,88 +28,419 @@
 <span class='linenumber'> 21</span> 
 <span class='linenumber'> 22</span> 
 <span class='linenumber'> 23</span> </span><span class="NAME">goog.provide</span><span class="PUNC">(</span><span class="STRN">'bidichecker'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 24</span> 
-<span class='linenumber'> 25</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'bidichecker.Error'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 26</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'bidichecker.ErrorGui'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 27</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'bidichecker.Filter'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 28</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'bidichecker.FilterFactory'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 29</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'bidichecker.TextErrorScanner'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 30</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'goog.array'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 31</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'goog.i18n.bidi'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 32</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'goog.json'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 33</span> 
-<span class='linenumber'> 34</span> 
-<span class='linenumber'> 35</span> </span><span class="COMM">/**
-<span class='linenumber'> 36</span>  * Checks the contents of the current web page, including all nested frames, for
-<span class='linenumber'> 37</span>  * BiDi-related errors. If <code>opt_element</code> is specified, checks only within
-<span class='linenumber'> 38</span>  * the given element of the DOM (including any nested frames). This is the main
-<span class='linenumber'> 39</span>  * entry point for the Javascript API.
-<span class='linenumber'> 40</span>  * @param {boolean} shouldBeRtl Is the root expected to be right-to-left?
-<span class='linenumber'> 41</span>  * @param {Element=} opt_element The root element of the DOM subtree to be
-<span class='linenumber'> 42</span>  *     checked; if null, checks the entire current web page.
-<span class='linenumber'> 43</span>  * @param {Array.&lt;!bidichecker.Filter>=} opt_filters Error suppression filters.
-<span class='linenumber'> 44</span>  * @return {!Array.&lt;!bidichecker.Error>} Array of error objects for all failing
-<span class='linenumber'> 45</span>  *     checks.
-<span class='linenumber'> 46</span>  * @export
-<span class='linenumber'> 47</span>  */</span><span class="WHIT">
-<span class='linenumber'> 48</span> </span><span class="NAME">bidichecker.checkPage</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">shouldBeRtl</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_element</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_filters</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
-<span class='linenumber'> 49</span>   </span><span class="NAME">bidichecker.Error.clearHighlightableAreas</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 50</span>   </span><span class="COMM">// {@top.document.body} always finds the top level of the current page, even</span><span class="WHIT">
-<span class='linenumber'> 51</span>   </span><span class="COMM">// if we started within a frame.</span><span class="WHIT">
-<span class='linenumber'> 52</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">element</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="COMM">/** @type {!Element} */</span><span class="WHIT"> </span><span class="NAME">opt_element</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT"> </span><span class="NAME">top.document.body</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 53</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">expectedDir</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
-<span class='linenumber'> 54</span>       </span><span class="NAME">shouldBeRtl</span><span class="WHIT"> </span><span class="PUNC">?</span><span class="WHIT"> </span><span class="NAME">goog.i18n.bidi.Dir.RTL</span><span class="WHIT"> </span><span class="PUNC">:</span><span class="WHIT"> </span><span class="NAME">goog.i18n.bidi.Dir.LTR</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 55</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">scanner</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">new</span><span class="WHIT"> </span><span class="NAME">bidichecker.TextErrorScanner</span><span class="PUNC">(</span><span class="NAME">opt_filters</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 56</span>   </span><span class="NAME">scanner.scan</span><span class="PUNC">(</span><span class="NAME">element</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">expectedDir</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 57</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">scanner.getErrors</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 58</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 59</span> 
-<span class='linenumber'> 60</span> 
-<span class='linenumber'> 61</span> </span><span class="COMM">/**
-<span class='linenumber'> 62</span>  * JSON interface to <code>checkPage</code>.
-<span class='linenumber'> 63</span>  * @param {boolean} shouldBeRtl Is the element/page expected to be
-<span class='linenumber'> 64</span>  *     right-to-left?
-<span class='linenumber'> 65</span>  * @param {Element=} opt_element The root element of the DOM subtree to be
-<span class='linenumber'> 66</span>  *     checked; if null, checks the entire current web page.
-<span class='linenumber'> 67</span>  * @param {string=} opt_filtersJson Error suppression filters in a JSON string.
-<span class='linenumber'> 68</span>  * @return {string} Array of <code>bidichecker.Error</code> objects for all failing
-<span class='linenumber'> 69</span>  *     checks, in JSON format. If no errors were found, returns an empty array
-<span class='linenumber'> 70</span>  *     ("[]").
+<span class='linenumber'> 24</span> </span><span class="NAME">goog.provide</span><span class="PUNC">(</span><span class="STRN">'bidichecker.BidiChecker'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 25</span> </span><span class="NAME">goog.provide</span><span class="PUNC">(</span><span class="STRN">'bidichecker.Revision'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 26</span> 
+<span class='linenumber'> 27</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'bidichecker.Error'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 28</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'bidichecker.Filter'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 29</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'bidichecker.FilterFactory'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 30</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'bidichecker.TextErrorScanner'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 31</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'bidichecker.gui.server.GuiContainerFactory'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 32</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'bidichecker.gui.server.GuiServer'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 33</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'goog.array'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 34</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'goog.i18n.bidi'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 35</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'goog.json'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 36</span> </span><span class="NAME">goog.require</span><span class="PUNC">(</span><span class="STRN">'goog.userAgent.product'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 37</span> 
+<span class='linenumber'> 38</span> 
+<span class='linenumber'> 39</span> </span><span class="COMM">/**
+<span class='linenumber'> 40</span>  * A class representing a revision of the BidiChecker checks. Higher revisions
+<span class='linenumber'> 41</span>  * indicate later releases, which check for more error situations.
+<span class='linenumber'> 42</span>  * @param {number} revision The revision number.
+<span class='linenumber'> 43</span>  * @constructor
+<span class='linenumber'> 44</span>  */</span><span class="WHIT">
+<span class='linenumber'> 45</span> </span><span class="NAME">bidichecker.Revision</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">revision</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'> 46</span>   </span><span class="COMM">/**
+<span class='linenumber'> 47</span>    * @type {number}
+<span class='linenumber'> 48</span>    */</span><span class="WHIT">
+<span class='linenumber'> 49</span>   </span><span class="NAME">this.revision</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">revision</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 50</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 51</span> 
+<span class='linenumber'> 52</span> 
+<span class='linenumber'> 53</span> </span><span class="COMM">/**
+<span class='linenumber'> 54</span>  * Currently the default revision, for backwards-compatibility with existing
+<span class='linenumber'> 55</span>  * user tests that did not specify an explicit revision. Includes checks for
+<span class='linenumber'> 56</span>  * overall page directionality, undeclared opposite-directionality inline text,
+<span class='linenumber'> 57</span>  * and "spillover" which causes garbling of numbers following declared opposite-
+<span class='linenumber'> 58</span>  * directionality text.
+<span class='linenumber'> 59</span>  * &lt;p>This revision is no longer recommended and will be deprecated. Tests
+<span class='linenumber'> 60</span>  * should use <code>REVISION_2</code>.
+<span class='linenumber'> 61</span>  * @type {!bidichecker.Revision}
+<span class='linenumber'> 62</span>  * @export
+<span class='linenumber'> 63</span>  */</span><span class="WHIT">
+<span class='linenumber'> 64</span> </span><span class="NAME">bidichecker.REVISION_1</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">new</span><span class="WHIT"> </span><span class="NAME">bidichecker.Revision</span><span class="PUNC">(</span><span class="NUMB">1</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 65</span> 
+<span class='linenumber'> 66</span> 
+<span class='linenumber'> 67</span> </span><span class="COMM">/**
+<span class='linenumber'> 68</span>  * Currently the latest revision. Adds checks for undeclared opposite-
+<span class='linenumber'> 69</span>  * directionality text attributes such as input values and tooltip text.
+<span class='linenumber'> 70</span>  * @type {!bidichecker.Revision}
 <span class='linenumber'> 71</span>  * @export
 <span class='linenumber'> 72</span>  */</span><span class="WHIT">
-<span class='linenumber'> 73</span> </span><span class="NAME">bidichecker.checkPageToJson</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">shouldBeRtl</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_element</span><span class="PUNC">,</span><span class="WHIT">
-<span class='linenumber'> 74</span>                                        </span><span class="NAME">opt_filtersJson</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
-<span class='linenumber'> 75</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">filters</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">bidichecker.FilterFactory.readFiltersFromJson</span><span class="PUNC">(</span><span class="NAME">opt_filtersJson</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 76</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">errors</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">bidichecker.checkPage</span><span class="PUNC">(</span><span class="NAME">shouldBeRtl</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_element</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">filters</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 77</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">bidichecker.Error.serialize</span><span class="PUNC">(</span><span class="NAME">errors</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 78</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 79</span> 
-<span class='linenumber'> 80</span> 
-<span class='linenumber'> 81</span> </span><span class="COMM">/**
-<span class='linenumber'> 82</span>  * Runs the interactive visual error browsing mode.
-<span class='linenumber'> 83</span>  * @param {Array.&lt;!bidichecker.Error>} errors An array of errors to be
-<span class='linenumber'> 84</span>  *     displayed.
-<span class='linenumber'> 85</span>  * @export
-<span class='linenumber'> 86</span>  */</span><span class="WHIT">
-<span class='linenumber'> 87</span> </span><span class="NAME">bidichecker.runGui</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">errors</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
-<span class='linenumber'> 88</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">gui</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">new</span><span class="WHIT"> </span><span class="NAME">bidichecker.ErrorGui</span><span class="PUNC">(</span><span class="NAME">errors</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 89</span>   </span><span class="NAME">gui.launch</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 90</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'> 91</span> 
-<span class='linenumber'> 92</span> 
-<span class='linenumber'> 93</span> </span><span class="COMM">/**
-<span class='linenumber'> 94</span>  * JSON interface to <code>runGui</code>.
-<span class='linenumber'> 95</span>  * @param {string} errorsJson An array of errors to be displayed, in JSON
-<span class='linenumber'> 96</span>  *     format (similar to that produced by <code>checkPageJson()</code>).
-<span class='linenumber'> 97</span>  * @export
-<span class='linenumber'> 98</span>  */</span><span class="WHIT">
-<span class='linenumber'> 99</span> </span><span class="NAME">bidichecker.runGuiFromJson</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">errorsJson</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
-<span class='linenumber'>100</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">bareErrors</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="COMM">/** @type {Array.&lt;!Object>} */</span><span class="WHIT"> </span><span class="NAME">goog.json.parse</span><span class="PUNC">(</span><span class="NAME">errorsJson</span><span class="PUNC">)</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'>101</span> 
-<span class='linenumber'>102</span>   </span><span class="COMM">/** @type {Array.&lt;!bidichecker.Error>} */</span><span class="WHIT">
-<span class='linenumber'>103</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">errors</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">goog.array.map</span><span class="PUNC">(</span><span class="NAME">bareErrors</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">bareError</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
-<span class='linenumber'>104</span>     </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="KEYW">new</span><span class="WHIT"> </span><span class="NAME">bidichecker.Error</span><span class="PUNC">(</span><span class="NAME">bareError</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'>105</span>   </span><span class="PUNC">}</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'>106</span>   </span><span class="NAME">bidichecker.runGui</span><span class="PUNC">(</span><span class="NAME">errors</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'>107</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
-<span class='linenumber'>108</span> </span></pre></body></html>
\ No newline at end of file
+<span class='linenumber'> 73</span> </span><span class="NAME">bidichecker.REVISION_2</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">new</span><span class="WHIT"> </span><span class="NAME">bidichecker.Revision</span><span class="PUNC">(</span><span class="NUMB">2</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 74</span> 
+<span class='linenumber'> 75</span> 
+<span class='linenumber'> 76</span> </span><span class="COMM">/**
+<span class='linenumber'> 77</span>  * Always points to the latest revision. Automated tests should avoid using
+<span class='linenumber'> 78</span>  * this, as it means that newly-added checks will cause the automated tests to
+<span class='linenumber'> 79</span>  * fail.
+<span class='linenumber'> 80</span>  * @type {!bidichecker.Revision}
+<span class='linenumber'> 81</span>  * @export
+<span class='linenumber'> 82</span>  */</span><span class="WHIT">
+<span class='linenumber'> 83</span> </span><span class="NAME">bidichecker.LATEST</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">bidichecker.REVISION_2</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 84</span> 
+<span class='linenumber'> 85</span> 
+<span class='linenumber'> 86</span> 
+<span class='linenumber'> 87</span> 
+<span class='linenumber'> 88</span> </span><span class="COMM">/**
+<span class='linenumber'> 89</span>  * Entry point of the GUI web application.
+<span class='linenumber'> 90</span>  * @const
+<span class='linenumber'> 91</span>  * @type {string}
+<span class='linenumber'> 92</span>  * @private
+<span class='linenumber'> 93</span>  */</span><span class="WHIT">
+<span class='linenumber'> 94</span> </span><span class="NAME">bidichecker.GUI_APP_URL_</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
+<span class='linenumber'> 95</span>     </span><span class="STRN">'https://bidichecker.googlecode.com/svn/trunk/lib/gui-app/errorpage.html'</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'> 96</span> 
+<span class='linenumber'> 97</span> 
+<span class='linenumber'> 98</span> </span><span class="COMM">/**
+<span class='linenumber'> 99</span>  * Default location of the precompiled bidichecker package.
+<span class='linenumber'>100</span>  * @const
+<span class='linenumber'>101</span>  * @type {string}
+<span class='linenumber'>102</span>  * @private
+<span class='linenumber'>103</span>  */</span><span class="WHIT">
+<span class='linenumber'>104</span> </span><span class="NAME">bidichecker.PACKAGE_URL_</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
+<span class='linenumber'>105</span>     </span><span class="STRN">'https://bidichecker.googlecode.com/svn/trunk/lib/bidichecker_packaged.js'</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>106</span> 
+<span class='linenumber'>107</span> 
+<span class='linenumber'>108</span> </span><span class="COMM">/**
+<span class='linenumber'>109</span>  * Class which checks a web page for bidi-related errors. The preferred way to
+<span class='linenumber'>110</span>  * invoke BidiChecker is by constructing an instance of this class. The previous
+<span class='linenumber'>111</span>  * API, based on static methods, is no longer recommended and will be
+<span class='linenumber'>112</span>  * deprecated.
+<span class='linenumber'>113</span>  * @param {!bidichecker.Revision} revision Revision of BidiChecker checks to
+<span class='linenumber'>114</span>  *     run.
+<span class='linenumber'>115</span>  * @export
+<span class='linenumber'>116</span>  * @constructor
+<span class='linenumber'>117</span>  */</span><span class="WHIT">
+<span class='linenumber'>118</span> </span><span class="NAME">bidichecker.BidiChecker</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">revision</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>119</span>   </span><span class="COMM">/**
+<span class='linenumber'>120</span>    * @type {!bidichecker.Revision}
+<span class='linenumber'>121</span>    * @private
+<span class='linenumber'>122</span>    */</span><span class="WHIT">
+<span class='linenumber'>123</span>   </span><span class="NAME">this.revision_</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">revision</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>124</span> 
+<span class='linenumber'>125</span>   </span><span class="COMM">/**
+<span class='linenumber'>126</span>    * The errors reported by the last call to <code>checkPage()</code>.
+<span class='linenumber'>127</span>    * @type {!Array.&lt;!bidichecker.Error>}
+<span class='linenumber'>128</span>    * @private
+<span class='linenumber'>129</span>    */</span><span class="WHIT">
+<span class='linenumber'>130</span>   </span><span class="NAME">this.errors_</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="PUNC">[</span><span class="PUNC">]</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>131</span> 
+<span class='linenumber'>132</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>133</span> 
+<span class='linenumber'>134</span> 
+<span class='linenumber'>135</span> </span><span class="COMM">/**
+<span class='linenumber'>136</span>  * A static instance of BidiChecker, for use by an external interface.
+<span class='linenumber'>137</span>  * @type {bidichecker.BidiChecker}
+<span class='linenumber'>138</span>  * @export
+<span class='linenumber'>139</span>  */</span><span class="WHIT">
+<span class='linenumber'>140</span> </span><span class="NAME">bidichecker.instance</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">null</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>141</span> 
+<span class='linenumber'>142</span> 
+<span class='linenumber'>143</span> </span><span class="COMM">/**
+<span class='linenumber'>144</span>  * Root path for the GUI application.
+<span class='linenumber'>145</span>  * @type {string}
+<span class='linenumber'>146</span>  * @private
+<span class='linenumber'>147</span>  */</span><span class="WHIT">
+<span class='linenumber'>148</span> </span><span class="NAME">bidichecker.BidiChecker.prototype.guiAppUrl_</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">bidichecker.GUI_APP_URL_</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>149</span> 
+<span class='linenumber'>150</span> 
+<span class='linenumber'>151</span> </span><span class="COMM">/**
+<span class='linenumber'>152</span>  * Checks the contents of the current web page, including all nested frames, for
+<span class='linenumber'>153</span>  * bidi-related errors. If <code>opt_element</code> is specified, checks only within
+<span class='linenumber'>154</span>  * the given element of the DOM (including any nested frames).
+<span class='linenumber'>155</span>  * @param {boolean} shouldBeRtl Is the root expected to be right-to-left?
+<span class='linenumber'>156</span>  * @param {Element=} opt_element The root element of the DOM subtree to be
+<span class='linenumber'>157</span>  *     checked; if null, checks the entire current web page.
+<span class='linenumber'>158</span>  * @param {Array.&lt;!bidichecker.Filter>=} opt_filters Error suppression filters.
+<span class='linenumber'>159</span>  * @return {!Array.&lt;!bidichecker.Error>} Array of error objects for all failing
+<span class='linenumber'>160</span>  *     checks.
+<span class='linenumber'>161</span>  * @export
+<span class='linenumber'>162</span>  */</span><span class="WHIT">
+<span class='linenumber'>163</span> </span><span class="NAME">bidichecker.BidiChecker.prototype.checkPage</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">shouldBeRtl</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_element</span><span class="PUNC">,</span><span class="WHIT">
+<span class='linenumber'>164</span>     </span><span class="NAME">opt_filters</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>165</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">expectedDir</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
+<span class='linenumber'>166</span>       </span><span class="NAME">shouldBeRtl</span><span class="WHIT"> </span><span class="PUNC">?</span><span class="WHIT"> </span><span class="NAME">goog.i18n.bidi.Dir.RTL</span><span class="WHIT"> </span><span class="PUNC">:</span><span class="WHIT"> </span><span class="NAME">goog.i18n.bidi.Dir.LTR</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>167</span>   </span><span class="COMM">// {@top.document.body} always finds the top level of the current page, even</span><span class="WHIT">
+<span class='linenumber'>168</span>   </span><span class="COMM">// if we started within a frame.</span><span class="WHIT">
+<span class='linenumber'>169</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">nonNullElement</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
+<span class='linenumber'>170</span>       </span><span class="PUNC">(</span><span class="COMM">/** @type {!Element} */</span><span class="WHIT"> </span><span class="NAME">opt_element</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT"> </span><span class="NAME">top.document.body</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>171</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">filters</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">opt_filters</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT"> </span><span class="PUNC">[</span><span class="PUNC">]</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>172</span> 
+<span class='linenumber'>173</span>   </span><span class="NAME">bidichecker.Error.clearHighlightableAreas</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>174</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">scanner</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
+<span class='linenumber'>175</span>       </span><span class="KEYW">new</span><span class="WHIT"> </span><span class="NAME">bidichecker.TextErrorScanner</span><span class="PUNC">(</span><span class="NAME">this.revision_.revision</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">filters</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>176</span>   </span><span class="NAME">scanner.scan</span><span class="PUNC">(</span><span class="NAME">nonNullElement</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">expectedDir</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>177</span>   </span><span class="NAME">this.errors_</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">scanner.getErrors</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>178</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">goog.array.clone</span><span class="PUNC">(</span><span class="NAME">this.errors_</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>179</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>180</span> 
+<span class='linenumber'>181</span> 
+<span class='linenumber'>182</span> </span><span class="COMM">/**
+<span class='linenumber'>183</span>  * JSON interface to <code>checkPage</code>.
+<span class='linenumber'>184</span>  * @param {boolean} shouldBeRtl Is the element/page expected to be
+<span class='linenumber'>185</span>  *     right-to-left?
+<span class='linenumber'>186</span>  * @param {Element} element The root element of the DOM subtree to be checked;
+<span class='linenumber'>187</span>  *     if null, checks the entire current web page.
+<span class='linenumber'>188</span>  * @param {string} filtersJson Error suppression filters in a JSON string,
+<span class='linenumber'>189</span>  *     representing a (possibly-empty) array of filter objects.
+<span class='linenumber'>190</span>  * @return {string} Array of <code>bidichecker.Error</code> objects for all failing
+<span class='linenumber'>191</span>  *     checks, in JSON format. If no errors were found, returns an empty array
+<span class='linenumber'>192</span>  *     ("[]").
+<span class='linenumber'>193</span>  * @export
+<span class='linenumber'>194</span>  */</span><span class="WHIT">
+<span class='linenumber'>195</span> </span><span class="NAME">bidichecker.BidiChecker.prototype.checkPageToJson</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">shouldBeRtl</span><span class="PUNC">,</span><span class="WHIT">
+<span class='linenumber'>196</span>     </span><span class="NAME">element</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">filtersJson</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>197</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">filters</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">bidichecker.FilterFactory.readFiltersFromJson</span><span class="PUNC">(</span><span class="NAME">filtersJson</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>198</span>   </span><span class="NAME">filters</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">filters</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT"> </span><span class="PUNC">[</span><span class="PUNC">]</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>199</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">errors</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">this.checkPage</span><span class="PUNC">(</span><span class="NAME">shouldBeRtl</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">element</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">filters</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>200</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">bidichecker.Error.serialize</span><span class="PUNC">(</span><span class="NAME">errors</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>201</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>202</span> 
+<span class='linenumber'>203</span> 
+<span class='linenumber'>204</span> </span><span class="COMM">/**
+<span class='linenumber'>205</span>  * Sets the location of the GUI files.
+<span class='linenumber'>206</span>  * @param {string} guiAppUrl Location of the GUI files.
+<span class='linenumber'>207</span>  * @export
+<span class='linenumber'>208</span>  */</span><span class="WHIT">
+<span class='linenumber'>209</span> </span><span class="NAME">bidichecker.BidiChecker.prototype.setGuiAppUrl</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">guiAppUrl</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>210</span>   </span><span class="NAME">this.guiAppUrl_</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">guiAppUrl</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>211</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>212</span> 
+<span class='linenumber'>213</span> 
+<span class='linenumber'>214</span> </span><span class="COMM">/**
+<span class='linenumber'>215</span>  * Runs the interactive visual error browsing GUI, displaying the errors
+<span class='linenumber'>216</span>  * reported by the last call to <code>checkPage()</code>. Calling <code>runGui()</code>
+<span class='linenumber'>217</span>  * before <code>checkPage()</code> is not supported (and is a no-op). If a GUI opened
+<span class='linenumber'>218</span>  * by any prior BidiChecker call in this window is still open, it will be closed
+<span class='linenumber'>219</span>  * and then re-opened.
+<span class='linenumber'>220</span>  * On IE versions 8 and above, the GUI will always be displayed in an in-page
+<span class='linenumber'>221</span>  * dialog box, regardless of the value of opt_noPopup.
+<span class='linenumber'>222</span>  * On earlier versions of IE, the GUI will not be displayed. An error message
+<span class='linenumber'>223</span>  * will be displayed instead.
+<span class='linenumber'>224</span>  * @param {boolean=} opt_noPopup Disables opening the error browser in a popup
+<span class='linenumber'>225</span>  *     window.
+<span class='linenumber'>226</span>  * @export
+<span class='linenumber'>227</span>  */</span><span class="WHIT">
+<span class='linenumber'>228</span> </span><span class="NAME">bidichecker.BidiChecker.prototype.runGui</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">opt_noPopup</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>229</span>   </span><span class="KEYW">if</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="NAME">this.errors_.length</span><span class="WHIT"> </span><span class="PUNC">==</span><span class="WHIT"> </span><span class="NUMB">0</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>230</span>     </span><span class="KEYW">return</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>231</span>   </span><span class="PUNC">}</span><span class="WHIT">
+<span class='linenumber'>232</span>   </span><span class="NAME">this.runGuiWithErrors_</span><span class="PUNC">(</span><span class="NAME">this.errors_</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_noPopup</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>233</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>234</span> 
+<span class='linenumber'>235</span> 
+<span class='linenumber'>236</span> </span><span class="COMM">/**
+<span class='linenumber'>237</span>  * Runs the interactive visual error browsing GUI, displaying the given errors.
+<span class='linenumber'>238</span>  * If a GUI opened by any prior BidiChecker call in this window is still open,
+<span class='linenumber'>239</span>  * it will be closed and then re-opened.
+<span class='linenumber'>240</span>  * On IE versions 8 and above, the GUI will always be displayed in an in-page
+<span class='linenumber'>241</span>  * dialog box, regardless of the value of opt_noPopup.
+<span class='linenumber'>242</span>  * On earlier versions of IE, the GUI will not be displayed. An error message
+<span class='linenumber'>243</span>  * will be displayed instead.
+<span class='linenumber'>244</span>  * @param {!Array.&lt;!bidichecker.Error>} errors Array of error objects to
+<span class='linenumber'>245</span>  *     display.
+<span class='linenumber'>246</span>  * @param {boolean=} opt_noPopup Disables opening the error browser in a popup
+<span class='linenumber'>247</span>  *     window.
+<span class='linenumber'>248</span>  * @private
+<span class='linenumber'>249</span>  */</span><span class="WHIT">
+<span class='linenumber'>250</span> </span><span class="NAME">bidichecker.BidiChecker.prototype.runGuiWithErrors_</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">errors</span><span class="PUNC">,</span><span class="WHIT">
+<span class='linenumber'>251</span>     </span><span class="NAME">opt_noPopup</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>252</span>   </span><span class="KEYW">if</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="NAME">goog.userAgent.IE</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>253</span>     </span><span class="KEYW">if</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="NAME">goog.userAgent.isVersion</span><span class="PUNC">(</span><span class="STRN">'8'</span><span class="PUNC">)</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>254</span>       </span><span class="COMM">// IE version 8 and up, force dialog to be used.</span><span class="WHIT">
+<span class='linenumber'>255</span>       </span><span class="NAME">opt_noPopup</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">true</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>256</span>     </span><span class="PUNC">}</span><span class="WHIT"> </span><span class="KEYW">else</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>257</span>       </span><span class="COMM">// IE before version 8, display error and quit.</span><span class="WHIT">
+<span class='linenumber'>258</span>       </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">guiContainer</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
+<span class='linenumber'>259</span>           </span><span class="NAME">bidichecker.gui.server.GuiContainerFactory.createFromScratch</span><span class="PUNC">(</span><span class="KEYW">true</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>260</span>       </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">msg</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="STRN">'Sorry, bidichecker GUI is not supported in Internet '</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>261</span>           </span><span class="STRN">'Explorer before version 8.'</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>262</span>       </span><span class="NAME">guiContainer.getContentWindow</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="PUNC">.</span><span class="NAME">document.write</span><span class="PUNC">(</span><span class="NAME">msg</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>263</span>       </span><span class="KEYW">return</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>264</span>     </span><span class="PUNC">}</span><span class="WHIT">
+<span class='linenumber'>265</span>   </span><span class="PUNC">}</span><span class="WHIT">
+<span class='linenumber'>266</span> 
+<span class='linenumber'>267</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">guiContainer</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
+<span class='linenumber'>268</span>       </span><span class="NAME">bidichecker.gui.server.GuiContainerFactory.createFromScratch</span><span class="PUNC">(</span><span class="NAME">opt_noPopup</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>269</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">server</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">new</span><span class="WHIT"> </span><span class="NAME">bidichecker.gui.server.GuiServer</span><span class="PUNC">(</span><span class="KEYW">this</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="PUNC">}</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">guiContainer</span><span class="PUNC">,</span><span class="WHIT">
+<span class='linenumber'>270</span>       </span><span class="NAME">this.guiAppUrl_</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">errors</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>271</span>   </span><span class="COMM">// This disposes of the last GuiServer created by BidiChecker for this window,</span><span class="WHIT">
+<span class='linenumber'>272</span>   </span><span class="COMM">// which disposes of the GuiContainer created for it, which closes the GUI.</span><span class="WHIT">
+<span class='linenumber'>273</span>   </span><span class="NAME">bidichecker.gui.server.GuiServer.startServer</span><span class="PUNC">(</span><span class="NAME">server</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>274</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>275</span> 
+<span class='linenumber'>276</span> 
+<span class='linenumber'>277</span> </span><span class="COMM">/**
+<span class='linenumber'>278</span>  * Runs the bookmarklet GUI with a given set of initial options. If a GUI opened
+<span class='linenumber'>279</span>  * by any prior BidiChecker call in this window is still open, it will be closed
+<span class='linenumber'>280</span>  * and then re-opened.
+<span class='linenumber'>281</span>  * On IE the given window is closed, and the GUI is opened in an in-page dialog.
+<span class='linenumber'>282</span>  * (This is relevant only for IE versions 9 and up, as the bookmarklet doesn't
+<span class='linenumber'>283</span>  * work on earlier versions of IE, due to URL length and other restrictions).
+<span class='linenumber'>284</span>  * @param {Object.&lt;string, Object>} options The initial options.
+<span class='linenumber'>285</span>  *     Options are specified as an object with the following (optional) keys:
+<span class='linenumber'>286</span>  *     &lt;ul>
+<span class='linenumber'>287</span>  *     &lt;li>dir -- string, "rtl" or "ltr" (the default). The expected page
+<span class='linenumber'>288</span>  *     directionality.
+<span class='linenumber'>289</span>  *     &lt;li>severity -- The severity level from which to suppress error messages,
+<span class='linenumber'>290</span>  *     or -1 (for no severity filtering). Default 4.
+<span class='linenumber'>291</span>  *     &lt;/ul>
+<span class='linenumber'>292</span>  * @param {Window} hostWindow The underlying browser window object
+<span class='linenumber'>293</span>  *     to be used by the GUI, as returned by window.open, or null to have the
+<span class='linenumber'>294</span>  *     function open a new window itself. If non-null, the window should be
+<span class='linenumber'>295</span>  *     empty. Do not pass null when calling this function in an onload handler
+<span class='linenumber'>296</span>  *     because pop-up blockers will not let it open a window.
+<span class='linenumber'>297</span>  * @param {string=} opt_guiAppUrl Location of the GUI files.
+<span class='linenumber'>298</span>  * @export
+<span class='linenumber'>299</span>  */</span><span class="WHIT">
+<span class='linenumber'>300</span> </span><span class="NAME">bidichecker.runBookmarkletGui</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">options</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">hostWindow</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_guiAppUrl</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>301</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">checker</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">new</span><span class="WHIT"> </span><span class="NAME">bidichecker.BidiChecker</span><span class="PUNC">(</span><span class="NAME">bidichecker.LATEST</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>302</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">guiContainer</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>303</span>   </span><span class="KEYW">if</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="NAME">goog.userAgent.IE</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>304</span>     </span><span class="KEYW">if</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="NAME">hostWindow</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>305</span>       </span><span class="NAME">hostWindow.close</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>306</span>     </span><span class="PUNC">}</span><span class="WHIT">
+<span class='linenumber'>307</span>     </span><span class="NAME">guiContainer</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
+<span class='linenumber'>308</span>         </span><span class="NAME">bidichecker.gui.server.GuiContainerFactory.createFromScratch</span><span class="PUNC">(</span><span class="KEYW">true</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>309</span>   </span><span class="PUNC">}</span><span class="WHIT"> </span><span class="KEYW">else</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>310</span>     </span><span class="NAME">guiContainer</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
+<span class='linenumber'>311</span>         </span><span class="NAME">bidichecker.gui.server.GuiContainerFactory.createFromWindow</span><span class="PUNC">(</span><span class="NAME">hostWindow</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>312</span>   </span><span class="PUNC">}</span><span class="WHIT">
+<span class='linenumber'>313</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">server</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">new</span><span class="WHIT"> </span><span class="NAME">bidichecker.gui.server.GuiServer</span><span class="PUNC">(</span><span class="NAME">checker</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">options</span><span class="PUNC">,</span><span class="WHIT">
+<span class='linenumber'>314</span>       </span><span class="NAME">guiContainer</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_guiAppUrl</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT"> </span><span class="NAME">bidichecker.GUI_APP_URL_</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>315</span>   </span><span class="NAME">bidichecker.gui.server.GuiServer.startServer</span><span class="PUNC">(</span><span class="NAME">server</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>316</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>317</span> 
+<span class='linenumber'>318</span> 
+<span class='linenumber'>319</span> </span><span class="COMM">/**
+<span class='linenumber'>320</span>  * Generates a BidiChecker bookmarklet. This is a javascript: url that loads the
+<span class='linenumber'>321</span>  * BidiChecker package and activates the options page.
+<span class='linenumber'>322</span>  * @param {!Object.&lt;string, !Object>} options The options that the options page
+<span class='linenumber'>323</span>  *     will be initially populated with. See OptionsPage constructor
+<span class='linenumber'>324</span>  *     documentation for more information.
+<span class='linenumber'>325</span>  * @param {string=} opt_scriptUrl Location of the BidiChecker package. Used to
+<span class='linenumber'>326</span>  *     install the GUI server. Must not include characters that have special
+<span class='linenumber'>327</span>  *     meaning inside JavaScript strings.
+<span class='linenumber'>328</span>  * @param {string=} opt_guiAppUrl Location of the GUI application. Must not
+<span class='linenumber'>329</span>  *     include characters that have special meaning inside JavaScript strings.
+<span class='linenumber'>330</span>  * @return {string} The generated link.
+<span class='linenumber'>331</span>  * @export
+<span class='linenumber'>332</span>  */</span><span class="WHIT">
+<span class='linenumber'>333</span> </span><span class="NAME">bidichecker.generateBookmarklet</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">options</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_scriptUrl</span><span class="PUNC">,</span><span class="WHIT">
+<span class='linenumber'>334</span>     </span><span class="NAME">opt_guiAppUrl</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>335</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">scriptUrl</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">opt_scriptUrl</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT"> </span><span class="NAME">bidichecker.PACKAGE_URL_</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>336</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">guiAppUrl</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">opt_guiAppUrl</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT"> </span><span class="NAME">bidichecker.GUI_APP_URL_</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>337</span> 
+<span class='linenumber'>338</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">template</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="STRN">'javascript:'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>339</span>     </span><span class="STRN">'(function() {'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>340</span>       </span><span class="STRN">'function run() {'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>341</span>         </span><span class="STRN">'bidichecker.runBookmarkletGui(%OPTIONS%, '</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>342</span>             </span><span class="STRN">'g_bidicheckerBookmarkletGuiWnd, "%APPURL%");'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>343</span>       </span><span class="STRN">'}'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>344</span>       </span><span class="COMM">// The window object for the last opened window. Make sure the variable is</span><span class="WHIT">
+<span class='linenumber'>345</span>       </span><span class="COMM">// defined.</span><span class="WHIT">
+<span class='linenumber'>346</span>       </span><span class="STRN">'if (typeof g_bidicheckerBookmarkletGuiWnd == "undefined") {'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>347</span>         </span><span class="STRN">'g_bidicheckerBookmarkletGuiWnd = null;'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>348</span>       </span><span class="STRN">'}'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>349</span>       </span><span class="STRN">'if (g_bidicheckerBookmarkletGuiWnd &&'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>350</span>           </span><span class="STRN">'!g_bidicheckerBookmarkletGuiWnd.closed) {'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>351</span>         </span><span class="COMM">// If the window is already open, there's nothing more for us to do.</span><span class="WHIT">
+<span class='linenumber'>352</span>         </span><span class="STRN">'g_bidicheckerBookmarkletGuiWnd.focus();'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>353</span>       </span><span class="STRN">'} else {'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>354</span>         </span><span class="COMM">// Open a new window. Must be done as an immediate result of the</span><span class="WHIT">
+<span class='linenumber'>355</span>         </span><span class="COMM">// bookmarklet being activated, not in the onload event; otherwise it</span><span class="WHIT">
+<span class='linenumber'>356</span>         </span><span class="COMM">// may be blocked by the popup blocker.</span><span class="WHIT">
+<span class='linenumber'>357</span>         </span><span class="STRN">'g_bidicheckerBookmarkletGuiWnd = window.open("about:blank", '</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>358</span>           </span><span class="STRN">'"_blank", "width=1,height=1,resizable=yes,scrollbars=yes");'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>359</span>         </span><span class="COMM">// ID of the element used to hold the script.</span><span class="WHIT">
+<span class='linenumber'>360</span>         </span><span class="STRN">'var scriptElemId = "_bidichecker_bookmarklet";'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>361</span>         </span><span class="COMM">// Load the script if we haven't done so already.</span><span class="WHIT">
+<span class='linenumber'>362</span>         </span><span class="STRN">'if (document.getElementById(scriptElemId)) {'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>363</span>           </span><span class="COMM">// Script element already exists. It doesn't mean that the script has</span><span class="WHIT">
+<span class='linenumber'>364</span>           </span><span class="COMM">// been loaded yet, though, so check that bidichecker exists before</span><span class="WHIT">
+<span class='linenumber'>365</span>           </span><span class="COMM">// proceeding. (We could probably just go ahead without checking, as</span><span class="WHIT">
+<span class='linenumber'>366</span>           </span><span class="COMM">// normally JavaScript errors are silently ignored, but the page may</span><span class="WHIT">
+<span class='linenumber'>367</span>           </span><span class="COMM">// have installed an error handler.)</span><span class="WHIT">
+<span class='linenumber'>368</span>           </span><span class="STRN">'if (window.bidichecker) {'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>369</span>             </span><span class="STRN">'run();'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>370</span>           </span><span class="STRN">'}'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>371</span>         </span><span class="STRN">'} else {'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>372</span>           </span><span class="COMM">// Add script to document and call it when it's loaded.</span><span class="WHIT">
+<span class='linenumber'>373</span>           </span><span class="STRN">'var elem = document.createElement("script");'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>374</span>           </span><span class="STRN">'elem.src = "%SCRIPTURL%";'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>375</span>           </span><span class="STRN">'elem.onload = run;'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>376</span>           </span><span class="STRN">'elem.id = scriptElemId;'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>377</span>           </span><span class="STRN">'document.getElementsByTagName("head")[0].appendChild(elem);'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>378</span>         </span><span class="STRN">'}'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>379</span>       </span><span class="STRN">'}'</span><span class="WHIT"> </span><span class="PUNC">+</span><span class="WHIT">
+<span class='linenumber'>380</span>     </span><span class="STRN">'})()'</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>381</span> 
+<span class='linenumber'>382</span>   </span><span class="COMM">// Substitute actual values in template. "$" is a meta character in the</span><span class="WHIT">
+<span class='linenumber'>383</span>   </span><span class="COMM">// replace() method, so we need to escape it.</span><span class="WHIT">
+<span class='linenumber'>384</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">optionsStr</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NAME">goog.json.serialize</span><span class="PUNC">(</span><span class="NAME">options</span><span class="PUNC">)</span><span class="PUNC">.</span><span class="NAME">replace</span><span class="PUNC">(</span><span class="REGX">/\$/g</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="STRN">'$$$$'</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>385</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">template.replace</span><span class="PUNC">(</span><span class="STRN">'%SCRIPTURL%'</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">scriptUrl</span><span class="PUNC">)</span><span class="WHIT">
+<span class='linenumber'>386</span>       </span><span class="PUNC">.</span><span class="NAME">replace</span><span class="PUNC">(</span><span class="STRN">'%APPURL%'</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">guiAppUrl</span><span class="PUNC">)</span><span class="WHIT">
+<span class='linenumber'>387</span>       </span><span class="PUNC">.</span><span class="NAME">replace</span><span class="PUNC">(</span><span class="STRN">'%OPTIONS%'</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">optionsStr</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>388</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>389</span> 
+<span class='linenumber'>390</span> 
+<span class='linenumber'>391</span> </span><span class="COMM">/**
+<span class='linenumber'>392</span>  * Checks the contents of the current web page, including all nested frames, for
+<span class='linenumber'>393</span>  * bidi-related errors. If <code>opt_element</code> is specified, checks only within
+<span class='linenumber'>394</span>  * the given element of the DOM (including any nested frames).
+<span class='linenumber'>395</span>  * &lt;p>This used to be the main entry point for the Javascript API. It is now
+<span class='linenumber'>396</span>  * deprecated, and is here only for compatibility with any bookmarklets created
+<span class='linenumber'>397</span>  * by users before the class-based API was introduced. All other code should
+<span class='linenumber'>398</span>  * instead construct an instance of <code>bidichecker.BidiChecker</code> and call its
+<span class='linenumber'>399</span>  * <code>checkPage()</code> instance method.
+<span class='linenumber'>400</span>  * @param {boolean} shouldBeRtl Is the root expected to be right-to-left?
+<span class='linenumber'>401</span>  * @param {Element=} opt_element The root element of the DOM subtree to be
+<span class='linenumber'>402</span>  *     checked; if null, checks the entire current web page.
+<span class='linenumber'>403</span>  * @param {Array.&lt;!bidichecker.Filter>=} opt_filters Error suppression filters.
+<span class='linenumber'>404</span>  * @return {!Array.&lt;!bidichecker.Error>} Array of error objects for all failing
+<span class='linenumber'>405</span>  *     checks.
+<span class='linenumber'>406</span>  * @export
+<span class='linenumber'>407</span>  * @deprecated Use the checkPage() instance method of the BidiChecker class.
+<span class='linenumber'>408</span>  */</span><span class="WHIT">
+<span class='linenumber'>409</span> </span><span class="NAME">bidichecker.checkPage</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">shouldBeRtl</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_element</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_filters</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>410</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">checker</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">new</span><span class="WHIT"> </span><span class="NAME">bidichecker.BidiChecker</span><span class="PUNC">(</span><span class="NAME">bidichecker.LATEST</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>411</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">checker.checkPage</span><span class="PUNC">(</span><span class="NAME">shouldBeRtl</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_element</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_filters</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>412</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>413</span> 
+<span class='linenumber'>414</span> 
+<span class='linenumber'>415</span> </span><span class="COMM">/**
+<span class='linenumber'>416</span>  * Runs the interactive visual error browsing GUI. If a GUI opened by any prior
+<span class='linenumber'>417</span>  * BidiChecker call in this window is still open, it will be closed and then
+<span class='linenumber'>418</span>  * re-opened.
+<span class='linenumber'>419</span>  * &lt;p>This entry point is deprecated, and is here only for compatibility with
+<span class='linenumber'>420</span>  * any bookmarklets created by users before the class-based API was introduced.
+<span class='linenumber'>421</span>  * All other code should instead construct an instance of
+<span class='linenumber'>422</span>  * <code>bidichecker.BidiChecker</code> and call its <code>checkPage()</code> and
+<span class='linenumber'>423</span>  * <code>runGui()</code> instance methods.
+<span class='linenumber'>424</span>  * @param {!Array.&lt;!bidichecker.Error>} errors An array of errors to be
+<span class='linenumber'>425</span>  *     displayed.
+<span class='linenumber'>426</span>  * @param {boolean=} opt_noPopup Disables opening the error browser in a popup
+<span class='linenumber'>427</span>  *     window.
+<span class='linenumber'>428</span>  * @param {string=} opt_guiAppUrl Location of the GUI files.
+<span class='linenumber'>429</span>  * @export
+<span class='linenumber'>430</span>  * @deprecated Use the runGui() instance method of the BidiChecker class.
+<span class='linenumber'>431</span>  */</span><span class="WHIT">
+<span class='linenumber'>432</span> </span><span class="NAME">bidichecker.runGui</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">errors</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_noPopup</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_guiAppUrl</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>433</span>   </span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">checker</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">new</span><span class="WHIT"> </span><span class="NAME">bidichecker.BidiChecker</span><span class="PUNC">(</span><span class="NAME">bidichecker.LATEST</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>434</span>   </span><span class="KEYW">if</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="NAME">opt_guiAppUrl</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
+<span class='linenumber'>435</span>     </span><span class="NAME">checker.setGuiAppUrl</span><span class="PUNC">(</span><span class="NAME">opt_guiAppUrl</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>436</span>   </span><span class="PUNC">}</span><span class="WHIT">
+<span class='linenumber'>437</span>   </span><span class="NAME">checker.runGuiWithErrors_</span><span class="PUNC">(</span><span class="NAME">errors</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">opt_noPopup</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>438</span> </span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
+<span class='linenumber'>439</span> </span></pre></body></html>
\ No newline at end of file
diff --git a/docs/jsdoc/src_03.html b/docs/jsdoc/src_03.html
index 6251e33..954cebc 100644
--- a/docs/jsdoc/src_03.html
+++ b/docs/jsdoc/src_03.html
@@ -47,7 +47,7 @@
 <span class='linenumber'> 40</span> </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="PUNC">}</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'> 41</span> 
 <span class='linenumber'> 42</span> 
-<span class='linenumber'> 43</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'> 43</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'> 44</span> </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
 <span class='linenumber'> 45</span>     </span><span class="NAME">goog.abstractMethod</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'> 46</span> 
@@ -555,7 +555,7 @@
 <span class='linenumber'>548</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>549</span> 
 <span class='linenumber'>550</span> 
-<span class='linenumber'>551</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>551</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>552</span> </span><span class="NAME">bidichecker.FilterFactory.AndFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="WHIT">
 <span class='linenumber'>553</span>     </span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>554</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">this.filter1_.isSuppressed</span><span class="PUNC">(</span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">&&</span><span class="WHIT">
@@ -585,7 +585,7 @@
 <span class='linenumber'>578</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>579</span> 
 <span class='linenumber'>580</span> 
-<span class='linenumber'>581</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>581</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>582</span> </span><span class="NAME">bidichecker.FilterFactory.AtTextFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="WHIT">
 <span class='linenumber'>583</span>     </span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>584</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">this.atText_</span><span class="WHIT"> </span><span class="PUNC">==</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="NAME">error.getAtText</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT"> </span><span class="STRN">''</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
@@ -615,7 +615,7 @@
 <span class='linenumber'>608</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>609</span> 
 <span class='linenumber'>610</span> 
-<span class='linenumber'>611</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>611</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>612</span> </span><span class="NAME">bidichecker.FilterFactory.AtTextRegexpFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="WHIT">
 <span class='linenumber'>613</span>     </span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>614</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">this.atTextRegexp_.test</span><span class="PUNC">(</span><span class="NAME">error.getAtText</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT"> </span><span class="STRN">''</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
@@ -644,7 +644,7 @@
 <span class='linenumber'>637</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>638</span> 
 <span class='linenumber'>639</span> 
-<span class='linenumber'>640</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>640</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>641</span> </span><span class="NAME">bidichecker.FilterFactory.FollowedByTextFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
 <span class='linenumber'>642</span>     </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>643</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">this.followedByText_</span><span class="WHIT"> </span><span class="PUNC">==</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="NAME">error.getFollowedByText</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT"> </span><span class="STRN">''</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
@@ -675,7 +675,7 @@
 <span class='linenumber'>668</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>669</span> 
 <span class='linenumber'>670</span> 
-<span class='linenumber'>671</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>671</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>672</span> </span><span class="NAME">bidichecker.FilterFactory.FollowedByTextRegexpFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
 <span class='linenumber'>673</span>     </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>674</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">this.followedByTextRegexp_.test</span><span class="PUNC">(</span><span class="NAME">error.getFollowedByText</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT"> </span><span class="STRN">''</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
@@ -704,7 +704,7 @@
 <span class='linenumber'>697</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>698</span> 
 <span class='linenumber'>699</span> 
-<span class='linenumber'>700</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>700</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>701</span> </span><span class="NAME">bidichecker.FilterFactory.LocationClassFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
 <span class='linenumber'>702</span>     </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>703</span>   </span><span class="KEYW">for</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">i</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NUMB">0</span><span class="PUNC">;</span><span class="WHIT"> </span><span class="NAME">i</span><span class="WHIT"> </span><span class="PUNC">&lt;</span><span class="WHIT"> </span><span class="NAME">locationElements.length</span><span class="PUNC">;</span><span class="WHIT"> </span><span class="PUNC">++</span><span class="NAME">i</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
@@ -747,7 +747,7 @@
 <span class='linenumber'>740</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>741</span> 
 <span class='linenumber'>742</span> 
-<span class='linenumber'>743</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>743</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>744</span> </span><span class="NAME">bidichecker.FilterFactory.LocationClassRegexpFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
 <span class='linenumber'>745</span>     </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>746</span>   </span><span class="KEYW">for</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">i</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NUMB">0</span><span class="PUNC">;</span><span class="WHIT"> </span><span class="NAME">i</span><span class="WHIT"> </span><span class="PUNC">&lt;</span><span class="WHIT"> </span><span class="NAME">locationElements.length</span><span class="PUNC">;</span><span class="WHIT"> </span><span class="PUNC">++</span><span class="NAME">i</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
@@ -788,7 +788,7 @@
 <span class='linenumber'>781</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>782</span> 
 <span class='linenumber'>783</span> 
-<span class='linenumber'>784</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>784</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>785</span> </span><span class="NAME">bidichecker.FilterFactory.LocationIdFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="WHIT">
 <span class='linenumber'>786</span>     </span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>787</span>   </span><span class="KEYW">for</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">i</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NUMB">0</span><span class="PUNC">;</span><span class="WHIT"> </span><span class="NAME">i</span><span class="WHIT"> </span><span class="PUNC">&lt;</span><span class="WHIT"> </span><span class="NAME">locationElements.length</span><span class="PUNC">;</span><span class="WHIT"> </span><span class="PUNC">++</span><span class="NAME">i</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
@@ -825,7 +825,7 @@
 <span class='linenumber'>818</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>819</span> 
 <span class='linenumber'>820</span> 
-<span class='linenumber'>821</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>821</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>822</span> </span><span class="NAME">bidichecker.FilterFactory.LocationIdRegexpFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
 <span class='linenumber'>823</span>     </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>824</span>   </span><span class="KEYW">for</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="KEYW">var</span><span class="WHIT"> </span><span class="NAME">i</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="NUMB">0</span><span class="PUNC">;</span><span class="WHIT"> </span><span class="NAME">i</span><span class="WHIT"> </span><span class="PUNC">&lt;</span><span class="WHIT"> </span><span class="NAME">locationElements.length</span><span class="PUNC">;</span><span class="WHIT"> </span><span class="PUNC">++</span><span class="NAME">i</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
@@ -865,7 +865,7 @@
 <span class='linenumber'>858</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>859</span> 
 <span class='linenumber'>860</span> 
-<span class='linenumber'>861</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>861</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>862</span> </span><span class="NAME">bidichecker.FilterFactory.LocationXpathFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
 <span class='linenumber'>863</span>     </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>864</span>   </span><span class="COMM">// TODO(user): This currently matches the path to the element in the</span><span class="WHIT">
@@ -902,7 +902,7 @@
 <span class='linenumber'>895</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>896</span> 
 <span class='linenumber'>897</span> 
-<span class='linenumber'>898</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>898</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>899</span> </span><span class="NAME">bidichecker.FilterFactory.NotFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="WHIT">
 <span class='linenumber'>900</span>     </span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>901</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="PUNC">!</span><span class="NAME">this.filter_.isSuppressed</span><span class="PUNC">(</span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
@@ -936,7 +936,7 @@
 <span class='linenumber'>929</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>930</span> 
 <span class='linenumber'>931</span> 
-<span class='linenumber'>932</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>932</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>933</span> </span><span class="NAME">bidichecker.FilterFactory.OrFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="WHIT">
 <span class='linenumber'>934</span>     </span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>935</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">this.filter1_.isSuppressed</span><span class="PUNC">(</span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT">
@@ -966,7 +966,7 @@
 <span class='linenumber'>959</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>960</span> 
 <span class='linenumber'>961</span> 
-<span class='linenumber'>962</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>962</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>963</span> </span><span class="NAME">bidichecker.FilterFactory.PrecededByTextFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
 <span class='linenumber'>964</span>     </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>965</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">this.precededByText_</span><span class="WHIT"> </span><span class="PUNC">==</span><span class="WHIT"> </span><span class="PUNC">(</span><span class="NAME">error.getPrecededByText</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT"> </span><span class="STRN">''</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
@@ -997,7 +997,7 @@
 <span class='linenumber'>990</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>991</span> 
 <span class='linenumber'>992</span> 
-<span class='linenumber'>993</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>993</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>994</span> </span><span class="NAME">bidichecker.FilterFactory.PrecededByTextRegexpFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT">
 <span class='linenumber'>995</span>     </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>996</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">this.precededByTextRegexp_.test</span><span class="PUNC">(</span><span class="NAME">error.getPrecededByText</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">||</span><span class="WHIT"> </span><span class="STRN">''</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
@@ -1025,7 +1025,7 @@
 <span class='linenumber'>1018</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>1019</span> 
 <span class='linenumber'>1020</span> 
-<span class='linenumber'>1021</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>1021</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>1022</span> </span><span class="NAME">bidichecker.FilterFactory.SeverityFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="WHIT">
 <span class='linenumber'>1023</span>     </span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>1024</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">this.severityThreshold_</span><span class="WHIT"> </span><span class="PUNC">&lt;=</span><span class="WHIT"> </span><span class="NAME">error.getSeverity</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
@@ -1051,7 +1051,7 @@
 <span class='linenumber'>1044</span>     </span><span class="NAME">bidichecker.FilterFactory.ComposableFilter</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
 <span class='linenumber'>1045</span> 
 <span class='linenumber'>1046</span> 
-<span class='linenumber'>1047</span> </span><span class="COMM">/** @inheritDoc */</span><span class="WHIT">
+<span class='linenumber'>1047</span> </span><span class="COMM">/** @override */</span><span class="WHIT">
 <span class='linenumber'>1048</span> </span><span class="NAME">bidichecker.FilterFactory.TypeFilter_.prototype.isSuppressed</span><span class="WHIT"> </span><span class="PUNC">=</span><span class="WHIT"> </span><span class="KEYW">function</span><span class="PUNC">(</span><span class="WHIT">
 <span class='linenumber'>1049</span>     </span><span class="NAME">error</span><span class="PUNC">,</span><span class="WHIT"> </span><span class="NAME">locationElements</span><span class="PUNC">)</span><span class="WHIT"> </span><span class="PUNC">{</span><span class="WHIT">
 <span class='linenumber'>1050</span>   </span><span class="KEYW">return</span><span class="WHIT"> </span><span class="NAME">this.type_</span><span class="WHIT"> </span><span class="PUNC">==</span><span class="WHIT"> </span><span class="NAME">error.getType</span><span class="PUNC">(</span><span class="PUNC">)</span><span class="PUNC">;</span><span class="WHIT">
diff --git a/docs/users_guide.html b/docs/users_guide.html
deleted file mode 100644
index df8b33d..0000000
--- a/docs/users_guide.html
+++ /dev/null
@@ -1,425 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <!--
-    Copyright 2010 Google Inc. All Rights Reserved.
-
-    Use of this source code is governed by an Apache 2.0 License.
-    See the COPYING file for details.
-  -->
-  <head>
-    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
-    <title>BidiChecker User's Guide</title>
-  </head>
-
-  <body style="font-family: arial,sans-serif;">
-
-<h1>BidiChecker User's Guide</h1>
-
-<h2>Table of Contents</h2>
-<ol>
-<li><a href="#TOC-Overview">Overview</a></li>
-<li><a href="#TOC-Getting-started">Getting started</a>
-<ol>
-  <li><a href="#TOC-Getting-BidiChecker">Getting BidiChecker</a></li>
-  <li><a href="#TOC-Platform-support">Platform support</a></li>
-  <li><a href="#TOC-Writing-a-regression">Writing a regression test using the Javascript API</a></li>
-  <li><a href="#TOC-Viewing-BidiChecker-output">Viewing BidiChecker output</a></li>
-</ol></li>
-<li><a href="#TOC-Error-descriptions">Error descriptions and error suppression</a>
-<ol>
-  <li><a href="#TOC-The-error-suppression">The error suppression API</a></li>
-</ol></li>
-<li><a href="#TOC-Catalog-of">Catalog of BiDi checks and errors</a>
-<ol>
-  <li><a href="#TOC-Incorrect-overall">Incorrect overall directionality</a></li>
-  <li><a href="#TOC-Undeclared-opposite">Undeclared opposite-directionality text</a></li>
-  <li><a href="#TOC-Spillover-from-declared">Spillover from declared opposite-directionality element to number</a></li>
-</ol></li>
-<li><a href="#TOC-How-to-devise">How to devise effective test cases</a></li>
-<li><a href="#TOC-Issues-with-HTML">Issues with HTML support</a></li>
-<li><a href="#TOC-Known-problems">Known problems</a></li>
-</ol>
-
-<h2><a name="TOC-Overview"></a>Overview</h2>
-<p><b>BidiChecker</b> is a tool for the automated testing of
-web pages for errors in support of right-to-left (RTL) languages, also known as
-bidirectional (BiDi) because they routinely include left-to-right items such as numbers and Latin-script words and phrases.
-</p>
-<p>BiDi support for a web page is a common
-requirement, even for pages in left-to-right scripts. Any page which accepts user input or displays multilingual content is likely to end up handling bidirectional text at
-some point, as it will eventually encounter data in Arabic, Hebrew or another
-RTL language. Unfortunately, handling bidirectional text can be tricky and requires special processing at every appearance of potentially BiDi data in the UI. (<a href="http://doctype.googlecode.com/svn-history/trunk/bidihowto/index.html">Examples of common BiDi UI bugs can be found here</a>.) As a result, BiDi text support often regresses when a developer adds a new feature and simply forgets about BiDi.
-</p>
-<p>BidiChecker is a library meant to be called from automated test suites that regression-test live web pages in a browser, usually using an automated testing framework such as JSUnit. BidiChecker provides a Javascript API which integrates easily into such a test. The BidiChecker API
-accepts a page element (by default, the body of the top-level document), runs BiDi
-tests on its contents, and returns a list of BiDi errors found,
-including the type of each error, its location on the page and an estimate of its
-level of severity.</p>
-<p>
-Note that using BidiChecker does not require any custom "hooks" or modifications
-to the product under test. New BidiChecker-based tests can be written in addition to the product's existing test suite.</p>
-<p>
-In the future, we plan to provide additional
-front ends for regression testing of applications whose test suites are
-based on other platforms.</p>
-<p>
-BidiChecker is currently in use at several projects inside Google.</p>
-<h2><a name="TOC-Getting-started"></a>Getting started</h2>
-<h3><a name="TOC-Getting-BidiChecker"></a>Getting BidiChecker</h3>
-<p>The BidiChecker source code can be downloaded from <a href="http://code.google.com/p/bidichecker">http://code.google.com/p/bidichecker</a> using the following command:</p>
-<div style="margin-left: 40px; margin-right: 80px">
-<div style="background-color: rgb(223, 223, 223);"><span style="font-family: courier new,monospace; color: rgb(0, 96, 0); font-weight: bold;">
-<code>svn checkout http://bidichecker.googlecode.com/svn/trunk/ bidichecker</code></span></div></div>
-<p>Source code and unit tests can be found in the <tt>src/</tt> subdirectory. This user's guide is in the <tt>docs/</tt> subdirectory, with the complete API documentation in <tt>docs/jsdoc/</tt>. A sample application, along with demonstrations of how BidiChecker can be used to check for BiDi errors, can be found in <tt>samples/reviews/</tt>. The <tt>lib/</tt> subdirectory contains a single-file, precompiled version of BidiChecker named <tt>bidichecker_packaged.js</tt>. Including this one file in the web page to be tested is the usual way to use BidiChecker; you only need BidiChecker's source code if you want to modify BidiChecker or understand its internal workings. For an example of how to use the precompiled package, see <tt>samples/reviews/reviews_packaged_test.html</tt>.</p>
-<p>BidiChecker source code uses the  <a href="http://code.google.com/p/closure-library/">Closure Library</a>, an open-source library of useful Javascript modules. If you want to run a modified version of BidiChecker or run BidiChecker's own unit tests, you will need to install a copy of the Closure Library on your system. To do that, run the following command from the same working directory as you ran the above command:</p>
-<div style="margin-left: 40px; margin-right: 80px">
-<div style="background-color: rgb(223, 223, 223);"><span style="font-family: courier new,monospace; color: rgb(0, 96, 0); font-weight: bold;">
-<code>svn checkout http://closure-library.googlecode.com/svn/trunk/ bidichecker/third_party/closure-library</code></span></div></div>
-<p>BidiChecker does not currently easily support linking with a copy of the Closure Library at a different location. Please note that you do <b>not</b> need to install the Closure Library to use the precompiled version of BidiChecker.</p>
-<p>For an example of how to use BidiChecker with the Closure Library, see <tt>samples/reviews/reviews_closure_test.html</tt>.</p>
-<h3><a name="TOC-Platform-support"></a>Platform support</h3>
-<p>BidiChecker supports all major browsers. Please note that the errors identified by BidiChecker are not specific to the browser platform on which it is run. That is, BidiChecker will report errors that cause display garbling on any browser, even when that does not include the browser on which it was run.</p>
-
-<h3><a name="TOC-Writing-a-regression"></a>Writing a regression test using the Javascript API</h3>
-BidiChecker can be integrated into Javascript automated unit tests based on a testing framework such as the JSUnit package.
-<div>
-<div><br>
-A sample test might look like this:<br>
-<br>
-<div style="margin-left: 40px; margin-right: 80px">
-<div style="background-color: rgb(223, 223, 223);"><span style="font-family: courier new,monospace; color: rgb(0, 96, 0);">
-<code>function testAppWithBidiChecker() {</code><br>
-<code>&nbsp;&nbsp;// Do something to load the application being tested into the page and get it into</code><br>
-<code>&nbsp;&nbsp;// an interesting state for BiDi, e.g. displaying LTR data in an RTL UI.</code><br>
-<code>&nbsp;&nbsp;....</code><br>
-<br>
-<code>&nbsp;&nbsp;// Check for errors in handling BiDi text. First parameter is true to indicate an RTL UI.</code><br>
-<code>&nbsp;&nbsp;// It would be false when testing an LTR UI (with RTL data).</code><br>
-<code>&nbsp;&nbsp;var bidiErrors = bidichecker.checkPage(true, top.document.body);</code><br>
-<code>&nbsp;&nbsp;assertArrayEquals([], errors);  // Should be no BiDi errors!</code><br>
-<code>}</code><br>
-</span>
-</div></div>
-<p>A complete code example, including a simple bilingual application and BidiChecker-based JSUnit tests, can be found in the <b style="font-family: courier new,monospace;">samples/reviews/</b> subdirectory of the download tree.</p>
-</div>
-<div>
-
-<h3><a name="TOC-Viewing-BidiChecker-output"></a>Viewing BidiChecker output</h3>
-<p>The tool will produce a list of error messages, one for each BiDi bug discovered. Below is a sample of the messages. The contents of the error messages will be explained in more detail later on.</p>
-<div style="margin-left: 40px; margin-right: 80px">
-<div style="background-color: rgb(223, 223, 223);"><span style="font-family: courier new,monospace; color: rgb(0, 96, 0); font-weight: bold;">
-<code> [4] Undeclared LTR text: 'The Princess Bride' followed by ': 23' in &lt;div id='reviews'&gt;&lt;div&gt;</code><br>
-<code> [4] Undeclared LTR text: 'Leagues Under the Sea' preceded by '20,000 ' followed by ': 17' in &lt;div id='reviews'&gt;&lt;div&gt;</code>
-</span></div></div>
-
-<p>When running a BidiChecker test interactively, however, it is a lot easier to view the errors right in the page where BidiChecker found them using BidiChecker's interactive error browser. To activate the error browser, call <b style="font-family: courier new,monospace;">bidichecker.runGui(errors)</b> from your test code if <b style="font-family: courier new,monospace;">bidichecker.checkPage()</b> returns errors. This will display a dialog box showing the first error, while highlighting the text that aroused BidiChecker's suspicions:</p>
-
-<div style="display: block; margin-top: 5px; margin-left: 40px; margin-right: auto; margin-bottom: 0pt; text-align: left;"><img src="bidichecker_screenshot.png" border="0" alt="BidiChecker screenshot"></div>
-<br>
-<p>The GUI mode is simple to control: Leaf through the errors with the Prev and Next buttons, or select an error by entering its index number in the input box. Each error in turn is highlighted in a yellow background where it appears on the page. The page will also be scrolled to keep the error's position near the top of the window if possible.</p>
-<p>The error description text can be copied from the dialog box and used in creating a filter to suppress the error if it is spurious, unimportant, or a known bug. Also, the page under test remains accessible, so you can select the page contents near an error and view the HTML source or DOM state using the browser's developer tools capabilities. Note that an error may not always be visibly highlighted, e.g. if its page location is concealed by another page element, or if it is scrolled out of view in a scrollable element.</p>
-<p>Unfortunately, the GUI currently has a major limitation: it will generally not work if more than one test is run from the same test file. Since each test typically manipulates the DOM of the page under test, it is no longer possible to highlight errors on the page after a subsequent test has been run. The GUI can only be relied upon to work correctly if there is only one test in the test file, or alternately if only one test from the file is run (most test runners allow the user to select a single test from a file with several tests).</p>
-</div>
-</div>
-
-<h2><a name="TOC-Error-descriptions"></a>Error descriptions and error suppression</h2>
-<p>BidiChecker's results consist of BiDi error reports. The command-line tool outputs them one-per-line as text to standard output, while in the API they are returned as a list of objects with descriptive fields. Either way, the content is the same.<br>
-</p>
-<p>An error may contain and or all of the following fields:<br>
-</p>
-<ol><li><b>Error type</b> (required). For example, "Undeclared RTL text".<br>
-</li>
-<li><b>Severity level</b> (required). Severity levels consist of integers from 1 to 4, with 1 indicating the most severe and 4 the least. There is no absolute significance to the different severity levels. They are meant to represent a combination of the likelihood that a given error represents a real bug and the likelihood that it causes visible text garbling. Severity levels are determined by heuristics described in the error catalog below.<br>
-</li>
-<li><b>The text at which the error occurs.</b></li>
-<li><b>The text immediately preceding and/or following the error text,</b> where it is useful to indicate the likelihood of garbling or to help locate the error on the page.<br>
-</li>
-<li><b>Page location where the error occurs.</b> This is given as a string containing the nested HTML tags (with attributes) surrounding the first character of the error text, starting from the
-highest-level containing parent element with an "id" attribute. The intent is to give sufficient information about the error location
-to allow the developer to find it in the page and in the code
-generating the page, without including too much extraneous detail. For
-example: "<code>&lt;div id='abc'&gt;&lt;table&gt;&lt;tr&gt;&lt;td align='left'&gt;&lt;p dir='rtl'&gt;</code>".
-Starting with an "id" attribute (if present) guarantees uniqueness at
-that point, though below it we don't indicate which of
-multiple repeated elements is the one in question (for example, which
-table row/cell or which paragraph).  In conjunction with the error text, that should be
-sufficient for identification of the error location.<br>
-</li></ol>
-<div>The sample output above demonstrates how these fields are combined into a textual error message. First the severity level is given in square brackets, followed by the error type, the error text, the preceding and/or following text, and the page location. Delimiters and separators between fields are as shown in the sample.<br>
-<br>
-The error details serve two purposes: <b>Error identification</b> and <b>error suppression</b>.<br>
-<br>
-<b>Error identification</b> is the human task of understanding what an error
-message refers to: what the problem is and where on the page it occurs.<br>
-<br>
-<b>Error suppression</b> is the filtering out of error messages that match a
-set of specifications. Not all "errors" found by BidiChecker
-represent real problems, and it is essential to suppress the generation
-of those that don't, so automated tests run clean until a code change
-results in new suspects. Similarly, after BidiChecker finds real problems, it may take time for them to be fixed. In the meantime, after filing appropriate bug reports, it often makes sense to suppress these errors in the automated tests until the problems have been fixed, so that the tests run clean and new problems are readily noticed.<br>
-<br>
-Each of the fields above may be relevant for suppression. Users may wish to suppress
-errors of a certain type which they know to be spurious everywhere on
-the page, or to ignore low-severity errors. They may know that a
-particular word is falsely reported as an error (for example, "Gmail"
-in a navigation menu), or that a particular area of the page contains
-user-generated content whose BiDi correctness cannot be ensured.<br>
-<br>
-</div>
-<h3><a name="TOC-The-error-suppression"></a>The error suppression API</h3>
-<div>The error suppression mechanism supports the specification and composition of filters on most fields of the Error object, as well as filters based on the error's location on the page.</div>
-<div><br></div>
-<div>Some filter examples:</div>
-<div><br></div>
-<div style="margin-left: 40px; margin-right: 80px; border-collapse: collapse;">
-<div style="background-color: rgb(223, 223, 223); font-family: courier new,monospace; color: rgb(0, 96, 0);">
-<code>var filters = [</code>
-<div><code>&nbsp;&nbsp; &nbsp;// Suppress errors with the&nbsp;</code><b><code>atText</code></b><code>&nbsp;field "&#x5e9;&#x5dc;&#x5d5;&#x5dd;":</code></div>
-<div><code>&nbsp;&nbsp; &nbsp;bidichecker.FilterFactory.atText("\u05e9\u05dc\u05d5\u05dd"),</code></div>
-<div><code><br>&nbsp;&nbsp; &nbsp;// Suppress errors appearing within a page element with the <b>element id</b>&nbsp;"other_id"</code></div>
-<div><code>&nbsp;&nbsp; &nbsp;//&nbsp;(matches any ancestor element, including those of enclosing frames):</code></div>
-<div><code>&nbsp;&nbsp; &nbsp;bidichecker.FilterFactory.locationId("other_id"),</code></div>
-<br>
-<div><code>&nbsp;&nbsp; &nbsp;// Composing multiple filters: Suppress errors of <b>severity levels</b> 3 and 4 and <b>error type</b><br>
-&nbsp;&nbsp; &nbsp;// "Declared RTL spillover to number":</code></div>
-<div><code>&nbsp;&nbsp; &nbsp;</code><span style="font-family: monospace; color: rgb(0, 96, 0);">bidichecker.FilterFactory</span><span style="font-family: monospace; color: rgb(0, 96, 0);">.severityFrom(3)</span><span style="font-family: monospace; color: rgb(0, 96, 0);">.and(</span></div>
-<div><span style="font-family: monospace; color: rgb(0, 96, 0);">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;bidichecker.FilterFactory.type("Declared RTL spillover to number")),</span></div>
-<br>
-<div><code>&nbsp;&nbsp; &nbsp;// Suppress errors within a page element with the <b>class</b> attribute&nbsp;"myclass" and<br>
-&nbsp;&nbsp; &nbsp;// <b>preceded by text</b> matching the regular expression "http:.*":</code></div>
-<div><code>&nbsp;&nbsp; &nbsp;</code><span style="font-family: monospace; color: rgb(0, 96, 0);">bidichecker.FilterFactory</span><code>.</code><code>locationClass("myclass")</code><code>.and(</code></div>
-<div><code>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;bidichecker.FilterFactory.precededByTextRegexp(</code><code>"http:.*"))</code></div>
-<div><code>];</code></div>
-<div><code><br>var errors = bidichecker.checkPage(true, top.document.body, filters);</code></div>
-<div><code>assertArrayEquals([], errors); &nbsp;// Should be no BiDi errors after filtering!</code></div>
-</div>
-</div>
-<br>
-<div>Below is the complete list of filters (static factory methods in the bidichecker.FilterFactory class):</div>
-<div><br>
-<table style="border-color: rgb(136, 136, 136); border-width: 1px; border-collapse: collapse; margin-right: 40px; margin-left: 80px" border="1" cellspacing="0" summary="List of filters supported by BidiChecker">
-<tbody>
-<tr>
-<td><b> Filter name</b></td>
-<td><b> Sample construction</b></td>
-<td><b> Description</b></td>
-</tr>
-<tr>
-<td> and</td>
-<td> bidichecker.FilterFactory.and(filter1, filter2)</td>
-<td> Composes two filters by <b>and</b>-ing their suppressions<span><br>
-</span></td>
-</tr>
-<tr>
-<td> atText</td>
-<td> bidichecker.FilterFactory.atText()</td>
-<td> Matches against the entire <b>atText</b> field of an error</td>
-</tr>
-<tr>
-<td> atTextRegexp</td>
-<td> bidichecker.FilterFactory.atTextRegexp(regexp)</td>
-<td> Matches against the entire <b>atText</b> field of an error</td>
-</tr>
-<tr>
-<td> followedByText<br>
-</td>
-<td> bidichecker.FilterFactory.followedByText(string)</td>
-<td> Matches against the entire <b>followedByText</b> field of an error</td>
-</tr>
-<tr>
-<td> followedByTextRegexp</td>
-<td> bidichecker.FilterFactory.followedByTextRegexp(regexp)</td>
-<td> Matches against the entire <b>followedByText</b> field of an error</td>
-</tr>
-<tr>
-<td> locationClass</td>
-<td> bidichecker.FilterFactory.locationClass(string)</td>
-<td> Matches against an entire <b>class</b> name on any ancestor element containing the error location (including any containing frames)</td>
-</tr>
-<tr>
-<td> locationClassRegexp</td>
-<td> bidichecker.FilterFactory.locationClassRegexp(regexp)</td>
-<td> Matches against an entire <b>class</b> name on any ancestor element containing the error location (including any containing frames)</td>
-</tr>
-<tr>
-<td> locationId</td>
-<td> bidichecker.FilterFactory.locationId(string)</td>
-<td> Matches against an entire <b>id</b> attribute on any ancestor element containing the error location (including any containing frames)</td>
-</tr>
-<tr>
-<td> locationIdRegexp</td>
-<td> bidichecker.FilterFactory.locationIdRegexp(regexp)</td>
-<td> Matches against an entire <b>id</b> attribute on any ancestor element containing the error location (including any containing frames)</td>
-</tr>
-<tr>
-<td> locationXpath</td>
-<td> bidichecker.FilterFactory.locationXpath(string)</td>
-<td> Matches an XPath expression against the element of the error location (including the elements representing any containing frames). This does not match against ancestor elements; to match against everything within a given location, you can add "/*" to the XPath expression. There is currently no mechanism for restricting the XPath match to specific frames. <b>NOTE: XPaths are not currently supported on Internet Explorer.</b></td>
-</tr>
-<tr>
-<td> not</td>
-<td> bidichecker.FilterFactory.not(filter)</td>
-<td> Inverts the meaning of a filter</td>
-</tr>
-<tr>
-<td> or</td>
-<td> bidichecker.FilterFactory.or(filter1, filter2)</td>
-<td> Composes two filters by <b>or</b>-ing their suppressions</td>
-</tr>
-<tr>
-<td> precededByText</td>
-<td> bidichecker.FilterFactory.precededByText(string)</td>
-<td> Matches against the entire <b>precededByText</b> field of an error</td>
-</tr>
-<tr>
-<td> precededByTextRegexp</td>
-<td> bidichecker.FilterFactory.precededByTextRegexp(regexp)</td>
-<td> Matches against the entire <b>precededByText</b> field of an error</td>
-</tr>
-<tr>
-<td> severityFrom</td>
-<td> bidichecker.FilterFactory.severityFrom(severityThreshold)</td>
-<td> Matches any errors with <b>severity</b> at the given threshold, or less severe than it. It is generally advisable to suppress errors of severity level 4; they often indicate insigificant issues.</td>
-</tr>
-<tr>
-<td> type</td>
-<td> bidichecker.FilterFactory.type(typeValue)</td>
-<td> Matches against the exact <b>type</b> field of an error</td>
-</tr>
-</tbody>
-</table>
-<br>
-</div>
-<div>Each filter object also supports instance methods <b>and()</b>, <b>not()</b>, and <b>or()</b> for an alternate way of composing/inverting filters.</div>
-<div>
-<br>
-</div>
-<div>
-<h2><a name="TOC-Catalog-of"></a>Catalog of BiDi checks and errors</h2>
-<p>The "meat" of BidiChecker is the actual BiDi checks. BidiChecker runs a series of checkers on the web page DOM, each of which scans for a particular kind of error and generates error reports. This section catalogs the checks implemented so far and the errors they produce.</p>
-<p><br>
-</p>
-<h3><a name="TOC-Incorrect-overall"></a>Incorrect overall directionality</h3>
-<h4><span style="border-collapse: collapse;">Description<br>
-</span></h4>
-<p><span style="border-collapse: collapse;">Checks whether the overall declared directionality of the web page (or root element being checked) is the same as that intended by the developer (as specified in the call to BidiChecker). If, for example, the developer specified an intended directionality of RTL, but the page body or root element is LTR, an error will be reported. This type of error is always
-severity level 1.</span></p>
-<h4><span style="border-collapse: collapse;">Sample output<br>
-</span></h4>
-<div style="margin-left: 40px; margin-right: 80px">
-<div style="background-color: rgb(223, 223, 223); font-family: courier new,monospace; color: rgb(0, 96, 0);">
-<b><code>[1] Overall directionality not LTR</code></b></div>
-</div>
-<p><a href="http://doctype.googlecode.com/svn-history/trunk/bidihowto/bidi-support-in-a-ui/declaring-page-directionality.html" target="_blank">More information about declaring the overall page directionality.</a></p>
-<br>
-<h3><a name="TOC-Undeclared-opposite"></a>Undeclared opposite-directionality text</h3>
-<h4><span style="border-collapse: collapse;">Description<br>
-</span></h4>
-<p><span style="border-collapse: collapse;">Checks for strongly-directional characters (such as English, Hebrew or Arabic letters) which are in an area declared to have the opposite directionality. Each run of opposite-directionality text
-(possibly mixed in with neutrals) is reported as an error.</span><span style="border-collapse: collapse;"><br>
-</span></p>
-</div>
-<div>
-<h4><span style="border-collapse: collapse;">Why is it a problem?</span></h4>
-<div><span style="border-collapse: collapse;">Undeclared opposite-directionality </span>text is a problem because</div>
-<ul><li><span style="border-collapse: collapse;">Undeclared opposite-directionality </span>text
-(LTR or RTL) is often displayed garbled. The common cases (see the link below for examples) are when it:
-<ul><li>Starts with a number or punctuation or other neutral characters (e.g. copyright symbol).</li>
-<li>Ends with punctuation or other neutral characters.</li>
-<li>Contains embedded text of directionality opposite to it, i.e. in the original directionality.</li></ul></li>
-<li>Even when it is not garbled itself, it can garble the layout
-of the line in which it appears by "sticking" to a logically separate
-opposite-directionality phrase next to it. This is especially
-problematic when these are separated by neutral items like images or
-inputs, since it will all be laid out in reverse.</li></ul>
-<h4>Why it might not be a problem<span style="border-collapse: collapse;"><br>
-</span></h4>
- Undeclared
-opposite-directionality text is not necessarily a problem. There are
-messages that you never want translated, e.g. "Gmail". If their text
-does not fall into one of the troublesome categories above and does not
-happen to lie next to another undeclared opposite-directionality
-phrase, no visible problem will result.
-<h4><span style="border-collapse: collapse;">Sample output<br>
-</span></h4>
-<div style="margin-left: 40px; margin-right: 80px">
-<div style="background-color: rgb(223, 223, 223); font-family: courier new,monospace; color: rgb(0, 96, 0);">
-<b><code>[2] Undeclared RTL text: '&#x5e9;&#x5dc;&#x5d5;&#x5dd;' followed by '.' in &lt;p id='resultStats'&gt;&lt;b&gt;</code></b></div></div>
-<div><span style="border-collapse: collapse;"><br>
-If the run of
-opposite-directionality text is immediately preceded or followed by a
-run of neutral characters, those characters are reported as the error
-context fields and the error severity is set at level 2. If there is no
-such adjacent run of neutral characters, the error severity is 3. (But see the next section.)<br>
-<br>
-</span><span style="border-collapse: collapse;"><a href="http://doctype.googlecode.com/svn-history/trunk/bidihowto/bidi-support-in-a-ui/declaring-opposite-directionality.html" target="_blank">More information about declaring opposite-directionality text.</a></span><span style="border-collapse: collapse;"><br>
-</span>
-<h4><span style="border-collapse: collapse;">Severity demotion of errors in areas of explicitly-declared directionality</span></h4>
-<span style="border-collapse: collapse;">In certain circumstances, the severity of undeclared opposite-directionality text errors is demoted to 4. If an element other than the root element has an explicitly-declared directionality (i.e., a "dir" attribute), and that element also does not contain any block-level elements (i.e., it is the lowest-level block in its subtree), then BiDi errors inside that element's subtree are assigned the lowest severity. This is based on the assumption that the explicit declaration of directionality indicates that the code which generated this part of the page has somehow deliberately assessed its directionality. Rather than second-guess the developers, we demote the severity of error reports in that subtree. It may, for example, represent a block of user-generated content included from an external website; errors in such content are not the responsibility of the application.<br>
-<br>
-This heuristic is far from perfect, and we may revisit it as necessary.<br>
-<br>
-</span></div>
-<h3><a name="TOC-Spillover-from-declared"></a>Spillover from declared opposite-directionality element to number</h3>
-<h4>Description<br>
-</h4>
-<p>When an opposite-directionality element is followed by a number (possibly with
-intervening neutral characters), the <a href="http://unicode.org/reports/tr9/" target="_blank">standard Unicode bidi algorithm</a> extends the
-opposite-directionality region to encompass the subsequent number. This
-can, and often does, cause text garbling. For examples, follow the link below.<br>
-<br>
-We identify spillover by the following heuristic criteria:<br>
-</p>
-<ol><li>When an HTML element with a 'dir' attribute closes, and
-this causes a change in the current declared directionality, the
-element becomes a spillover candidate.</li>
-<li>If we then encounter a
-text node containing a number, with only neutral characters preceding
-it, a spillover error has been identified.</li>
-<li>However, if
-following the spillover candidate we encounter: a) a text node
-containing a strongly-directional character, b) the opening of an
-element with a 'dir' attribute, c) the closing of an element with a
-'dir' attribute which does not change the current directionality, or d)
-the opening or closing of a block-level element - then the spillover
-candidate is canceled.</li></ol>
-<h4>Sample output</h4>
-<div style="margin-left: 40px; margin-right: 80px">
-<div style="background-color: rgb(223, 223, 223);"><span style="font-family: courier new,monospace; color: rgb(0, 96, 0);">
-<b><code>[2]
-Declared LTR spillover to number: '1' preceded by '2001 A Space Odyssey
-Opening' in &lt;ol id='rso'&gt;&lt;li class='g'&gt;&lt;table
-class='ts'&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width='290' valign='top'
-colspan='1'&gt;</code></b>
-</span></div></div>
-<br>
-Spillover errors have severity level 2. As with undeclared opposite-directionality text, errors in an area of explictly-declared directionality are demoted to severity level 4 (see above).<br>
-<br>
-<a href="http://doctype.googlecode.com/svn-history/trunk/bidihowto/bidi-support-in-a-ui/resetting-directionality.html" target="_blank">More information about preventing spillover errors.</a><br>
-<br>
-<h2><a name="TOC-How-to-devise"></a>How to devise effective test cases</h2>
-Just running BidiChecker on random pages of your application may reveal some BiDi support errors, but it is unlikely to be an effective approach to BiDi testing. To start with the obvious, if you run BiDi checks on a page with a left-to-right UI and contents in a left-to-right language, you probably won't find any errors, but neither would you have tested the handling of right-to-left text! An application with an LTR UI should at the minimum run BidiChecker on each page while displaying RTL text contents. For example, a search application should test pages with an RTL search query. If your application also supports RTL UIs, they should be tested both with RTL contents and with LTR contents, as each one may reveal different errors.<br>
-<br>
-Keep in mind that most user input fields, and output which displays them, should be able to support RTL contents, even on an LTR page. Hebrew- and Arabic-speaking users may access web content or enter data in their native languages, even if the UI is in English. There are exceptions; fields such as phone numbers, currency values or e-mail addresses need only support LTR data (though the human name associated with an e-mail account may well be RTL). But as a rule, any data field your application displays may need to handle RTL text. Thorough testing should include displaying RTL contents in every such field and checking the page with BidiChecker.<br>
-<br>
-<h2><a name="TOC-Issues-with"></a>Issues with HTML support</h2>
-How BidiChecker handles various features of HTML:<br>
-<ol><li><b>Undisplayed text.</b> Content designated as "display:none" is ignored by BidiChecker. If a page has elements which are conditionally displayed when something is clicked, for example, they will not be checked while invisible.</li>
-<li><b>Frames.</b> When traversing the DOM of the page, BidiChecker also enters the contents of frames (either FRAME or IFRAME elements). The frame's location is appended to the element's location description, such as: "<b style="font-family: courier new,monospace;">in &lt;div id='abc'&gt;&lt;p&gt; in &lt;iframe id='frame1'&gt;</b>". In the case of FRAMEs making up the top-level page passed to
-BidiChecker, their overall directionality is checked to match the
-specified value; in the case of IFRAMEs and FRAMEs below IFRAMEs, their overall
-directionality is not checked. If a frame's contents are hosted on a different domain, they are not checked; the Javascript security model makes them inaccessible, and you probably don't intend to check them anyway.</li>
-<li><b>Unicode BiDi characters.</b> BidiChecker does not yet handle <a href="http://www.w3.org/TR/unicode-xml/#Bidi" target="_blank">Unicode BiDi embedding control characters</a>. This means that in the rare situation where embedding control characters are used to fix a BiDi bug, such as in <b style="font-family: courier new,monospace;">&lt;option&gt;</b> elements, BidiChecker will report the bug anyway. In the rarer circumstance where incorrectly used embedding control characters may introduce a bug, the bug will not be identified.</li>
-<li><b>Layout garbling of non-text inline elements.</b> Certain page elements, such as inputs and images, are affected by BiDi layout garbling bugs as if they were neutral characters. This is not yet identified.</li>
-<li><b>&lt;noscript&gt; elements.</b> The contents of <b>noscript</b> tags (which are meant to be rendered when scripting is disabled) are not checked by BidiChecker; anything inside them is skipped.</li></ol>
-<h2><a name="TOC-Known-problems"></a>Known problems</h2>
-<ol><li>The GUI does not work correctly if more than one test is run from a given test file; otherwise, subsequent tests may corrupt the DOM of the test for which the GUI is run, making it unusable.</li>
-<li>The dialog box of the GUI mode does not work correctly when run on some pages.</li>
-<li>The GUI mode does not interact well with frameset-style frames. The dialog box will always appear in the first frame on the page, where it may not fit or be inaccessible or invisible.</li>
-<li>If an error's page location is already on a yellow background, or is scrolled out of view in a scrollable component, it will not be visible when highlighted by the GUI.<br>
-</li>
-<li>No support yet for Unicode BiDi embedding control characters.</li></ol>
-</div>
-
-  </body>
-</html>
diff --git a/docs/users_guide/bidichecker_screenshot.png b/docs/users_guide/bidichecker_screenshot.png
new file mode 100644
index 0000000..d30233d
--- /dev/null
+++ b/docs/users_guide/bidichecker_screenshot.png
Binary files differ
diff --git a/docs/users_guide/catalog_of_checks.html b/docs/users_guide/catalog_of_checks.html
new file mode 100644
index 0000000..60c0a6f
--- /dev/null
+++ b/docs/users_guide/catalog_of_checks.html
@@ -0,0 +1,343 @@
+<!DOCTYPE html>
+<html>
+  <!--
+      Copyright 2010 Google Inc. All Rights Reserved.
+
+      Use of this source code is governed by an Apache 2.0 License.
+      See the COPYING file for details.
+    -->
+
+
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <link href="users_guide.css" rel="stylesheet" type="text/css">
+
+    <title>BidiChecker User's Guide</title>
+  </head>
+
+  <body>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%"><a href="error_descriptions.html">&lt;&lt; Error descriptions and error suppression &lt;&lt;</a></td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%"><a href="how_to_devise.html">&gt;&gt; How to devise effective test cases &gt;&gt;</a></td>
+    </tr></table>
+
+    <hr>
+
+    <h1><a href="index.html">BidiChecker User's Guide</a></h1>
+
+    <h2>5. Catalog of checks</h2>
+
+        <p>The "meat" of BidiChecker is the actual bidi
+    checks. BidiChecker runs a series of checkers on the web page DOM,
+    each of which scans for a particular kind of error and generates
+    error reports. This section catalogs the checks implemented so far
+    and the errors they produce.</p>
+
+    <ul>
+      <li><a href="#IncorrectOverall">Incorrect overall directionality</a></li>
+      <li><a href="#UndeclaredText">Undeclared opposite-directionality text</a>
+      </li>
+      <li><a href="#UndeclaredAttributes">
+          Undeclared opposite-directionality attributes</a></li>
+      <li><a href="#SpilloverToNumber">
+          Spillover from declared opposite-directionality element to number
+      </a></li>
+    </ul>
+
+    <h3><a name="IncorrectOverall">Incorrect overall directionality</a></h3>
+
+    <h4>Description</h4>
+
+    <p>Checks whether the overall declared directionality of the web
+      page (or root element being checked) is the same as that intended
+      by the developer (as specified in the call to BidiChecker). If,
+      for example, the developer specified an intended directionality of
+      RTL, but the page body or root element is LTR, an error will be
+      reported. This type of error is always severity level 1.</p>
+
+    <h4>Sample output</h4>
+
+    <div class="codeblock"><code>[1] Overall directionality not LTR</code>
+    </div>
+
+    <p><a href="http://doctype.googlecode.com/svn-history/trunk/bidihowto/bidi-support-in-a-ui/declaring-page-directionality.html"
+          target="_blank">More
+    information about declaring the overall page directionality.</a></p>
+
+
+    <h3><a name="UndeclaredText">Undeclared opposite-directionality
+        text</a></h3>
+
+    <h4>Description</h4>
+
+    <p>Checks for strongly-directional characters (such as English,
+      Hebrew or Arabic letters) which are in an area declared to have
+      the opposite directionality. Each run of opposite-directionality
+      text (possibly mixed in with neutrals) is reported as an
+      error.</p>
+
+    <p>When testing bidi support, RTL text is sometimes simulated by surrounding
+      English letters with the Unicode control characters RLO and PDF, forcing
+      the English text to behave like right-to-left characters. This is
+      sometimes known as "Fake Bidi" or "Fake RTL". Starting from revision 2,
+      the undeclared opposite-directionality checker also generates an error for
+      fake-RTL text in an LTR context.</p>
+
+    <h4>Why is it a problem?</h4>
+
+    <p>Undeclared opposite-directionality text is a problem because</p>
+
+    <ul>
+      <li>Undeclared opposite-directionality text (LTR or RTL) is
+        often displayed garbled. The common cases (see the link below for
+        examples) are when it:
+        <ul>
+          <li>Starts with a number or punctuation or other neutral
+            characters (e.g. copyright symbol).</li>
+          <li>Ends with punctuation or other neutral characters.</li>
+          <li>Contains embedded text of directionality opposite to it,
+            i.e. in the original directionality.</li>
+        </ul>
+      </li>
+      <li>Even when it is not garbled itself, it can garble the layout
+        of the line in which it appears by "sticking" to a logically
+        separate opposite-directionality phrase next to it. This is
+        especially problematic when these are separated by neutral
+        items like images or inputs, since it will all be laid out in
+        reverse.</li></ul>
+
+    <h4>Why it might not be a problem</h4>
+
+    <p>Undeclared opposite-directionality text is not necessarily a
+      problem. There are messages that you never want translated,
+      e.g. "Gmail". If their text does not fall into one of the troublesome
+      categories above and does not happen to lie next to another undeclared
+      opposite-directionality phrase, no visible problem will result.</p>
+
+    <h4>Sample output</h4>
+
+    <div class="codeblock">
+      <code>[2] Undeclared RTL text: '&#x5e9;&#x5dc;&#x5d5;&#x5dd;'
+        followed by '.' in &lt;p id='resultStats'&gt;&lt;b&gt;</code></div>
+
+    <p>If the run of opposite-directionality text is immediately preceded
+      or followed by a run of neutral characters, those characters are
+      reported as the error context fields and the error severity is set at
+      level 2. If there is no such adjacent run of neutral characters, the
+      error severity is 3. (But see the next section.)</p>
+
+    <p><a href="http://doctype.googlecode.com/svn-history/trunk/bidihowto/bidi-support-in-a-ui/declaring-opposite-directionality.html"
+          target="_blank">More
+    information about declaring opposite-directionality text.</a></p>
+
+
+    <h4>Severity demotion of errors in areas of explicitly-declared
+    directionality</h4>
+
+    <p>In certain circumstances, the severity of undeclared
+      opposite-directionality text errors is demoted to 4. If an element
+      other than the root element has an explicitly-declared directionality
+      (i.e., a "dir" attribute), and that element also does not contain any
+      block-level elements (i.e., it is the lowest-level block in its
+      subtree), then bidi errors inside that element's subtree are assigned
+      the lowest severity. This is based on the assumption that the explicit
+      declaration of directionality indicates that the code which generated
+      this part of the page has somehow deliberately assessed its
+      directionality. Rather than second-guess the developers, we demote the
+      severity of error reports in that subtree. It may, for example,
+      represent a block of user-generated content included from an external
+      website; errors in such content are not the responsibility of the
+      application.</p>
+
+    <p>This heuristic is far from perfect, and we may revisit it as
+      necessary.</p>
+
+
+    <h3><a name="UndeclaredAttributes">
+        Undeclared opposite-directionality attributes</a></h3>
+
+    <h4>Description</h4>
+
+    <p>Checks text-valued attributes, such as input fields, button labels and
+      tooltips ("title" and "alt" attributes), looking for those which have
+      strongly-directional characters (such as English, Hebrew or Arabic
+      letters) with the opposite of the declared directionality, while
+      containing no letters with the declared directionality itself. Each such
+      attribute is reported as an error.</p>
+
+    <p>This set of checks was introduced in Revision 2, and is not active in
+      tests run at Revision 1.</p>
+
+    <p>The following attribute types are checked:</p>
+
+    <ul>
+      <li>On all elements: "title" attributes (used to display tooltips).</li>
+      <li>On "input" elements of type "text", "search", "button", "reset" and
+        "submit": the "value" attribute (contains the input field value or the
+        button label).</li>
+      <li>On "input" elements of type "file": checks that the element is
+        declared as left-to-right.
+      <li>On "img" elements and on "input" elements of type="image": "alt"
+        attributes (used to display tooltips).</li>
+      <li>On "textarea" elements: the "value" attribute (contains the textarea
+        contents).</li>
+    </ul>
+
+    <p>These attributes have several points in common:</p>
+    <ul>
+      <li>The text is contained not in a text node in the DOM, but in a property
+        of the element.</li>
+      <li>The text they contain is not part of the text flow around them.</li>
+      <li>The directionality must be declared for the entire element, as the
+        text does not support internal markup with spans of different
+        directions.</li>
+    </ul>
+
+    <p>Note that when the attribute value contains both LTR and RTL characters,
+      it is not flagged as an error regardless of its declared directionality.
+      This is because only one directionality can be declared for the whole
+      value, and different applications use different criteria to estimate the
+      directionality of mixed-directionality text. <b>That it is not flagged as
+      an error does not necessarily mean that there is no problem.</b> In fact,
+      when the wrong directionality is declared for a mixed-directionality
+      value, very severe garbling usually results. We just have no way of
+      knowing whether there is a problem or not, and the application has no way
+      of avoiding the situation.</p>
+
+    <p>This set of checks can produce errors of the following types:</p>
+    <ul>
+      <li>File input not LTR</li>
+      <li>Undeclared LTR alt text</li>
+      <li>Undeclared RTL alt text</li>
+      <li>Undeclared LTR button label</li>
+      <li>Undeclared RTL button label</li>
+      <li>Undeclared LTR input value</li>
+      <li>Undeclared RTL input value</li>
+      <li>Undeclared LTR textarea value</li>
+      <li>Undeclared RTL textarea value</li>
+      <li>Undeclared LTR title text</li>
+      <li>Undeclared RTL title text</li>
+    </ul>
+
+    <h4>Why is it a problem?</h4>
+
+    <p>As with undeclared opposite-directionality inline text, text garbling can
+      affect text attributes with the wrong directionality declaration.
+      Also, entering text into an input or textarea with the wrong
+      directionality is a real pain for the user.</p>
+
+    <p>Ideally, text inputs (&lt;input type=text|search&gt; and
+      &lt;textarea&gt;) in which the user could enter a value of either
+      direction should change their directionality automatically on the fly
+      depending on the value the user has entered so far. Functions which
+      implement this can be found in Javascript libraries and template systems,
+      such as Closure's
+      <a href="http://closure-library.googlecode.com/svn/docs/closure_goog_i18n_bidi.js.html"
+         target="_blank">goog.i18n.bidi.estimateDirection()</a>.</p>
+
+    <p>In cases where the intended directionality of the title attribute does
+      not match that of some other text property, such as an input's text
+      content or a button's label or an image's alt attribute, place a span or
+      div around the element, move the title attribute there, and give the two
+      elements different directionalities.</p>
+
+
+    <h4>Why it might not be a problem</h4>
+
+    <p>If the text value is known to contain only one direction of text, and not
+      to start or end with punctuation or other direction-neutral characters,
+      the appearance of the text will not in practice be different when the
+      wrong directionality is declared. In such cases, the error severity is
+      set at level 3; otherwise, it will be 2.</p>
+
+    <p>However, if the element with the text-valued attribute itself has a "dir"
+      attribute (or a "direction" style applied directly or via a style file),
+      the severity will be demoted to 4. This is based on the assumption that
+      the explicit declaration of directionality indicates that the code which
+      generated this part of the page has somehow deliberately assessed its
+      directionality. Rather than second-guess the developers, we demote the
+      severity of error reports for that element.</p>
+
+    <p>On the other hand, errors in textarea or input values always get severity
+      1 due to the nuisance to users of entering data in a box with the wrong
+      directionality.</p>
+
+
+    <h4>Sample output</h4>
+
+    <div class="codeblock">
+      <code>
+        [2] Undeclared RTL textarea value: '&#x5e9;&#x5dc;&#x5d5;&#x5dd;'
+        followed by '.' in &lt;p id='userinput'&gt;&lt;textarea&gt;<br>
+        [3] Undeclared LTR input value: 'Shalom' in &lt;p
+        dir='rtl'&gt;&lt;input type='text' value='Shalom'&gt;<br>
+        [4] Undeclared LTR title text: 'Hello' in &lt;p&gt;&lt;div dir='rtl'
+        title='Hello'&gt; <br>
+        [2] Undeclared RTL alt text: '&#x5e9;&#x5dc;&#x5d5;&#x5dd;' followed by
+        '!' in &lt;p&gt;&lt;img alt='&#x5e9;&#x5dc;&#x5d5;&#x5dd;!'
+        src='http://fake.url/'&gt;<br>
+        [2] File input not LTR in &lt;p dir='rtl'&gt;&lt;input type='file'&gt;
+    </code></div>
+
+
+    <h3><a name="SpilloverToNumber">Spillover from declared
+        opposite-directionality element to number</a></h3>
+
+    <h4>Description</h4>
+
+    <p>When an opposite-directionality element is followed by a number
+      (possibly with intervening neutral characters),
+      the <a href="http://unicode.org/reports/tr9/" target="_blank">standard
+        Unicode bidi algorithm</a> extends the opposite-directionality region
+      to encompass the subsequent number. This can, and often does, cause
+      text garbling. For examples, follow the link below.</p>
+
+    <p>We identify spillover by the following heuristic criteria:</p>
+
+    <ul><li>When an HTML element with a 'dir' attribute closes, and this
+        causes a change in the current declared directionality, the element
+        becomes a spillover candidate.</li>
+      <li>If we then encounter a text node containing a number, with only
+        neutral characters preceding it, a spillover error has been
+        identified.</li>
+      <li>However, if following the spillover candidate we encounter: a) a
+        text node containing a strongly-directional character, b) the opening
+        of an element with a 'dir' attribute, c) the closing of an element
+        with a 'dir' attribute which does not change the current
+        directionality, or d) the opening or closing of a block-level element
+        - then the spillover candidate is canceled.</li></ul>
+
+    <h4>Sample output</h4>
+
+    <div class="codeblock">
+      <code>[2] Declared LTR spillover to
+          number: '1' preceded by 'The Unbearable Light&hellip;' in
+          &lt;ol id='rso'&gt;&lt;li class='g'&gt;&lt;table
+          class='ts'&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width='290' valign='top'
+          colspan='1'&gt;
+      </code>
+    </div>
+
+    <p>Spillover errors have severity level 2. As with undeclared
+      opposite-directionality text, errors in an area of explictly-declared
+      directionality are demoted to severity level 4 (see above).</p>
+
+    <p><a href="http://doctype.googlecode.com/svn-history/trunk/bidihowto/bidi-support-in-a-ui/resetting-directionality.html"
+          target="_blank">More
+    information about preventing spillover errors.</a></p>
+
+
+    <hr>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%"><a href="error_descriptions.html">&lt;&lt; Error descriptions and error suppression &lt;&lt;</a></td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%"><a href="how_to_devise.html">&gt;&gt; How to devise effective test cases &gt;&gt;</a></td>
+    </tr></table>
+
+  </body>
+</html>
diff --git a/docs/users_guide/closing_notes.html b/docs/users_guide/closing_notes.html
new file mode 100644
index 0000000..940c135
--- /dev/null
+++ b/docs/users_guide/closing_notes.html
@@ -0,0 +1,132 @@
+<!DOCTYPE html>
+<html>
+  <!--
+      Copyright 2010 Google Inc. All Rights Reserved.
+
+      Use of this source code is governed by an Apache 2.0 License.
+      See the COPYING file for details.
+    -->
+
+
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <link href="users_guide.css" rel="stylesheet" type="text/css">
+
+    <title>BidiChecker User's Guide</title>
+  </head>
+
+  <body>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%"><a href="how_to_devise.html">&lt;&lt; How to devise effective test cases &lt;&lt;</a></td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%">&nbsp;</td>
+    </tr></table>
+
+    <hr>
+
+    <h1><a href="index.html">BidiChecker User's Guide</a></h1>
+
+    <h2>7. Closing notes</h2>
+
+        <ul>
+      <li><a href="#HtmlIssues">Issues with HTML support</a></li>
+      <li><a href="#KnownProblems">Known problems</a></li>
+    </ul>
+
+    <h3><a name="HtmlIssues">Issues with HTML support</a></h3>
+
+    <p>Certain features of HTML require special handling:</p>
+
+    <ul>
+      <li><b>Undisplayed text.</b> Content designated as
+        "display:none" is ignored by BidiChecker. If a page has elements
+        which are conditionally displayed when something is clicked, for
+        example, they will not be checked while invisible.</li>
+
+      <li><b>Frames.</b> When traversing the DOM of the page,
+        BidiChecker also enters the contents of frames (either FRAME or IFRAME
+        elements). The frame's location is appended to the element's location
+        description, such as: "<span class="inline-code">in
+          &lt;div id='abc'&gt;&lt;p&gt; in &lt;iframe id='frame1'&gt;</span>".
+        In the case of FRAMEs making up the top-level page passed to
+        BidiChecker, their overall directionality is checked to match the
+        specified value; in the case of IFRAMEs and FRAMEs below IFRAMEs, their
+        overall directionality is not checked. If a frame's contents are hosted
+        on a different domain, they are not checked; the Javascript security
+        model makes them inaccessible, and you probably don't intend to check
+        them anyway.
+      </li>
+
+      <li><b>Unicode bidi characters.</b> BidiChecker does not yet handle
+        <a href="http://www.w3.org/TR/unicode-xml/#Bidi" target="_blank">Unicode
+        bidi embedding control characters</a>. This
+        means that in the rare situation where embedding control characters
+        are used to fix a bidi bug, such as
+        in <b>&lt;option&gt;</b> elements, BidiChecker will report
+        the bug anyway. In the rarer circumstance where incorrectly used
+        embedding control characters may introduce a bug, the bug will not be
+        identified. However, BidiChecker currently <b>does</b> correctly
+        handle the
+        <a href="http://code.google.com/p/pseudolocalization-tool/"
+           target="_blank">Fake
+        Bidi pseudolocale</a>, treating Fake Bidi messages as RTL text when
+        searching for undeclared LTR text. (Below revision 2, it is only
+        treated as RTL when looking for undeclared LTR text, but not when
+        looking for undeclared RTL text.)</li>
+
+      <li><b>Layout garbling of non-text inline elements.</b> Certain page
+        elements, such as inputs and images, are affected by bidi layout
+        garbling bugs as if they were neutral characters. This is not yet
+        identified.</li>
+
+      <li><b>&lt;noscript&gt; elements.</b> The contents
+        of <b>noscript</b> tags (which are meant to be rendered when
+        scripting is disabled) are not checked by BidiChecker; anything inside
+        them is skipped.</li>
+    </ul>
+
+
+    <h3><a name="KnownProblems">Known problems</a></h3>
+
+    <ul>
+      <li>The GUI may not work correctly if more than one test is run from a
+        given JavaScript test file. Assuming each test navigates the application
+        and modifies the DOM of the page, errors identified by a run of
+        BidiChecker in one test may refer to DOM elements which are modified or
+        deleted by a subsequent test. This will leave a malfunctioning GUI,
+        which will be unable to highlight some or all of the error locations.
+        Furthermore, even if errors are found in more than one test, only one
+        instance of the GUI will be available. If the GUI is to be run from
+        automated tests, it is recommended to structure the system so as to run
+        only one test per test page.</li>
+
+      <li>The in-page dialog box of the GUI mode does not work correctly
+        when run on some pages. For example, in a page based on frameset-style
+        frames, the dialog box will always appear in the first frame on the
+        page, where it may not fit or may be inaccessible or invisible.
+        Generally you should prefer to run the GUI in popup mode when possible.
+      </li>
+
+      <li>If an error's page location is scrolled out of view in a scrollable
+        component, covered by another element, or generally hidden in some way
+        (other than by setting <span class="inline-code">display:none</span>,
+        which would prevent BidiChecker reporting an error on it in the first
+        place), it will not be visible when highlighted by the GUI.</li>
+    </ul>
+
+
+
+
+    <hr>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%"><a href="how_to_devise.html">&lt;&lt; How to devise effective test cases &lt;&lt;</a></td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%">&nbsp;</td>
+    </tr></table>
+
+  </body>
+</html>
diff --git a/docs/users_guide/error_descriptions.html b/docs/users_guide/error_descriptions.html
new file mode 100644
index 0000000..103762c
--- /dev/null
+++ b/docs/users_guide/error_descriptions.html
@@ -0,0 +1,291 @@
+<!DOCTYPE html>
+<html>
+  <!--
+      Copyright 2010 Google Inc. All Rights Reserved.
+
+      Use of this source code is governed by an Apache 2.0 License.
+      See the COPYING file for details.
+    -->
+
+
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <link href="users_guide.css" rel="stylesheet" type="text/css">
+
+    <title>BidiChecker User's Guide</title>
+  </head>
+
+  <body>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%"><a href="writing_regression_tests.html">&lt;&lt; Writing regression tests &lt;&lt;</a></td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%"><a href="catalog_of_checks.html">&gt;&gt; Catalog of checks &gt;&gt;</a></td>
+    </tr></table>
+
+    <hr>
+
+    <h1><a href="index.html">BidiChecker User's Guide</a></h1>
+
+    <h2>4. Error descriptions and error suppression</h2>
+
+        <p>BidiChecker's results consist of bidi error reports. In the API they
+      are returned as a list of objects with descriptive fields. The
+      interactive GUI displays them in rows of a table, sortable by field.
+      Regardless of how BidiChecker is invoked, the content is the same.</p>
+
+    <p>An error may contain and or all of the following fields:</p>
+
+    <ul><li><b>Error type</b> (required). For example, "Undeclared RTL
+        text".</li>
+      <li><b>Severity level</b> (required). Severity levels consist of integers
+        from 1 to 4, with 1 indicating the most severe and 4 the least. There is
+        no absolute significance to the different severity levels. They are
+        meant to represent a combination of the likelihood that a given error
+        represents a real bug and the likelihood that it causes visible text
+        garbling. Severity levels are determined by heuristics described in the
+        error catalog below.</li>
+      <li><b>The text at which the error occurs.</b></li>
+      <li><b>The text immediately preceding and/or following the error text,</b>
+        where it is useful to indicate the likelihood of garbling or to help
+        locate the error on the page.</li>
+      <li><b>Page location where the error occurs.</b> This is given as a string
+        containing the nested HTML tags (with attributes) surrounding the first
+        character of the error text, starting from the highest-level containing
+        parent element. The intent is to give sufficient information about the
+        error location to allow the developer to find it in the page and in the
+        code generating the page, without including too much extraneous detail.
+        Values of attributes other than <span class="inline-code">class</span>
+        and <span class="inline-code">id</span> are truncated at 20 characters.
+        For example: "<span class="inline-code">&lt;div
+          onclick='aVeryLongFunctionNam&hellip;'&gt;&lt;div
+          id='abc'&gt;&lt;table&gt;&lt;tr&gt;&lt;td align='left'&gt;&lt;p
+          dir='rtl'&gt;</span>". In conjunction with the error text,
+        this should be sufficient for identification of the error location.</li>
+    </ul>
+
+    <p>The sample output above demonstrates how these fields are combined into
+      a textual error message. First the severity level is given in square
+      brackets, followed by the error type, the error text, the preceding and/or
+      following text, and the page location. Delimiters and separators between
+      fields are as shown in the sample.
+    </p>
+
+    <p>The error details serve two purposes: <b>Error identification</b>
+      and <b>error suppression</b>.</p>
+
+    <p><b>Error identification</b> is the human task of understanding what an
+      error message refers to: what the problem is and where on the page it
+      occurs.</p>
+
+    <p><b>Error suppression</b> is the filtering out of error messages that
+      match a set of specifications. Not all "errors" found by BidiChecker
+      represent real problems, and it is essential to suppress the generation
+      of those that don't, so automated tests run clean until a code change
+      results in new suspects. Similarly, after BidiChecker finds real
+      problems, it may take time for these to be fixed. In the meantime, after
+      filing appropriate bug reports, it often makes sense to suppress these
+      errors in the automated tests (with TODO comments to unsuppress them
+      after the problems have been fixed), so that the tests run clean, and
+      new problems are readily noticed.</p>
+
+    <p>Each of the fields above may be relevant for suppression. Users may
+      wish to suppress errors of a certain type which they know to be
+      spurious everywhere on the page, or to ignore low-severity errors. They
+      may know that a particular word is falsely reported as an error (for
+      example, "Gmail" in a navigation menu), or that a particular area of the
+      page contains user-generated content whose bidi correctness cannot be
+      ensured.</p>
+
+    <h3><a name="Suppression">The error suppression API</a></h3>
+
+    <p>BidiChecker provides a sophisticated error suppression mechanism. The
+      API supports
+      the specification and composition of filters on most fields of the
+      Error object, as well as filters based on the error's location on the
+      page.
+    </p>
+
+    <p>Some filter examples in Javascript:</p>
+
+    <div class="codeblock"><code>
+      var filters = [<br>
+      &nbsp;&nbsp;&nbsp;&nbsp;// Suppress errors with
+        the <b>atText</b> field "&#x5e9;&#x5dc;&#x5d5;&#x5dd;":<br>
+      &nbsp;&nbsp;&nbsp;&nbsp;bidichecker.FilterFactory.atText("\u05e9\u05dc\u05d5\u05dd"),<br>
+      <br>
+      &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Suppress errors appearing within a
+        page element with the <b>element id</b> "other_id"<br>
+      &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;(matches any ancestor element,
+        including those of enclosing frames):<br>
+      &nbsp;&nbsp;&nbsp;&nbsp;bidichecker.FilterFactory.locationId("other_id"),<br>
+      <br>
+      &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Composing multiple filters: Suppress
+      errors of <b>severity levels</b> 3 and 4 and <b>error type</b><br>
+      &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;"Declared RTL spillover to number":<br>
+      &nbsp;&nbsp;&nbsp;&nbsp;bidichecker.FilterFactory.severityFrom(3).and(<br>
+      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bidichecker.FilterFactory.type("Declared
+      RTL spillover to number")),<br>
+      <br>
+      &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Suppress errors within a page element with
+        the <b>class</b> attribute "myclass" and<br>
+      &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;<b>preceded by text</b> matching the
+      regular expression "http:.*":<br>
+      &nbsp;&nbsp;&nbsp;&nbsp;bidichecker.FilterFactory.locationClass("myclass").and(<br>
+      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bidichecker.FilterFactory.precededByTextRegexp("http:.*"))<br>
+      ];<br>
+      var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);<br>
+      var errors = checker.checkPage(true, top.document.body, filters);<br>
+      assertArrayEquals([], errors); &nbsp;// Should be no bidi errors
+        after filtering!<br>
+    </code></div>
+
+
+    <p>In addition,
+      the bookmarklet supports
+      global error suppression by severity level (and it is generally
+      recommended to filter out the lowest severity errors, level 4).</p>
+
+    <p>Below is the complete list of
+      filters (static factory methods in the
+      <a href="http://bidichecker.googlecode.com/svn/trunk/docs/jsdoc/_03.html"
+         target="_blank">bidichecker.FilterFactory
+      class</a>). Each filter object also supports instance methods
+      <b>and()</b>, <b>not()</b>, and <b>or()</b> for an alternate way of
+      composing/inverting filters.
+
+    <div>
+      <table border="1" bordercolor="#888888" cellspacing="0">
+        <tbody>
+          <tr>
+            <td style="width:20%"><b> Filter name</b></td>
+            <td style="width:30%"><b> Sample construction</b></td>
+            <td style="width:50%"><b> Description</b></td>
+          </tr>
+          <tr>
+            <td style="width:20%"> and</td>
+            <td style="width:30%"> bidichecker.FilterFactory.and(filter1,
+              filter2)</td>
+            <td style="width:50%"> Composes two filters
+              by <b>and</b>-ing their suppressions<span><br>
+            </span></td>
+          </tr>
+          <tr>
+            <td style="width:20%"> atText</td>
+            <td style="width:30%"> bidichecker.FilterFactory.atText()</td>
+            <td style="width:50%"> Matches against the
+              entire <b>atText</b> field of an error</td>
+          </tr>
+          <tr>
+            <td style="width:20%"> atTextRegexp</td>
+            <td style="width:30%"> bidichecker.FilterFactory.atTextRegexp(regexp)</td>
+            <td style="width:50%"> Matches against the
+              entire <b>atText</b> field of an error</td>
+          </tr>
+          <tr>
+            <td style="width:20%"> followedByText<br>
+            </td>
+            <td style="width:30%"> bidichecker.FilterFactory.followedByText(string)</td>
+            <td style="width:50%"> Matches against the
+              entire <b>followedByText</b> field of an error</td>
+          </tr>
+          <tr>
+            <td style="width:20%"> followedByTextRegexp</td>
+            <td style="width:30%"> bidichecker.FilterFactory.followedByTextRegexp(regexp)</td>
+            <td style="width:50%"> Matches against the
+              entire <b>followedByText</b> field of an error</td>
+          </tr>
+          <tr>
+            <td style="width:20%"> locationClass</td>
+            <td style="width:30%"> bidichecker.FilterFactory.locationClass(string)</td>
+            <td style="width:50%"> Matches against an
+              entire <b>class</b> name on any ancestor element containing the error
+              location (including any containing frames)</td>
+          </tr>
+          <tr>
+            <td style="width:20%"> locationClassRegexp</td>
+            <td style="width:30%"> bidichecker.FilterFactory.locationClassRegexp(regexp)</td>
+            <td style="width:50%"> Matches against an entire <b>class</b> name
+              on any ancestor element containing the error
+              location (including any containing frames)</td>
+          </tr>
+          <tr>
+            <td style="width:20%"> locationId</td>
+            <td style="width:30%"> bidichecker.FilterFactory.locationId(string)</td>
+            <td style="width:50%"> Matches against an entire <b>id</b>
+              attribute on any ancestor element containing the error
+              location (including any containing frames)</td>
+          </tr>
+          <tr>
+            <td style="width:20%"> locationIdRegexp</td>
+            <td style="width:30%"> bidichecker.FilterFactory.locationIdRegexp(regexp)</td>
+            <td style="width:50%"> Matches against an entire <b>id</b>
+              attribute on any ancestor element containing the error
+              location (including any containing frames)</td>
+          </tr>
+          <tr>
+            <td> locationXpath</td>
+            <td> bidichecker.FilterFactory.locationXpath(string)</td>
+            <td> Matches an XPath expression against the element of the error
+              location (including the elements representing any containing
+              frames). This does not match against ancestor elements; to
+              match against everything within a given location, you can add
+              "/*" to the XPath expression. There is currently no mechanism
+              for restricting the XPath match to specific frames.
+              <b>NOTE: XPaths are not currently supported on Internet
+                Explorer.</b></td>
+          </tr>
+          <tr>
+            <td style="width:20%"> not</td>
+            <td style="width:30%"> bidichecker.FilterFactory.not(filter)</td>
+            <td style="width:50%"> Inverts the meaning of a
+              filter</td>
+          </tr>
+          <tr>
+            <td style="width:20%"> or</td>
+            <td style="width:30%"> bidichecker.FilterFactory.or(filter1,
+              filter2)</td>
+            <td style="width:50%"> Composes two filters
+              by <b>or</b>-ing their suppressions</td>
+          </tr>
+          <tr>
+            <td style="width:20%"> precededByText</td>
+            <td style="width:30%"> bidichecker.FilterFactory.precededByText(string)</td>
+            <td style="width:50%"> Matches against the
+              entire <b>precededByText</b> field of an error</td>
+          </tr>
+          <tr>
+            <td style="width:20%"> precededByTextRegexp</td>
+            <td style="width:30%"> bidichecker.FilterFactory.precededByTextRegexp(regexp)</td>
+            <td style="width:50%"> Matches against the
+              entire <b>precededByText</b> field of an error</td>
+          </tr>
+          <tr>
+            <td style="width:20%"> severityFrom</td>
+            <td style="width:30%"> bidichecker.FilterFactory.severityFrom(severityThreshold)</td>
+            <td style="width:50%"> Matches any errors with <b>severity</b>
+              at the given threshold, or less severe than it</td>
+          </tr>
+          <tr>
+            <td style="width:20%"> type</td>
+            <td style="width:30%"> bidichecker.FilterFactory.type(typeValue)</td>
+            <td style="width:50%"> Matches against the
+              exact <b>type</b> field of an error</td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+
+
+    <hr>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%"><a href="writing_regression_tests.html">&lt;&lt; Writing regression tests &lt;&lt;</a></td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%"><a href="catalog_of_checks.html">&gt;&gt; Catalog of checks &gt;&gt;</a></td>
+    </tr></table>
+
+  </body>
+</html>
diff --git a/docs/users_guide/getting_started.html b/docs/users_guide/getting_started.html
new file mode 100644
index 0000000..78a420f
--- /dev/null
+++ b/docs/users_guide/getting_started.html
@@ -0,0 +1,149 @@
+<!DOCTYPE html>
+<html>
+  <!--
+      Copyright 2010 Google Inc. All Rights Reserved.
+
+      Use of this source code is governed by an Apache 2.0 License.
+      See the COPYING file for details.
+    -->
+
+
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <link href="users_guide.css" rel="stylesheet" type="text/css">
+
+    <title>BidiChecker User's Guide</title>
+  </head>
+
+  <body>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%"><a href="overview.html">&lt;&lt; Overview &lt;&lt;</a></td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%"><a href="writing_regression_tests.html">&gt;&gt; Writing regression tests &gt;&gt;</a></td>
+    </tr></table>
+
+    <hr>
+
+    <h1><a href="index.html">BidiChecker User's Guide</a></h1>
+
+    <h2>2. Getting started</h2>
+
+        <ul>
+      <li><a href="#GettingBidiChecker">Getting BidiChecker</a></li>
+      <li><a href="#PlatformSupport">Platform support</a></li>
+    </ul>
+
+    <h3><a name="GettingBidiChecker">Getting BidiChecker</a></h3>
+
+    <p><b>Browser bookmarklet:</b> To install the bookmarklet in your
+      browser's Bookmarks toolbar, go to the
+      <a href="http://bidichecker.googlecode.com/svn/trunk/src/bookmarklet.html"
+         target="_blank">BidiChecker
+      Bookmarklet Installation Page</a>. You will find two links labeled
+      "BidiChecker LTR" and "BidiChecker RTL". Dragging each of those links to
+      your Bookmarks toolbar will install a button which, when clicked, runs
+      BidiChecker on the page currently in the browser. The LTR bookmarklet
+      expects the page to have a left-to-right UI; the RTL bookmarklet is for
+      pages with a right-to-left UI.</p>
+
+    <p><b>Source code:</b> The BidiChecker source code can be downloaded from
+      <a href="http://code.google.com/p/bidichecker">http://code.google.com/p/bidichecker</a>
+      using the following command:</p>
+
+    <p><span class="inline-code">svn checkout
+        http://bidichecker.googlecode.com/svn/trunk/ bidichecker</span></p>
+
+    <p>Source code and unit tests can be found in the
+      <a href="http://code.google.com/p/bidichecker/source/browse/#svn/trunk/src"><span class="inline-code">src/</span></a>
+      subdirectory. This user's guide is in the
+      <a href="http://code.google.com/p/bidichecker/source/browse/#svn/trunk/docs/users_guide"><span class="inline-code">docs/users_guide</span></a>
+      subdirectory, with the complete API documentation in
+      <a href="http://code.google.com/p/bidichecker/source/browse/#svn/trunk/docs/jsdoc"><span class="inline-code">docs/jsdoc/</span></a>.
+      A sample application, along with demonstrations of how BidiChecker can be
+      used to check for bidi errors, can be found in
+      <a href="http://code.google.com/p/bidichecker/source/browse/#svn/trunk/samples/reviews"><span class="inline-code">samples/reviews/</span></a>.</p>
+
+    <p>The
+      <a href="http://code.google.com/p/bidichecker/source/browse/#svn/trunk/lib"><span class="inline-code">lib/</span></a>
+      subdirectory contains a self-contained, deployable installation of
+      BidiChecker. If you copy this directory to a web server, you can easily
+      run BidiChecker either from automated unit tests or via the browser
+      bookmarklet. The directory contains:
+      <ol>
+        <li>a single-file, precompiled version of BidiChecker, named
+          <span class="inline-code">bidichecker_packaged.js</span>. Loading
+      this one file from the web page to be tested is the usual way to use
+      BidiChecker (you only need BidiChecker's source code if you want to
+      modify BidiChecker or understand its internal workings). For an example of
+      how to use the precompiled package, see
+      <a href="http://code.google.com/p/bidichecker/source/browse/trunk/samples/reviews/reviews_packaged_test.html"><span class="inline-code">samples/reviews/reviews_packaged_test.html</span></a>.</li>
+        <li>a local copy of the bookmarklet installation page (
+          <span class="inline-code">bookmarklet.html</span> and
+          <span class="inline-code">bookmarklet.css</span>). The bookmarklet
+          links generated by this page will load Javascript files from the same
+          installation directory, allowing you to easily run BidiChecker on a
+          local web server.</li>
+        <li>The BidiChecker GUI code, located in the
+          <span class="inline-code">gui-app</span> subdirectory. This contains
+          a precompiled file <span class="inline-code">gui_compiled.js</span>,
+          the web pages which host the GUI, and their style file.</li>
+      </ol>
+      Note that the entire <span class="inline-code">lib/</span> subdirectory
+      tree should be installed on a web server and accessed via
+      <span class="inline-code">http:</span> or
+      <span class="inline-code">https:</span>.
+    </p>
+
+    <p>BidiChecker source code uses the
+      <a href="http://code.google.com/p/closure-library/">Closure Library</a>,
+      an open-source library of useful Javascript modules. If you want to run
+      a modified version of BidiChecker or run BidiChecker's own unit tests,
+      you will need to install a copy of the Closure Library on your system.
+      To do that, run the following command from the same working directory as
+      you ran the above command:</p>
+
+    <p><span class="inline-code">svn checkout
+        http://closure-library.googlecode.com/svn/trunk/
+        bidichecker/third_party/closure-library</span></p>
+
+    <p>BidiChecker does not currently easily support linking with a copy of
+      the Closure Library at a different location. Please note that you do
+      <b>not</b> need to install the Closure Library to use the precompiled
+      version of BidiChecker.</p>
+
+    <p>For an example of how to use BidiChecker with the Closure Library,
+      see
+      <a href="http://code.google.com/p/bidichecker/source/browse/trunk/samples/reviews/reviews_closure_test.html"><span class="inline-code">samples/reviews/reviews_closure_test.html</span></a>.
+    </p>
+
+    <h3><a name="PlatformSupport">Platform support</a></h3>
+
+    <p>The core BidiChecker backend Javascript code is regularly tested on
+      a selection of browsers. The browser bookmarklet has been tested on
+      Firefox and Chrome. It is not currently supported on Internet Explorer
+      prior to version 9.
+    </p>
+
+    <p>Regardless, the bidi errors identified by the tool are not
+      platform-specific; the code searches the DOM for errors, and it
+      may find errors which only cause display garbling on browsers
+      other than the one on which it is run. It should not be
+      necessary to run the tool on a particular browser in order to
+      find bidi errors for that browser.</p>
+
+
+
+
+    <hr>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%"><a href="overview.html">&lt;&lt; Overview &lt;&lt;</a></td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%"><a href="writing_regression_tests.html">&gt;&gt; Writing regression tests &gt;&gt;</a></td>
+    </tr></table>
+
+  </body>
+</html>
diff --git a/docs/users_guide/how_to_devise.html b/docs/users_guide/how_to_devise.html
new file mode 100644
index 0000000..a7bb985
--- /dev/null
+++ b/docs/users_guide/how_to_devise.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+  <!--
+      Copyright 2010 Google Inc. All Rights Reserved.
+
+      Use of this source code is governed by an Apache 2.0 License.
+      See the COPYING file for details.
+    -->
+
+
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <link href="users_guide.css" rel="stylesheet" type="text/css">
+
+    <title>BidiChecker User's Guide</title>
+  </head>
+
+  <body>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%"><a href="catalog_of_checks.html">&lt;&lt; Catalog of checks &lt;&lt;</a></td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%"><a href="closing_notes.html">&gt;&gt; Closing notes &gt;&gt;</a></td>
+    </tr></table>
+
+    <hr>
+
+    <h1><a href="index.html">BidiChecker User's Guide</a></h1>
+
+    <h2>6. How to devise effective test cases</h2>
+
+        <p>Just running BidiChecker on random pages of your application
+      may reveal some bidi support errors, but it is unlikely to be an
+      effective approach to bidi testing. To start with the obvious, if
+      you run bidi checks on a page with a left-to-right UI and contents
+      in a left-to-right language, you probably won't find any errors,
+      but neither would you have tested the handling of right-to-left
+      text! An application with an LTR UI should at the minimum run
+      BidiChecker on each page while displaying RTL text contents. For
+      example, a search application should test pages with an RTL search
+      query. If your application also supports RTL UIs, they should be
+      tested both with RTL contents and with LTR contents, as each one
+      may reveal different errors.</p>
+
+    <p>Keep in mind that most user input fields, and output which displays
+      them, should be able to support RTL contents, even on an LTR
+      page. Hebrew- and Arabic-speaking users may access web content or
+      enter data in their native languages, even if the UI is in
+      English. There are exceptions; fields such as phone numbers, currency
+      values or e-mail addresses need only support LTR data (though the
+      human name associated with an e-mail account may well be RTL). But as
+      a rule, any data field your application displays may need to handle
+      RTL text. Thorough testing should include displaying RTL contents in
+      every such field and checking the page with BidiChecker.</p>
+
+
+    <hr>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%"><a href="catalog_of_checks.html">&lt;&lt; Catalog of checks &lt;&lt;</a></td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%"><a href="closing_notes.html">&gt;&gt; Closing notes &gt;&gt;</a></td>
+    </tr></table>
+
+  </body>
+</html>
diff --git a/docs/users_guide/index.html b/docs/users_guide/index.html
new file mode 100644
index 0000000..1b9cc7c
--- /dev/null
+++ b/docs/users_guide/index.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+  <!--
+      Copyright 2010 Google Inc. All Rights Reserved.
+
+      Use of this source code is governed by an Apache 2.0 License.
+      See the COPYING file for details.
+    -->
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <link href="users_guide.css" rel="stylesheet" type="text/css">
+
+    <title>BidiChecker User's Guide</title>
+  </head>
+
+  <body>
+
+    <h1>BidiChecker User's Guide</h1>
+
+
+    <h2>Table of Contents</h2>
+    <ol class="toc">
+      <li><a href="overview.html">Overview</a></li>
+      <li><a href="getting_started.html">Getting started</a>
+        <ol>
+          <li><a href="getting_started.html#GettingBidiChecker">
+              Getting BidiChecker</a></li>
+          <li><a href="getting_started.html#PlatformSupport">
+              Platform support</a></li>
+        </ol></li>
+      <li><a href="writing_regression_tests.html">Writing regression tests</a>
+        <ol>
+          <li><a href="writing_regression_tests.html#Revisions">
+              Selecting a revision</a>
+              <span class="new-item">NEW!</span></li>
+          <li><a href="writing_regression_tests.html#UsingApi">
+              Using the API</a></li>
+          <li><a href="writing_regression_tests.html#Viewing">
+              Viewing BidiChecker output</a></li>
+        </ol></li>
+      <li><a href="error_descriptions.html">
+          Error descriptions and error suppression</a>
+        <ol>
+          <li><a href="error_descriptions.html#Suppression">
+              The error suppression API</a></li>
+      </ol></li>
+      <li><a href="catalog_of_checks.html">Catalog of bidi checks and errors</a>
+        <ol>
+          <li><a href="catalog_of_checks.html#IncorrectOverall">
+              Incorrect overall directionality</a></li>
+          <li><a href="catalog_of_checks.html#UndeclaredText">
+              Undeclared opposite-directionality text</a></li>
+          <li><a href="catalog_of_checks.html#UndeclaredAttributes">
+              Undeclared opposite-directionality attributes</a>
+              <span class="new-item">NEW!</span></li>
+          <li><a href="catalog_of_checks.html#SpilloverToNumber">
+              Spillover from declared opposite-directionality element to number
+          </a></li>
+      </ol></li>
+      <li><a href="how_to_devise.html">
+          How to devise effective test cases</a></li>
+      <li><a href="closing_notes.html">Closing notes</a>
+        <ol>
+          <li><a href="closing_notes.html#HtmlIssues">
+              Issues with HTML support</a></li>
+          <li><a href="closing_notes.html#KnownProblems">Known problems</a></li>
+      </ol></li>
+    </ol>
+
+  </body>
+</html>
diff --git a/docs/users_guide/overview.html b/docs/users_guide/overview.html
new file mode 100644
index 0000000..312f14b
--- /dev/null
+++ b/docs/users_guide/overview.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<html>
+  <!--
+      Copyright 2010 Google Inc. All Rights Reserved.
+
+      Use of this source code is governed by an Apache 2.0 License.
+      See the COPYING file for details.
+    -->
+
+
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <link href="users_guide.css" rel="stylesheet" type="text/css">
+
+    <title>BidiChecker User's Guide</title>
+  </head>
+
+  <body>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%">&nbsp;</td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%"><a href="getting_started.html">&gt;&gt; Getting started &gt;&gt;</a></td>
+    </tr></table>
+
+    <hr>
+
+    <h1><a href="index.html">BidiChecker User's Guide</a></h1>
+
+    <h2>1. Overview</h2>
+
+        <p><b>BidiChecker</b> is a tool for the automated testing of web pages for
+      errors in support of right-to-left (RTL) languages, also known as
+      bidirectional (bidi) because they routinely include left-to-right items
+      such as numbers and Latin-script words and phrases.</p>
+
+    <p>Bidi support for a web page is a common requirement, even for pages
+      in left-to-right scripts. Any page which accepts user input or
+      displays multilingual content is likely to end up handling
+      bidirectional text at some point, as it will eventually encounter data
+      in Arabic, Hebrew or another RTL language. Unfortunately, handling
+      bidirectional text can be tricky and requires special processing at
+      every appearance of potentially bidi data in the
+      UI.
+      (<a href="http://doctype.googlecode.com/svn-history/trunk/bidihowto/index.html">Examples
+      of common bidi UI bugs can be found here</a>.) As a result, bidi
+      text support often regresses when a developer adds a new feature and
+      simply forgets about bidi.</p>
+
+    <p>BidiChecker can be used in two ways:</p>
+
+    <ol>
+      <li>for <b>regression testing</b>, as part of an automated test
+        suite, or</li>
+      <li>for <b>exploratory testing</b>, manually reviewing the results of
+        running it on the current page in a web browser
+      </li>
+    </ol>
+
+    <p><b>For regression testing,</b> web applications typically use an
+      automated testing framework such as
+      <a href="http://www.jsunit.net" target="_blank">JSUnit</a>
+      for testing against a live browser instance. BidiChecker provides a
+      Javascript API for integration into Javascript tests.
+      The API accepts a page element (by default, the
+      body of the top-level document), runs bidi tests on its contents, and
+      returns a list of bidi errors found, including the type of each error,
+      its location on the page and an estimate of its level of severity.</p>
+
+    <p><b>For exploratory testing,</b> BidiChecker can be run on any page open
+      in a web browser after installing the BidiChecker bookmarklet in the
+      browser's Bookmarks toolbar.
+      When the bookmarklet is run,
+      an interactive error browser will
+      highlight the bidi errors on the displayed page itself, providing an
+      interactive user interface for viewing their details.</p>
+
+
+    <p>Note that BidiChecker
+      does not require any custom "hooks" or modifications to the product under
+      test. New BidiChecker-based tests can be written in addition to the
+      product's existing test suite.</p>
+
+
+    <h3>Who's using it?</h3>
+
+    <p>BidiChecker is currently in use
+    at several projects inside Google,
+         as well as the open-source
+         <a href="http://www.chromium.org">Chromium</a> project.</p>
+
+
+    <hr>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%">&nbsp;</td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%"><a href="getting_started.html">&gt;&gt; Getting started &gt;&gt;</a></td>
+    </tr></table>
+
+  </body>
+</html>
diff --git a/docs/users_guide/users_guide.css b/docs/users_guide/users_guide.css
new file mode 100644
index 0000000..017e103
--- /dev/null
+++ b/docs/users_guide/users_guide.css
@@ -0,0 +1,85 @@
+body {
+  font-family: arial, sans-serif;
+}
+
+h1 {
+  font-size: 30pt;
+  font-weight: bold;
+}
+
+h2 {
+  font-size: 24pt;
+  font-weight: bold;
+}
+
+h3 {
+  font-size: 18pt;
+  font-weight: bold;
+}
+
+h4 {
+  font-size: 14pt;
+  font-weight: bold;
+}
+
+p, td {
+  font-size: 14pt;
+  padding: 3px;
+}
+
+ul li {
+  font-size: 14pt;
+}
+
+ol.toc {
+  font-size: 18pt;
+  line-height: 140%;
+}
+
+ol.toc * ol {
+  font-size: 14pt;
+}
+
+table {
+  border-width: 1px;
+  border-color: "#888888";
+  border-collapse: collapse;
+}
+
+.inline-code {
+  font-family: courier, monospace;
+  font-weight: bold;
+}
+
+.codeblock {
+  background-color: #EFEFEF;
+  color: #006600;
+  font-size: 14pt;
+  font-weight: bold;
+  border: 1px solid lightGrey;
+  padding: 0.5em 0 0.5em 1em;
+}
+
+.prev-link {
+  text-align: left;
+  font-size: 12pt;
+}
+
+.up-link {
+  text-align: center;
+  font-size: 12pt;
+}
+
+.next-link {
+  text-align: right;
+  font-size: 12pt;
+}
+
+.new-item {
+  font-size: 8pt;
+  font-weight: bold;
+  vertical-align: middle;
+  background-color: yellow;
+  color: red;
+  border: 1px solid red;
+}
diff --git a/docs/users_guide/writing_regression_tests.html b/docs/users_guide/writing_regression_tests.html
new file mode 100644
index 0000000..0d4cbec
--- /dev/null
+++ b/docs/users_guide/writing_regression_tests.html
@@ -0,0 +1,221 @@
+<!DOCTYPE html>
+<html>
+  <!--
+      Copyright 2010 Google Inc. All Rights Reserved.
+
+      Use of this source code is governed by an Apache 2.0 License.
+      See the COPYING file for details.
+    -->
+
+
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <link href="users_guide.css" rel="stylesheet" type="text/css">
+
+    <title>BidiChecker User's Guide</title>
+  </head>
+
+  <body>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%"><a href="getting_started.html">&lt;&lt; Getting started &lt;&lt;</a></td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%"><a href="error_descriptions.html">&gt;&gt; Error descriptions and error suppression &gt;&gt;</a></td>
+    </tr></table>
+
+    <hr>
+
+    <h1><a href="index.html">BidiChecker User's Guide</a></h1>
+
+    <h2>3. Writing regression tests</h2>
+
+        <p>While the bookmarklet
+      is
+      handy for manually checking pages of an application, the main value of
+      BidiChecker is intended to come from the
+      API. Using
+      Javascript, developers can write regression tests which
+      become a permanent part of the application's automated test suite.</p>
+
+    <p>A web page can be opened, the application perhaps manipulated in some
+      way, and then BidiChecker can be invoked to check the contents of the
+      resulting page. BidiChecker returns a collection of error objects, which
+      can be checked for emptiness or compared for equality against some fixed
+      list of expected errors. Known errors or known false positives (really
+      non-errors) can automatically be suppressed from the results using a
+      rich set of built-in filters.</p>
+
+    <ul>
+      <li><a href="#Revisions">Selecting a revision</a></li>
+      <li><a href="#UsingApi">Using the API</a></li>
+      <li><a href="#Viewing">Viewing BidiChecker output</a></li>
+    </ul>
+
+    <h3><a name="Revisions"></a>Selecting a revision</h3>
+
+    <p>From time to time, new checks are added to BidiChecker. In order to keep
+      this from breaking existing automated tests, BidiChecker's constructor
+      takes a parameter known as the "revision", which specifies which release
+      of the checks should be run. Higher revision numbers indicate later
+      releases, which check for more error situations.
+    </p>
+
+    <p>BidiChecker-based tests should generally choose a specific revision.
+      It is also possible to specify the "latest" revision; in this case, the
+      most comprehensive set of checks will always be run, in exchange for the
+      risk that the test suite may break when a new revision is released.</p>
+
+    <table border="1">
+      <tr><td>Revision</td><td>Checks included</td></tr>
+      <tr><td style="text-align: center">1</td><td>
+          <ul>
+            <li><a href="catalog_of_checks.html#IncorrectOverall">
+                Incorrect overall directionality</a></li>
+            <li><a href="catalog_of_checks.html#UndeclaredText">
+                Undeclared opposite-directionality text</a></li>
+            <li><a href="catalog_of_checks.html#SpilloverToNumber">
+                Spillover from declared opposite-directionality element to
+                number</a></li>
+          </ul>
+      </td></tr>
+      <tr><td style="text-align: center">2<br>(latest)</td><td>
+          <p>All the above, plus:</p>
+          <ul>
+          <li><a href="catalog_of_checks.html#UndeclaredAttributes">
+              Undeclared opposite-directionality attributes</a></li>
+          <li><a href="catalog_of_checks.html#UndeclaredText">
+              Undeclared "fake RTL" strings in a declared left-to-right context
+              (upgrade to the check for opposite-directionality text)</a></li>
+          </ul>
+      </td></tr>
+    </table>
+
+    <p>Not meant for use in automated tests, the browser bookmarklet
+      will always run the latest revision.</p>
+
+
+    <h3><a name="UsingApi"></a>Using the API</h3>
+
+    <p>BidiChecker can be integrated into pure Javascript automated unit tests
+      based on
+    a testing framework such as
+         the JSUnit testing package.
+
+    <p>A JSUnit test can navigate the application to a page and check it with
+      BidiChecker. A sample test may look like this:</p>
+
+    <div class="codeblock"><code>
+      function testAppWithBidiChecker() {<br>
+      &nbsp;&nbsp;// Do something to load the application being
+        tested into the page and get it into<br>
+      &nbsp;&nbsp;// an interesting state for bidi, e.g. displaying
+        LTR data in an RTL UI.<br>
+      &nbsp;&nbsp;....<br>
+      <br>
+      &nbsp;&nbsp;// Revision 2 is currently the latest set of bidi
+        checks,<br>
+      &nbsp;&nbsp;// which catches the greatest number of possible
+        errors.<br>
+      &nbsp;&nbsp;var checker =
+        new bidichecker.BidiChecker(bidichecker.REVISION_2);<br>
+      <br>
+      &nbsp;&nbsp;// Check for errors in handling bidi text. First
+        parameter is true to indicate an RTL UI.<br>
+      &nbsp;&nbsp;// It would be false when testing an LTR UI (with
+        RTL data).<br>
+      &nbsp;&nbsp;var bidiErrors = checker.checkPage(true,
+        top.document.body);<br>
+      &nbsp;&nbsp;checker.runGui(); // If errors are found, run the
+        error GUI.<br>
+      &nbsp;&nbsp;assertArrayEquals([], bidiErrors); // Should be no
+        bidi errors!<br>
+      }
+    </code></div>
+
+    <p>A complete code example, including a simple bilingual application and
+      BidiChecker-based JSUnit tests, can be found in the
+      <a href="http://code.google.com/p/bidichecker/source/browse/#svn/trunk/samples/reviews"
+         target="_blank">
+      <span class="inline-code">samples/reviews/</span></a> subdirectory of the
+      download
+      tree.</p>
+
+
+    <h3><a name="Viewing"></a>Viewing BidiChecker output</h3>
+    <p>The tool will produce a list of error messages, one for each bidi
+      bug discovered. Below is a sample of the messages. The contents of
+      the error messages will be explained in more detail later on.</p>
+    <div class="codeblock"><code>
+        [4] Undeclared LTR text: 'The Princess Bride' followed by ': 23'
+        in &lt;div id='reviews'&gt;&lt;div&gt;<br>
+        [4] Undeclared LTR text: 'Leagues Under the Sea' preceded by
+        '20,000 ' followed by ': 17' in &lt;div id='reviews'&gt;&lt;div&gt;
+    </code></div>
+
+    <p>When running a BidiChecker test interactively, however, it is a
+    lot easier to view the errors right in the page where BidiChecker
+    found them using BidiChecker's interactive error browser. To
+    activate the error browser, call
+      <span class="inline-code">bidichecker.runGui(errors)</span> from
+      your test code if
+      <span class="inline-code">bidichecker.checkPage()</span> returns
+      errors. This will display a dialog box showing a table with the
+      errors found:</p>
+    <p><a href="bidichecker_screenshot.png" imageanchor="1">
+        <img border="0" src="bidichecker_screenshot.png">
+    </a></p>
+
+    <p>The GUI mode is simple to control: Select an error by clicking
+      on it, or change the table's sort order by clicking on a column
+      title. The full description of the currently-selected error appears
+      in the box below the table, and its location is highlighted with a
+      yellow background in a red border where it appears on the page. The
+      page being checked will also be scrolled to keep the error's position
+      near the top of the window if possible. The error description text can
+      be copied from the dialog box.</p>
+
+    <p>The page under test remains accessible, so you can select the page
+      contents near an error and view the HTML source using the browser.
+      Note that an error will not be visibly highlighted if its page
+      location is concealed by another page element, for example, or if it
+      is scrolled out of view in a scrollable element. To widen the error
+      table, drag the popup window border and then refresh the window
+      (i.e., press F5).</p>
+
+    <p>Whether or not to call <span class="inline-code">runGui()</span> from an
+      automated test may depend on your test environment. On first thought, when
+      run in an automated framework the visual GUI might not seem to add much
+      value. However, some automated test frameworks store a screenshot on the
+      termination of a failed test; in that case, the screenshot might show
+      the location of the first BidiChecker error highlighted on the page.
+      Furthermore, even automated tests are sometimes run manually in a browser
+      during development or for debugging; in that case, full GUI interactivity
+      would be available when a test fails. Even when the test is run
+      automatically, running the GUI probably does not do any harm.</p>
+
+    <p>Note that if a test page contains more than one test, using
+      <span class="inline-code">runGui()</span> is problematic. Assuming that
+      each test navigates the application in some way and thus manipulates the
+      DOM, the DOM elements where BidiChecker found an error may no longer have
+      the same content or even exist by the time the GUI is used. To maximize
+      the utility of the GUI, tests should be organized so that no more than one
+      test is run in each test page. If multiple tests are nonetheless contained
+      in each page (perhaps for efficiency reasons), it is still possible to use
+      the GUI effectively when tests are run manually, by requesting that the
+      test runner run a single failing test from the page in isolation.</p>
+
+
+
+
+    <hr>
+
+    <table width="100%"><tr>
+    <td class="prev-link" width="33%"><a href="getting_started.html">&lt;&lt; Getting started &lt;&lt;</a></td>
+    <td class="up-link" width="33%"><a href="index.html">
+        ^^ Table of Contents ^^</a></td>
+    <td class="next-link" width="33%"><a href="error_descriptions.html">&gt;&gt; Error descriptions and error suppression &gt;&gt;</a></td>
+    </tr></table>
+
+  </body>
+</html>
diff --git a/lib/bidichecker_packaged.js b/lib/bidichecker_packaged.js
index 7535ac1..c5255aa 100755
--- a/lib/bidichecker_packaged.js
+++ b/lib/bidichecker_packaged.js
@@ -1,105 +1,113 @@
-(function (){ function h(a){throw a;}
-var i=true,j=null,k=false,m,n=this,aa=function(){},ba=function(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if(c=="[object Window]")return"object";if(c=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(c=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!=
-"undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if(b=="function"&&typeof a.call=="undefined")return"object";return b},p=function(a){return ba(a)=="array"},ca=function(a){var b=ba(a);return b=="array"||b=="object"&&typeof a.length=="number"},s=function(a){return typeof a=="string"},da=function(a){return ba(a)=="function"},ea=function(a){a=ba(a);return a=="object"||a=="array"||a=="function"},ha=function(a){return a[fa]||(a[fa]=++ga)},fa="closure_uid_"+Math.floor(Math.random()*
-2147483648).toString(36),ga=0,ia=function(a){return a.call.apply(a.bind,arguments)},ja=function(a,b){var c=b||n;if(arguments.length>2){var d=Array.prototype.slice.call(arguments,2);return function(){var e=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(e,d);return a.apply(c,e)}}else return function(){return a.apply(c,arguments)}},ka=function(){ka=Function.prototype.bind&&Function.prototype.bind.toString().indexOf("native code")!=-1?ia:ja;return ka.apply(j,arguments)},ma=function(a){var b=
-Array.prototype.slice.call(arguments,1);return function(){var c=Array.prototype.slice.call(arguments);c.unshift.apply(c,b);return a.apply(this,c)}},na=Date.now||function(){return+new Date},t=function(a,b){var c=a.split("."),d=n;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)if(!c.length&&b!==undefined)d[e]=b;else d=d[e]?d[e]:d[e]={}},v=function(a,b){function c(){}c.prototype=b.prototype;a.k=b.prototype;a.prototype=new c};
-Function.prototype.bind=Function.prototype.bind||function(a){if(arguments.length>1){var b=Array.prototype.slice.call(arguments,1);b.unshift(this,a);return ka.apply(j,b)}else return ka(this,a)};var oa=function(a){this.stack=Error().stack||"";if(a)this.message=String(a)};v(oa,Error);oa.prototype.name="CustomError";var pa=function(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a},va=function(a){if(!qa.test(a))return a;if(a.indexOf("&")!=-1)a=a.replace(ra,"&amp;");if(a.indexOf("<")!=-1)a=a.replace(sa,"&lt;");if(a.indexOf(">")!=-1)a=a.replace(ta,"&gt;");if(a.indexOf('"')!=-1)a=a.replace(ua,"&quot;");return a},ra=/&/g,sa=/</g,ta=/>/g,ua=/\"/g,qa=/[&<>\"]/,xa=function(a,b){for(var c=0,d=String(a).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),
-e=String(b).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),f=Math.max(d.length,e.length),g=0;c==0&&g<f;g++){var l=d[g]||"",o=e[g]||"",q=RegExp("(\\d*)(\\D*)","g"),la=RegExp("(\\d*)(\\D*)","g");do{var u=q.exec(l)||["","",""],r=la.exec(o)||["","",""];if(u[0].length==0&&r[0].length==0)break;c=wa(u[1].length==0?0:parseInt(u[1],10),r[1].length==0?0:parseInt(r[1],10))||wa(u[2].length==0,r[2].length==0)||wa(u[2],r[2])}while(c==0)}return c},wa=function(a,b){if(a<b)return-1;else if(a>b)return 1;return 0},
-ya={},za=function(a){return ya[a]||(ya[a]=String(a).replace(/\-([a-z])/g,function(b,c){return c.toUpperCase()}))};var Aa=function(a,b){b.unshift(a);oa.call(this,pa.apply(j,b));b.shift();this.Pc=a};v(Aa,oa);Aa.prototype.name="AssertionError";var Ba=function(a,b){if(!a){var c=Array.prototype.slice.call(arguments,2),d="Assertion failed";if(b){d+=": "+b;var e=c}h(new Aa(""+d,e||[]))}};var w=function(a){return a[a.length-1]},x=Array.prototype,Ca=x.indexOf?function(a,b,c){Ba(a.length!=j);return x.indexOf.call(a,b,c)}:function(a,b,c){c=c==j?0:c<0?Math.max(0,a.length+c):c;if(s(a)){if(!s(b)||b.length!=1)return-1;return a.indexOf(b,c)}for(;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},Da=x.forEach?function(a,b,c){Ba(a.length!=j);x.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=s(a)?a.split(""):a,f=0;f<d;f++)f in e&&b.call(c,e[f],f,a)},Ea=function(a,b){for(var c=s(a)?
-a.split(""):a,d=a.length-1;d>=0;--d)d in c&&b.call(void 0,c[d],d,a)},Fa=x.map?function(a,b,c){Ba(a.length!=j);return x.map.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=Array(d),f=s(a)?a.split(""):a,g=0;g<d;g++)if(g in f)e[g]=b.call(c,f[g],g,a);return e},Ga=x.every?function(a,b,c){Ba(a.length!=j);return x.every.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=s(a)?a.split(""):a,f=0;f<d;f++)if(f in e&&!b.call(c,e[f],f,a))return k;return i},Ha=function(){return x.concat.apply(x,arguments)},Ia=
-function(a){if(p(a))return Ha(a);else{for(var b=[],c=0,d=a.length;c<d;c++)b[c]=a[c];return b}},Ja=function(a,b,c){Ba(a.length!=j);return arguments.length<=2?x.slice.call(a,b):x.slice.call(a,b,c)},Ka=function(a,b,c){for(var d=0,e=a.length,f;d<e;){var g=d+e>>1,l;l=b(c,a[g]);if(l>0)d=g+1;else{e=g;f=!l}}return f?d:~d},La=function(a,b){return a>b?1:a<b?-1:0};var y="StopIteration"in n?n.StopIteration:Error("StopIteration"),Ma=function(){};Ma.prototype.next=function(){h(y)};Ma.prototype.Na=function(){return this};
-var Na=function(a){if(a instanceof Ma)return a;if(typeof a.Na=="function")return a.Na(k);if(ca(a)){var b=0,c=new Ma;c.next=function(){for(;;){b>=a.length&&h(y);if(b in a)return a[b++];else b++}};return c}h(Error("Not implemented"))},Oa=function(a,b){if(ca(a))try{Da(a,b,void 0)}catch(c){c!==y&&h(c)}else{a=Na(a);try{for(;;)b.call(void 0,a.next(),undefined,a)}catch(d){d!==y&&h(d)}}};var Pa=function(a,b){this.x=a!==undefined?a:0;this.y=b!==undefined?b:0};Pa.prototype.toString=function(){return"("+this.x+", "+this.y+")"};var z=function(a,b){this.width=a;this.height=b};z.prototype.toString=function(){return"("+this.width+" x "+this.height+")"};z.prototype.Ea=function(){return!(this.width*this.height)};z.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};z.prototype.round=function(){this.width=Math.round(this.width);this.height=Math.round(this.height);return this};var Qa=function(a,b){for(var c in a)b.call(void 0,a[c],c,a)},Ra=function(a){var b=[],c=0,d;for(d in a)b[c++]=a[d];return b},Sa=function(a){var b=[],c=0,d;for(d in a)b[c++]=d;return b},Ta=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],Ua=function(a){for(var b,c,d=1;d<arguments.length;d++){c=arguments[d];for(b in c)a[b]=c[b];for(var e=0;e<Ta.length;e++){b=Ta[e];if(Object.prototype.hasOwnProperty.call(c,b))a[b]=c[b]}}},Va=function(){var a=
-arguments.length;if(a==1&&p(arguments[0]))return Va.apply(j,arguments[0]);for(var b={},c=0;c<a;c++)b[arguments[c]]=i;return b};var Wa,Xa,Ya,Za,$a,ab,bb=function(){return n.navigator?n.navigator.userAgent:j},cb=function(){return n.navigator};$a=Za=Ya=Xa=Wa=k;var db;if(db=bb()){var eb=cb();Wa=db.indexOf("Opera")==0;Xa=!Wa&&db.indexOf("MSIE")!=-1;Za=(Ya=!Wa&&db.indexOf("WebKit")!=-1)&&db.indexOf("Mobile")!=-1;$a=!Wa&&!Ya&&eb.product=="Gecko"}var fb=Wa,A=Xa,gb=$a,B=Ya,hb=Za,ib=cb();ab=(ib&&ib.platform||"").indexOf("Mac")!=-1;var jb=!!cb()&&(cb().appVersion||"").indexOf("X11")!=-1,kb;
-a:{var lb="",mb;if(fb&&n.opera){var nb=n.opera.version;lb=typeof nb=="function"?nb():nb}else{if(gb)mb=/rv\:([^\);]+)(\)|;)/;else if(A)mb=/MSIE\s+([^\);]+)(\)|;)/;else if(B)mb=/WebKit\/(\S+)/;if(mb){var ob=mb.exec(bb());lb=ob?ob[1]:""}}if(A){var pb,qb=n.document;pb=qb?qb.documentMode:undefined;if(pb>parseFloat(lb)){kb=String(pb);break a}}kb=lb}var rb=kb,sb={},C=function(a){return sb[a]||(sb[a]=xa(rb,a)>=0)};var tb,ub=!A||C("9");A&&C("9");var vb=function(a){var b;b=(b=a.className)&&typeof b.split=="function"?b.split(/\s+/):[];var c;c=Ja(arguments,1);for(var d=0,e=0;e<c.length;e++)if(!(Ca(b,c[e])>=0)){b.push(c[e]);d++}c=d==c.length;a.className=b.join(" ");return c};var G=function(a){return a?new E(F(a)):tb||(tb=new E)},xb=function(a,b,c,d){a=d||a;b=b&&b!="*"?b.toUpperCase():"";if(a.querySelectorAll&&a.querySelector&&(!B||wb(document)||C("528"))&&(b||c))return a.querySelectorAll(b+(c?"."+c:""));if(c&&a.getElementsByClassName){a=a.getElementsByClassName(c);if(b){d={};for(var e=0,f=0,g;g=a[f];f++)if(b==g.nodeName)d[e++]=g;d.length=e;return d}else return a}a=a.getElementsByTagName(b||"*");if(c){d={};for(f=e=0;g=a[f];f++){b=g.className;if(typeof b.split=="function"&&
-Ca(b.split(/\s+/),c)>=0)d[e++]=g}d.length=e;return d}else return a},zb=function(a,b){Qa(b,function(c,d){if(d=="style")a.style.cssText=c;else if(d=="class")a.className=c;else if(d=="for")a.htmlFor=c;else if(d in yb)a.setAttribute(yb[d],c);else a[d]=c})},yb={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",rowspan:"rowSpan",valign:"vAlign",height:"height",width:"width",usemap:"useMap",frameborder:"frameBorder",maxlength:"maxLength",type:"type"},Ab=function(a){var b=a.document;if(B&&
-!C("500")&&!hb){if(typeof a.innerHeight=="undefined")a=window;b=a.innerHeight;var c=a.document.documentElement.scrollHeight;if(a==a.top)if(c<b)b-=15;return new z(a.innerWidth,b)}a=wb(b);if(fb&&!C("9.50"))a=k;a=a?b.documentElement:b.body;return new z(a.clientWidth,a.clientHeight)},Bb=function(a){return a?a.parentWindow||a.defaultView:window},Db=function(){return Cb(document,arguments)},Cb=function(a,b){var c=b[0],d=b[1];if(!ub&&d&&(d.name||d.type)){c=["<",c];d.name&&c.push(' name="',va(d.name),'"');
-if(d.type){c.push(' type="',va(d.type),'"');var e={};Ua(e,d);d=e;delete d.type}c.push(">");c=c.join("")}c=a.createElement(c);if(d)if(s(d))c.className=d;else p(d)?vb.apply(j,[c].concat(d)):zb(c,d);b.length>2&&Eb(a,c,b,2);return c},Eb=function(a,b,c,d){function e(g){if(g)b.appendChild(s(g)?a.createTextNode(g):g)}for(;d<c.length;d++){var f=c[d];ca(f)&&!(ea(f)&&f.nodeType>0)?Da(Fb(f)?Ia(f):f,e):e(f)}},wb=function(a){return a.compatMode=="CSS1Compat"},Gb=function(a){a&&a.parentNode&&a.parentNode.removeChild(a)},
-Hb=function(a,b){var c=b.parentNode;c&&c.replaceChild(a,b)},F=function(a){return a.nodeType==9?a:a.ownerDocument||a.document},Ib=function(a,b){if("textContent"in a)a.textContent=b;else if(a.firstChild&&a.firstChild.nodeType==3){for(;a.lastChild!=a.firstChild;)a.removeChild(a.lastChild);a.firstChild.data=b}else{for(var c;c=a.firstChild;)a.removeChild(c);a.appendChild(F(a).createTextNode(b))}},Fb=function(a){if(a&&typeof a.length=="number")if(ea(a))return typeof a.item=="function"||typeof a.item=="string";
-else if(da(a))return typeof a.item=="function";return k},E=function(a){this.h=a||n.document||document};E.prototype.m=G;var Jb=function(a){return a.h};E.prototype.c=function(a){return s(a)?this.h.getElementById(a):a};E.prototype.j=function(){return Cb(this.h,arguments)};E.prototype.createElement=function(a){return this.h.createElement(a)};E.prototype.createTextNode=function(a){return this.h.createTextNode(a)};
-var Kb=function(a){a=!B&&wb(a.h)?a.h.documentElement:a.h.body;return new Pa(a.scrollLeft,a.scrollTop)};E.prototype.appendChild=function(a,b){a.appendChild(b)};E.prototype.append=function(a){Eb(F(a),a,arguments,1)};var H=function(a,b,c,d,e){this.n=!!b;a&&Lb(this,a,d);this.la=e!=undefined?e:this.o||0;if(this.n)this.la*=-1;this.Xb=!c};v(H,Ma);H.prototype.q=j;H.prototype.o=0;H.prototype.Kb=k;var Lb=function(a,b,c){if(a.q=b)a.o=typeof c=="number"?c:a.q.nodeType!=1?0:a.n?-1:1};
-H.prototype.next=function(){var a;if(this.Kb){if(!this.q||this.Xb&&this.la==0)h(y);a=this.q;var b=this.n?-1:1;if(this.o==b){var c=this.n?a.lastChild:a.firstChild;c?Lb(this,c):Lb(this,a,b*-1)}else(c=this.n?a.previousSibling:a.nextSibling)?Lb(this,c):Lb(this,a.parentNode,b*-1);this.la+=this.o*(this.n?-1:1)}else this.Kb=i;(a=this.q)||h(y);return a};
-H.prototype.splice=function(){var a=this.q,b=this.n?1:-1;if(this.o==b){this.o=b*-1;this.la+=this.o*(this.n?-1:1)}this.n=!this.n;H.prototype.next.call(this);this.n=!this.n;b=ca(arguments[0])?arguments[0]:arguments;for(var c=b.length-1;c>=0;c--)a.parentNode&&a.parentNode.insertBefore(b[c],a.nextSibling);Gb(a)};var Mb=new Function("a","return a");var Nb,Ob=!A||C("9"),Pb=A&&!C("8");var Qb=function(){};Qb.prototype.mb=k;Qb.prototype.t=function(){if(!this.mb){this.mb=i;this.g()}};Qb.prototype.g=function(){};var I=function(a,b){this.type=a;this.currentTarget=this.target=b};v(I,Qb);m=I.prototype;m.g=function(){delete this.type;delete this.target;delete this.currentTarget};m.U=k;m.ra=i;m.stopPropagation=function(){this.U=i};m.preventDefault=function(){this.ra=k};var Rb=function(a){a.preventDefault()};var J=function(a,b){a&&this.aa(a,b)};v(J,I);var Sb=[1,4,2];m=J.prototype;m.target=j;m.relatedTarget=j;m.offsetX=0;m.offsetY=0;m.clientX=0;m.clientY=0;m.screenX=0;m.screenY=0;m.button=0;m.keyCode=0;m.charCode=0;m.ctrlKey=k;m.altKey=k;m.shiftKey=k;m.metaKey=k;m.Ac=k;m.u=j;
-m.aa=function(a,b){var c=this.type=a.type;I.call(this,c);this.target=a.target||a.srcElement;this.currentTarget=b;var d=a.relatedTarget;if(d){if(gb)try{Mb(d.nodeName)}catch(e){d=j}}else if(c=="mouseover")d=a.fromElement;else if(c=="mouseout")d=a.toElement;this.relatedTarget=d;this.offsetX=a.offsetX!==undefined?a.offsetX:a.layerX;this.offsetY=a.offsetY!==undefined?a.offsetY:a.layerY;this.clientX=a.clientX!==undefined?a.clientX:a.pageX;this.clientY=a.clientY!==undefined?a.clientY:a.pageY;this.screenX=
-a.screenX||0;this.screenY=a.screenY||0;this.button=a.button;this.keyCode=a.keyCode||0;this.charCode=a.charCode||(c=="keypress"?a.keyCode:0);this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=a.shiftKey;this.metaKey=a.metaKey;this.Ac=ab?a.metaKey:a.ctrlKey;this.state=a.state;this.u=a;delete this.ra;delete this.U};m.stopPropagation=function(){J.k.stopPropagation.call(this);if(this.u.stopPropagation)this.u.stopPropagation();else this.u.cancelBubble=i};
-m.preventDefault=function(){J.k.preventDefault.call(this);var a=this.u;if(a.preventDefault)a.preventDefault();else{a.returnValue=k;if(Pb)try{if(a.ctrlKey||a.keyCode>=112&&a.keyCode<=123)a.keyCode=-1}catch(b){}}};m.g=function(){J.k.g.call(this);this.relatedTarget=this.currentTarget=this.target=this.u=j};var K=function(a,b){this.Ab=b;this.R=[];a>this.Ab&&h(Error("[goog.structs.SimplePool] Initial cannot be greater than max"));for(var c=0;c<a;c++)this.R.push(this.C?this.C():{})};v(K,Qb);K.prototype.C=j;K.prototype.lb=j;K.prototype.getObject=function(){if(this.R.length)return this.R.pop();return this.C?this.C():{}};var Ub=function(a,b){a.R.length<a.Ab?a.R.push(b):Tb(a,b)},Tb=function(a,b){if(a.lb)a.lb(b);else if(ea(b))if(da(b.t))b.t();else for(var c in b)delete b[c]};
-K.prototype.g=function(){K.k.g.call(this);for(var a=this.R;a.length;)Tb(this,a.pop());delete this.R};var Vb;var Wb=(Vb="ScriptEngine"in n&&n.ScriptEngine()=="JScript")?n.ScriptEngineMajorVersion()+"."+n.ScriptEngineMinorVersion()+"."+n.ScriptEngineBuildVersion():"0";var Xb=function(){},Yb=0;m=Xb.prototype;m.key=0;m.ha=k;m.Pa=k;m.aa=function(a,b,c,d,e,f){if(da(a))this.xb=i;else if(a&&a.handleEvent&&da(a.handleEvent))this.xb=k;else h(Error("Invalid listener argument"));this.ca=a;this.Fb=b;this.src=c;this.type=d;this.capture=!!e;this.Da=f;this.Pa=k;this.key=++Yb;this.ha=k};m.handleEvent=function(a){if(this.xb)return this.ca.call(this.Da||this.src,a);return this.ca.handleEvent.call(this.ca,a)};var Zb,$b,ac,bc,cc,dc,ec,fc,gc,hc,ic;
-(function(){function a(){return{i:0,v:0}}function b(){return[]}function c(){var r=function(D){return g.call(r.src,r.key,D)};return r}function d(){return new Xb}function e(){return new J}var f=Vb&&!(xa(Wb,"5.7")>=0),g;dc=function(r){g=r};if(f){Zb=function(){return l.getObject()};$b=function(r){Ub(l,r)};ac=function(){return o.getObject()};bc=function(r){Ub(o,r)};cc=function(){return q.getObject()};ec=function(){Ub(q,c())};fc=function(){return la.getObject()};gc=function(r){Ub(la,r)};hc=function(){return u.getObject()};
-ic=function(r){Ub(u,r)};var l=new K(0,600);l.C=a;var o=new K(0,600);o.C=b;var q=new K(0,600);q.C=c;var la=new K(0,600);la.C=d;var u=new K(0,600);u.C=e}else{Zb=a;$b=aa;ac=b;bc=aa;cc=c;ec=aa;fc=d;gc=aa;hc=e;ic=aa}})();var jc={},L={},M={},kc={},N=function(a,b,c,d,e){if(b)if(p(b)){for(var f=0;f<b.length;f++)N(a,b[f],c,d,e);return j}else{d=!!d;var g=L;b in g||(g[b]=Zb());g=g[b];if(!(d in g)){g[d]=Zb();g.i++}g=g[d];var l=ha(a),o;g.v++;if(g[l]){o=g[l];for(f=0;f<o.length;f++){g=o[f];if(g.ca==c&&g.Da==e){if(g.ha)break;return o[f].key}}}else{o=g[l]=ac();g.i++}f=cc();f.src=a;g=fc();g.aa(c,f,a,b,d,e);c=g.key;f.key=c;o.push(g);jc[c]=g;M[l]||(M[l]=ac());M[l].push(g);if(a.addEventListener){if(a==n||!a.kb)a.addEventListener(b,
-f,d)}else a.attachEvent(lc(b),f);return c}else h(Error("Invalid event type"))},mc=function(a,b,c,d,e){if(p(b)){for(var f=0;f<b.length;f++)mc(a,b[f],c,d,e);return j}a=N(a,b,c,d,e);jc[a].Pa=i;return a},nc=function(a,b,c,d,e){if(p(b))for(var f=0;f<b.length;f++)nc(a,b[f],c,d,e);else{d=!!d;if(a=oc(a,b,d))for(f=0;f<a.length;f++)if(a[f].ca==c&&a[f].capture==d&&a[f].Da==e){O(a[f].key);break}}},O=function(a){if(jc[a]){var b=jc[a];if(!b.ha){var c=b.src,d=b.type,e=b.Fb,f=b.capture;if(c.removeEventListener){if(c==
-n||!c.kb)c.removeEventListener(d,e,f)}else c.detachEvent&&c.detachEvent(lc(d),e);c=ha(c);e=L[d][f][c];if(M[c]){var g=M[c],l=Ca(g,b);if(l>=0){Ba(g.length!=j);x.splice.call(g,l,1)}g.length==0&&delete M[c]}b.ha=i;e.Bb=i;pc(d,f,c,e);delete jc[a]}}},pc=function(a,b,c,d){if(!d.Fa)if(d.Bb){for(var e=0,f=0;e<d.length;e++)if(d[e].ha){var g=d[e].Fb;g.src=j;ec(g);gc(d[e])}else{if(e!=f)d[f]=d[e];f++}d.length=f;d.Bb=k;if(f==0){bc(d);delete L[a][b][c];L[a][b].i--;if(L[a][b].i==0){$b(L[a][b]);delete L[a][b];L[a].i--}if(L[a].i==
-0){$b(L[a]);delete L[a]}}}},qc=function(a){var b,c=0,d=b==j;b=!!b;if(a==j)Qa(M,function(g){for(var l=g.length-1;l>=0;l--){var o=g[l];if(d||b==o.capture){O(o.key);c++}}});else{a=ha(a);if(M[a]){a=M[a];for(var e=a.length-1;e>=0;e--){var f=a[e];if(d||b==f.capture){O(f.key);c++}}}}},oc=function(a,b,c){var d=L;if(b in d){d=d[b];if(c in d){d=d[c];a=ha(a);if(d[a])return d[a]}}return j},lc=function(a){if(a in kc)return kc[a];return kc[a]="on"+a},sc=function(a,b,c,d,e){var f=1;b=ha(b);if(a[b]){a.v--;a=a[b];
-if(a.Fa)a.Fa++;else a.Fa=1;try{for(var g=a.length,l=0;l<g;l++){var o=a[l];if(o&&!o.ha)f&=rc(o,e)!==k}}finally{a.Fa--;pc(c,d,b,a)}}return Boolean(f)},rc=function(a,b){var c=a.handleEvent(b);a.Pa&&O(a.key);return c};
-dc(function(a,b){if(!jc[a])return i;var c=jc[a],d=c.type,e=L;if(!(d in e))return i;e=e[d];var f,g;if(Nb===undefined)Nb=A&&!n.addEventListener;if(Nb){var l;if(!(l=b))a:{l="window.event".split(".");for(var o=n;f=l.shift();)if(o[f]!=j)o=o[f];else{l=j;break a}l=o}f=l;l=i in e;o=k in e;if(l){if(f.keyCode<0||f.returnValue!=undefined)return i;a:{var q=k;if(f.keyCode==0)try{f.keyCode=-1;break a}catch(la){q=i}if(q||f.returnValue==undefined)f.returnValue=i}}q=hc();q.aa(f,this);f=i;try{if(l){for(var u=ac(),
-r=q.currentTarget;r;r=r.parentNode)u.push(r);g=e[i];g.v=g.i;for(var D=u.length-1;!q.U&&D>=0&&g.v;D--){q.currentTarget=u[D];f&=sc(g,u[D],d,i,q)}if(o){g=e[k];g.v=g.i;for(D=0;!q.U&&D<u.length&&g.v;D++){q.currentTarget=u[D];f&=sc(g,u[D],d,k,q)}}}else f=rc(c,q)}finally{if(u){u.length=0;bc(u)}q.t();ic(q)}return f}d=new J(b,this);try{f=rc(c,d)}finally{d.t()}return f});var P=function(a){this.ab=a};v(P,Qb);
-var tc=new K(0,100),uc=[],Q=function(a,b,c,d,e){if(!p(c)){uc[0]=c;c=uc}for(var f=0;f<c.length;f++)vc(a,N(b,c[f],d||a,e||k,a.ab||a));return a},wc=function(a,b,c,d,e,f){if(p(c))for(var g=0;g<c.length;g++)wc(a,b,c[g],d,e,f);else vc(a,mc(b,c,d||a,e||k,f||a.ab||a))},vc=function(a,b){if(a.a)a.a[b]=i;else if(a.L){a.a=tc.getObject();a.a[a.L]=i;a.L=j;a.a[b]=i}else a.L=b},xc=function(a,b,c,d,e,f){if(a.L||a.a)if(p(c))for(var g=0;g<c.length;g++)xc(a,b,c[g],d,e,f);else{a:{d=d||a;f=f||a.ab||a;e=!!e;if(b=oc(b,c,
-e))for(c=0;c<b.length;c++)if(b[c].ca==d&&b[c].capture==e&&b[c].Da==f){b=b[c];break a}b=j}if(b){b=b.key;O(b);if(a.a){c=a.a;b in c&&delete c[b]}else if(a.L==b)a.L=j}}return a};P.prototype.ga=function(){if(this.a){for(var a in this.a){O(a);delete this.a[a]}Ub(tc,this.a);this.a=j}else this.L&&O(this.L)};P.prototype.g=function(){P.k.g.call(this);this.ga()};P.prototype.handleEvent=function(){h(Error("EventHandler.handleEvent not implemented"))};var R=function(){};v(R,Qb);m=R.prototype;m.kb=i;m.Ha=j;m.fb=function(a){this.Ha=a};m.addEventListener=function(a,b,c,d){N(this,a,b,c,d)};m.removeEventListener=function(a,b,c,d){nc(this,a,b,c,d)};
-m.dispatchEvent=function(a){var b=a.type||a,c=L;if(b in c){if(s(a))a=new I(a,this);else if(a instanceof I)a.target=a.target||this;else{var d=a;a=new I(b,this);Ua(a,d)}d=1;var e;c=c[b];b=i in c;var f;if(b){e=[];for(f=this;f;f=f.Ha)e.push(f);f=c[i];f.v=f.i;for(var g=e.length-1;!a.U&&g>=0&&f.v;g--){a.currentTarget=e[g];d&=sc(f,e[g],a.type,i,a)&&a.ra!=k}}if(k in c){f=c[k];f.v=f.i;if(b)for(g=0;!a.U&&g<e.length&&f.v;g++){a.currentTarget=e[g];d&=sc(f,e[g],a.type,k,a)&&a.ra!=k}else for(e=this;!a.U&&e&&f.v;e=
-e.Ha){a.currentTarget=e;d&=sc(f,e,a.type,k,a)&&a.ra!=k}}a=Boolean(d)}else a=i;return a};m.g=function(){R.k.g.call(this);qc(this);this.Ha=j};var yc=function(a){a=String(a);var b;b=/^\s*$/.test(a)?k:/^[\],:{}\s\u2028\u2029]*$/.test(a.replace(/\\["\\\/bfnrtu]/g,"@").replace(/"[^"\\\n\r\u2028\u2029\x00-\x08\x10-\x1f\x80-\x9f]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:[\s\u2028\u2029]*\[)+/g,""));if(b)try{return eval("("+a+")")}catch(c){}h(Error("Invalid JSON string: "+a))},zc=function(){},Bc=function(a,b,c){switch(typeof b){case "string":Ac(a,b,c);break;case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");
-break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(b==j){c.push("null");break}if(p(b)){var d=b.length;c.push("[");for(var e="",f=0;f<d;f++){c.push(e);Bc(a,b[f],c);e=","}c.push("]");break}c.push("{");d="";for(e in b)if(Object.prototype.hasOwnProperty.call(b,e)){f=b[e];if(typeof f!="function"){c.push(d);Ac(a,e,c);c.push(":");Bc(a,f,c);d=","}}c.push("}");break;case "function":break;default:h(Error("Unknown type: "+typeof b))}},Cc={'"':'\\"',"\\":"\\\\","/":"\\/",
-"\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},Dc=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g,Ac=function(a,b,c){c.push('"',b.replace(Dc,function(d){if(d in Cc)return Cc[d];var e=d.charCodeAt(0),f="\\u";if(e<16)f+="000";else if(e<256)f+="00";else if(e<4096)f+="0";return Cc[d]=f+e.toString(16)}),'"')};var Ec=function(a){this.w=Vb?[]:"";a!=j&&this.append.apply(this,arguments)};Ec.prototype.N=function(a){this.clear();this.append(a)};if(Vb){Ec.prototype.Oa=0;Ec.prototype.append=function(a,b){if(b==j)this.w[this.Oa++]=a;else{this.w.push.apply(this.w,arguments);this.Oa=this.w.length}return this}}else Ec.prototype.append=function(a,b){this.w+=a;if(b!=j)for(var c=1;c<arguments.length;c++)this.w+=arguments[c];return this};Ec.prototype.clear=function(){if(Vb)this.Oa=this.w.length=0;else this.w=""};
-Ec.prototype.toString=function(){if(Vb){var a=this.w.join("");this.clear();a&&this.append(a);return a}else return this.w};var Fc=function(a,b,c,d){this.left=a;this.top=b;this.width=c;this.height=d};Fc.prototype.toString=function(){return"("+this.left+", "+this.top+" - "+this.width+"w x "+this.height+"h)"};var Hc=function(a,b){s("background-color")?Gc(a,b,"background-color"):Qa("background-color",ma(Gc,a))},Gc=function(a,b,c){a.style[za(c)]=b},Ic=function(a,b){var c=F(a);if(c.defaultView&&c.defaultView.getComputedStyle)if(c=c.defaultView.getComputedStyle(a,j))return c[b]||c.getPropertyValue(b);return""},S=function(a,b){return Ic(a,b)||(a.currentStyle?a.currentStyle[b]:j)||a.style[b]},Kc=function(a,b,c){var d,e=gb&&(ab||jb)&&C("1.9");if(b instanceof Pa){d=b.x;b=b.y}else{d=b;b=c}a.style.left=Jc(d,e);
-a.style.top=Jc(b,e)},Lc=function(a){if(A)return a.offsetParent;var b=F(a),c=S(a,"position"),d=c=="fixed"||c=="absolute";for(a=a.parentNode;a&&a!=b;a=a.parentNode){c=S(a,"position");d=d&&c=="static"&&a!=b.documentElement&&a!=b.body;if(!d&&(a.scrollWidth>a.clientWidth||a.scrollHeight>a.clientHeight||c=="fixed"||c=="absolute"))return a}return j},Mc=function(a){var b,c=F(a),d=S(a,"position"),e=gb&&c.getBoxObjectFor&&!a.getBoundingClientRect&&d=="absolute"&&(b=c.getBoxObjectFor(a))&&(b.screenX<0||b.screenY<
-0),f=new Pa(0,0),g;b=c?c.nodeType==9?c:F(c):document;if(g=A){g=G(b);g=!wb(g.h)}g=g?b.body:b.documentElement;if(a==g)return f;if(a.getBoundingClientRect){d=a.getBoundingClientRect();if(A){a=a.ownerDocument;d.left-=a.documentElement.clientLeft+a.body.clientLeft;d.top-=a.documentElement.clientTop+a.body.clientTop}b=d;c=Kb(G(c));f.x=b.left+c.x;f.y=b.top+c.y}else if(c.getBoxObjectFor&&!e){b=c.getBoxObjectFor(a);c=c.getBoxObjectFor(g);f.x=b.screenX-c.screenX;f.y=b.screenY-c.screenY}else{e=a;do{f.x+=e.offsetLeft;
-f.y+=e.offsetTop;if(e!=a){f.x+=e.clientLeft||0;f.y+=e.clientTop||0}if(B&&S(e,"position")=="fixed"){f.x+=c.body.scrollLeft;f.y+=c.body.scrollTop;break}e=e.offsetParent}while(e&&e!=a);if(fb||B&&d=="absolute")f.y-=c.body.offsetTop;for(e=a;(e=Lc(e))&&e!=c.body&&e!=g;){f.x-=e.scrollLeft;if(!fb||e.tagName!="TR")f.y-=e.scrollTop}}return f},Nc=function(a,b,c){if(b instanceof z){c=b.height;b=b.width}else c==undefined&&h(Error("missing height argument"));a.style.width=Jc(b,i);a.style.height=Jc(c,i)},Jc=function(a,
-b){if(typeof a=="number")a=(b?Math.round(a):a)+"px";return a},Oc=function(a){var b=fb&&!C("10");if(S(a,"display")!="none")return b?new z(a.offsetWidth||a.clientWidth,a.offsetHeight||a.clientHeight):new z(a.offsetWidth,a.offsetHeight);var c=a.style,d=c.display,e=c.visibility,f=c.position;c.visibility="hidden";c.position="absolute";c.display="inline";if(b){b=a.offsetWidth||a.clientWidth;a=a.offsetHeight||a.clientHeight}else{b=a.offsetWidth;a=a.offsetHeight}c.display=d;c.position=f;c.visibility=e;return new z(b,
-a)},Pc=function(a,b){var c=a.style;if("opacity"in c)c.opacity=b;else if("MozOpacity"in c)c.MozOpacity=b;else if("filter"in c)c.filter=b===""?"":"alpha(opacity="+b*100+")"},T=function(a,b){a.style.display=b?"":"none"},Qc=function(a,b){if(A)a.cssText=b;else a[B?"innerText":"innerHTML"]=b};var Rc=function(a){a.setAttribute("role","dialog");a.Qc="dialog"};var Sc=function(a){this.b=a;a=A?"focusout":"blur";this.qc=N(this.b,A?"focusin":"focus",this,!A);this.rc=N(this.b,a,this,!A)};v(Sc,R);Sc.prototype.handleEvent=function(a){var b=new J(a.u);b.type=a.type=="focusin"||a.type=="focus"?"focusin":"focusout";try{this.dispatchEvent(b)}finally{b.t()}};Sc.prototype.g=function(){Sc.k.g.call(this);O(this.qc);O(this.rc);delete this.b};var Tc=function(a,b,c){this.target=a;this.handle=b||a;this.bb=c||new Fc(NaN,NaN,NaN,NaN);this.h=F(a);this.l=new P(this);N(this.handle,["touchstart","mousedown"],this.Hb,k,this)};v(Tc,R);var Uc=A||gb&&C("1.9.3");m=Tc.prototype;m.clientX=0;m.clientY=0;m.screenX=0;m.screenY=0;m.Ib=0;m.Jb=0;m.ja=0;m.ka=0;m.ob=i;m.K=k;m.ub=0;m.tc=0;m.oc=k;m.X=function(){return this.l};
-m.g=function(){Tc.k.g.call(this);nc(this.handle,["touchstart","mousedown"],this.Hb,k,this);this.l.t();delete this.target;delete this.handle;delete this.l};
-m.Hb=function(a){var b=a.type=="mousedown";if(this.ob&&!this.K&&(!b||(Ob?a.u.button==0:a.type=="click"||a.u.button&Sb[0])&&!(B&&ab&&a.ctrlKey))){Vc(this,a);if(this.ub==0){Wc(this,a);if(this.K)a.preventDefault();else return}else a.preventDefault();b=this.h;var c=b.documentElement,d=!Uc;Q(this.l,b,["touchmove","mousemove"],this.lc,d);Q(this.l,b,["touchend","mouseup"],this.za,d);if(Uc){c.setCapture(k);Q(this.l,c,"losecapture",this.za)}else Q(this.l,Bb(b),"blur",this.za);A&&this.oc&&Q(this.l,b,"dragstart",
-Rb);this.Fc&&Q(this.l,this.Fc,"scroll",this.xc,d);this.clientX=this.Ib=a.clientX;this.clientY=this.Jb=a.clientY;this.screenX=a.screenX;this.screenY=a.screenY;this.ja=this.target.offsetLeft;this.ka=this.target.offsetTop;this.qa=Kb(G(this.h));this.tc=na()}};var Wc=function(a,b){if(a.dispatchEvent(new Xc("start",a,b.clientX,b.clientY,b))!==k)a.K=i};
-Tc.prototype.za=function(a,b){this.l.ga();Uc&&this.h.releaseCapture();if(this.K){Vc(this,a);this.K=k;this.dispatchEvent(new Xc("end",this,a.clientX,a.clientY,a,Yc(this,this.ja),Zc(this,this.ka),b||a.type=="touchcancel"))}if(a.type=="touchend"||a.type=="touchcancel")a.preventDefault()};var Vc=function(a,b){var c=b.type;if(c=="touchstart"||c=="touchmove")b.aa(b.u.targetTouches[0],b.currentTarget);else if(c=="touchend"||c=="touchcancel")b.aa(b.u.changedTouches[0],b.currentTarget)};
-Tc.prototype.lc=function(a){if(this.ob){Vc(this,a);var b=a.clientX-this.clientX,c=a.clientY-this.clientY;this.clientX=a.clientX;this.clientY=a.clientY;this.screenX=a.screenX;this.screenY=a.screenY;if(!this.K){var d=this.Ib-this.clientX,e=this.Jb-this.clientY;if(d*d+e*e>this.ub){Wc(this,a);if(!this.K){this.za(a);return}}}c=$c(this,b,c);b=c.x;c=c.y;if(this.K)if(this.dispatchEvent(new Xc("beforedrag",this,a.clientX,a.clientY,a,b,c))!==k){ad(this,a,b,c,k);a.preventDefault()}}};
-var $c=function(a,b,c){var d=Kb(G(a.h));b+=d.x-a.qa.x;c+=d.y-a.qa.y;a.qa=d;a.ja+=b;a.ka+=c;return new Pa(Yc(a,a.ja),Zc(a,a.ka))};Tc.prototype.xc=function(a){var b=$c(this,0,0);a.clientX=this.qa.x-this.clientX;a.clientY=this.qa.y-this.clientY;ad(this,a,b.x,b.y,i)};
-var ad=function(a,b,c,d){a.target.style.left=c+"px";a.target.style.top=d+"px";a.dispatchEvent(new Xc("drag",a,b.clientX,b.clientY,b,c,d))},Yc=function(a,b){var c=a.bb,d=!isNaN(c.left)?c.left:j;c=!isNaN(c.width)?c.width:0;return Math.min(d!=j?d+c:Infinity,Math.max(d!=j?d:-Infinity,b))},Zc=function(a,b){var c=a.bb,d=!isNaN(c.top)?c.top:j;c=!isNaN(c.height)?c.height:0;return Math.min(d!=j?d+c:Infinity,Math.max(d!=j?d:-Infinity,b))},Xc=function(a,b,c,d,e,f,g,l){I.call(this,a);this.clientX=c;this.clientY=
-d;this.Mc=e;this.left=f!==undefined?f:b.ja;this.top=g!==undefined?g:b.ka;this.Oc=b;this.Nc=!!l};v(Xc,I);var bd=function(a){if(typeof a.Ca=="function")return a.Ca();if(s(a))return a.split("");if(ca(a)){for(var b=[],c=a.length,d=0;d<c;d++)b.push(a[d]);return b}return Ra(a)},cd=function(a,b,c){if(typeof a.forEach=="function")a.forEach(b,c);else if(ca(a)||s(a))Da(a,b,c);else{var d;if(typeof a.Za=="function")d=a.Za();else if(typeof a.Ca!="function")if(ca(a)||s(a)){d=[];for(var e=a.length,f=0;f<e;f++)d.push(f)}else d=Sa(a);else d=void 0;e=bd(a);f=e.length;for(var g=0;g<f;g++)b.call(c,e[g],d&&d[g],a)}};var U=function(a){this.M={};this.a=[];var b=arguments.length;if(b>1){b%2&&h(Error("Uneven number of arguments"));for(var c=0;c<b;c+=2)this.N(arguments[c],arguments[c+1])}else if(a){if(a instanceof U){b=a.Za();c=a.Ca()}else{b=Sa(a);c=Ra(a)}for(var d=0;d<b.length;d++)this.N(b[d],c[d])}};m=U.prototype;m.i=0;m.La=0;m.Ca=function(){dd(this);for(var a=[],b=0;b<this.a.length;b++)a.push(this.M[this.a[b]]);return a};m.Za=function(){dd(this);return this.a.concat()};m.Ea=function(){return this.i==0};
-m.clear=function(){this.M={};this.La=this.i=this.a.length=0};var dd=function(a){if(a.i!=a.a.length){for(var b=0,c=0;b<a.a.length;){var d=a.a[b];if(Object.prototype.hasOwnProperty.call(a.M,d))a.a[c++]=d;b++}a.a.length=c}if(a.i!=a.a.length){var e={};for(c=b=0;b<a.a.length;){d=a.a[b];if(!Object.prototype.hasOwnProperty.call(e,d)){a.a[c++]=d;e[d]=1}b++}a.a.length=c}};U.prototype.get=function(a,b){if(Object.prototype.hasOwnProperty.call(this.M,a))return this.M[a];return b};
-U.prototype.N=function(a,b){if(!Object.prototype.hasOwnProperty.call(this.M,a)){this.i++;this.a.push(a);this.La++}this.M[a]=b};U.prototype.Na=function(a){dd(this);var b=0,c=this.a,d=this.M,e=this.La,f=this,g=new Ma;g.next=function(){for(;;){e!=f.La&&h(Error("The map has changed since the iterator was created"));b>=c.length&&h(y);var l=c[b++];return a?l:d[l]}};return g};var ed=n.window;var fd=function(){};(function(a){a.rb=function(){return a.pc||(a.pc=new a)}})(fd);fd.prototype.Cb=0;fd.rb();var V=function(a){this.ya=a||G();this.Dc=gd};v(V,R);V.prototype.vb=fd.rb();var gd=j;m=V.prototype;m.$=j;m.G=k;m.b=j;m.Dc=j;m.sc=j;m.fa=j;m.va=j;m.ua=j;m.Kc=k;m.c=function(){return this.b};m.X=function(){return this.Z||(this.Z=new P(this))};m.fb=function(a){this.fa&&this.fa!=a&&h(Error("Method not supported"));V.k.fb.call(this,a)};m.m=function(){return this.ya};m.j=function(){this.b=this.ya.createElement("div")};
-m.ia=function(a){this.G&&h(Error("Component already rendered"));this.b||this.j();a?a.insertBefore(this.b,j):this.ya.h.body.appendChild(this.b);if(!this.fa||this.fa.G)this.Aa()};m.Aa=function(){this.G=i;hd(this,function(a){!a.G&&a.c()&&a.Aa()})};m.na=function(){hd(this,function(a){a.G&&a.na()});this.Z&&this.Z.ga();this.G=k};
-m.g=function(){V.k.g.call(this);this.G&&this.na();if(this.Z){this.Z.t();delete this.Z}hd(this,function(a){a.t()});!this.Kc&&this.b&&Gb(this.b);this.fa=this.sc=this.b=this.ua=this.va=j};var hd=function(a,b){a.va&&Da(a.va,b,void 0)};
-V.prototype.removeChild=function(a,b){if(a){var c=s(a)?a:a.$||(a.$=":"+(a.vb.Cb++).toString(36)),d;if(this.ua&&c){d=this.ua;d=c in d?d[c]:void 0;d=d||j}else d=j;a=d;if(c&&a){d=this.ua;c in d&&delete d[c];c=this.va;d=Ca(c,a);if(d>=0){Ba(c.length!=j);x.splice.call(c,d,1)}if(b){a.na();a.b&&Gb(a.b)}c=a;c==j&&h(Error("Unable to set parent component"));c.fa=j;V.k.fb.call(c,j)}}a||h(Error("Child is not in parent component"));return a};var W=function(a,b,c){V.call(this,c);this.s=a||"modal-dialog";this.ib=!!b;this.r=id()};v(W,V);m=W.prototype;m.Ba=j;m.$b=i;m.sb=i;m.ib=k;m.pa=i;m.nb=i;m.Tb=0.5;m.Ob="";m.Sa="";m.r=j;m.V=j;m.jb=k;m.Yb=k;m.f=j;m.e=j;m.Ka=j;m.ta=j;m.Nb=j;m.Ja=j;m.wa=j;m.z=j;
-m.j=function(){jd(this);var a=this.m();this.b=a.j("div",{className:this.s,tabIndex:0},this.Ka=a.j("div",{className:this.s+"-title",id:this.$||(this.$=":"+(this.vb.Cb++).toString(36))},this.ta=a.j("span",this.s+"-title-text",this.Ob),this.Ja=a.j("span",this.s+"-title-close")),this.wa=a.j("div",this.s+"-content"),this.z=a.j("div",this.s+"-buttons"),this.Lb=a.j("span",{tabIndex:0}));this.Nb=this.Ka.id;Rc(this.c());this.c().setAttribute("aria-labelledby",this.Nb||"");if(this.Sa)this.wa.innerHTML=this.Sa;
-T(this.Ja,this.sb);T(this.c(),k);if(this.r){a=this.r;a.b=this.z;a.ia()}};var jd=function(a){if(a.ib&&a.pa&&!a.e){var b;b=a.m().j("iframe",{frameborder:0,style:"border:0;vertical-align:bottom;",src:'javascript:""'});a.e=b;a.e.className=a.s+"-bg";T(a.e,k);Pc(a.e,0)}else if((!a.ib||!a.pa)&&a.e){Gb(a.e);a.e=j}if(a.pa&&!a.f){a.f=a.m().j("div",a.s+"-bg");Pc(a.f,a.Tb);T(a.f,k)}else if(!a.pa&&a.f){Gb(a.f);a.f=j}};
-W.prototype.ia=function(a){this.G&&h(Error("Component already rendered"));this.c()||this.j();a=a||Jb(this.m()).body;this.e&&a.appendChild(this.e);this.f&&a.appendChild(this.f);W.k.ia.call(this,a)};
-W.prototype.Aa=function(){W.k.Aa.call(this);this.Ba=new Sc(Jb(this.m()));if(this.nb&&!this.V){var a=new Tc(this.c(),this.Ka);vb(this.Ka,this.s+"-title-draggable");this.V=a}Q(Q(this.X(),this.Ja,"click",this.yc),this.Ba,"focusin",this.wc);Rc(this.c());this.ta.id!==""&&this.c().setAttribute("aria-labelledby",this.ta.id)};W.prototype.na=function(){this.jb&&kd(this,k);this.Ba.t();this.Ba=j;if(this.V){this.V.t();this.V=j}W.k.na.call(this)};
-var kd=function(a,b){if(b!=a.jb){var c=Jb(a.m()),d=Bb(c)||window;a.G||a.ia(c.body);if(b){ld(a);md(a);Q(Q(Q(a.X(),a.c(),"keydown",a.Ga),a.c(),"keypress",a.Ga),d,"resize",a.Eb)}else xc(xc(xc(a.X(),a.c(),"keydown",a.Ga),a.c(),"keypress",a.Ga),d,"resize",a.Eb);a.e&&T(a.e,b);a.f&&T(a.f,b);T(a.c(),b);b&&a.focus();if(a.jb=b)Q(a.X(),a.z,"click",a.Db);else{xc(a.X(),a.z,"click",a.Db);a.dispatchEvent("afterhide");a.Yb&&a.t()}}};
-W.prototype.focus=function(){try{this.c().focus()}catch(a){}if(this.r){var b=this.r.xa;if(b)for(var c=Jb(this.m()),d=this.z.getElementsByTagName("button"),e=0,f;f=d[e];e++)if(f.name==b){try{if(B||fb){var g=c.createElement("input");g.style.cssText="position:fixed;width:0;height:0;left:0;top:0;";this.c().appendChild(g);g.focus();this.c().removeChild(g)}f.focus()}catch(l){}break}}};
-var ld=function(a){a.e&&T(a.e,k);a.f&&T(a.f,k);var b=Jb(a.m()),c=Ab(Bb(b)||window||window),d=Math.max(b.body.scrollWidth,c.width);b=Math.max(b.body.scrollHeight,c.height);if(a.e){T(a.e,i);Nc(a.e,d,b)}if(a.f){T(a.f,i);Nc(a.f,d,b)}if(a.nb){c=Oc(a.c());a.V.bb=new Fc(0,0,d-c.width,b-c.height)}},md=function(a){var b=Jb(a.m()),c=Bb(b)||window;if(S(a.c(),"position")=="fixed")var d=b=0;else{d=Kb(a.m());b=d.x;d=d.y}var e=Oc(a.c());c=Ab(c||window);Kc(a.c(),Math.max(b+c.width/2-e.width/2,0),Math.max(d+c.height/
-2-e.height/2,0))};m=W.prototype;m.yc=function(){if(this.sb){var a=this.r,b=a&&a.Qa;if(b){a=a.get(b);this.dispatchEvent(new nd(b,a))&&kd(this,k)}else kd(this,k)}};m.g=function(){W.k.g.call(this);if(this.f){Gb(this.f);this.f=j}if(this.e){Gb(this.e);this.e=j}this.Lb=this.z=this.Ja=j};m.Db=function(a){a:{for(a=a.target;a!=j&&a!=this.z;){if(a.tagName=="BUTTON")break a;a=a.parentNode}a=j}if(a&&!a.disabled){a=a.name;var b=this.r.get(a);this.dispatchEvent(new nd(a,b))&&kd(this,k)}};
-m.Ga=function(a){var b=k,c=k,d=this.r,e=a.target;if(a.type=="keydown")if(this.$b&&a.keyCode==27){var f=d&&d.Qa;e=e.tagName=="SELECT"&&!e.disabled;if(f&&!e){c=i;b=d.get(f);b=this.dispatchEvent(new nd(f,b))}else e||(b=i)}else{if(a.keyCode==9&&a.shiftKey&&e==this.c())c=i}else if(a.keyCode==13){if(e.tagName=="BUTTON")f=e.name;else if(d){var g=d.xa,l;if(l=g)a:{l=d.b.getElementsByTagName("BUTTON");for(var o=0,q;q=l[o];o++)if(q.name==g||q.id==g){l=q;break a}l=j}e=(e.tagName=="TEXTAREA"||e.tagName=="SELECT")&&
-!e.disabled;if(l&&!l.disabled&&!e)f=g}if(f){c=i;b=this.dispatchEvent(new nd(f,String(d.get(f))))}}if(b||c){a.stopPropagation();a.preventDefault()}b&&kd(this,k)};m.Eb=function(){ld(this)};m.wc=function(a){if(this.Lb==a.target){a=this.cc;if(da(a)){if(this)a=ka(a,this)}else if(a&&typeof a.handleEvent=="function")a=ka(a.handleEvent,a);else h(Error("Invalid listener argument"));ed.setTimeout(a,0)}};m.cc=function(){A&&Jb(this.m()).body.focus();this.c().focus()};
-var nd=function(a,b){this.type="dialogselect";this.key=a;this.caption=b};v(nd,I);var X=function(a){this.ya=a||G();U.call(this)};v(X,U);m=X.prototype;m.s="goog-buttonset";m.xa=j;m.b=j;m.Qa=j;m.N=function(a,b,c,d){U.prototype.N.call(this,a,b);if(c)this.xa=a;if(d)this.Qa=a;return this};var Y=function(a,b,c,d){return a.N(b.key,b.caption,c,d)};
-X.prototype.ia=function(){if(this.b){this.b.innerHTML="";var a=G(this.b);cd(this,function(b,c){var d=a.j("button",{name:c},b);if(c==this.xa)d.className=this.s+"-default";this.b.appendChild(d)},this)}};var od={key:"ok",caption:"OK"},pd={key:"cancel",caption:"Cancel"},qd={key:"yes",caption:"Yes"},rd={key:"no",caption:"No"},id=function(){return Y(Y(new X,od,i),pd,k,i)};Y(new X,od,i,i);id();Y(Y(new X,qd,i),rd,k,i);Y(Y(Y(new X,qd),rd,i),pd,k,i);
-Y(Y(Y(new X,{key:"continue",caption:"Continue"}),{key:"save",caption:"Save"}),pd,i,i);var sd=RegExp("[\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc](?:[^A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff\u202a-\u202e]*[\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc])?","g"),td=RegExp("[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff](?:[^\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc\u202a-\u202e]*[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff])?",
-"g"),ud=RegExp("^[\u0000-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*[\u0000-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff]"),vd=RegExp("[\u0000-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff][\u0000-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*$"),
-wd=RegExp("[\u0000-\u001f\u0085\u00a0\u1680\u180e\u2000-\u200f\u2028\u2029\u202f\u205f\u3000]"),xd=RegExp("^[\u0000-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\u200e]+$"),yd=RegExp("^[\u0000-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\u200f]+$"),
-zd=RegExp("^[\u0000-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*\\d"),Ad=RegExp("[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc]"),Bd=function(a,b){this.text=a;this.index=b},Cd=function(a){for(var b=[],c;c=sd.exec(a);)b.push(new Bd(c[0],
-c.index));return b},Dd=function(a){for(var b=[],c;c=td.exec(a);)a.charAt(c.index-1)=="\u202e"&&a.charAt(c.index+c[0].length)=="\u202c"||b.push(new Bd(c[0],c.index));return b},Ed=function(a){if(a=zd.exec(a))return new Bd(a[0],0);return j},Fd={"\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t",'"':'\\"',"'":"\\'","\\":"\\\\"},Gd=function(a){for(var b=[],c=0;c<a.length;c++){var d=b,e=c,f;f=a.charAt(c);if(f in Fd)f=Fd[f];else{var g=f;if(wd.test(f)){var l=f.charCodeAt(0);g="\\u";if(l<4096){g+=
-"0";if(l<256){g+="0";if(l<16)g+="0"}}g+=l.toString(16)}f=Fd[f]=g}d[e]=f}return b.join("")},Hd=function(a){return a.nodeName+"="+("'"+Gd(a.nodeValue)+"'")},Id=function(a){var b=[];if(a.attributes)for(var c=0;c<a.attributes.length;++c){var d=a.attributes[c];if(d.specified===undefined||d.specified)b.push(d)}a=[a.nodeName.toLowerCase()];b=Fa(b,Hd);b.sort();a=a.concat(b);return"<"+a.join(" ")+">"},Jd=function(a){for(var b=[];a;a=a.parentNode){b.push(Id(a));if(a.id||a.nodeName=="BODY")break}b.reverse();
-return b.join("")},Kd=function(a){var b=[],c=new H(a);Oa(c,function(){c.q.nodeType==3&&b.push(c.q.data)});return b.join("")},Ld=Va("ADDRESS","BLOCKQUOTE","BODY","CAPTION","CENTER","COL","COLGROUP","DIR","DIV","DL","DD","DT","FIELDSET","FORM","H1","H2","H3","H4","H5","H6","HR","ISINDEX","OL","LI","MAP","MENU","OPTGROUP","OPTION","P","PRE","TABLE","TBODY","TD","TFOOT","TH","THEAD","TR","TL","UL"),Md=Va("inline","inline-block","inline-table"),Nd={element:j,style:j},Od=function(a){if(Nd.element==a)return Nd.style;
-var b=(a.currentStyle?a.currentStyle.display:j)||Ic(a,"display");Nd={element:a,style:b};return b},Pd=function(a){var b=Od(a);return b?!Md[b]:!!Ld[a.tagName]},Qd=function(a){if(a.nodeType==1){if(a.nodeName=="SCRIPT"||a.nodeName=="STYLE"||a.nodeName=="NOSCRIPT")return k;return Od(a)!="none"}return i};var Rd=function(a,b,c){this.T=a;this.Hc=b;this.Zb=c;this.S=[]};Rd.prototype.tb=function(){if(this.S.length==0)for(var a=0;a<this.T.length;++a)this.S.push(Sd(this.T[a],a==0?this.Hc:0,a==this.T.length-1?this.Zb:this.T[a].length));else for(a=0;a<this.S.length;++a)Hb(this.S[a],this.T[a]);return Mc(this.S[0])};Rd.prototype.Pb=function(){if(this.S.length!=0)for(var a=0;a<this.T.length;++a)Hb(this.T[a],this.S[a])};
-var Sd=function(a,b,c){b=b||0;c=c||a.data.length;var d=[];b>0&&d.push(a.data.substring(0,b));d.push(Db("span",{style:"color:red; background-color:yellow"},a.data.substring(b,c)));c<a.data.length&&d.push(a.data.substring(c));b=Db("span",j,d);Hb(b,a);return b};var Td=function(a){this.b=a};Td.prototype.eb=j;Td.prototype.tb=function(){this.eb=S(this.b,"backgroundColor");Hc(this.b,"yellow");return Mc(this.b)};Td.prototype.Pb=function(){this.eb!=j&&Hc(this.b,this.eb)};var Z=function(a,b,c,d){if(typeof a=="object"){b=["id","type","severity","atText","locationDescription","precededByText","followedByText"];c=["id","type","severity"];for(d=0;d<b.length;++d){var e=b[d];this[e]=e in a?a[e]:j;this[e]==j&&Ca(c,e)>=0&&h("Required field '"+e+"' not found in bidichecker.Error.")}}else{b==undefined&&h("Required parameter 'opt_severity' not found in bidichecker.Error.");this.id=Ud++;this.type=a;this.severity=b;Vd[this.id]=c||j;this.atText=d||j}};
-Z.prototype.precededByText=j;Z.prototype.followedByText=j;Z.prototype.locationDescription=j;Z.prototype.asString=j;var Ud=0,Vd=[];Z.prototype.Y=function(){return Vd[this.id]||j};Z.prototype.toString=function(){var a=new Ec("[",this.severity.toString(),"] ",this.type),b;if(b=this.atText)a.append(": ","'"+Gd(b)+"'");if(b=this.precededByText)a.append(" preceded by ","'"+Gd(b)+"'");if(b=this.followedByText)a.append(" followed by ","'"+Gd(b)+"'");if(b=this.locationDescription)a.append(" in ",b);return a.toString()};var Wd=function(a){this.A=a;this.p=0;this.qb=this.Q=this.P=j};Wd.prototype.kc=function(){var a;if(/[^0-9]/.test(this.Q.value))a=-1;else{a=this.Q.value;var b=Number(a);a=b==0&&/^[\s\xa0]*$/.test(a)?NaN:b;a-=1}if(a>=0&&a<this.A.length&&a!=this.p){Xd(this);this.p=a;this.Q.value=this.p+1;Yd(this)}else this.Q.value=this.p+1};Wd.prototype.gc=function(a){a=a.key=="next"?this.p==this.A.length-1?0:this.p+1:this.p==0?this.A.length-1:this.p-1;Xd(this);this.p=a;this.Q.value=this.p+1;Yd(this);return k};
-var Yd=function(a){var b=a.A[a.p],c=b.Y();if(c){var d=c.tb();c=window.scrollY;window.scrollTo(0,d.y-100);d=new Pa(a.P.offsetLeft,a.P.offsetTop);Kc(a.P,d.x,d.y+(window.scrollY-c))}Ib(a.qb,b.toString())},Xd=function(a){(a=a.A[a.p].Y())&&a.Pb()};var Zd=function(a,b){this.Ra=a;this.q=b},$d=function(a){this.ea=[new Zd(0,a)];this.zb=a};$d.prototype.append=function(a,b){if(this.zb!=b){this.ea.push(new Zd(a,b));this.zb=b}};var ae=function(a,b){var c=Ka(a.ea,function(d,e){return d-e.Ra}||La,b);return c>=0?c:-c-2};$d.prototype.Wa=function(a){return this.ea[ae(this,a)].q};$d.prototype.Y=function(a,b){for(var c=ae(this,a),d=ae(this,a+b-1),e=[],f=c;f<=d;++f)e.push(this.ea[f].q);return new Rd(e,a-this.ea[c].Ra,a+b-this.ea[d].Ra)};
-var be=function(a,b,c,d,e){this.yb=b;this.wb=e;this.Ub=d;this.hb=[a];this.Mb=a.length;this.cb=new $d(c)};be.prototype.Ia=j;be.prototype.Ea=function(){return Ga(this.hb,function(a){return a.length==0})};be.prototype.append=function(a,b){this.cb.append(this.Mb,b);this.Mb+=a.length;this.hb.push(a);this.Ia=j};var ce=function(a){if(a.Ia===j)a.Ia=a.hb.join("");return a.Ia};be.prototype.Wa=function(a){return this.cb.Wa(a)};be.prototype.Y=function(a,b){return this.cb.Y(a,b)};var de=new be("",k,j,j,k);var ee=function(a){this.da=new H(a);this.Ec=a;this.B=["rtl"==S(a,"direction")];this.ba=[];this.O=[a];this.W=[]};v(ee,R);ee.prototype.H=j;ee.prototype.go=function(){try{for(;;fe(this));}catch(a){a!==y?h(a):this.dispatchEvent("EndOfDom")}};
-var fe=function(a){for(var b=a.da.next();a.da.o==1&&!Qd(b);){b=a.da;var c=b.n?-1:1;if(b.o==c){b.o=c*-1;b.la+=b.o*(b.n?-1:1)}b=a.da.next()}a.H=b;if(a.da.o==1){b=a.H;c="rtl"==S(b,"direction");a.ba.push(w(a.ba)||c!=w(a.B)||ge(a,b));a.B.push(c);if(b.nodeName=="IFRAME"||b.nodeName=="FRAME")a.W.push(b);else Pd(b)&&a.O.push(b);a.dispatchEvent("StartTag")}else if(a.da.o==-1){a.dispatchEvent("EndTag");a.B.pop();a.ba.pop();a.H==w(a.O)&&a.O.pop()}else a.H.nodeType==3&&a.dispatchEvent("TextNode")};
-ee.prototype.Ya=function(){return this.W};var ge=function(a,b){if(!b.dir||b==a.Ec)return k;for(var c=b.firstChild;c;c=c.nextSibling)if(c.nodeType==1&&Pd(c))return k;return i};var he=function(a){this.J=de;this.l=new P(this);Q(this.l,a,"TextNode",this.$a);wc(this.l,a,"EndOfDom",this.ic)};v(he,R);he.prototype.$a=function(a){a=a.target;var b=a.H;if(w(a.B)==this.J.yb&&w(a.O)==this.J.Ub&&w(a.ba)==this.J.wb)this.J.append(b.data,b);else{this.J.Ea()||this.dispatchEvent("DirChunk");this.J=new be(b.data,w(a.B),b,w(a.O),w(a.ba))}};he.prototype.ic=function(){this.J.Ea()||this.dispatchEvent("DirChunk");this.dispatchEvent("EndOfChunks");this.l.ga()};var ie=function(a){this.Ma=a};var $=function(){};t("bidichecker.FilterFactory.ComposableFilter",$);$.prototype.Qb=function(a){return je(this,a)};$.prototype.and=$.prototype.Qb;$.prototype.vc=function(){return ke(this)};$.prototype.not=$.prototype.vc;$.prototype.zc=function(a){return le(this,a)};$.prototype.or=$.prototype.zc;
-var Ce=function(a){var b=a.opcode;switch(b){case "AND":return new me(a);case "AT_TEXT":return new ne(a);case "AT_TEXT_REGEXP":return new oe(a);case "FOLLOWED_BY_TEXT":return new pe(a);case "FOLLOWED_BY_TEXT_REGEXP":return new qe(a);case "LOCATION_CLASS":return new re(a);case "LOCATION_CLASS_REGEXP":return new se(a);case "LOCATION_ID":return new te(a);case "LOCATION_ID_REGEXP":return new ue(a);case "LOCATION_XPATH":return new ve(a);case "NOT":return new we(a);case "OR":return new xe(a);case "PRECEDED_BY_TEXT":return new ye(a);
-case "PRECEDED_BY_TEXT_REGEXP":return new ze(a);case "SEVERITY":return new Ae(a);case "TYPE":return new Be(a);default:h("Unknown filter opcode: '"+b+"'")}},De=function(a){if(!a)return j;a=yc(a);return Fa(a,function(b){return Ce(b)})},je=function(a,b){return new me({filter1:a,filter2:b})};t("bidichecker.FilterFactory.and",je);t("bidichecker.FilterFactory.atText",function(a){return new ne({atText:a||""})});t("bidichecker.FilterFactory.atTextRegexp",function(a){return new oe({atTextRegexp:a||""})});
-t("bidichecker.FilterFactory.followedByText",function(a){return new pe({followedByText:a||""})});t("bidichecker.FilterFactory.followedByTextRegexp",function(a){return new qe({followedByTextRegexp:a||""})});t("bidichecker.FilterFactory.locationClass",function(a){a||h("Empty or null argument to bidichecker.FilterFactory.locationClass");return new re({className:a})});
-t("bidichecker.FilterFactory.locationClassRegexp",function(a){a||h("Empty or null argument to bidichecker.FilterFactory.locationClassRegexp");return new se({classRegexp:a})});t("bidichecker.FilterFactory.locationId",function(a){a||h("Empty or null argument to bidichecker.FilterFactory.locationId");return new te({id:a})});t("bidichecker.FilterFactory.locationIdRegexp",function(a){a||h("Empty or null argument to bidichecker.FilterFactory.locationIdRegexp");return new ue({idRegexp:a})});
-t("bidichecker.FilterFactory.locationXpath",function(a){a||h("Empty or null argument to bidichecker.FilterFactory.locationXpath");return new ve({xpath:a})});var ke=function(a){return new we({filter:a})};t("bidichecker.FilterFactory.not",ke);var le=function(a,b){return new xe({filter1:a,filter2:b})};t("bidichecker.FilterFactory.or",le);t("bidichecker.FilterFactory.precededByText",function(a){return new ye({precededByText:a||""})});
-t("bidichecker.FilterFactory.precededByTextRegexp",function(a){return new ze({precededByTextRegexp:a||""})});t("bidichecker.FilterFactory.severityFrom",function(a){return new Ae({severityThreshold:a})});t("bidichecker.FilterFactory.type",function(a){return new Be({type:a})});
-var Ee=function(a,b){b in a||h("No '"+b+"' parameter found for '"+a.opcode+"' filter")},Fe=function(a,b,c){Ee(a,b);typeof a[b]!=c&&h("Wrong type for '"+b+"' parameter of '"+a.opcode+"' filter; expected "+c)},Ge=function(a,b){Fe(a,b,"string");return a[b]},He=function(a,b){Ee(a,b);var c=a[b],d;if(typeof c=="string")d=c;else if(c instanceof RegExp)d=c.source;else h("Wrong type for '"+b+"' parameter of '"+a.opcode+"' filter; expected string or RegExp");return RegExp("^("+d+")$")},Ie=function(a,b){Fe(a,
-b,"object");var c=a[b];if(c instanceof $)return c;else if(typeof c.opcode=="string")return Ce(c);else h("Can't make a filter out of the '"+b+"' parameter of '"+a.opcode+"' filter")},me=function(a){this.Ua=Ie(a,"filter1");this.Va=Ie(a,"filter2")};v(me,$);me.prototype.d=function(a,b){return this.Ua.d(a,b)&&this.Va.d(a,b)};var ne=function(a){this.Sb=Ge(a,"atText")};v(ne,$);ne.prototype.d=function(a){return this.Sb==(a.atText||"")};var oe=function(a){this.Rb=He(a,"atTextRegexp")};v(oe,$);
-oe.prototype.d=function(a){return this.Rb.test(a.atText||"")};var pe=function(a){this.ec=Ge(a,"followedByText")};v(pe,$);pe.prototype.d=function(a){return this.ec==(a.followedByText||"")};var qe=function(a){this.dc=He(a,"followedByTextRegexp")};v(qe,$);qe.prototype.d=function(a){return this.dc.test(a.followedByText||"")};var re=function(a){this.Vb=Ge(a,"className")};v(re,$);
-re.prototype.d=function(a,b){for(var c=0;c<b.length;++c)for(var d=b[c];d;d=d.parentNode)if(d.className)for(var e=d.className.split(/\s/),f=0;f<e.length;++f)if(this.Vb==e[f])return i;return k};var se=function(a){this.Wb=He(a,"classRegexp")};v(se,$);se.prototype.d=function(a,b){for(var c=0;c<b.length;++c)for(var d=b[c];d;d=d.parentNode)if(d.className)for(var e=d.className.split(/\s/),f=0;f<e.length;++f)if(this.Wb.test(e[f]))return i;return k};var te=function(a){this.$=Ge(a,"id")};v(te,$);
-te.prototype.d=function(a,b){for(var c=0;c<b.length;++c)for(var d=b[c];d;d=d.parentNode)if(d.id&&this.$==d.id)return i;return k};var ue=function(a){this.nc=He(a,"idRegexp")};v(ue,$);ue.prototype.d=function(a,b){for(var c=0;c<b.length;++c)for(var d=b[c];d;d=d.parentNode)if(d.id&&this.nc.test(d.id))return i;return k};var ve=function(a){a=Ge(a,"xpath");this.Lc=new ie(a)};v(ve,$);
-ve.prototype.d=function(a,b){for(var c=0;c<b.length;++c){var d;a:{d=b[c];var e;e=this.Lc;var f=d.ownerDocument,g=f._bidicheckerXpathMatcherCache_[e.Ma];if(!g)try{f.evaluate||h("XPath not supported by this browser");g=f.evaluate(e.Ma,f,j,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,j);f._bidicheckerXpathMatcherCache_[e.Ma]=g}catch(l){h("Error evaluating XPath expression "+e.Ma+": "+l)}e=g;for(f=0;f<e.snapshotLength;++f)if(e.snapshotItem(f)==d){d=i;break a}d=k}if(d)return i}return k};
-var we=function(a){this.ac=Ie(a,"filter")};v(we,$);we.prototype.d=function(a,b){return!this.ac.d(a,b)};var xe=function(a){this.Ua=Ie(a,"filter1");this.Va=Ie(a,"filter2")};v(xe,$);xe.prototype.d=function(a,b){return this.Ua.d(a,b)||this.Va.d(a,b)};var ye=function(a){this.Cc=Ge(a,"precededByText")};v(ye,$);ye.prototype.d=function(a){return this.Cc==(a.precededByText||"")};var ze=function(a){this.Bc=He(a,"precededByTextRegexp")};v(ze,$);
-ze.prototype.d=function(a){return this.Bc.test(a.precededByText||"")};var Ae=function(a){Fe(a,"severityThreshold","number");this.Gc=a.severityThreshold};v(Ae,$);Ae.prototype.d=function(a){return this.Gc<=a.severity};var Be=function(a){this.Jc=Ge(a,"type")};v(Be,$);Be.prototype.d=function(a){return this.Jc==a.type};var Je=function(){this.W=[]};v(Je,R);m=Je.prototype;m.start=function(){this.dispatchEvent("StartFrames")};m.end=function(){this.dispatchEvent("EndFrames")};m.push=function(a){this.W.push(a);this.dispatchEvent("EnterFrame")};m.pop=function(){this.dispatchEvent("ExitFrame");this.W.pop()};m.Ya=function(){return this.W};var Ke=function(a,b){this.fc=a;this.bc=b||[];this.A=[]};Ke.prototype.Ic=k;Ke.prototype.Xa=function(){return this.A};var Me=function(a,b,c){var d=a.fc.Ya().slice(0);c&&d.push(c);if(Ga(a.bc,function(e){return!e.d(b,d)})){c=Le(a,d);if(c!="")b.locationDescription=c;a.A.push(b);a.Ic&&h(b.toString()+"\n")}},Le=function(a,b){var c=[];Ea(b,function(d){c.push(Jd(d))});return c.join(" in ")};var Ne=function(a,b){this.uc=!!b;this.oa=new Je;this.pb=new Ke(this.oa,a)};Ne.prototype.F=j;Ne.prototype.Ta=j;Ne.prototype.Xa=function(){return this.pb.Xa()};
-var Re=function(a,b,c){b.ownerDocument._bidicheckerXpathMatcherCache_={};var d,e=a.pb;d=[new Oe(e),new Pe(e)];c!=0&&d.unshift(new Qe(c==-1,e));a.F=new ee(b);a.Ta=a.uc?new he(a.F):j;for(b=0;b<d.length;++b)d[b].gb(a);a.F.go();d=a.F.Ya();for(b=0;b<d.length;++b){e=d[b];a.oa.push(e);try{var f=(B?e.document||e.contentWindow.document:e.contentDocument||e.contentWindow.document).body;if(e.tagName=="IFRAME")c=0;Re(a,f,c)}catch(g){}a.oa.pop()}};var Qe=function(a,b){this.Gb=a;this.ma=b};Qe.prototype.gb=function(a){mc(a.F,"StartTag",this)};Qe.prototype.handleEvent=function(a){a=a.target;if(this.Gb!=w(a.B))Me(this.ma,new Z("Overall directionality not "+(this.Gb?"RTL":"LTR"),1,new Td(a.H)))};var Pe=function(a){this.ma=a;this.sa=[]};m=Pe.prototype;m.I=j;m.gb=function(a){var b=new P(this);Q(b,a.F,"StartTag",this.mc);Q(b,a.F,"EndTag",this.jc);Q(b,a.F,"TextNode",this.$a);wc(b,a.F,"EndOfDom",b.ga,k,b)};m.mc=function(a){a=a.target;var b=a.H;if(b.dir||b==w(a.O))this.I=j};m.jc=function(a){a=a.target;var b=a.H;if(b==w(a.O))this.I=j;else if(b.dir)if(w(a.B)==a.B[a.B.length-2])this.I=j;else{this.I=b;this.sa=[]}};
-m.$a=function(a){a=a.target;var b=a.H;if(this.I){this.sa.push(b);var c=Ed(b.data);if(c){var d=Fa(this.sa,function(f){return f.data}).join(""),e=w(this.sa).parentNode;Me(this.ma,Se(this,d.substr(0,d.length-(b.data.length-c.text.length)),c.text.length,w(a.B),w(a.ba)),e);this.I=j}else if(Ad.test(b.data))this.I=j}};var Se=function(a,b,c,d,e){b=new Z("Declared "+(d?"LTR":"RTL")+" spillover to number",e?4:2,new Rd(a.sa,0,c),b);a=Kd(a.I);b.precededByText=a;return b};var Oe=function(a){this.ma=a};Oe.prototype.gb=function(a){var b=new P(this);Q(b,a.Ta,"DirChunk",this.hc);wc(b,a.Ta,"EndOfChunks",b.ga,k,b)};Oe.prototype.hc=function(a){var b=this,c=a.target.J;if(c.yb){a=Dd(ce(c));Da(a,function(d){xd.exec(d.text)||Te(b,c,d,"Undeclared LTR text")})}else{a=Cd(ce(c));Da(a,function(d){yd.exec(d.text)||Te(b,c,d,"Undeclared RTL text")})}};
-var Te=function(a,b,c,d){var e=b.wb?4:3,f=b.Y(c.index,c.text.length);d=new Z(d,e,f,c.text);e=ce(b);f=c.index;var g=vd.exec(e.substr(0,f));f=g?new Bd(g[0],f-g[0].length):j;if(f){if(d.severity==3)d.severity=2;d.precededByText=f.text}f=c.index+c.text.length;e=(e=ud.exec(e.substr(f)))?new Bd(e[0],f):j;if(e){if(d.severity==3)d.severity=2;d.followedByText=e.text}b=b.Wa(c.index).parentNode;Me(a.ma,d,b)};var Ue=function(a){Ne.call(this,a,i)};v(Ue,Ne);var Ve=function(a,b,c){Vd=[];Ud=0;b=b||top.document.body;a=a?-1:1;c=new Ue(c);c.oa.start();Re(c,b,a);c.oa.end();return c.Xa()};t("bidichecker.checkPage",Ve);t("bidichecker.checkPageToJson",function(a,b,c){c=De(c);a=Ve(a,b,c);for(b=0;b<a.length;++b){c=a[b];c.asString=c.toString()}b=[];Bc(new zc,a,b);return b.join("")});
-var We=function(a){a=new Wd(a);if(!(a.P||a.A.length==0)){a.D=new W("bidichecker-dialog");var b=a.D;b.Ob="BidiChecker error browser";b.ta&&Ib(b.ta,"BidiChecker error browser");b=a.D;b.pa=k;jd(b);b.m();var c=new X;c.N("prev","< Prev");c.N("next","Next >");b=a.D;b.r=c;if(b.z)if(b.r){c=b.r;c.b=b.z;c.ia()}else b.z.innerHTML="";b=a.D;b.Sa='<div id="bidichecker-dialog-error-text" class="bidichecker-dialog-error-text"> </div><p>Error <input name="current" id="bidichecker-dialog-error-num" type="text" size="3" value="1" /> of <span id="bidichecker-dialog-error-count"></span></p><p style="font-size:75%">Drag this box if it conceals a part of the page you need.</p>';
-if(b.wa)b.wa.innerHTML='<div id="bidichecker-dialog-error-text" class="bidichecker-dialog-error-text"> </div><p>Error <input name="current" id="bidichecker-dialog-error-num" type="text" size="3" value="1" /> of <span id="bidichecker-dialog-error-count"></span></p><p style="font-size:75%">Drag this box if it conceals a part of the page you need.</p>';kd(a.D,i);a.P=a.D.c();b=G(a.P);var d=j;if(A){d=b.h.createStyleSheet();Qc(d,".bidichecker-dialog-bg { position: absolute; top: 0; left: 0; }.bidichecker-dialog { position: absolute; padding: 5px; background-color: #fcb; border: 1px solid #000; font-family: arial, sans-serif; width: 475px; color: #000; outline: none; direction: ltr }.bidichecker-dialog a, .bidichecker-dialog a:link,.bidichecker-dialog a:visited  { color: #0066cc; cursor: pointer; }.bidichecker-dialog-title { position: relative; background-color: #f9efeb; color: #000000; padding: 10px 15px; font-size: 16px; font-weight: bold; vertical-align: middle; cursor: pointer; cursor: hand }.bidichecker-dialog-content { padding: 15px; font-size: 90%; background-color: #fff }.bidichecker-dialog-buttons { padding: 0 15px 15px; background-color: #fff }.bidichecker-dialog-error-text { font-weight: bold; font-size: 125%; color: #f00; height: 80px; overflow: auto; border: 1px dotted #f00 }")}else{c=
-xb(b.h,"head",void 0,void 0)[0];if(!c){d=xb(b.h,"body",void 0,void 0)[0];c=b.j("head");d.parentNode.insertBefore(c,d)}d=b.j("style");Qc(d,".bidichecker-dialog-bg { position: absolute; top: 0; left: 0; }.bidichecker-dialog { position: absolute; padding: 5px; background-color: #fcb; border: 1px solid #000; font-family: arial, sans-serif; width: 475px; color: #000; outline: none; direction: ltr }.bidichecker-dialog a, .bidichecker-dialog a:link,.bidichecker-dialog a:visited  { color: #0066cc; cursor: pointer; }.bidichecker-dialog-title { position: relative; background-color: #f9efeb; color: #000000; padding: 10px 15px; font-size: 16px; font-weight: bold; vertical-align: middle; cursor: pointer; cursor: hand }.bidichecker-dialog-content { padding: 15px; font-size: 90%; background-color: #fff }.bidichecker-dialog-buttons { padding: 0 15px 15px; background-color: #fff }.bidichecker-dialog-error-text { font-weight: bold; font-size: 125%; color: #f00; height: 80px; overflow: auto; border: 1px dotted #f00 }");
-b.appendChild(c,d)}a.P.style.zIndex=1E4;b=a.D.m();Ib(b.c("bidichecker-dialog-error-count"),a.A.length+"");a.Q=b.c("bidichecker-dialog-error-num");a.qb=b.c("bidichecker-dialog-error-text");md(a.D);Yd(a);N(a.D,"dialogselect",a.gc,k,a);a.Q.onchange=ka(a.kc,a)}};t("bidichecker.runGui",We);t("bidichecker.runGuiFromJson",function(a){a=yc(a);a=Fa(a,function(b){return new Z(b)});We(a)}); })()
+(function (){ function g(a){throw a;}
+var i=void 0,j=!0,k=null,m=!1,n,o=this,aa=function(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&
+!a.propertyIsEnumerable("call"))return"function"}else return"null";else if("function"==b&&"undefined"==typeof a.call)return"object";return b},p=function(a){return"array"==aa(a)},ba=function(a){var b=aa(a);return"array"==b||"object"==b&&"number"==typeof a.length},q=function(a){return"string"==typeof a},ca=function(a){return"function"==aa(a)},da=function(a){a=aa(a);return"object"==a||"array"==a||"function"==a},ga=function(a){return a[ea]||(a[ea]=++fa)},ea="closure_uid_"+Math.floor(2147483648*Math.random()).toString(36),
+fa=0,ha=function(a,b,c){return a.call.apply(a.bind,arguments)},ia=function(a,b,c){a||g(Error());if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}},r=function(a,b,c){r=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?ha:ia;return r.apply(k,arguments)},ja=Date.now||function(){return+new Date},
+u=function(a,b){var c=a.split("."),d=o;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)!c.length&&b!==i?d[e]=b:d=d[e]?d[e]:d[e]={}},w=function(a,b){function c(){}c.prototype=b.prototype;a.e=b.prototype;a.prototype=new c};Function.prototype.bind=Function.prototype.bind||function(a,b){if(1<arguments.length){var c=Array.prototype.slice.call(arguments,1);c.unshift(this,a);return r.apply(k,c)}return r(this,a)};var ka=function(a){this.stack=Error().stack||"";if(a)this.message=""+a};w(ka,Error);ka.prototype.name="CustomError";var la=function(a,b){for(var c=1;c<arguments.length;c++)var d=(""+arguments[c]).replace(/\$/g,"$$$$"),a=a.replace(/\%s/,d);return a},ra=function(a){if(!ma.test(a))return a;-1!=a.indexOf("&")&&(a=a.replace(na,"&amp;"));-1!=a.indexOf("<")&&(a=a.replace(oa,"&lt;"));-1!=a.indexOf(">")&&(a=a.replace(pa,"&gt;"));-1!=a.indexOf('"')&&(a=a.replace(qa,"&quot;"));return a},na=/&/g,oa=/</g,pa=/>/g,qa=/\"/g,ma=/[&<>\"]/;var sa=function(a,b){b.unshift(a);ka.call(this,la.apply(k,b));b.shift();this.od=a};w(sa,ka);sa.prototype.name="AssertionError";var x=function(a,b,c){if(!a){var d=Array.prototype.slice.call(arguments,2),e="Assertion failed";if(b)var e=e+(": "+b),f=d;g(new sa(""+e,f||[]))}};var y=function(a){return a[a.length-1]},z=Array.prototype,ta=z.indexOf?function(a,b,c){x(a.length!=k);return z.indexOf.call(a,b,c)}:function(a,b,c){c=c==k?0:0>c?Math.max(0,a.length+c):c;if(q(a))return!q(b)||1!=b.length?-1:a.indexOf(b,c);for(;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},ua=z.forEach?function(a,b,c){x(a.length!=k);z.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=q(a)?a.split(""):a,f=0;f<d;f++)f in e&&b.call(c,e[f],f,a)},va=function(a,b){for(var c=q(a)?a.split(""):
+a,d=a.length-1;0<=d;--d)d in c&&b.call(i,c[d],d,a)},wa=z.map?function(a,b,c){x(a.length!=k);return z.map.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=Array(d),f=q(a)?a.split(""):a,h=0;h<d;h++)h in f&&(e[h]=b.call(c,f[h],h,a));return e},xa=z.every?function(a,b,c){x(a.length!=k);return z.every.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=q(a)?a.split(""):a,f=0;f<d;f++)if(f in e&&!b.call(c,e[f],f,a))return m;return j},ya=function(a,b){var c=ta(a,b);0<=c&&(x(a.length!=k),z.splice.call(a,c,1))},
+za=function(a){return z.concat.apply(z,arguments)},Aa=function(a){if(p(a))return za(a);for(var b=[],c=0,d=a.length;c<d;c++)b[c]=a[c];return b},Ca=function(a,b,c,d){x(a.length!=k);z.splice.apply(a,Ba(arguments,1))},Ba=function(a,b,c){x(a.length!=k);return 2>=arguments.length?z.slice.call(a,b):z.slice.call(a,b,c)},Da=function(a,b,c){for(var d=0,e=a.length,f;d<e;){var h=d+e>>1,l;l=b(c,a[h]);0<l?d=h+1:(e=h,f=!l)}return f?d:~d},Ea=function(a,b){return a>b?1:a<b?-1:0};var Fa=function(a,b){this.x=a!==i?a:0;this.y=b!==i?b:0};Fa.prototype.toString=function(){return"("+this.x+", "+this.y+")"};var A=function(a,b){this.width=a;this.height=b};A.prototype.toString=function(){return"("+this.width+" x "+this.height+")"};A.prototype.za=function(){return!(this.width*this.height)};A.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};A.prototype.round=function(){this.width=Math.round(this.width);this.height=Math.round(this.height);return this};var Ga=function(a,b){for(var c in a)b.call(i,a[c],c,a)},Ha=function(a){var b=[],c=0,d;for(d in a)b[c++]=a[d];return b},Ia=function(a){var b=[],c=0,d;for(d in a)b[c++]=d;return b},Ja="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(","),Ka=function(a,b){for(var c,d,e=1;e<arguments.length;e++){d=arguments[e];for(c in d)a[c]=d[c];for(var f=0;f<Ja.length;f++)c=Ja[f],Object.prototype.hasOwnProperty.call(d,c)&&(a[c]=d[c])}},La=function(a){var b=arguments.length;
+if(1==b&&p(arguments[0]))return La.apply(k,arguments[0]);for(var c={},d=0;d<b;d++)c[arguments[d]]=j;return c};var Ma,Na,Oa,Pa,Qa,Ra,Sa=function(){return o.navigator?o.navigator.userAgent:k},Ta=function(){return o.navigator};Qa=Pa=Oa=Na=Ma=m;var Ua;if(Ua=Sa()){var Va=Ta();Ma=0==Ua.indexOf("Opera");Na=!Ma&&-1!=Ua.indexOf("MSIE");Pa=(Oa=!Ma&&-1!=Ua.indexOf("WebKit"))&&-1!=Ua.indexOf("Mobile");Qa=!Ma&&!Oa&&"Gecko"==Va.product}var Wa=Ma,B=Na,C=Qa,D=Oa,Xa=Pa,Ya=Ta();Ra=-1!=(Ya&&Ya.platform||"").indexOf("Mac");var Za=!!Ta()&&-1!=(Ta().appVersion||"").indexOf("X11"),$a;
+a:{var ab="",bb;if(Wa&&o.opera)var cb=o.opera.version,ab="function"==typeof cb?cb():cb;else if(C?bb=/rv\:([^\);]+)(\)|;)/:B?bb=/MSIE\s+([^\);]+)(\)|;)/:D&&(bb=/WebKit\/(\S+)/),bb)var db=bb.exec(Sa()),ab=db?db[1]:"";if(B){var eb,fb=o.document;eb=fb?fb.documentMode:i;if(eb>parseFloat(ab)){$a=""+eb;break a}}$a=ab}
+var gb=$a,hb={},E=function(a){var b;if(!(b=hb[a])){b=0;for(var c=(""+gb).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),d=(""+a).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),e=Math.max(c.length,d.length),f=0;0==b&&f<e;f++){var h=c[f]||"",l=d[f]||"",s=RegExp("(\\d*)(\\D*)","g"),t=RegExp("(\\d*)(\\D*)","g");do{var O=s.exec(h)||["","",""],v=t.exec(l)||["","",""];if(0==O[0].length&&0==v[0].length)break;b=((0==O[1].length?0:parseInt(O[1],10))<(0==v[1].length?0:parseInt(v[1],10))?-1:(0==O[1].length?
+0:parseInt(O[1],10))>(0==v[1].length?0:parseInt(v[1],10))?1:0)||((0==O[2].length)<(0==v[2].length)?-1:(0==O[2].length)>(0==v[2].length)?1:0)||(O[2]<v[2]?-1:O[2]>v[2]?1:0)}while(0==b)}b=hb[a]=0<=b}return b},ib={},jb=function(a){return ib[a]||(ib[a]=B&&document.documentMode&&document.documentMode>=a)};var kb,mb=!B||jb(9);!C&&!B||B&&jb(9)||C&&E("1.9.1");B&&E("9");var nb=function(a){return(a=a.className)&&"function"==typeof a.split?a.split(/\s+/):[]},ob=function(a,b){var c=nb(a),d=Ba(arguments,1),e;e=c;for(var f=0,h=0;h<d.length;h++)0<=ta(e,d[h])||(e.push(d[h]),f++);e=f==d.length;a.className=c.join(" ");return e},pb=function(a,b){for(var c=nb(a),d=Ba(arguments,1),e=c,f=0,h=0;h<e.length;h++)0<=ta(d,e[h])&&(Ca(e,h--,1),f++);a.className=c.join(" ")};var G=function(a){return a?new F(qb(a)):kb||(kb=new F)},sb=function(a,b){var c=b&&"*"!=b?b.toUpperCase():"";return a.querySelectorAll&&a.querySelector&&(!D||rb(document)||E("528"))&&c?a.querySelectorAll(c+""):a.getElementsByTagName(c||"*")},ub=function(a,b){Ga(b,function(b,d){"style"==d?a.style.cssText=b:"class"==d?a.className=b:"for"==d?a.htmlFor=b:d in tb?a.setAttribute(tb[d],b):0==d.lastIndexOf("aria-",0)?a.setAttribute(d,b):a[d]=b})},tb={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",
+rowspan:"rowSpan",valign:"vAlign",height:"height",width:"width",usemap:"useMap",frameborder:"frameBorder",maxlength:"maxLength",type:"type"},vb=function(a){var b=a.document;if(D&&!E("500")&&!Xa){"undefined"==typeof a.innerHeight&&(a=window);var b=a.innerHeight,c=a.document.documentElement.scrollHeight;a==a.top&&c<b&&(b-=15);return new A(a.innerWidth,b)}a=rb(b)?b.documentElement:b.body;return new A(a.clientWidth,a.clientHeight)},wb=function(a){return a.parentWindow||a.defaultView},yb=function(a,b,
+c){return xb(document,arguments)},xb=function(a,b){var c=b[0],d=b[1];if(!mb&&d&&(d.name||d.type)){c=["<",c];d.name&&c.push(' name="',ra(d.name),'"');if(d.type){c.push(' type="',ra(d.type),'"');var e={};Ka(e,d);d=e;delete d.type}c.push(">");c=c.join("")}c=a.createElement(c);if(d)q(d)?c.className=d:p(d)?ob.apply(k,[c].concat(d)):ub(c,d);2<b.length&&zb(a,c,b,2);return c},zb=function(a,b,c,d){function e(c){c&&b.appendChild(q(c)?a.createTextNode(c):c)}for(;d<c.length;d++){var f=c[d];ba(f)&&!(da(f)&&0<
+f.nodeType)?ua(Ab(f)?Aa(f):f,e):e(f)}},rb=function(a){return"CSS1Compat"==a.compatMode},Bb=function(a,b){zb(qb(a),a,arguments,1)},Cb=function(a){return a&&a.parentNode?a.parentNode.removeChild(a):k},Db=function(a,b){var c=b.parentNode;c&&c.replaceChild(a,b)},qb=function(a){return 9==a.nodeType?a:a.ownerDocument||a.document},Ab=function(a){if(a&&"number"==typeof a.length){if(da(a))return"function"==typeof a.item||"string"==typeof a.item;if(ca(a))return"function"==typeof a.item}return m},F=function(a){this.f=
+a||o.document||document};F.prototype.h=G;var Eb=function(a){return a.f};F.prototype.a=function(a){return q(a)?this.f.getElementById(a):a};F.prototype.i=function(a,b,c){return xb(this.f,arguments)};F.prototype.createElement=function(a){return this.f.createElement(a)};F.prototype.createTextNode=function(a){return this.f.createTextNode(a)};var Fb=function(a){var b=a.f,a=!D&&rb(b)?b.documentElement:b.body,b=wb(b);return new Fa(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)};
+F.prototype.appendChild=function(a,b){a.appendChild(b)};F.prototype.append=Bb;F.prototype.removeNode=Cb;var Gb=function(a,b,c,d){this.top=a;this.right=b;this.bottom=c;this.left=d};Gb.prototype.toString=function(){return"("+this.top+"t, "+this.right+"r, "+this.bottom+"b, "+this.left+"l)"};var Hb=function(a,b,c,d){this.left=a;this.top=b;this.width=c;this.height=d};Hb.prototype.toString=function(){return"("+this.left+", "+this.top+" - "+this.width+"w x "+this.height+"h)"};var H=function(a,b){var c=qb(a);return c.defaultView&&c.defaultView.getComputedStyle&&(c=c.defaultView.getComputedStyle(a,k))?c[b]||c.getPropertyValue(b):""},Ib=function(a,b){return a.currentStyle?a.currentStyle[b]:k},Jb=function(a,b){return H(a,b)||Ib(a,b)||a.style&&a.style[b]},Lb=function(a,b,c){var d,e=C&&(Ra||Za)&&E("1.9");b instanceof Fa?(d=b.x,b=b.y):(d=b,b=c);a.style.left=Kb(d,e);a.style.top=Kb(b,e)},Mb=function(a){var b=a.getBoundingClientRect();if(B)a=a.ownerDocument,b.left-=a.documentElement.clientLeft+
+a.body.clientLeft,b.top-=a.documentElement.clientTop+a.body.clientTop;return b},Nb=function(a){if(B&&!jb(8))return a.offsetParent;for(var b=qb(a),c=Jb(a,"position"),d="fixed"==c||"absolute"==c,a=a.parentNode;a&&a!=b;a=a.parentNode)if(c=Jb(a,"position"),d=d&&"static"==c&&a!=b.documentElement&&a!=b.body,!d&&(a.scrollWidth>a.clientWidth||a.scrollHeight>a.clientHeight||"fixed"==c||"absolute"==c||"relative"==c))return a;return k},Ob=function(a){var b,c=qb(a),d=Jb(a,"position"),e=C&&c.getBoxObjectFor&&
+!a.getBoundingClientRect&&"absolute"==d&&(b=c.getBoxObjectFor(a))&&(0>b.screenX||0>b.screenY),f=new Fa(0,0),h;b=c?9==c.nodeType?c:qb(c):document;if(h=B)if(h=!jb(9))h=G(b),h=!rb(h.f);h=h?b.body:b.documentElement;if(a==h)return f;if(a.getBoundingClientRect)b=Mb(a),a=Fb(G(c)),f.x=b.left+a.x,f.y=b.top+a.y;else if(c.getBoxObjectFor&&!e)b=c.getBoxObjectFor(a),a=c.getBoxObjectFor(h),f.x=b.screenX-a.screenX,f.y=b.screenY-a.screenY;else{e=a;do{f.x+=e.offsetLeft;f.y+=e.offsetTop;e!=a&&(f.x+=e.clientLeft||0,
+f.y+=e.clientTop||0);if(D&&"fixed"==Jb(e,"position")){f.x+=c.body.scrollLeft;f.y+=c.body.scrollTop;break}e=e.offsetParent}while(e&&e!=a);if(Wa||D&&"absolute"==d)f.y-=c.body.offsetTop;for(e=a;(e=Nb(e))&&e!=c.body&&e!=h;)if(f.x-=e.scrollLeft,!Wa||"TR"!=e.tagName)f.y-=e.scrollTop}return f},Pb=function(a,b,c){b instanceof A?(c=b.height,b=b.width):c==i&&g(Error("missing height argument"));a.style.width=Kb(b,j);a.style.height=Kb(c,j)},Kb=function(a,b){"number"==typeof a&&(a=(b?Math.round(a):a)+"px");return a},
+Rb=function(a){if("none"!=Jb(a,"display"))return Qb(a);var b=a.style,c=b.display,d=b.visibility,e=b.position;b.visibility="hidden";b.position="absolute";b.display="inline";a=Qb(a);b.display=c;b.position=e;b.visibility=d;return a},Qb=function(a){var b=a.offsetWidth,c=a.offsetHeight,d=D&&!b&&!c;return(b===i||d)&&a.getBoundingClientRect?(a=Mb(a),new A(a.right-a.left,a.bottom-a.top)):new A(b,c)},Sb=function(a,b){var c=a.style;if("opacity"in c)c.opacity=b;else if("MozOpacity"in c)c.MozOpacity=b;else if("filter"in
+c)c.filter=""===b?"":"alpha(opacity="+100*b+")"},I=function(a,b){a.style.display=b?"":"none"},Tb=function(a){B?a.cssText=".bidichecker-dialog-bg { position: absolute; top: 0; left: 0; }.bidichecker-dialog {font-family: arial, sans-serif}.bidichecker-dialog-buttons {display: none;}.bidichecker-dialog-title-close {position: absolute;right: 0;padding-right: 5px;padding-left: 5px;}.bidichecker-dialog-title-close:hover {background-color: #fee;}.bidichecker-dialog iframe {border: 0;height: 100%;width: 100%;background: white;}.bidichecker-dialog { position: absolute; background-color: #fcb; border: 1px solid #000; width: 800px; height: 600px; color: #000; outline: none; direction: ltr }.bidichecker-dialog-title { position: relative; padding-bottom: 5px;height: 1em;color: #000000;font-size: 16px; font-weight: bold; vertical-align: middle; }.bidichecker-dialog .bidichecker-dialog-title {cursor: pointer; cursor: hand }":
+a[D?"innerText":"innerHTML"]=".bidichecker-dialog-bg { position: absolute; top: 0; left: 0; }.bidichecker-dialog {font-family: arial, sans-serif}.bidichecker-dialog-buttons {display: none;}.bidichecker-dialog-title-close {position: absolute;right: 0;padding-right: 5px;padding-left: 5px;}.bidichecker-dialog-title-close:hover {background-color: #fee;}.bidichecker-dialog iframe {border: 0;height: 100%;width: 100%;background: white;}.bidichecker-dialog { position: absolute; background-color: #fcb; border: 1px solid #000; width: 800px; height: 600px; color: #000; outline: none; direction: ltr }.bidichecker-dialog-title { position: relative; padding-bottom: 5px;height: 1em;color: #000000;font-size: 16px; font-weight: bold; vertical-align: middle; }.bidichecker-dialog .bidichecker-dialog-title {cursor: pointer; cursor: hand }"},
+Ub=function(a){return"rtl"==Jb(a,"direction")},Vb=function(a,b,c,d){if(/^\d+px?$/.test(b))return parseInt(b,10);var e=a.style[c],f=a.runtimeStyle[c];a.runtimeStyle[c]=a.currentStyle[c];a.style[c]=b;b=a.style[d];a.style[c]=e;a.runtimeStyle[c]=f;return b},Wb=function(a,b){return Vb(a,Ib(a,b),"left","pixelLeft")},Xb={thin:2,medium:4,thick:6},Yb=function(a,b){if("none"==Ib(a,b+"Style"))return 0;var c=Ib(a,b+"Width");return c in Xb?Xb[c]:Vb(a,c,"left","pixelLeft")};var Zb=function(){};Zb.prototype.Pb=m;Zb.prototype.l=function(){if(!this.Pb)this.Pb=j,this.k()};Zb.prototype.k=function(){this.ad&&$b.apply(k,this.ad)};var ac=function(a){a&&"function"==typeof a.l&&a.l()},$b=function(a){for(var b=0,c=arguments.length;b<c;++b){var d=arguments[b];ba(d)?$b.apply(k,d):ac(d)}};var bc=function(a){a.setAttribute("role","dialog");a.pd="dialog"};var J=function(a,b){this.type=a;this.currentTarget=this.target=b};w(J,Zb);n=J.prototype;n.k=function(){delete this.type;delete this.target;delete this.currentTarget};n.S=m;n.ma=j;n.stopPropagation=function(){this.S=j};n.preventDefault=function(){this.ma=m};var cc=function(a){a.preventDefault()};var dc=function(a){dc[" "](a);return a};dc[" "]=function(){};var ec=!B||jb(9),fc=!B||jb(9),gc=B&&!E("8");!D||E("528");C&&E("1.9b")||B&&E("8")||Wa&&E("9.5")||D&&E("528");!C||E("8");var hc=function(a,b){a&&this.ca(a,b)};w(hc,J);var ic=[1,4,2];n=hc.prototype;n.target=k;n.relatedTarget=k;n.offsetX=0;n.offsetY=0;n.clientX=0;n.clientY=0;n.screenX=0;n.screenY=0;n.button=0;n.keyCode=0;n.charCode=0;n.ctrlKey=m;n.altKey=m;n.shiftKey=m;n.metaKey=m;n.Ec=m;n.q=k;
+n.ca=function(a,b){var c=this.type=a.type;J.call(this,c);this.target=a.target||a.srcElement;this.currentTarget=b;var d=a.relatedTarget;if(d){if(C){var e;a:{try{dc(d.nodeName);e=j;break a}catch(f){}e=m}e||(d=k)}}else if("mouseover"==c)d=a.fromElement;else if("mouseout"==c)d=a.toElement;this.relatedTarget=d;this.offsetX=D||a.offsetX!==i?a.offsetX:a.layerX;this.offsetY=D||a.offsetY!==i?a.offsetY:a.layerY;this.clientX=a.clientX!==i?a.clientX:a.pageX;this.clientY=a.clientY!==i?a.clientY:a.pageY;this.screenX=
+a.screenX||0;this.screenY=a.screenY||0;this.button=a.button;this.keyCode=a.keyCode||0;this.charCode=a.charCode||("keypress"==c?a.keyCode:0);this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=a.shiftKey;this.metaKey=a.metaKey;this.Ec=Ra?a.metaKey:a.ctrlKey;this.state=a.state;this.q=a;delete this.ma;delete this.S};n.stopPropagation=function(){hc.e.stopPropagation.call(this);this.q.stopPropagation?this.q.stopPropagation():this.q.cancelBubble=j};
+n.preventDefault=function(){hc.e.preventDefault.call(this);var a=this.q;if(a.preventDefault)a.preventDefault();else if(a.returnValue=m,gc)try{if(a.ctrlKey||112<=a.keyCode&&123>=a.keyCode)a.keyCode=-1}catch(b){}};n.k=function(){hc.e.k.call(this);this.relatedTarget=this.currentTarget=this.target=this.q=k};var jc=function(){},kc=0;n=jc.prototype;n.key=0;n.Q=m;n.kb=m;n.ca=function(a,b,c,d,e,f){ca(a)?this.Nb=j:a&&a.handleEvent&&ca(a.handleEvent)?this.Nb=m:g(Error("Invalid listener argument"));this.ba=a;this.Ib=b;this.src=c;this.type=d;this.capture=!!e;this.ya=f;this.kb=m;this.key=++kc;this.Q=m};n.handleEvent=function(a){return this.Nb?this.ba.call(this.ya||this.src,a):this.ba.handleEvent.call(this.ba,a)};var lc={},K={},L={},mc={},M=function(a,b,c,d,e){if(b){if(p(b)){for(var f=0;f<b.length;f++)M(a,b[f],c,d,e);return k}var d=!!d,h=K;b in h||(h[b]={g:0,r:0});h=h[b];d in h||(h[d]={g:0,r:0},h.g++);var h=h[d],l=ga(a),s;h.r++;if(h[l]){s=h[l];for(f=0;f<s.length;f++)if(h=s[f],h.ba==c&&h.ya==e){if(h.Q)break;return s[f].key}}else s=h[l]=[],h.g++;f=nc();f.src=a;h=new jc;h.ca(c,f,a,b,d,e);c=h.key;f.key=c;s.push(h);lc[c]=h;L[l]||(L[l]=[]);L[l].push(h);a.addEventListener?(a==o||!a.Hb)&&a.addEventListener(b,f,d):
+a.attachEvent(b in mc?mc[b]:mc[b]="on"+b,f);return c}g(Error("Invalid event type"))},nc=function(){var a=oc,b=fc?function(c){return a.call(b.src,b.key,c)}:function(c){c=a.call(b.src,b.key,c);if(!c)return c};return b},pc=function(a,b,c,d,e){if(p(b)){for(var f=0;f<b.length;f++)pc(a,b[f],c,d,e);return k}a=M(a,b,c,d,e);lc[a].kb=j;return a},qc=function(a,b,c,d,e){if(p(b))for(var f=0;f<b.length;f++)qc(a,b[f],c,d,e);else if(d=!!d,a=rc(a,b,d))for(f=0;f<a.length;f++)if(a[f].ba==c&&a[f].capture==d&&a[f].ya==
+e){N(a[f].key);break}},N=function(a){if(!lc[a])return m;var b=lc[a];if(b.Q)return m;var c=b.src,d=b.type,e=b.Ib,f=b.capture;c.removeEventListener?(c==o||!c.Hb)&&c.removeEventListener(d,e,f):c.detachEvent&&c.detachEvent(d in mc?mc[d]:mc[d]="on"+d,e);c=ga(c);e=K[d][f][c];if(L[c]){var h=L[c];ya(h,b);0==h.length&&delete L[c]}b.Q=j;e.Lb=j;sc(d,f,c,e);delete lc[a];return j},sc=function(a,b,c,d){if(!d.Fa&&d.Lb){for(var e=0,f=0;e<d.length;e++)d[e].Q?d[e].Ib.src=k:(e!=f&&(d[f]=d[e]),f++);d.length=f;d.Lb=m;
+0==f&&(delete K[a][b][c],K[a][b].g--,0==K[a][b].g&&(delete K[a][b],K[a].g--),0==K[a].g&&delete K[a])}},tc=function(a){var b,c=0,d=b==k;b=!!b;if(a==k)Ga(L,function(a){for(var e=a.length-1;0<=e;e--){var f=a[e];if(d||b==f.capture)N(f.key),c++}});else if(a=ga(a),L[a])for(var a=L[a],e=a.length-1;0<=e;e--){var f=a[e];if(d||b==f.capture)N(f.key),c++}},rc=function(a,b,c){var d=K;return b in d&&(d=d[b],c in d&&(d=d[c],a=ga(a),d[a]))?d[a]:k},vc=function(a,b,c,d,e){var f=1,b=ga(b);if(a[b]){a.r--;a=a[b];a.Fa?
+a.Fa++:a.Fa=1;try{for(var h=a.length,l=0;l<h;l++){var s=a[l];s&&!s.Q&&(f&=uc(s,e)!==m)}}finally{a.Fa--,sc(c,d,b,a)}}return Boolean(f)},uc=function(a,b){var c=a.handleEvent(b);a.kb&&N(a.key);return c},oc=function(a,b){if(!lc[a])return j;var c=lc[a],d=c.type,e=K;if(!(d in e))return j;var e=e[d],f,h;if(!fc){var l;if(!(l=b))a:{l="window.event".split(".");for(var s=o;f=l.shift();)if(s[f]!=k)s=s[f];else{l=k;break a}l=s}f=l;l=j in e;s=m in e;if(l){if(0>f.keyCode||f.returnValue!=i)return j;a:{var t=m;if(0==
+f.keyCode)try{f.keyCode=-1;break a}catch(O){t=j}if(t||f.returnValue==i)f.returnValue=j}}t=new hc;t.ca(f,this);f=j;try{if(l){for(var v=[],lb=t.currentTarget;lb;lb=lb.parentNode)v.push(lb);h=e[j];h.r=h.g;for(var X=v.length-1;!t.S&&0<=X&&h.r;X--)t.currentTarget=v[X],f&=vc(h,v[X],d,j,t);if(s){h=e[m];h.r=h.g;for(X=0;!t.S&&X<v.length&&h.r;X++)t.currentTarget=v[X],f&=vc(h,v[X],d,m,t)}}else f=uc(c,t)}finally{if(v)v.length=0;t.l()}return f}d=new hc(b,this);try{f=uc(c,d)}finally{d.l()}return f};var P=function(a){this.bb=a;this.c=[]};w(P,Zb);
+var wc=[],Q=function(a,b,c,d,e){p(c)||(wc[0]=c,c=wc);for(var f=0;f<c.length;f++)a.c.push(M(b,c[f],d||a,e||m,a.bb||a));return a},xc=function(a,b,c,d,e,f){if(p(c))for(var h=0;h<c.length;h++)xc(a,b,c[h],d,e,f);else a.c.push(pc(b,c,d||a,e,f||a.bb||a))},yc=function(a,b,c,d,e,f){if(p(c))for(var h=0;h<c.length;h++)yc(a,b,c[h],d,e,f);else{a:{d=d||a;f=f||a.bb||a;e=!!e;if(b=rc(b,c,e))for(c=0;c<b.length;c++)if(!b[c].Q&&b[c].ba==d&&b[c].capture==e&&b[c].ya==f){b=b[c];break a}b=k}if(b)b=b.key,N(b),ya(a.c,b)}return a};
+P.prototype.O=function(){ua(this.c,N);this.c.length=0};P.prototype.k=function(){P.e.k.call(this);this.O()};P.prototype.handleEvent=function(){g(Error("EventHandler.handleEvent not implemented"))};var R=function(){};w(R,Zb);n=R.prototype;n.Hb=j;n.Aa=k;n.Xa=function(a){this.Aa=a};n.addEventListener=function(a,b,c,d){M(this,a,b,c,d)};n.removeEventListener=function(a,b,c,d){qc(this,a,b,c,d)};
+n.dispatchEvent=function(a){var b=a.type||a,c=K;if(b in c){if(q(a))a=new J(a,this);else if(a instanceof J)a.target=a.target||this;else{var d=a,a=new J(b,this);Ka(a,d)}var d=1,e,c=c[b],b=j in c,f;if(b){e=[];for(f=this;f;f=f.Aa)e.push(f);f=c[j];f.r=f.g;for(var h=e.length-1;!a.S&&0<=h&&f.r;h--)a.currentTarget=e[h],d&=vc(f,e[h],a.type,j,a)&&a.ma!=m}if(m in c)if(f=c[m],f.r=f.g,b)for(h=0;!a.S&&h<e.length&&f.r;h++)a.currentTarget=e[h],d&=vc(f,e[h],a.type,m,a)&&a.ma!=m;else for(e=this;!a.S&&e&&f.r;e=e.Aa)a.currentTarget=
+e,d&=vc(f,e,a.type,m,a)&&a.ma!=m;a=Boolean(d)}else a=j;return a};n.k=function(){R.e.k.call(this);tc(this);this.Aa=k};var zc=function(a,b,c){this.target=a;this.handle=b||a;this.Wa=c||new Hb(NaN,NaN,NaN,NaN);this.f=qb(a);this.m=new P(this);M(this.handle,["touchstart","mousedown"],this.Eb,m,this)};w(zc,R);var Ac=B||C&&E("1.9.3");n=zc.prototype;n.clientX=0;n.clientY=0;n.screenX=0;n.screenY=0;n.Bb=0;n.Cb=0;n.$=0;n.aa=0;n.zb=j;n.H=m;n.Ab=0;n.fc=0;n.ec=m;n.D=function(){return this.m};
+n.k=function(){zc.e.k.call(this);qc(this.handle,["touchstart","mousedown"],this.Eb,m,this);this.m.l();delete this.target;delete this.handle;delete this.m};
+n.Eb=function(a){var b="mousedown"==a.type;if(this.zb&&!this.H&&(!b||(ec?0==a.q.button:"click"==a.type||a.q.button&ic[0])&&(!D||!Ra||!a.ctrlKey))){Bc(a);if(0==this.Ab)if(Cc(this,a),this.H)a.preventDefault();else return;else a.preventDefault();var b=this.f,c=b.documentElement,d=!Ac;Q(this.m,b,["touchmove","mousemove"],this.dc,d);Q(this.m,b,["touchend","mouseup"],this.xa,d);Ac?(c.setCapture(m),Q(this.m,c,"losecapture",this.xa)):Q(this.m,b?wb(b):window,"blur",this.xa);B&&this.ec&&Q(this.m,b,"dragstart",
+cc);this.hc&&Q(this.m,this.hc,"scroll",this.gc,d);this.clientX=this.Bb=a.clientX;this.clientY=this.Cb=a.clientY;this.screenX=a.screenX;this.screenY=a.screenY;this.$=this.target.offsetLeft;this.aa=this.target.offsetTop;this.Ua=Fb(G(this.f));this.fc=ja()}else this.dispatchEvent("earlycancel")};var Cc=function(a,b){if(a.dispatchEvent(new Dc("start",a,b.clientX,b.clientY,b))!==m)a.H=j};
+zc.prototype.xa=function(a,b){this.m.O();Ac&&this.f.releaseCapture();var c=Ec(this,this.$),d=Fc(this,this.aa);this.H?(Bc(a),this.H=m,this.dispatchEvent(new Dc("end",this,a.clientX,a.clientY,a,c,d,b||"touchcancel"==a.type))):this.dispatchEvent("earlycancel");("touchend"==a.type||"touchcancel"==a.type)&&a.preventDefault()};var Bc=function(a){var b=a.type;"touchstart"==b||"touchmove"==b?a.ca(a.q.targetTouches[0],a.currentTarget):("touchend"==b||"touchcancel"==b)&&a.ca(a.q.changedTouches[0],a.currentTarget)};
+zc.prototype.dc=function(a){if(this.zb){Bc(a);var b=a.clientX-this.clientX,c=a.clientY-this.clientY;this.clientX=a.clientX;this.clientY=a.clientY;this.screenX=a.screenX;this.screenY=a.screenY;if(!this.H){var d=this.Bb-this.clientX,e=this.Cb-this.clientY;if(d*d+e*e>this.Ab&&(Cc(this,a),!this.H)){this.xa(a);return}}c=Gc(this,b,c);b=c.x;c=c.y;this.H&&this.dispatchEvent(new Dc("beforedrag",this,a.clientX,a.clientY,a,b,c))!==m&&(Hc(this,a,b,c),a.preventDefault())}};
+var Gc=function(a,b,c){var d=Fb(G(a.f)),b=b+(d.x-a.Ua.x),c=c+(d.y-a.Ua.y);a.Ua=d;a.$+=b;a.aa+=c;b=Ec(a,a.$);a=Fc(a,a.aa);return new Fa(b,a)};zc.prototype.gc=function(a){var b=Gc(this,0,0);a.clientX=this.clientX;a.clientY=this.clientY;Hc(this,a,b.x,b.y)};
+var Hc=function(a,b,c,d){a.target.style.left=c+"px";a.target.style.top=d+"px";a.dispatchEvent(new Dc("drag",a,b.clientX,b.clientY,b,c,d))},Ec=function(a,b){var c=a.Wa,d=!isNaN(c.left)?c.left:k,c=!isNaN(c.width)?c.width:0;return Math.min(d!=k?d+c:Infinity,Math.max(d!=k?d:-Infinity,b))},Fc=function(a,b){var c=a.Wa,d=!isNaN(c.top)?c.top:k,c=!isNaN(c.height)?c.height:0;return Math.min(d!=k?d+c:Infinity,Math.max(d!=k?d:-Infinity,b))},Dc=function(a,b,c,d,e,f,h,l){J.call(this,a);this.clientX=c;this.clientY=
+d;this.ld=e;this.left=f!==i?f:b.$;this.top=h!==i?h:b.aa;this.nd=b;this.md=!!l};w(Dc,J);var Ic="StopIteration"in o?o.StopIteration:Error("StopIteration"),Jc=function(){};Jc.prototype.next=function(){g(Ic)};Jc.prototype.rb=function(){return this};
+var Kc=function(a){if(a instanceof Jc)return a;if("function"==typeof a.rb)return a.rb(m);if(ba(a)){var b=0,c=new Jc;c.next=function(){for(;;){b>=a.length&&g(Ic);if(b in a)return a[b++];b++}};return c}g(Error("Not implemented"))},Lc=function(a,b){if(ba(a))try{ua(a,b,i)}catch(c){c!==Ic&&g(c)}else{a=Kc(a);try{for(;;)b.call(i,a.next(),i,a)}catch(d){d!==Ic&&g(d)}}};var Mc=function(a){if("function"==typeof a.Ia)return a.Ia();if(q(a))return a.split("");if(ba(a)){for(var b=[],c=a.length,d=0;d<c;d++)b.push(a[d]);return b}return Ha(a)},Nc=function(a,b,c){if("function"==typeof a.forEach)a.forEach(b,c);else if(ba(a)||q(a))ua(a,b,c);else{var d;if("function"==typeof a.eb)d=a.eb();else if("function"!=typeof a.Ia)if(ba(a)||q(a)){d=[];for(var e=a.length,f=0;f<e;f++)d.push(f)}else d=Ia(a);else d=i;for(var e=Mc(a),f=e.length,h=0;h<f;h++)b.call(c,e[h],d&&d[h],a)}};var Oc=function(a,b){this.K={};this.c=[];var c=arguments.length;if(1<c){c%2&&g(Error("Uneven number of arguments"));for(var d=0;d<c;d+=2)this.set(arguments[d],arguments[d+1])}else if(a){a instanceof Oc?(c=a.eb(),d=a.Ia()):(c=Ia(a),d=Ha(a));for(var e=0;e<c.length;e++)this.set(c[e],d[e])}};n=Oc.prototype;n.g=0;n.Ea=0;n.Ia=function(){Pc(this);for(var a=[],b=0;b<this.c.length;b++)a.push(this.K[this.c[b]]);return a};n.eb=function(){Pc(this);return this.c.concat()};n.za=function(){return 0==this.g};
+n.clear=function(){this.K={};this.Ea=this.g=this.c.length=0};var Pc=function(a){if(a.g!=a.c.length){for(var b=0,c=0;b<a.c.length;){var d=a.c[b];Object.prototype.hasOwnProperty.call(a.K,d)&&(a.c[c++]=d);b++}a.c.length=c}if(a.g!=a.c.length){for(var e={},c=b=0;b<a.c.length;)d=a.c[b],Object.prototype.hasOwnProperty.call(e,d)||(a.c[c++]=d,e[d]=1),b++;a.c.length=c}};Oc.prototype.get=function(a,b){return Object.prototype.hasOwnProperty.call(this.K,a)?this.K[a]:b};
+Oc.prototype.set=function(a,b){Object.prototype.hasOwnProperty.call(this.K,a)||(this.g++,this.c.push(a),this.Ea++);this.K[a]=b};Oc.prototype.rb=function(a){Pc(this);var b=0,c=this.c,d=this.K,e=this.Ea,f=this,h=new Jc;h.next=function(){for(;;){e!=f.Ea&&g(Error("The map has changed since the iterator was created"));b>=c.length&&g(Ic);var h=c[b++];return a?h:d[h]}};return h};var Qc=function(a){this.b=a;a=B?"focusout":"blur";this.oc=M(this.b,B?"focusin":"focus",this,!B);this.pc=M(this.b,a,this,!B)};w(Qc,R);Qc.prototype.handleEvent=function(a){var b=new hc(a.q);b.type="focusin"==a.type||"focus"==a.type?"focusin":"focusout";try{this.dispatchEvent(b)}finally{b.l()}};Qc.prototype.k=function(){Qc.e.k.call(this);N(this.oc);N(this.pc);delete this.b};var Rc=o.window;var Sc=function(){};(function(a){a.Vb=function(){return a.Tc||(a.Tc=new a)}})(Sc);Sc.prototype.Qc=0;Sc.Vb();var S=function(a){this.ja=a||G();this.Rc=Tc};w(S,R);S.prototype.Pc=Sc.Vb();var Tc=k;n=S.prototype;n.La=k;n.w=m;n.b=k;n.Rc=k;n.bc=k;n.X=k;n.va=k;n.ia=k;n.cc=m;n.Oa=function(){return this.La||(this.La=":"+(this.Pc.Qc++).toString(36))};n.a=function(){return this.b};n.D=function(){return this.Y||(this.Y=new P(this))};n.Xa=function(a){this.X&&this.X!=a&&g(Error("Method not supported"));S.e.Xa.call(this,a)};n.h=function(){return this.ja};n.i=function(){this.b=this.ja.createElement("div")};
+n.ra=function(a){this.w&&g(Error("Component already rendered"));this.b||this.i();a?a.insertBefore(this.b,k):this.ja.f.body.appendChild(this.b);(!this.X||this.X.w)&&this.W()};n.W=function(){this.w=j;Uc(this,function(a){!a.w&&a.a()&&a.W()})};n.N=function(){Uc(this,function(a){a.w&&a.N()});this.Y&&this.Y.O();this.w=m};n.k=function(){S.e.k.call(this);this.w&&this.N();this.Y&&(this.Y.l(),delete this.Y);Uc(this,function(a){a.l()});!this.cc&&this.b&&Cb(this.b);this.X=this.bc=this.b=this.ia=this.va=k};
+n.yb=function(){return this.b};var Uc=function(a,b){a.va&&ua(a.va,b,i)};S.prototype.removeChild=function(a,b){if(a){var c=q(a)?a:a.Oa(),a=this.ia&&c?(c in this.ia?this.ia[c]:i)||k:k;if(c&&a){var d=this.ia;c in d&&delete d[c];ya(this.va,a);b&&(a.N(),a.b&&Cb(a.b));c=a;c==k&&g(Error("Unable to set parent component"));c.X=k;S.e.Xa.call(c,k)}}a||g(Error("Child is not in parent component"));return a};var Vc=function(a,b){S.call(this,b);this.ac=!!a};w(Vc,S);n=Vc.prototype;n.Ta=k;n.Ca=m;n.n=k;n.j=k;n.A=k;n.wa=function(){return"goog-modalpopup"};n.qa=function(){return this.n};
+n.i=function(){Vc.e.i.call(this);var a=this.a();ob(a,this.wa());a.tabIndex=0;I(a,m);if(this.ac&&!this.j)this.j=this.h().i("iframe",{frameborder:0,style:"border:0;vertical-align:bottom;",src:'javascript:""'}),this.j.className=this.wa()+"-bg",I(this.j,m),Sb(this.j,0);if(!this.n)this.n=this.h().i("div",this.wa()+"-bg"),I(this.n,m);if(!this.A)this.A=this.h().createElement("span"),I(this.A,m),this.A.tabIndex=0,this.A.style.position="absolute"};
+n.W=function(){x(!!this.n,"Background element must not be null.");if(this.j){var a=this.a();a.parentNode&&a.parentNode.insertBefore(this.j,a)}a=this.a();a.parentNode&&a.parentNode.insertBefore(this.n,a);Vc.e.W.call(this);a=this.a();a.parentNode&&a.parentNode.insertBefore(this.A,a.nextSibling);this.Ta=new Qc(Eb(this.h()));Q(this.D(),this.Ta,"focusin",this.$b)};n.N=function(){this.sa()&&this.C(m);ac(this.Ta);Vc.e.N.call(this);Cb(this.j);Cb(this.n);Cb(this.A)};
+n.C=function(a){x(this.w,"ModalPopup must be rendered first.");a!=this.Ca&&(a?this.Kc():this.Jc())};n.Kc=function(){if(this.dispatchEvent("beforeshow")){this.Za();this.wb();var a=this.D(),b=this.h();Q(a,wb(b.f),"resize",this.Za);Wc(this,j);this.focus();this.Ca=j;this.dispatchEvent("show")}};n.Jc=function(){if(this.dispatchEvent("beforehide")){var a=yc,b=this.D(),c=this.h();a(b,wb(c.f),"resize",this.Za);Wc(this,m);this.Ca=m;this.dispatchEvent("hide")}};
+var Wc=function(a,b){a.j&&I(a.j,b);a.n&&I(a.n,b);I(a.a(),b);I(a.A,b)};n=Vc.prototype;n.sa=function(){return this.Ca};n.focus=function(){this.Sb()};n.Za=function(){this.j&&I(this.j,m);this.n&&I(this.n,m);var a=Eb(this.h()),b=vb((a?wb(a):window)||window||window),c=Math.max(a.body.scrollWidth,b.width),a=Math.max(a.body.scrollHeight,b.height);this.j&&(I(this.j,j),Pb(this.j,c,a));this.n&&(I(this.n,j),Pb(this.n,c,a))};
+n.wb=function(){var a=Eb(this.h()),b=(a?wb(a):window)||window;if("fixed"==Jb(this.a(),"position"))var c=a=0;else c=Fb(this.h()),a=c.x,c=c.y;var d=Rb(this.a()),b=vb(b||window),a=Math.max(a+b.width/2-d.width/2,0),c=Math.max(c+b.height/2-d.height/2,0);Lb(this.a(),a,c);Lb(this.A,a,c)};n.$b=function(a){if(a.target==this.A)a=this.Sb,ca(a)?this&&(a=r(a,this)):a&&"function"==typeof a.handleEvent?a=r(a.handleEvent,a):g(Error("Invalid listener argument")),Rc.setTimeout(a,0)};
+n.Sb=function(){try{B&&Eb(this.h()).body.focus(),this.a().focus()}catch(a){}};var T=function(a,b,c){Vc.call(this,b,c);this.z=a||"modal-dialog";this.G=Xc()};w(T,Vc);n=T.prototype;n.lc=j;n.sb=j;n.Qa=j;n.ic=j;n.Ra=0.5;n.Yb="";n.tb="";n.R=k;n.vb=m;n.M=k;n.Pa=k;n.ub=k;n.ha=k;n.Sa=k;n.F=k;n.wa=function(){return this.z};var Yc=function(a){a.a()||a.ra()};T.prototype.yb=function(){Yc(this);return this.Sa};T.prototype.qa=function(){Yc(this);return T.e.qa.call(this)};
+var Zc=function(a){a.Qa=m;if(a.w){var b=a.h(),c=a.qa();b.removeNode(a.j);b.removeNode(c)}},$c=function(a,b){if(a.a()){var c=a.M,d=a.z+"-title-draggable";b?ob(c,d):pb(c,d)}if(b&&!a.R)a.R=new zc(a.a(),a.M),ob(a.M,a.z+"-title-draggable"),M(a.R,"start",a.nc,m,a);else if(!b&&a.R)a.R.l(),a.R=k};n=T.prototype;
+n.i=function(){T.e.i.call(this);var a=this.a();x(a,"getElement() returns null");var b=this.h();this.M=b.i("div",{className:this.z+"-title",id:this.Oa()},this.Pa=b.i("span",this.z+"-title-text",this.Yb),this.ha=b.i("span",this.z+"-title-close"));Bb(a,this.M,this.Sa=b.i("div",this.z+"-content"),this.F=b.i("div",this.z+"-buttons"));this.ub=this.M.id;bc(a);a.setAttribute("aria-labelledby",this.ub||"");if(this.tb)this.Sa.innerHTML=this.tb;I(this.ha,this.sb);if(this.G)a=this.G,a.b=this.F,a.ra();I(this.F,
+!!this.G);this.Ra=this.Ra;this.a()&&(a=this.qa())&&Sb(a,this.Ra)};n.W=function(){T.e.W.call(this);Q(this.D(),this,["show","hide"],this.kc);$c(this,this.ic);Q(this.D(),this.ha,"click",this.jc);bc(this.a());""!==this.Pa.id&&this.a().setAttribute("aria-labelledby",this.Pa.id);this.Qa||Zc(this)};n.N=function(){this.sa()&&this.C(m);$c(this,m);T.e.N.call(this)};n.C=function(a){a!=this.sa()&&(this.w||this.ra(),T.e.C.call(this,a))};
+n.kc=function(a){a.target==this&&(this.sa()?(Q(Q(this.D(),this.a(),"keydown",this.Ba),this.a(),"keypress",this.Ba),this.dispatchEvent("aftershow"),Q(this.D(),this.F,"click",this.Gb)):(yc(yc(yc(this.D(),this.a(),"keydown",this.Ba),this.a(),"keypress",this.Ba),this.F,"click",this.Gb),this.dispatchEvent("afterhide"),this.vb&&this.l()))};
+n.focus=function(){T.e.focus.call(this);if(this.G){var a=this.G.ta;if(a)for(var b=Eb(this.h()),c=this.F.getElementsByTagName("button"),d=0,e;e=c[d];d++)if(e.name==a){try{if(D||Wa){var f=b.createElement("input");f.style.cssText="position:fixed;width:0;height:0;left:0;top:0;";this.a().appendChild(f);f.focus();this.a().removeChild(f)}e.focus()}catch(h){}break}}};
+n.nc=function(){var a=Eb(this.h()),b=vb((a?wb(a):window)||window||window),c=Math.max(a.body.scrollWidth,b.width),a=Math.max(a.body.scrollHeight,b.height),d=Rb(this.a());this.R.Wa="fixed"==Jb(this.a(),"position")?new Hb(0,0,Math.max(0,b.width-d.width),Math.max(0,b.height-d.height))||new Hb(NaN,NaN,NaN,NaN):new Hb(0,0,c-d.width,a-d.height)||new Hb(NaN,NaN,NaN,NaN)};n.jc=function(){if(this.sb){var a=this.G,b=a&&a.Va;b?(a=a.get(b),this.dispatchEvent(new ad(b,a))&&this.C(m)):this.C(m)}};
+n.k=function(){this.F=this.ha=k;T.e.k.call(this)};n.Gb=function(a){a:{for(a=a.target;a!=k&&a!=this.F;){if("BUTTON"==a.tagName)break a;a=a.parentNode}a=k}if(a&&!a.disabled){var a=a.name,b=this.G.get(a);this.dispatchEvent(new ad(a,b))&&this.C(m)}};
+n.Ba=function(a){var b=m,c=m,d=this.G,e=a.target;if("keydown"==a.type)if(this.lc&&27==a.keyCode){var f=d&&d.Va,e="SELECT"==e.tagName&&!e.disabled;f&&!e?(c=j,b=d.get(f),b=this.dispatchEvent(new ad(f,b))):e||(b=j)}else 9==a.keyCode&&a.shiftKey&&e==this.a()&&(c=j);else if(13==a.keyCode){if("BUTTON"==e.tagName)f=e.name;else if(d){var h=d.ta,l;if(l=h)a:{l=d.b.getElementsByTagName("BUTTON");for(var s=0,t;t=l[s];s++)if(t.name==h||t.id==h){l=t;break a}l=k}e=("TEXTAREA"==e.tagName||"SELECT"==e.tagName)&&!e.disabled;
+l&&!l.disabled&&!e&&(f=h)}f&&d&&(c=j,b=this.dispatchEvent(new ad(f,""+d.get(f))))}if(b||c)a.stopPropagation(),a.preventDefault();b&&this.C(m)};var ad=function(a,b){this.type="dialogselect";this.key=a;this.caption=b};w(ad,J);var U=function(a){this.ja=a||G();Oc.call(this)};w(U,Oc);n=U.prototype;n.z="goog-buttonset";n.ta=k;n.b=k;n.Va=k;n.set=function(a,b,c,d){Oc.prototype.set.call(this,a,b);if(c)this.ta=a;if(d)this.Va=a;return this};var V=function(a,b,c,d){return a.set(b.key,b.caption,c,d)};
+U.prototype.ra=function(){if(this.b){this.b.innerHTML="";var a=G(this.b);Nc(this,function(b,c){var d=a.i("button",{name:c},b);if(c==this.ta)d.className=this.z+"-default";this.b.appendChild(d)},this)}};U.prototype.a=function(){return this.b};U.prototype.h=function(){return this.ja};
+var bd={key:"ok",caption:"OK"},cd={key:"cancel",caption:"Cancel"},dd={key:"yes",caption:"Yes"},ed={key:"no",caption:"No"},fd={key:"save",caption:"Save"},gd={key:"continue",caption:"Continue"},Xc=function(){return V(V(new U,bd,j),cd,m,j)};"undefined"!=typeof document&&(V(new U,bd,j,j),Xc(),V(V(new U,dd,j),ed,m,j),V(V(V(new U,dd),ed,j),cd,m,j),V(V(V(new U,gd),fd),cd,j,j));var hd=function(){};hd.prototype.Qb=function(){};var id=function(){var a=new T("bidichecker-dialog");m!=a.Qa&&Zc(a);a.C(j);var b=a.a();b.style.zIndex=1E4;Yc(a);a.ha.innerHTML="&times;";a.vb=j;var c=document.createElement("iframe"),d=a.yb();d.appendChild(c);this.ua=c.contentWindow;var c=G(d),e=k;if(B)e=c.f.createStyleSheet(),Tb(e);else{var f=sb(c.f,"head")[0];f||(e=sb(c.f,"body")[0],f=c.i("head"),e.parentNode.insertBefore(f,e));e=c.i("style");Tb(e);c.appendChild(f,e)}this.Zb=e;f=qb(b);if(e=c=B&&b.currentStyle)f=G(f),e=rb(f.f)&&"auto"!=c.width&&"auto"!=
+c.height&&!c.boxSizing;if(e)f=Vb(b,c.width,"width","pixelWidth"),b=Vb(b,c.height,"height","pixelHeight"),b=new A(f,b);else{c=new A(b.offsetWidth,b.offsetHeight);if(B)var f=Wb(b,"paddingLeft"),e=Wb(b,"paddingRight"),h=Wb(b,"paddingTop"),l=Wb(b,"paddingBottom"),f=new Gb(h,e,l,f);else f=H(b,"paddingLeft"),e=H(b,"paddingRight"),h=H(b,"paddingTop"),l=H(b,"paddingBottom"),f=new Gb(parseFloat(h),parseFloat(e),parseFloat(l),parseFloat(f));B?(e=Yb(b,"borderLeft"),h=Yb(b,"borderRight"),l=Yb(b,"borderTop"),
+b=Yb(b,"borderBottom"),b=new Gb(l,h,b,e)):(e=H(b,"borderLeftWidth"),h=H(b,"borderRightWidth"),l=H(b,"borderTopWidth"),b=H(b,"borderBottomWidth"),b=new Gb(parseFloat(l),parseFloat(h),parseFloat(b),parseFloat(e)));b=new A(c.width-b.left-f.left-f.right-b.right,c.height-b.top-f.top-f.bottom-b.bottom)}b=b.height;Yc(a);d.style.height=Kb(b-a.M.offsetHeight,j);a.wb();this.xb=a};w(id,hd);id.prototype.l=function(){this.xb.l();var a=this.Zb;Cb(a.ownerNode||a.owningElement||a)};
+id.prototype.Qb=function(a){var b=this.xb.a(),c=new Fa(b.offsetLeft,b.offsetTop);Lb(b,c.x,c.y+a)};var kd=function(a){a||(a=window.open("about:blank","_blank","width=800,height=600,menubar=no,toolbar=no,location=no"))||g(Error("can't create window"));jd(a);this.ua=a};w(kd,hd);var jd=function(a){setTimeout(function(){a.resizeTo(800,600)},1)};kd.prototype.l=function(){try{this.ua.close()}catch(a){}};var ld=function(a){try{return new kd(a)}catch(b){return new id}};var md=function(a){a=""+a;if(/^\s*$/.test(a)?0:/^[\],:{}\s\u2028\u2029]*$/.test(a.replace(/\\["\\\/bfnrtu]/g,"@").replace(/"[^"\\\n\r\u2028\u2029\x00-\x08\x10-\x1f\x80-\x9f]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:[\s\u2028\u2029]*\[)+/g,"")))try{return eval("("+a+")")}catch(b){}g(Error("Invalid JSON string: "+a))},nd=function(){this.Na=i},pd=function(a){var b=[];od(new nd,a,b);return b.join("")},od=function(a,b,c){switch(typeof b){case "string":qd(b,c);break;
+case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(b==k){c.push("null");break}if(p(b)){var d=b.length;c.push("[");for(var e="",f=0;f<d;f++)c.push(e),e=b[f],od(a,a.Na?a.Na.call(b,""+f,e):e,c),e=",";c.push("]");break}c.push("{");d="";for(f in b)Object.prototype.hasOwnProperty.call(b,f)&&(e=b[f],"function"!=typeof e&&(c.push(d),qd(f,c),c.push(":"),od(a,a.Na?a.Na.call(b,f,e):e,c),d=","));c.push("}");break;case "function":break;
+default:g(Error("Unknown type: "+typeof b))}},rd={'"':'\\"',"\\":"\\\\","/":"\\/","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},sd=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g,qd=function(a,b){b.push('"',a.replace(sd,function(a){if(a in rd)return rd[a];var b=a.charCodeAt(0),e="\\u";16>b?e+="000":256>b?e+="00":4096>b&&(e+="0");return rd[a]=e+b.toString(16)}),'"')};var td=function(a,b){this.Oc=a;this.Ob=b;this.Nc=M(window,"message",this.Mc,m,this)};td.prototype.send=function(a,b){this.Oc.postMessage(pd({type:a,data:b}),"*")};td.prototype.l=function(){N(this.Nc)};td.prototype.Mc=function(a){var b=md(a.q.data),a=""+b.type,b=b.data;this.Ob.hasOwnProperty(a)||g("Unknown message type received by CommChannel: "+a);(0,this.Ob[a])(a,b)};var ud;(ud="ScriptEngine"in o&&"JScript"==o.ScriptEngine())&&(o.ScriptEngineMajorVersion(),o.ScriptEngineMinorVersion(),o.ScriptEngineBuildVersion());var vd=function(a,b){this.t=ud?[]:"";a!=k&&this.append.apply(this,arguments)};vd.prototype.set=function(a){this.clear();this.append(a)};ud?(vd.prototype.qb=0,vd.prototype.append=function(a,b,c){b==k?this.t[this.qb++]=a:(this.t.push.apply(this.t,arguments),this.qb=this.t.length);return this}):vd.prototype.append=function(a,b,c){this.t+=a;if(b!=k)for(var d=1;d<arguments.length;d++)this.t+=arguments[d];return this};vd.prototype.clear=function(){ud?this.qb=this.t.length=0:this.t=""};
+vd.prototype.toString=function(){if(ud){var a=this.t.join("");this.clear();a&&this.append(a);return a}return this.t};var W=function(a,b,c,d,e){this.o=!!b;a&&wd(this,a,d);this.depth=e!=i?e:this.p||0;this.o&&(this.depth*=-1);this.qc=!c};w(W,Jc);W.prototype.s=k;W.prototype.p=0;W.prototype.Kb=m;var wd=function(a,b,c){if(a.s=b)a.p="number"==typeof c?c:1!=a.s.nodeType?0:a.o?-1:1};
+W.prototype.next=function(){var a;if(this.Kb){(!this.s||this.qc&&0==this.depth)&&g(Ic);a=this.s;var b=this.o?-1:1;if(this.p==b){var c=this.o?a.lastChild:a.firstChild;c?wd(this,c):wd(this,a,-1*b)}else(c=this.o?a.previousSibling:a.nextSibling)?wd(this,c):wd(this,a.parentNode,-1*b);this.depth+=this.p*(this.o?-1:1)}else this.Kb=j;(a=this.s)||g(Ic);return a};
+W.prototype.splice=function(a){var b=this.s,c=this.o?1:-1;if(this.p==c)this.p=-1*c,this.depth+=this.p*(this.o?-1:1);this.o=!this.o;W.prototype.next.call(this);this.o=!this.o;for(var c=ba(arguments[0])?arguments[0]:arguments,d=c.length-1;0<=d;d--)b.parentNode&&b.parentNode.insertBefore(c[d],b.nextSibling);Cb(b)};var xd=RegExp("[\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc](?:[^A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff\u202a-\u202e]*[\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc])?","g"),yd=RegExp("(?:[\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc](?:[^A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff\u202a-\u202e]*[\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc])?)|(?:\u202e[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff](?:[^\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc\u202a-\u202e]*[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff])?\u202c[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*)+",
+"g"),zd=RegExp("[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff](?:[^\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc\u202a-\u202e]*[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff])?","g"),Ad=RegExp("^[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff]"),
+Bd=RegExp("[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff][\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*$"),Cd=RegExp("[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*$"),
+Dd=RegExp("[\x00-\u001f\u007f\u0085\u00a0\u1680\u180e\u2000-\u200f\u2028-\u202f\u205f\u3000]"),Ed=RegExp("^[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\u200e]+$"),Fd=RegExp("^[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\u200f]+$"),
+Gd=RegExp("^[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*\\d"),Hd=RegExp("[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc]"),Id=function(a,b){this.text=a;this.index=b},Jd=function(a){for(var b=[],c;c=xd.exec(a);)b.push(new Id(c[0],
+c.index));return b},Kd=function(a){for(var b=[],c;c=yd.exec(a);){var d=c[0],e=Cd.exec(c[0]);e&&(d=d.substr(0,d.length-e[0].length));b.push(new Id(d,c.index))}return b},Ld=function(a){for(var b=[],c;c=zd.exec(a);)"\u202e"==a.charAt(c.index-1)&&"\u202c"==a.charAt(c.index+c[0].length)||b.push(new Id(c[0],c.index));return b},Md=function(a,b){var c=Ad.exec(a.substr(b));return c?new Id(c[0],b):k},Nd=function(a,b){var c=Bd.exec(a.substr(0,b));return c?new Id(c[0],b-c[0].length):k},Od=function(a){return(a=
+Gd.exec(a))?new Id(a[0],0):k},Pd={"\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t",'"':'\\"',"'":"\\'","\\":"\\\\"},Qd=function(a){for(var b=[],c=0;c<a.length;c++){var d=b,e=c,f;f=a.charAt(c);if(f in Pd)f=Pd[f];else{var h=f;if(Dd.test(f)){var l=f.charCodeAt(0),h="\\u";4096>l&&(h+="0",256>l&&(h+="0",16>l&&(h+="0")));h+=l.toString(16)}f=Pd[f]=h}d[e]=f}return b.join("")},Rd=function(a){var b=a.nodeValue;"class"!=a.nodeName&&"id"!=a.nodeName&&(b=20<b.length?b.substr(0,20)+"\u2026":b);"style"==
+a.nodeName&&(b=b.toLowerCase());return a.nodeName+"="+("'"+Qd(b)+"'")},Sd=function(a){var b=[];if(a.attributes)for(var c=0;c<a.attributes.length;++c){var d=a.attributes[c];d.nodeValue&&(d.specified===i||d.specified)&&b.push(d)}a=[a.nodeName.toLowerCase()];b=wa(b,Rd);b.sort();a=a.concat(b);return"<"+a.join(" ")+">"},Td=function(a){for(var b=[];a&&!(b.push(Sd(a)),"BODY"==a.parentNode.nodeName||"FRAMESET"==a.parentNode.nodeName);a=a.parentNode);b.reverse();return b.join("")},Ud=function(a){var b=[],
+c=new W(a);Lc(c,function(){3==c.s.nodeType&&b.push(c.s.data)});return b.join("")},Vd=La("ADDRESS","BLOCKQUOTE","BODY","CAPTION","CENTER","COL","COLGROUP","DIR","DIV","DL","DD","DT","FIELDSET","FORM","H1","H2","H3","H4","H5","H6","HR","ISINDEX","OL","LI","MAP","MENU","OPTGROUP","OPTION","P","PRE","TABLE","TBODY","TD","TFOOT","TH","THEAD","TR","TL","UL"),Wd=La("inline","inline-block","inline-table"),Xd={element:k,style:k},Yd=function(a){if(Xd.element==a)return Xd.style;var b=Ib(a,"display")||H(a,"display");
+Xd={element:a,style:b};return b},Zd=function(a){var b=Yd(a);return b?!Wd[b]:!!Vd[a.tagName]},$d=function(a){if(1==a.nodeType){if("SCRIPT"==a.nodeName||"STYLE"==a.nodeName||"NOSCRIPT"==a.nodeName)return m;if("none"==Yd(a))return m;a=Ib(a,"visibility")||H(a,"visibility");return"hidden"!=a&&"collapse"!=a}return j},ae=function(a){var b={color:a.style.color||"",backgroundColor:a.style.backgroundColor||"",outline:a.style.outline||""};a.style.color="red";a.style.backgroundColor="yellow";a.style.outline=
+"medium solid red";return b};var Y=function(a,b,c,d){if("object"==typeof a){b="id,type,severity,atText,locationDescription,precededByText,followedByText".split(",");c=["id","type","severity"];for(d=0;d<b.length;++d){var e=b[d];this[e]=e in a?a[e]:k;this[e]==k&&0<=ta(c,e)&&g("Required field '"+e+"' not found in bidichecker.Error.")}}else b==i&&g("Required parameter 'opt_severity' not found in bidichecker.Error."),this.id=be++,this.type=a,this.severity=b,ce[this.id]=c||k,this.atText=d||k};Y.prototype.precededByText=k;
+Y.prototype.followedByText=k;Y.prototype.locationDescription=k;Y.prototype.asString=k;var be=0,ce=[];Y.prototype.Oa=function(){return this.id};Y.prototype.Wb=function(){return this.type};Y.prototype.fa=function(){return ce[this.id]||k};
+Y.prototype.toString=function(){var a=new vd("[",this.severity.toString(),"] ",this.Wb()),b;if(b=this.atText)b=20<b.length?b.substr(0,20)+"\u2026":b,a.append(": ","'"+Qd(b)+"'");(b=this.precededByText)&&a.append(" preceded by ","'"+Qd(b)+"'");(b=this.followedByText)&&a.append(" followed by ","'"+Qd(b)+"'");(b=this.locationDescription)&&a.append(" in ",b);return a.toString()};var de=function(a){for(var b=0;b<a.length;++b){var c=a[b];c.asString=c.toString()}return pd(a)};var ee=function(a,b,c,d,e){var f={},h;for(h in b)f[h]=b[h];b=f;h={dir:"ltr",severity:4};for(var l in h)l in b||(b[l]=h[l]);this.wc=a;this.fb=b;this.Da=c;this.Ga=d;this.gb=e||k},fe;n=ee.prototype;n.oa=k;n.start=function(){var a=this.Da.ua;this.oa=new td(a,{checkPage:r(this.xc,this),highlightError:r(this.zc,this),unhighlightError:r(this.Bc,this),getOptions:r(this.yc,this),setOptions:r(this.Ac,this)});a.location=this.Ga};n.l=function(){ac(this.oa);delete this.oa;ac(this.Da);delete this.Da};
+n.yc=function(){this.oa.send("options",this.fb)};n.Ac=function(a,b){this.fb=Object(b)};n.xc=function(){var a;if(this.gb)a=this.gb,this.gb=k;else{a=this.fb;var b=[];-1!=a.severity&&b.push(ge(a.severity));a=this.wc.Ja("rtl"==a.dir,k,b)}this.oa.send("errorList",md(de(a)))};n.zc=function(a,b){var c=(new Y(Object(b))).fa();if(c){var c=c.Rb(),d=window.scrollY;window.scrollTo(0,c.y-100);this.Da.Qb(window.scrollY-d)}};n.Bc=function(a,b){var c=(new Y(Object(b))).fa();c&&c.Ub()};var he=function(a,b,c){this.V=a;this.Hc=b;this.Gc=c;this.U=[]};he.prototype.Rb=function(){if(0==this.U.length)for(var a=0;a<this.V.length;++a)this.U.push(ie(this.V[a],0==a?this.Hc:0,a==this.V.length-1?this.Gc:this.V[a].length));else for(a=0;a<this.U.length;++a)Db(this.U[a],this.V[a]);return Ob(this.U[0])};he.prototype.Ub=function(){if(0!=this.U.length)for(var a=0;a<this.V.length;++a)Db(this.V[a],this.U[a])};
+var ie=function(a,b,c){var b=b||0,c=c||a.data.length,d=[];0<b&&d.push(a.data.substring(0,b));b=yb("span",{},a.data.substring(b,c));ae(b);d.push(b);c<a.data.length&&d.push(a.data.substring(c));b=yb("span",k,d);Db(b,a);return b};var je=function(a){this.b=a};je.prototype.pa=k;je.prototype.Rb=function(){this.pa=ae(this.b);return Ob(this.b)};je.prototype.Ub=function(){if(this.pa)this.b.style.color=this.pa.color,this.b.style.backgroundColor=this.pa.backgroundColor,this.b.style.outline=this.pa.outline};var ke=function(a,b){this.pb=a;this.s=b},le=function(a){this.ga=[new ke(0,a)];this.Tb=a};le.prototype.append=function(a,b){if(this.Tb!=b)this.ga.push(new ke(a,b)),this.Tb=b};var me=function(a,b){var c=Da(a.ga,function(a,b){return a-b.pb}||Ea,b);return 0<=c?c:-c-2};le.prototype.ob=function(a){return this.ga[me(this,a)].s};le.prototype.fa=function(a,b){for(var c=me(this,a),d=me(this,a+b-1),e=[],f=c;f<=d;++f)e.push(this.ga[f].s);return new he(e,a-this.ga[c].pb,a+b-this.ga[d].pb)};
+var ne=function(a,b,c,d,e){this.Fb=b;this.Db=e;this.mc=d;this.mb=[a];this.nb=a.length;this.cb=new le(c)};ne.prototype.Ka=k;ne.prototype.za=function(){return xa(this.mb,function(a){return 0==a.length})};ne.prototype.append=function(a,b){this.cb.append(this.nb,b);this.nb+=a.length;this.mb.push(a);this.Ka=k};var oe=function(a){if(a.Ka===k)a.Ka=a.mb.join("");return a.Ka};ne.prototype.ob=function(a){return this.cb.ob(a)};ne.prototype.fa=function(a,b){return this.cb.fa(a,b)};var pe=new ne("",m,k,k,m);var qe=function(a){this.ea=new W(a);this.sc=a;this.B=[Ub(a)];this.Z=[];this.P=[a];this.da=[]};w(qe,R);qe.prototype.u=k;qe.prototype.go=function(){try{for(;;re(this));}catch(a){a!==Ic&&g(a),this.dispatchEvent("EndOfDom")}};
+var re=function(a){for(var b=a.ea.next();1==a.ea.p&&!$d(b);){var b=a.ea,c=b.o?-1:1;if(b.p==c)b.p=-1*c,b.depth+=b.p*(b.o?-1:1);b=a.ea.next()}a.u=b;1==a.ea.p?(b=a.u,c=Ub(b),a.Z.push(y(a.Z)||se(a,b,c)),a.B.push(c),"IFRAME"==b.nodeName||"FRAME"==b.nodeName?a.da.push(b):Zd(b)&&a.P.push(b),a.dispatchEvent("StartTag")):-1==a.ea.p?(a.dispatchEvent("EndTag"),a.B.pop(),a.Z.pop(),a.u==y(a.P)&&a.P.pop()):3==a.u.nodeType&&"TEXTAREA"!=a.u.parentNode.nodeName&&a.dispatchEvent("TextNode")};qe.prototype.Ya=function(){return this.da};
+var se=function(a,b,c){if(!b.dir&&!b.style.direction&&c==y(a.B)||b==a.sc)return m;for(a=b.firstChild;a;a=a.nextSibling)if(1==a.nodeType&&Zd(a))return m;return j};var te=function(a){this.I=pe;this.m=new P(this);Q(this.m,a,"TextNode",this.$a);xc(this.m,a,"EndOfDom",this.Dc)};w(te,R);te.prototype.$a=function(a){var a=a.target,b=a.u;y(a.B)==this.I.Fb&&y(a.P)==this.I.mc&&y(a.Z)==this.I.Db?this.I.append(b.data,b):(this.I.za()||this.dispatchEvent("DirChunk"),this.I=new ne(b.data,y(a.B),b,y(a.P),y(a.Z)))};te.prototype.Dc=function(){this.I.za()||this.dispatchEvent("DirChunk");this.dispatchEvent("EndOfChunks");this.m.O()};var ue=function(a){this.Ma=a};var Z=function(){};u("bidichecker.FilterFactory.ComposableFilter",Z);Z.prototype.Vc=function(a){return ve(this,a)};Z.prototype.and=Z.prototype.Vc;Z.prototype.ed=function(){return we(this)};Z.prototype.not=Z.prototype.ed;Z.prototype.fd=function(a){return xe(this,a)};Z.prototype.or=Z.prototype.fd;
+var Oe=function(a){var b=a.opcode;switch(b){case "AND":return new ye(a);case "AT_TEXT":return new ze(a);case "AT_TEXT_REGEXP":return new Ae(a);case "FOLLOWED_BY_TEXT":return new Be(a);case "FOLLOWED_BY_TEXT_REGEXP":return new Ce(a);case "LOCATION_CLASS":return new De(a);case "LOCATION_CLASS_REGEXP":return new Ee(a);case "LOCATION_ID":return new Fe(a);case "LOCATION_ID_REGEXP":return new Ge(a);case "LOCATION_XPATH":return new He(a);case "NOT":return new Ie(a);case "OR":return new Je(a);case "PRECEDED_BY_TEXT":return new Ke(a);
+case "PRECEDED_BY_TEXT_REGEXP":return new Le(a);case "SEVERITY":return new Me(a);case "TYPE":return new Ne(a);default:g("Unknown filter opcode: '"+b+"'")}},Pe=function(a){if(!a)return k;a=md(a);return wa(a,function(a){return Oe(a)})},ve=function(a,b){return new ye({filter1:a,filter2:b})};u("bidichecker.FilterFactory.and",ve);u("bidichecker.FilterFactory.atText",function(a){return new ze({atText:a||""})});u("bidichecker.FilterFactory.atTextRegexp",function(a){return new Ae({atTextRegexp:a||""})});
+u("bidichecker.FilterFactory.followedByText",function(a){return new Be({followedByText:a||""})});u("bidichecker.FilterFactory.followedByTextRegexp",function(a){return new Ce({followedByTextRegexp:a||""})});u("bidichecker.FilterFactory.locationClass",function(a){a||g("Empty or null argument to bidichecker.FilterFactory.locationClass");return new De({className:a})});
+u("bidichecker.FilterFactory.locationClassRegexp",function(a){a||g("Empty or null argument to bidichecker.FilterFactory.locationClassRegexp");return new Ee({classRegexp:a})});u("bidichecker.FilterFactory.locationId",function(a){a||g("Empty or null argument to bidichecker.FilterFactory.locationId");return new Fe({id:a})});u("bidichecker.FilterFactory.locationIdRegexp",function(a){a||g("Empty or null argument to bidichecker.FilterFactory.locationIdRegexp");return new Ge({idRegexp:a})});
+u("bidichecker.FilterFactory.locationXpath",function(a){a||g("Empty or null argument to bidichecker.FilterFactory.locationXpath");return new He({xpath:a})});var we=function(a){return new Ie({filter:a})};u("bidichecker.FilterFactory.not",we);var xe=function(a,b){return new Je({filter1:a,filter2:b})};u("bidichecker.FilterFactory.or",xe);u("bidichecker.FilterFactory.precededByText",function(a){return new Ke({precededByText:a||""})});
+u("bidichecker.FilterFactory.precededByTextRegexp",function(a){return new Le({precededByTextRegexp:a||""})});var ge=function(a){return new Me({severityThreshold:a})};u("bidichecker.FilterFactory.severityFrom",ge);u("bidichecker.FilterFactory.type",function(a){return new Ne({type:a})});
+var Qe=function(a,b){b in a||g("No '"+b+"' parameter found for '"+a.opcode+"' filter")},Re=function(a,b,c){Qe(a,b);typeof a[b]!=c&&g("Wrong type for '"+b+"' parameter of '"+a.opcode+"' filter; expected "+c)},Se=function(a,b){Re(a,b,"string");return a[b]},Te=function(a,b){Qe(a,b);var c=a[b],d;"string"==typeof c?d=c:c instanceof RegExp?d=c.source:g("Wrong type for '"+b+"' parameter of '"+a.opcode+"' filter; expected string or RegExp");return RegExp("^("+d+")$")},Ue=function(a,b){Re(a,b,"object");var c=
+a[b];if(c instanceof Z)return c;if("string"==typeof c.opcode)return Oe(c);g("Can't make a filter out of the '"+b+"' parameter of '"+a.opcode+"' filter")},ye=function(a){this.hb=Ue(a,"filter1");this.ib=Ue(a,"filter2")};w(ye,Z);ye.prototype.d=function(a,b){return this.hb.d(a,b)&&this.ib.d(a,b)};var ze=function(a){this.Xc=Se(a,"atText")};w(ze,Z);ze.prototype.d=function(a){return this.Xc==(a.atText||"")};var Ae=function(a){this.Wc=Te(a,"atTextRegexp")};w(Ae,Z);
+Ae.prototype.d=function(a){return this.Wc.test(a.atText||"")};var Be=function(a){this.cd=Se(a,"followedByText")};w(Be,Z);Be.prototype.d=function(a){return this.cd==(a.followedByText||"")};var Ce=function(a){this.bd=Te(a,"followedByTextRegexp")};w(Ce,Z);Ce.prototype.d=function(a){return this.bd.test(a.followedByText||"")};var De=function(a){this.Zc=Se(a,"className")};w(De,Z);
+De.prototype.d=function(a,b){for(var c=0;c<b.length;++c)for(var d=b[c];d;d=d.parentNode)if(d.className)for(var e=d.className.split(/\s/),f=0;f<e.length;++f)if(this.Zc==e[f])return j;return m};var Ee=function(a){this.$c=Te(a,"classRegexp")};w(Ee,Z);Ee.prototype.d=function(a,b){for(var c=0;c<b.length;++c)for(var d=b[c];d;d=d.parentNode)if(d.className)for(var e=d.className.split(/\s/),f=0;f<e.length;++f)if(this.$c.test(e[f]))return j;return m};var Fe=function(a){this.La=Se(a,"id")};w(Fe,Z);
+Fe.prototype.d=function(a,b){for(var c=0;c<b.length;++c)for(var d=b[c];d;d=d.parentNode)if(d.id&&this.La==d.id)return j;return m};var Ge=function(a){this.dd=Te(a,"idRegexp")};w(Ge,Z);Ge.prototype.d=function(a,b){for(var c=0;c<b.length;++c)for(var d=b[c];d;d=d.parentNode)if(d.id&&this.dd.test(d.id))return j;return m};var He=function(a){a=Se(a,"xpath");this.Sc=new ue(a)};w(He,Z);
+He.prototype.d=function(a,b){for(var c=0;c<b.length;++c){var d;a:{d=b[c];var e;e=this.Sc;var f=d.ownerDocument,h=f._bidicheckerXpathMatcherCache_[e.Ma];if(!h)try{f.evaluate||g("XPath not supported by this browser"),h=f.evaluate(e.Ma,f,k,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,k),f._bidicheckerXpathMatcherCache_[e.Ma]=h}catch(l){g("Error evaluating XPath expression "+e.Ma+": "+l)}e=h;for(f=0;f<e.snapshotLength;++f)if(e.snapshotItem(f)==d){d=j;break a}d=m}if(d)return j}return m};
+var Ie=function(a){this.Ic=Ue(a,"filter")};w(Ie,Z);Ie.prototype.d=function(a,b){return!this.Ic.d(a,b)};var Je=function(a){this.hb=Ue(a,"filter1");this.ib=Ue(a,"filter2")};w(Je,Z);Je.prototype.d=function(a,b){return this.hb.d(a,b)||this.ib.d(a,b)};var Ke=function(a){this.hd=Se(a,"precededByText")};w(Ke,Z);Ke.prototype.d=function(a){return this.hd==(a.precededByText||"")};var Le=function(a){this.gd=Te(a,"precededByTextRegexp")};w(Le,Z);
+Le.prototype.d=function(a){return this.gd.test(a.precededByText||"")};var Me=function(a){Re(a,"severityThreshold","number");this.kd=a.severityThreshold};w(Me,Z);Me.prototype.d=function(a){return this.kd<=a.severity};var Ne=function(a){this.Uc=Se(a,"type")};w(Ne,Z);Ne.prototype.d=function(a){return this.Uc==a.Wb()};var Ve=function(){this.da=[]};w(Ve,R);n=Ve.prototype;n.start=function(){this.dispatchEvent("StartFrames")};n.end=function(){this.dispatchEvent("EndFrames")};n.push=function(a){this.da.push(a);this.dispatchEvent("EnterFrame")};n.pop=function(){this.dispatchEvent("ExitFrame");this.da.pop()};n.Ya=function(){return this.da};var We=function(a,b){this.uc=a;this.tc=b||[];this.T=[]};We.prototype.vc=m;We.prototype.lb=function(){return this.T};var Ye=function(a,b,c){var d=a.uc.Ya().slice(0);c&&d.push(c);if(xa(a.tc,function(a){return!a.d(b,d)}))c=Xe(d),""!=c&&(b.locationDescription=c),a.T.push(b),a.vc&&g(b.toString()+"\n")},Xe=function(a){var b=[];va(a,function(a){b.push(Td(a))});return b.join(" in ")};var Ze=function(a,b){this.rc=!!b;this.na=new Ve;this.Jb=new We(this.na,a)};Ze.prototype.v=k;Ze.prototype.ab=k;Ze.prototype.lb=function(){return this.Jb.lb()};
+var df=function(a,b,c){b.ownerDocument._bidicheckerXpathMatcherCache_={};var d,e=a.Jb,f=a.ka;d=[];0!=c&&d.push(new $e(-1==c,e));d.push(new af(f,e));2<=f&&d.push(new bf(e));d.push(new cf(e));a.v=new qe(b);a.ab=a.rc?new te(a.v):k;for(b=0;b<d.length;++b)d[b].Ha(a);a.v.go();d=a.v.Ya();for(b=0;b<d.length;++b){e=d[b];a.na.push(e);try{var h=(e.contentDocument||e.contentWindow.document).body;"IFRAME"==e.tagName&&(c=0);df(a,h,c)}catch(l){}a.na.pop()}};var $e=function(a,b){this.Mb=a;this.J=b};$e.prototype.Ha=function(a){pc(a.v,"StartTag",this)};$e.prototype.handleEvent=function(a){a=a.target;this.Mb!=y(a.B)&&Ye(this.J,new Y("Overall directionality not "+(this.Mb?"RTL":"LTR"),1,new je(a.u)))};var cf=function(a){this.J=a;this.la=[]};n=cf.prototype;n.L=k;n.Ha=function(a){var b=new P(this);Q(b,a.v,"StartTag",this.jb);Q(b,a.v,"EndTag",this.Cc);Q(b,a.v,"TextNode",this.$a);xc(b,a.v,"EndOfDom",b.O,m,b)};n.jb=function(a){var a=a.target,b=a.u;if(b.dir||b==y(a.P))this.L=k};n.Cc=function(a){var a=a.target,b=a.u;if(b==y(a.P))this.L=k;else if(b.dir)y(a.B)==a.B[a.B.length-2]?this.L=k:(this.L=b,this.la=[])};
+n.$a=function(a){var a=a.target,b=a.u;if(this.L){this.la.push(b);var c=Od(b.data);if(c){var d=wa(this.la,function(a){return a.data}).join(""),e=y(this.la).parentNode;Ye(this.J,ef(this,d.substr(0,d.length-(b.data.length-c.text.length)),c.text.length,y(a.B),y(a.Z)),e);this.L=k}else if(Hd.test(b.data))this.L=k}};var ef=function(a,b,c,d,e){b=new Y("Declared "+(d?"LTR":"RTL")+" spillover to number",e?4:2,new he(a.la,0,c),b);a=Ud(a.L);b.precededByText=a;return b};var bf=function(a){this.J=a};bf.prototype.Ha=function(a){var b=new P(this);Q(b,a.v,"StartTag",this.jb);xc(b,a.v,"EndOfDom",b.O,m,b)};
+bf.prototype.jb=function(a){a=a.target.u;a.title&&ff(this,a,a.title,"title text");var b=a.nodeName;"INPUT"==b?a.type.match(/^(text|search)$/)?ff(this,a,a.value,"input value"):"image"==a.type?ff(this,a,a.alt,"alt text"):a.type.match(/^(button|reset|submit)$/)?ff(this,a,a.value,"button label"):"file"==a.type&&Ub(a)&&Ye(this.J,new Y("File input not LTR",2,new je(a)),a):"IMG"==b?ff(this,a,a.alt,"alt text"):"TEXTAREA"==b&&ff(this,a,a.value,"textarea value")};
+var ff=function(a,b,c,d){var e=Ub(b),f=!!Ld(c).length,h=!!Kd(c).length;f!=h&&e!=h&&(e="Undeclared "+(e?"LTR":"RTL")+" "+d,d="input value"==d||"textarea value"==d?1:b.dir||b.style.direction||Ub(b)!=Ub(b.parentNode)?4:Md(c,0)||Nd(c,c.length)?2:3,Ye(a.J,new Y(e,d,new je(b),c),b))};var af=function(a,b){this.ka=a;this.J=b};af.prototype.Ha=function(a){var b=new P(this);Q(b,a.ab,"DirChunk",this.Lc);xc(b,a.ab,"EndOfChunks",b.O,m,b)};af.prototype.Lc=function(a){var b=this,c=a.target.I;c.Fb?(a=Ld(oe(c)),ua(a,function(a){Ed.exec(a.text)||gf(b,c,a,"Undeclared LTR text")})):(a=2<=this.ka?Kd(oe(c)):Jd(oe(c)),ua(a,function(a){Fd.exec(a.text)||gf(b,c,a,"Undeclared RTL text")}))};
+var gf=function(a,b,c,d){var e=b.Db?4:3,f=b.fa(c.index,c.text.length),d=new Y(d,e,f,c.text),e=oe(b);if(f=Nd(e,c.index))3==d.severity&&(d.severity=2),d.precededByText=f.text;if(e=Md(e,c.index+c.text.length))3==d.severity&&(d.severity=2),d.followedByText=e.text;b=b.ob(c.index).parentNode;Ye(a.J,d,b)};var hf=function(a,b){Ze.call(this,b,j);this.ka=a};w(hf,Ze);var jf=function(a){this.Fc=a};u("bidichecker.REVISION_1",new jf(1));var kf=new jf(2);u("bidichecker.REVISION_2",kf);u("bidichecker.LATEST",kf);var $=function(a){this.ka=a;this.T=[]};u("bidichecker.BidiChecker",$);u("bidichecker.instance",k);$.prototype.Ga="https://bidichecker.googlecode.com/svn/trunk/lib/gui-app/errorpage.html";$.prototype.Ja=function(a,b,c){a=a?-1:1;b=b||top.document.body;c=c||[];ce=[];be=0;c=new hf(this.ka.Fc,c);c.na.start();df(c,b,a);c.na.end();this.T=c.lb();return Aa(this.T)};
+$.prototype.checkPage=$.prototype.Ja;$.prototype.Yc=function(a,b,c){c=(c=Pe(c))||[];a=this.Ja(a,b,c);return de(a)};$.prototype.checkPageToJson=$.prototype.Yc;$.prototype.Xb=function(a){this.Ga=a};$.prototype.setGuiAppUrl=$.prototype.Xb;$.prototype.jd=function(a){0!=this.T.length&&lf(this,this.T,a)};$.prototype.runGui=$.prototype.jd;
+var lf=function(a,b,c){if(B)if(E("8"))c=j;else{c=new id;c.ua.document.write("Sorry, bidichecker GUI is not supported in Internet Explorer before version 8.");return}c=c?new id:ld(k);a=new ee(a,{},c,a.Ga,b);ac(fe);fe=a;a.start()};u("bidichecker.runBookmarkletGui",function(a,b,c){var d=new $(kf);B?(b&&b.close(),b=new id):b=ld(b);a=new ee(d,a,b,c||"https://bidichecker.googlecode.com/svn/trunk/lib/gui-app/errorpage.html");ac(fe);fe=a;a.start()});
+u("bidichecker.generateBookmarklet",function(a,b,c){b=b||"https://bidichecker.googlecode.com/svn/trunk/lib/bidichecker_packaged.js";c=c||"https://bidichecker.googlecode.com/svn/trunk/lib/gui-app/errorpage.html";a=pd(a).replace(/\$/g,"$$$$");return'javascript:(function() {function run() {bidichecker.runBookmarkletGui(%OPTIONS%, g_bidicheckerBookmarkletGuiWnd, "%APPURL%");}if (typeof g_bidicheckerBookmarkletGuiWnd == "undefined") {g_bidicheckerBookmarkletGuiWnd = null;}if (g_bidicheckerBookmarkletGuiWnd &&!g_bidicheckerBookmarkletGuiWnd.closed) {g_bidicheckerBookmarkletGuiWnd.focus();} else {g_bidicheckerBookmarkletGuiWnd = window.open("about:blank", "_blank", "width=1,height=1,resizable=yes,scrollbars=yes");var scriptElemId = "_bidichecker_bookmarklet";if (document.getElementById(scriptElemId)) {if (window.bidichecker) {run();}} else {var elem = document.createElement("script");elem.src = "%SCRIPTURL%";elem.onload = run;elem.id = scriptElemId;document.getElementsByTagName("head")[0].appendChild(elem);}}})()'.replace("%SCRIPTURL%",
+b).replace("%APPURL%",c).replace("%OPTIONS%",a)});u("bidichecker.checkPage",function(a,b,c){return(new $(kf)).Ja(a,b,c)});u("bidichecker.runGui",function(a,b,c){var d=new $(kf);c&&d.Xb(c);lf(d,a,b)}); })()
diff --git a/lib/bookmarklet.css b/lib/bookmarklet.css
new file mode 100644
index 0000000..5f94267
--- /dev/null
+++ b/lib/bookmarklet.css
@@ -0,0 +1,44 @@
+body {
+  width: 600px;
+  font-family: sans-serif;
+  font-size: 13pt;
+  margin-left: 20px
+}
+
+h1 {
+  font-size: 16pt;
+}
+
+h2 {
+  font-size: 14pt;
+}
+
+table {
+  border: 1px dotted black;
+}
+
+td {
+  font-size: 11pt;
+  font-weight: bold;
+  text-align: center;
+}
+
+#ltr-bookmarklet, #rtl-bookmarklet {
+  font-size: 14pt;
+  border-style: solid;
+  border-width: thin;
+}
+
+#installation-error {
+  display: none;
+  font-size: 16pt;
+  color: red;
+  border-style: solid;
+  border-width: thin;
+  border-color: red;
+}
+
+.inline-code {
+  font-family: courier, monospace;
+  font-weight: bold;
+}
diff --git a/lib/bookmarklet.html b/lib/bookmarklet.html
new file mode 100644
index 0000000..6c03b14
--- /dev/null
+++ b/lib/bookmarklet.html
@@ -0,0 +1,158 @@
+<!DOCTYPE HTML>
+<html>
+  <!--
+    Copyright 2012 Google Inc. All Rights Reserved.
+
+    Use of this source code is governed by an Apache 2.0 License.
+    See the COPYING file for details.
+  -->
+  <head>
+    <title>BidiChecker Bookmarklet Installation Page</title>
+    <link href="bookmarklet.css" rel="stylesheet" type="text/css">
+    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
+
+    <!-- We load the GUI code to validate that it's installed as required. -->
+    <script src="gui-app/gui_compiled.js"></script>
+
+    <script>
+      function validateInstallation() {
+        var protocol = window.location.protocol;
+        if (protocol != 'http:' && protocol != 'https:') {
+          return 'The URL must begin with http: or https:';
+        }
+        if (!window.bidichecker) {
+          return '"bidichecker" namespace is not loaded - ' +
+              'is bidichecker_packaged.js missing?';
+        }
+        if (!window.bidichecker.gui) {
+          return '"bidichecker.gui" namespace is not loaded - ' +
+              'is gui_compiled.js missing?';
+        }
+      }
+
+      function alertFailedInstallation(errorMessage) {
+        var errorDiv = document.getElementById('installation-error');
+        var messageDiv = document.getElementById('error-message');
+
+        var htmlMessage =
+            'Error: <span style="font-weight: bold">' + errorMessage +
+            '<\/span><\/p>';
+        document.getElementById('ltr-bookmarklet').href = 'about:blank';
+        document.getElementById('rtl-bookmarklet').href = 'about:blank';
+        errorDiv.style.display = 'block';
+        messageDiv.innerHTML = htmlMessage;
+      }
+
+      function init() {
+        var errorMessage = validateInstallation();
+        if (errorMessage) {
+          alertFailedInstallation(errorMessage);
+        }
+
+        var locationUrl = window.location.toString();
+        var lastSlash = locationUrl.lastIndexOf('/');
+        var baseUrl = locationUrl.substr(0, lastSlash);
+        var scriptUrl = baseUrl + '/bidichecker_packaged.js';
+        var guiAppUrl = baseUrl + '/gui-app/errorpage.html';
+        document.getElementById('ltr-bookmarklet').href =
+            bidichecker.generateBookmarklet({}, scriptUrl, guiAppUrl);
+        document.getElementById('rtl-bookmarklet').href =
+            bidichecker.generateBookmarklet({dir: 'rtl'}, scriptUrl, guiAppUrl);
+      }
+
+      // Notify the user on any error (result of failure to load script, etc.).
+      // Otherwise the user would be silently left with non-functional
+      // bookmarklets.
+      window.onerror = alertFailedInstallation;
+    </script>
+  </head>
+
+  <body onload="init();">
+    <div id='installation-error'>
+      <p>BidiChecker does not appear to be correctly installed at this location!
+        The bookmarklet links on this page have been disabled.</p>
+
+      <div id='error-message'></div>
+
+      <p>For this bookmarklet installation page to work, it must be
+        installed on a web server and accessed via
+        <span class="inline-code">http:</span> or
+        <span class="inline-code">https:</span>.</p>
+
+      <p>It must be installed along with the complete BidiChecker deployment
+        directory.
+        That's the
+             <a href="http://code.google.com/p/bidichecker/source/browse/#svn/trunk/lib">lib/ subdirectory in the source tree.</a>
+      </p>
+    </div>
+
+    <h1>BidiChecker Bookmarklet Installation Page</h1>
+
+    <h2>What is a BidiChecker Bookmarklet?</h2>
+
+    <p>A "BidiChecker Bookmarklet" is a button you can add to your web browser
+      that will run
+      <a href="http://code.google.com/p/bidichecker/">BidiChecker</a>
+      on any web page, displaying any bidi errors in an interactive window.
+
+
+    <h2>How do I install one?</h2>
+
+    <p>Just drag one or both of the links below to your browser's Bookmarks
+      toolbar. This will create a button on the Bookmarks toolbar. You can then
+      click the button to run BidiChecker on the current page for ad hoc
+      spot-checking. (You may first have to make the Bookmarks toolbar visible
+      in your browser; each browser has a command or menu option to do
+      this.)</p>
+
+    <table>
+      <tr>
+        <td>
+          <a href='#' id='ltr-bookmarklet' onclick="return false;">
+            BidiChecker LTR
+          </a>
+        </td>
+        <td>
+          <a href='#' id='rtl-bookmarklet' onclick="return false;">
+            BidiChecker RTL
+          </a>
+        </td>
+      </tr>
+      <tr>
+        <td>This bookmarklet checks that the page being checked has an overall
+          directionality of left-to-right (for example, an English UI)</td>
+        <td>This bookmarklet checks that the page being checked has an
+          overall directionality of right-to-left (for example, a Hebrew or
+          Arabic UI)</td>
+      </tr>
+    </table>
+
+    <h2>How do I use it?</h2>
+
+    <p>To run BidiChecker, just navigate your browser to the page you want to
+      test, interact with the page to get it into the state you want to test,
+      and click on one of the BidiChecker bookmarklets in your browser's
+      bookmarks toolbar. A window will appear with the results of the
+      run. You can browse through the errors, change the table sort key, and
+      select an individual error to highlight its location on the page.</p>
+    <p>Click "Show options" to change the checker options; from that page,
+      you can also install a new bookmarklet that starts with the set of
+      options you configure.</p>
+
+    <h2>Known limitations</h2>
+    <p>The bookmarklet works on most recent browsers. Internet Explorer 9 and up
+      is supported but not older versions.</p>
+
+    <h2>Acknowledgments</h2>
+    <p>We'd like to thank
+      <a href="http://chris.improbable.org/">developer/blogger Chris Adams</a>
+      for
+      <a href="http://chris.improbable.org/2010/11/4/google-bidichecker-bookmarklet/">demonstrating
+      the BidiChecker bookmarklet concept</a>. His original source code can be
+      found <a href="https://gist.github.com/662454">here on GitHub</a>.</p>
+
+    <p>The bookmarklet links we offer here differ somewhat from Chris's
+      implementation, but the basic concept is the same.</p>
+
+  </body>
+</html>
diff --git a/lib/gui-app/bidichecker.css b/lib/gui-app/bidichecker.css
new file mode 100644
index 0000000..154ad7a
--- /dev/null
+++ b/lib/gui-app/bidichecker.css
@@ -0,0 +1,51 @@
+body {
+  font-family: arial, sans-serif;
+}
+
+h1 {
+  background-color: #f9efeb;
+  color: #000000;
+  padding: 10px 15px;
+  font-size: 16px;
+  font-weight: bold;
+  vertical-align: middle;
+}
+
+#content {
+  padding: 15px;
+  background-color: #fff;
+}
+
+#buttons {
+  padding: 0 15px 15px;
+  background-color: #fff;
+}
+
+#error-text {
+  margin-top: 16px;
+  color: #f00;
+  height: 80px;
+  overflow: auto;
+  border: 1px dotted #f00;
+}
+
+#summary {
+  margin-top: 10px;
+}
+
+#happy-message {
+  color: green;
+  padding: 5px;
+  border: 1px dashed;
+}
+
+#bookmarklet-section {
+  font-size: 80%;
+}
+
+.table-cell-ellipsize {
+  display:inline-block;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
diff --git a/lib/gui-app/errorpage.html b/lib/gui-app/errorpage.html
new file mode 100755
index 0000000..06b183b
--- /dev/null
+++ b/lib/gui-app/errorpage.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+  <!--
+    Copyright 2011 Google Inc. All Rights Reserved.
+
+    Use of this source code is governed by an Apache 2.0 License.
+    See the COPYING file for details.
+  -->
+
+  <head>
+    <title>BidiChecker</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
+    <link href="bidichecker.css" rel="stylesheet" type="text/css">
+    <script type="text/javascript" src="gui_compiled.js"></script>
+    <script type='text/javascript' src='https://www.google.com/jsapi'></script>
+    <script type='text/javascript'>
+      google.load('visualization', '1', {packages:['table']});
+    </script>
+  </head>
+
+  <body onload="new bidichecker.gui.app.ErrorPage();">
+    <h1>BidiChecker Error Browser</h1>
+    <div id="content">
+
+      <div class="show-on-errors" style="display: none">
+        <div id="table-container"></div>
+
+        <!-- Text content of the current error. -->
+        <div id="error-text"></div>
+
+      </div>
+
+      <div id="no-errors-container" style="display: none">
+        <span id="happy-message">
+          Hooray! No bidi errors found.
+        </span>
+      </div>
+
+      <div id="summary">
+        <span class="show-on-errors" style="display: none">
+          Found <span id="error-count"></span> errors. |
+
+          <a href="#" id="select-table">Select all errors</a>
+          (for easy copy and paste) |
+        </span>
+
+        <a href="options.html">Show options</a>
+      </div>
+
+
+    </div>
+  </body>
+</html>
diff --git a/lib/gui-app/gui_compiled.js b/lib/gui-app/gui_compiled.js
new file mode 100755
index 0000000..ffa7f3b
--- /dev/null
+++ b/lib/gui-app/gui_compiled.js
@@ -0,0 +1,145 @@
+function g(a){throw a;}
+var i=void 0,j=!0,k=null,m=!1,n,p=this,aa=function(a){for(var a=a.split("."),b=p,c;c=a.shift();)if(b[c]!=k)b=b[c];else return k;return b},ba=function(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==
+c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if("function"==b&&"undefined"==typeof a.call)return"object";return b},q=function(a){return"array"==ba(a)},ca=function(a){var b=ba(a);return"array"==b||"object"==b&&"number"==typeof a.length},s=function(a){return"string"==typeof a},da=function(a){return"function"==ba(a)},ea=function(a){a=ba(a);return"object"==a||"array"==a||"function"==a},ha=function(a){return a[fa]||
+(a[fa]=++ga)},fa="closure_uid_"+Math.floor(2147483648*Math.random()).toString(36),ga=0,ia=function(a,b,c){return a.call.apply(a.bind,arguments)},ja=function(a,b,c){a||g(Error());if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}},t=function(a,b,c){t=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?
+ia:ja;return t.apply(k,arguments)},ka=Date.now||function(){return+new Date},u=function(a,b){var c=a.split("."),d=p;!(c[0]in d)&&d.execScript&&d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)!c.length&&b!==i?d[e]=b:d=d[e]?d[e]:d[e]={}},x=function(a,b){function c(){}c.prototype=b.prototype;a.g=b.prototype;a.prototype=new c};
+Function.prototype.bind=Function.prototype.bind||function(a,b){if(1<arguments.length){var c=Array.prototype.slice.call(arguments,1);c.unshift(this,a);return t.apply(k,c)}return t(this,a)};var la=function(a){this.stack=Error().stack||"";if(a)this.message=""+a};x(la,Error);la.prototype.name="CustomError";var ma=function(a,b){for(var c=1;c<arguments.length;c++)var d=(""+arguments[c]).replace(/\$/g,"$$$$"),a=a.replace(/\%s/,d);return a},sa=function(a){if(!na.test(a))return a;-1!=a.indexOf("&")&&(a=a.replace(oa,"&amp;"));-1!=a.indexOf("<")&&(a=a.replace(pa,"&lt;"));-1!=a.indexOf(">")&&(a=a.replace(qa,"&gt;"));-1!=a.indexOf('"')&&(a=a.replace(ra,"&quot;"));return a},oa=/&/g,pa=/</g,qa=/>/g,ra=/\"/g,na=/[&<>\"]/,ta=function(a){var b=Number(a);return 0==b&&/^[\s\xa0]*$/.test(a)?NaN:b};var ua=function(a,b){b.unshift(a);la.call(this,ma.apply(k,b));b.shift();this.ne=a};x(ua,la);ua.prototype.name="AssertionError";var y=function(a,b,c){if(!a){var d=Array.prototype.slice.call(arguments,2),e="Assertion failed";if(b)var e=e+(": "+b),f=d;g(new ua(""+e,f||[]))}},va=function(a,b){g(new ua("Failure"+(a?": "+a:""),Array.prototype.slice.call(arguments,1)))};var z=function(a){return a[a.length-1]},A=Array.prototype,wa=A.indexOf?function(a,b,c){y(a.length!=k);return A.indexOf.call(a,b,c)}:function(a,b,c){c=c==k?0:0>c?Math.max(0,a.length+c):c;if(s(a))return!s(b)||1!=b.length?-1:a.indexOf(b,c);for(;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},xa=A.forEach?function(a,b,c){y(a.length!=k);A.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=s(a)?a.split(""):a,f=0;f<d;f++)f in e&&b.call(c,e[f],f,a)},ya=function(a,b){for(var c=s(a)?a.split(""):
+a,d=a.length-1;0<=d;--d)d in c&&b.call(i,c[d],d,a)},za=A.map?function(a,b,c){y(a.length!=k);return A.map.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=Array(d),f=s(a)?a.split(""):a,h=0;h<d;h++)h in f&&(e[h]=b.call(c,f[h],h,a));return e},Aa=A.some?function(a,b,c){y(a.length!=k);return A.some.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=s(a)?a.split(""):a,f=0;f<d;f++)if(f in e&&b.call(c,e[f],f,a))return j;return m},Ba=A.every?function(a,b,c){y(a.length!=k);return A.every.call(a,b,c)}:function(a,
+b,c){for(var d=a.length,e=s(a)?a.split(""):a,f=0;f<d;f++)if(f in e&&!b.call(c,e[f],f,a))return m;return j},Ca=function(a,b){var c=wa(a,b);0<=c&&(y(a.length!=k),A.splice.call(a,c,1))},Da=function(a){return A.concat.apply(A,arguments)},Ea=function(a){if(q(a))return Da(a);for(var b=[],c=0,d=a.length;c<d;c++)b[c]=a[c];return b},Ga=function(a,b,c,d){y(a.length!=k);A.splice.apply(a,Fa(arguments,1))},Fa=function(a,b,c){y(a.length!=k);return 2>=arguments.length?A.slice.call(a,b):A.slice.call(a,b,c)},Ha=function(a,
+b,c){for(var d=0,e=a.length,f;d<e;){var h=d+e>>1,l;l=b(c,a[h]);0<l?d=h+1:(e=h,f=!l)}return f?d:~d},Ia=function(a,b){return a>b?1:a<b?-1:0};var Ja=function(a,b){for(var c in a)b.call(i,a[c],c,a)},Ka=function(a){var b=[],c=0,d;for(d in a)b[c++]=a[d];return b},La=function(a){var b=[],c=0,d;for(d in a)b[c++]=d;return b},Ma="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(","),Na=function(a,b){for(var c,d,e=1;e<arguments.length;e++){d=arguments[e];for(c in d)a[c]=d[c];for(var f=0;f<Ma.length;f++)c=Ma[f],Object.prototype.hasOwnProperty.call(d,c)&&(a[c]=d[c])}},Oa=function(a){var b=arguments.length;
+if(1==b&&q(arguments[0]))return Oa.apply(k,arguments[0]);for(var c={},d=0;d<b;d++)c[arguments[d]]=j;return c};var Pa,Qa,Ra,Sa,Ta,Ua,Wa=function(){return p.navigator?p.navigator.userAgent:k},Xa=function(){return p.navigator};Ta=Sa=Ra=Qa=Pa=m;var Ya;if(Ya=Wa()){var Za=Xa();Pa=0==Ya.indexOf("Opera");Qa=!Pa&&-1!=Ya.indexOf("MSIE");Sa=(Ra=!Pa&&-1!=Ya.indexOf("WebKit"))&&-1!=Ya.indexOf("Mobile");Ta=!Pa&&!Ra&&"Gecko"==Za.product}var $a=Pa,B=Qa,C=Ta,D=Ra,ab=Sa,bb=Xa();Ua=-1!=(bb&&bb.platform||"").indexOf("Mac");var cb=!!Xa()&&-1!=(Xa().appVersion||"").indexOf("X11"),db;
+a:{var eb="",fb;if($a&&p.opera)var gb=p.opera.version,eb="function"==typeof gb?gb():gb;else if(C?fb=/rv\:([^\);]+)(\)|;)/:B?fb=/MSIE\s+([^\);]+)(\)|;)/:D&&(fb=/WebKit\/(\S+)/),fb)var hb=fb.exec(Wa()),eb=hb?hb[1]:"";if(B){var ib,jb=p.document;ib=jb?jb.documentMode:i;if(ib>parseFloat(eb)){db=""+ib;break a}}db=eb}
+var kb=db,lb={},E=function(a){var b;if(!(b=lb[a])){b=0;for(var c=(""+kb).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),d=(""+a).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),e=Math.max(c.length,d.length),f=0;0==b&&f<e;f++){var h=c[f]||"",l=d[f]||"",o=RegExp("(\\d*)(\\D*)","g"),r=RegExp("(\\d*)(\\D*)","g");do{var v=o.exec(h)||["","",""],w=r.exec(l)||["","",""];if(0==v[0].length&&0==w[0].length)break;b=((0==v[1].length?0:parseInt(v[1],10))<(0==w[1].length?0:parseInt(w[1],10))?-1:(0==v[1].length?
+0:parseInt(v[1],10))>(0==w[1].length?0:parseInt(w[1],10))?1:0)||((0==v[2].length)<(0==w[2].length)?-1:(0==v[2].length)>(0==w[2].length)?1:0)||(v[2]<w[2]?-1:v[2]>w[2]?1:0)}while(0==b)}b=lb[a]=0<=b}return b},mb={},nb=function(a){return mb[a]||(mb[a]=B&&document.documentMode&&document.documentMode>=a)};var ob=function(a){ob[" "](a);return a};ob[" "]=function(){};var pb=!B||nb(9),qb=!B||nb(9),rb=B&&!E("8");!D||E("528");C&&E("1.9b")||B&&E("8")||$a&&E("9.5")||D&&E("528");!C||E("8");var sb=function(){};sb.prototype.vc=m;sb.prototype.t=function(){if(!this.vc)this.vc=j,this.r()};sb.prototype.r=function(){this.Wd&&tb.apply(k,this.Wd)};var ub=function(a){a&&"function"==typeof a.t&&a.t()},tb=function(a){for(var b=0,c=arguments.length;b<c;++b){var d=arguments[b];ca(d)?tb.apply(k,d):ub(d)}};var F=function(a,b){this.type=a;this.currentTarget=this.target=b};x(F,sb);n=F.prototype;n.r=function(){delete this.type;delete this.target;delete this.currentTarget};n.ka=m;n.Ha=j;n.stopPropagation=function(){this.ka=j};n.preventDefault=function(){this.Ha=m};var vb=function(a){a.preventDefault()};var wb=function(a,b){a&&this.ta(a,b)};x(wb,F);var xb=[1,4,2];n=wb.prototype;n.target=k;n.relatedTarget=k;n.offsetX=0;n.offsetY=0;n.clientX=0;n.clientY=0;n.screenX=0;n.screenY=0;n.button=0;n.keyCode=0;n.charCode=0;n.ctrlKey=m;n.altKey=m;n.shiftKey=m;n.metaKey=m;n.wd=m;n.I=k;
+n.ta=function(a,b){var c=this.type=a.type;F.call(this,c);this.target=a.target||a.srcElement;this.currentTarget=b;var d=a.relatedTarget;if(d){if(C){var e;a:{try{ob(d.nodeName);e=j;break a}catch(f){}e=m}e||(d=k)}}else if("mouseover"==c)d=a.fromElement;else if("mouseout"==c)d=a.toElement;this.relatedTarget=d;this.offsetX=D||a.offsetX!==i?a.offsetX:a.layerX;this.offsetY=D||a.offsetY!==i?a.offsetY:a.layerY;this.clientX=a.clientX!==i?a.clientX:a.pageX;this.clientY=a.clientY!==i?a.clientY:a.pageY;this.screenX=
+a.screenX||0;this.screenY=a.screenY||0;this.button=a.button;this.keyCode=a.keyCode||0;this.charCode=a.charCode||("keypress"==c?a.keyCode:0);this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=a.shiftKey;this.metaKey=a.metaKey;this.wd=Ua?a.metaKey:a.ctrlKey;this.state=a.state;this.I=a;delete this.Ha;delete this.ka};n.stopPropagation=function(){wb.g.stopPropagation.call(this);this.I.stopPropagation?this.I.stopPropagation():this.I.cancelBubble=j};
+n.preventDefault=function(){wb.g.preventDefault.call(this);var a=this.I;if(a.preventDefault)a.preventDefault();else if(a.returnValue=m,rb)try{if(a.ctrlKey||112<=a.keyCode&&123>=a.keyCode)a.keyCode=-1}catch(b){}};n.r=function(){wb.g.r.call(this);this.relatedTarget=this.currentTarget=this.target=this.I=k};var yb=function(){},zb=0;n=yb.prototype;n.key=0;n.ia=m;n.Ob=m;n.ta=function(a,b,c,d,e,f){da(a)?this.qc=j:a&&a.handleEvent&&da(a.handleEvent)?this.qc=m:g(Error("Invalid listener argument"));this.sa=a;this.kc=b;this.src=c;this.type=d;this.capture=!!e;this.Ua=f;this.Ob=m;this.key=++zb;this.ia=m};n.handleEvent=function(a){return this.qc?this.sa.call(this.Ua||this.src,a):this.sa.handleEvent.call(this.sa,a)};var Ab={},G={},Bb={},Cb={},H=function(a,b,c,d,e){if(b){if(q(b)){for(var f=0;f<b.length;f++)H(a,b[f],c,d,e);return k}var d=!!d,h=G;b in h||(h[b]={n:0,L:0});h=h[b];d in h||(h[d]={n:0,L:0},h.n++);var h=h[d],l=ha(a),o;h.L++;if(h[l]){o=h[l];for(f=0;f<o.length;f++)if(h=o[f],h.sa==c&&h.Ua==e){if(h.ia)break;return o[f].key}}else o=h[l]=[],h.n++;f=Db();f.src=a;h=new yb;h.ta(c,f,a,b,d,e);c=h.key;f.key=c;o.push(h);Ab[c]=h;Bb[l]||(Bb[l]=[]);Bb[l].push(h);a.addEventListener?(a==p||!a.jc)&&a.addEventListener(b,
+f,d):a.attachEvent(b in Cb?Cb[b]:Cb[b]="on"+b,f);return c}g(Error("Invalid event type"))},Db=function(){var a=Eb,b=qb?function(c){return a.call(b.src,b.key,c)}:function(c){c=a.call(b.src,b.key,c);if(!c)return c};return b},Fb=function(a,b,c,d,e){if(q(b)){for(var f=0;f<b.length;f++)Fb(a,b[f],c,d,e);return k}a=H(a,b,c,d,e);Ab[a].Ob=j;return a},Gb=function(a,b,c,d,e){if(q(b))for(var f=0;f<b.length;f++)Gb(a,b[f],c,d,e);else if(d=!!d,a=Hb(a,b,d))for(f=0;f<a.length;f++)if(a[f].sa==c&&a[f].capture==d&&a[f].Ua==
+e){Ib(a[f].key);break}},Ib=function(a){if(!Ab[a])return m;var b=Ab[a];if(b.ia)return m;var c=b.src,d=b.type,e=b.kc,f=b.capture;c.removeEventListener?(c==p||!c.jc)&&c.removeEventListener(d,e,f):c.detachEvent&&c.detachEvent(d in Cb?Cb[d]:Cb[d]="on"+d,e);c=ha(c);e=G[d][f][c];if(Bb[c]){var h=Bb[c];Ca(h,b);0==h.length&&delete Bb[c]}b.ia=j;e.mc=j;Jb(d,f,c,e);delete Ab[a];return j},Jb=function(a,b,c,d){if(!d.cb&&d.mc){for(var e=0,f=0;e<d.length;e++)d[e].ia?d[e].kc.src=k:(e!=f&&(d[f]=d[e]),f++);d.length=
+f;d.mc=m;0==f&&(delete G[a][b][c],G[a][b].n--,0==G[a][b].n&&(delete G[a][b],G[a].n--),0==G[a].n&&delete G[a])}},Kb=function(a){var b,c=0,d=b==k;b=!!b;if(a==k)Ja(Bb,function(a){for(var e=a.length-1;0<=e;e--){var f=a[e];if(d||b==f.capture)Ib(f.key),c++}});else if(a=ha(a),Bb[a])for(var a=Bb[a],e=a.length-1;0<=e;e--){var f=a[e];if(d||b==f.capture)Ib(f.key),c++}},Hb=function(a,b,c){var d=G;return b in d&&(d=d[b],c in d&&(d=d[c],a=ha(a),d[a]))?d[a]:k},Mb=function(a,b,c,d,e){var f=1,b=ha(b);if(a[b]){a.L--;
+a=a[b];a.cb?a.cb++:a.cb=1;try{for(var h=a.length,l=0;l<h;l++){var o=a[l];o&&!o.ia&&(f&=Lb(o,e)!==m)}}finally{a.cb--,Jb(c,d,b,a)}}return Boolean(f)},Lb=function(a,b){var c=a.handleEvent(b);a.Ob&&Ib(a.key);return c},Eb=function(a,b){if(!Ab[a])return j;var c=Ab[a],d=c.type,e=G;if(!(d in e))return j;var e=e[d],f,h;if(!qb){f=b||aa("window.event");var l=j in e,o=m in e;if(l){if(0>f.keyCode||f.returnValue!=i)return j;a:{var r=m;if(0==f.keyCode)try{f.keyCode=-1;break a}catch(v){r=j}if(r||f.returnValue==i)f.returnValue=
+j}}r=new wb;r.ta(f,this);f=j;try{if(l){for(var w=[],Va=r.currentTarget;Va;Va=Va.parentNode)w.push(Va);h=e[j];h.L=h.n;for(var R=w.length-1;!r.ka&&0<=R&&h.L;R--)r.currentTarget=w[R],f&=Mb(h,w[R],d,j,r);if(o){h=e[m];h.L=h.n;for(R=0;!r.ka&&R<w.length&&h.L;R++)r.currentTarget=w[R],f&=Mb(h,w[R],d,m,r)}}else f=Lb(c,r)}finally{if(w)w.length=0;r.t()}return f}d=new wb(b,this);try{f=Lb(c,d)}finally{d.t()}return f};var Nb=function(a){a=""+a;if(/^\s*$/.test(a)?0:/^[\],:{}\s\u2028\u2029]*$/.test(a.replace(/\\["\\\/bfnrtu]/g,"@").replace(/"[^"\\\n\r\u2028\u2029\x00-\x08\x10-\x1f\x80-\x9f]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:[\s\u2028\u2029]*\[)+/g,"")))try{return eval("("+a+")")}catch(b){}g(Error("Invalid JSON string: "+a))},Ob=function(){this.mb=i},Qb=function(a){var b=[];Pb(new Ob,a,b);return b.join("")},Pb=function(a,b,c){switch(typeof b){case "string":Rb(b,c);break;
+case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(b==k){c.push("null");break}if(q(b)){var d=b.length;c.push("[");for(var e="",f=0;f<d;f++)c.push(e),e=b[f],Pb(a,a.mb?a.mb.call(b,""+f,e):e,c),e=",";c.push("]");break}c.push("{");d="";for(f in b)Object.prototype.hasOwnProperty.call(b,f)&&(e=b[f],"function"!=typeof e&&(c.push(d),Rb(f,c),c.push(":"),Pb(a,a.mb?a.mb.call(b,f,e):e,c),d=","));c.push("}");break;case "function":break;
+default:g(Error("Unknown type: "+typeof b))}},Sb={'"':'\\"',"\\":"\\\\","/":"\\/","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},Tb=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g,Rb=function(a,b){b.push('"',a.replace(Tb,function(a){if(a in Sb)return Sb[a];var b=a.charCodeAt(0),e="\\u";16>b?e+="000":256>b?e+="00":4096>b&&(e+="0");return Sb[a]=e+b.toString(16)}),'"')};var I="StopIteration"in p?p.StopIteration:Error("StopIteration"),Ub=function(){};Ub.prototype.next=function(){g(I)};Ub.prototype.La=function(){return this};
+var Vb=function(a){if(a instanceof Ub)return a;if("function"==typeof a.La)return a.La(m);if(ca(a)){var b=0,c=new Ub;c.next=function(){for(;;){b>=a.length&&g(I);if(b in a)return a[b++];b++}};return c}g(Error("Not implemented"))},Wb=function(a,b){if(ca(a))try{xa(a,b,i)}catch(c){c!==I&&g(c)}else{a=Vb(a);try{for(;;)b.call(i,a.next(),i,a)}catch(d){d!==I&&g(d)}}};var Xb=function(a){if("function"==typeof a.fb)return a.fb();if(s(a))return a.split("");if(ca(a)){for(var b=[],c=a.length,d=0;d<c;d++)b.push(a[d]);return b}return Ka(a)},Yb=function(a,b,c){if("function"==typeof a.forEach)a.forEach(b,c);else if(ca(a)||s(a))xa(a,b,c);else{var d;if("function"==typeof a.Ib)d=a.Ib();else if("function"!=typeof a.fb)if(ca(a)||s(a)){d=[];for(var e=a.length,f=0;f<e;f++)d.push(f)}else d=La(a);else d=i;for(var e=Xb(a),f=e.length,h=0;h<f;h++)b.call(c,e[h],d&&d[h],a)}};var Zb=function(a,b){this.ba={};this.i=[];var c=arguments.length;if(1<c){c%2&&g(Error("Uneven number of arguments"));for(var d=0;d<c;d+=2)this.set(arguments[d],arguments[d+1])}else if(a){a instanceof Zb?(c=a.Ib(),d=a.fb()):(c=La(a),d=Ka(a));for(var e=0;e<c.length;e++)this.set(c[e],d[e])}};n=Zb.prototype;n.n=0;n.ab=0;n.fb=function(){$b(this);for(var a=[],b=0;b<this.i.length;b++)a.push(this.ba[this.i[b]]);return a};n.Ib=function(){$b(this);return this.i.concat()};n.Ya=function(){return 0==this.n};
+n.clear=function(){this.ba={};this.ab=this.n=this.i.length=0};var $b=function(a){if(a.n!=a.i.length){for(var b=0,c=0;b<a.i.length;){var d=a.i[b];Object.prototype.hasOwnProperty.call(a.ba,d)&&(a.i[c++]=d);b++}a.i.length=c}if(a.n!=a.i.length){for(var e={},c=b=0;b<a.i.length;)d=a.i[b],Object.prototype.hasOwnProperty.call(e,d)||(a.i[c++]=d,e[d]=1),b++;a.i.length=c}};Zb.prototype.get=function(a,b){return Object.prototype.hasOwnProperty.call(this.ba,a)?this.ba[a]:b};
+Zb.prototype.set=function(a,b){Object.prototype.hasOwnProperty.call(this.ba,a)||(this.n++,this.i.push(a),this.ab++);this.ba[a]=b};Zb.prototype.La=function(a){$b(this);var b=0,c=this.i,d=this.ba,e=this.ab,f=this,h=new Ub;h.next=function(){for(;;){e!=f.ab&&g(Error("The map has changed since the iterator was created"));b>=c.length&&g(I);var h=c[b++];return a?h:d[h]}};return h};var ac=function(a,b){this.Hd=a;this.uc=b;this.Fd=H(window,"message",this.Ed,m,this)};ac.prototype.send=function(a,b){this.Hd.postMessage(Qb({type:a,data:b}),"*")};ac.prototype.t=function(){Ib(this.Fd)};ac.prototype.Ed=function(a){var b=Nb(a.I.data),a=""+b.type,b=b.data;this.uc.hasOwnProperty(a)||g("Unknown message type received by CommChannel: "+a);(0,this.uc[a])(a,b)};var bc;(bc="ScriptEngine"in p&&"JScript"==p.ScriptEngine())&&(p.ScriptEngineMajorVersion(),p.ScriptEngineMinorVersion(),p.ScriptEngineBuildVersion());var cc=function(a,b){this.M=bc?[]:"";a!=k&&this.append.apply(this,arguments)};cc.prototype.set=function(a){this.clear();this.append(a)};bc?(cc.prototype.Tb=0,cc.prototype.append=function(a,b,c){b==k?this.M[this.Tb++]=a:(this.M.push.apply(this.M,arguments),this.Tb=this.M.length);return this}):cc.prototype.append=function(a,b,c){this.M+=a;if(b!=k)for(var d=1;d<arguments.length;d++)this.M+=arguments[d];return this};cc.prototype.clear=function(){bc?this.Tb=this.M.length=0:this.M=""};
+cc.prototype.toString=function(){if(bc){var a=this.M.join("");this.clear();a&&this.append(a);return a}return this.M};var dc=function(a,b){this.x=a!==i?a:0;this.y=b!==i?b:0};dc.prototype.toString=function(){return"("+this.x+", "+this.y+")"};var J=function(a,b){this.width=a;this.height=b};J.prototype.toString=function(){return"("+this.width+" x "+this.height+")"};J.prototype.Ya=function(){return!(this.width*this.height)};J.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};J.prototype.round=function(){this.width=Math.round(this.width);this.height=Math.round(this.height);return this};var ec,fc=!B||nb(9);!C&&!B||B&&nb(9)||C&&E("1.9.1");B&&E("9");var gc=function(a){return(a=a.className)&&"function"==typeof a.split?a.split(/\s+/):[]},hc=function(a,b){var c=gc(a),d=Fa(arguments,1),e;e=c;for(var f=0,h=0;h<d.length;h++)0<=wa(e,d[h])||(e.push(d[h]),f++);e=f==d.length;a.className=c.join(" ");return e},ic=function(a,b){for(var c=gc(a),d=Fa(arguments,1),e=c,f=0,h=0;h<e.length;h++)0<=wa(d,e[h])&&(Ga(e,h--,1),f++);a.className=c.join(" ")};var L=function(a){return a?new jc(K(a)):ec||(ec=new jc)},M=function(a){return s(a)?document.getElementById(a):a},lc=function(a,b){var c=b&&"*"!=b?b.toUpperCase():"";return a.querySelectorAll&&a.querySelector&&(!D||kc(document)||E("528"))&&c?a.querySelectorAll(c+""):a.getElementsByTagName(c||"*")},nc=function(a,b){Ja(b,function(b,d){"style"==d?a.style.cssText=b:"class"==d?a.className=b:"for"==d?a.htmlFor=b:d in mc?a.setAttribute(mc[d],b):0==d.lastIndexOf("aria-",0)?a.setAttribute(d,b):a[d]=b})},mc=
+{cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",rowspan:"rowSpan",valign:"vAlign",height:"height",width:"width",usemap:"useMap",frameborder:"frameBorder",maxlength:"maxLength",type:"type"},oc=function(a){var b=a.document;if(D&&!E("500")&&!ab){"undefined"==typeof a.innerHeight&&(a=window);var b=a.innerHeight,c=a.document.documentElement.scrollHeight;a==a.top&&c<b&&(b-=15);return new J(a.innerWidth,b)}a=kc(b)?b.documentElement:b.body;return new J(a.clientWidth,a.clientHeight)},
+pc=function(a){return a?a.parentWindow||a.defaultView:window},rc=function(a,b,c){return qc(document,arguments)},qc=function(a,b){var c=b[0],d=b[1];if(!fc&&d&&(d.name||d.type)){c=["<",c];d.name&&c.push(' name="',sa(d.name),'"');if(d.type){c.push(' type="',sa(d.type),'"');var e={};Na(e,d);d=e;delete d.type}c.push(">");c=c.join("")}c=a.createElement(c);if(d)s(d)?c.className=d:q(d)?hc.apply(k,[c].concat(d)):nc(c,d);2<b.length&&sc(a,c,b,2);return c},sc=function(a,b,c,d){function e(c){c&&b.appendChild(s(c)?
+a.createTextNode(c):c)}for(;d<c.length;d++){var f=c[d];ca(f)&&!(ea(f)&&0<f.nodeType)?xa(tc(f)?Ea(f):f,e):e(f)}},kc=function(a){return"CSS1Compat"==a.compatMode},uc=function(a,b){sc(K(a),a,arguments,1)},vc=function(a){return a&&a.parentNode?a.parentNode.removeChild(a):k},wc=function(a,b){var c=b.parentNode;c&&c.replaceChild(a,b)},xc=function(a,b){if(a.contains&&1==b.nodeType)return a==b||a.contains(b);if("undefined"!=typeof a.compareDocumentPosition)return a==b||Boolean(a.compareDocumentPosition(b)&
+16);for(;b&&a!=b;)b=b.parentNode;return b==a},K=function(a){return 9==a.nodeType?a:a.ownerDocument||a.document},yc=function(a,b){if("textContent"in a)a.textContent=b;else if(a.firstChild&&3==a.firstChild.nodeType){for(;a.lastChild!=a.firstChild;)a.removeChild(a.lastChild);a.firstChild.data=b}else{for(var c;c=a.firstChild;)a.removeChild(c);a.appendChild(K(a).createTextNode(b))}},tc=function(a){if(a&&"number"==typeof a.length){if(ea(a))return"function"==typeof a.item||"string"==typeof a.item;if(da(a))return"function"==
+typeof a.item}return m},jc=function(a){this.l=a||p.document||document};n=jc.prototype;n.p=L;n.F=function(){return this.l};n.b=function(a){return s(a)?this.l.getElementById(a):a};n.o=function(a,b,c){return qc(this.l,arguments)};n.createElement=function(a){return this.l.createElement(a)};n.createTextNode=function(a){return this.l.createTextNode(a)};n.Db=function(){return this.l.parentWindow||this.l.defaultView};
+var zc=function(a){var b=a.l,a=!D&&kc(b)?b.documentElement:b.body,b=b.parentWindow||b.defaultView;return new dc(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)};jc.prototype.appendChild=function(a,b){a.appendChild(b)};jc.prototype.append=uc;jc.prototype.removeNode=vc;jc.prototype.contains=xc;var N=function(a,b,c,d,e){this.C=!!b;a&&Ac(this,a,d);this.depth=e!=i?e:this.A||0;this.C&&(this.depth*=-1);this.Yc=!c};x(N,Ub);N.prototype.B=k;N.prototype.A=0;N.prototype.wb=m;var Ac=function(a,b,c){if(a.B=b)a.A="number"==typeof c?c:1!=a.B.nodeType?0:a.C?-1:1};N.prototype.tb=function(){var a=this.C?-1:1;if(this.A==a)this.A=-1*a,this.depth+=this.A*(this.C?-1:1)};
+N.prototype.next=function(){var a;if(this.wb){(!this.B||this.Yc&&0==this.depth)&&g(I);a=this.B;var b=this.C?-1:1;if(this.A==b){var c=this.C?a.lastChild:a.firstChild;c?Ac(this,c):Ac(this,a,-1*b)}else(c=this.C?a.previousSibling:a.nextSibling)?Ac(this,c):Ac(this,a.parentNode,-1*b);this.depth+=this.A*(this.C?-1:1)}else this.wb=j;(a=this.B)||g(I);return a};
+N.prototype.splice=function(a){var b=this.B,c=this.C?1:-1;if(this.A==c)this.A=-1*c,this.depth+=this.A*(this.C?-1:1);this.C=!this.C;N.prototype.next.call(this);this.C=!this.C;for(var c=ca(arguments[0])?arguments[0]:arguments,d=c.length-1;0<=d;d--)b.parentNode&&b.parentNode.insertBefore(c[d],b.nextSibling);vc(b)};var Bc=function(a,b,c,d){this.top=a;this.right=b;this.bottom=c;this.left=d};Bc.prototype.toString=function(){return"("+this.top+"t, "+this.right+"r, "+this.bottom+"b, "+this.left+"l)"};Bc.prototype.contains=function(a){return!this||!a?m:a instanceof Bc?a.left>=this.left&&a.right<=this.right&&a.top>=this.top&&a.bottom<=this.bottom:a.x>=this.left&&a.x<=this.right&&a.y>=this.top&&a.y<=this.bottom};var Cc=function(a,b,c,d){this.left=a;this.top=b;this.width=c;this.height=d};Cc.prototype.toString=function(){return"("+this.left+", "+this.top+" - "+this.width+"w x "+this.height+"h)"};Cc.prototype.contains=function(a){return a instanceof Cc?this.left<=a.left&&this.left+this.width>=a.left+a.width&&this.top<=a.top&&this.top+this.height>=a.top+a.height:a.x>=this.left&&a.x<=this.left+this.width&&a.y>=this.top&&a.y<=this.top+this.height};var O=function(a,b){var c=K(a);return c.defaultView&&c.defaultView.getComputedStyle&&(c=c.defaultView.getComputedStyle(a,k))?c[b]||c.getPropertyValue(b):""},Dc=function(a,b){return a.currentStyle?a.currentStyle[b]:k},Ec=function(a,b){return O(a,b)||Dc(a,b)||a.style&&a.style[b]},Gc=function(a,b,c){var d,e=C&&(Ua||cb)&&E("1.9");b instanceof dc?(d=b.x,b=b.y):(d=b,b=c);a.style.left=Fc(d,e);a.style.top=Fc(b,e)},Hc=function(a){var b=a.getBoundingClientRect();if(B)a=a.ownerDocument,b.left-=a.documentElement.clientLeft+
+a.body.clientLeft,b.top-=a.documentElement.clientTop+a.body.clientTop;return b},Ic=function(a){if(B&&!nb(8))return a.offsetParent;for(var b=K(a),c=Ec(a,"position"),d="fixed"==c||"absolute"==c,a=a.parentNode;a&&a!=b;a=a.parentNode)if(c=Ec(a,"position"),d=d&&"static"==c&&a!=b.documentElement&&a!=b.body,!d&&(a.scrollWidth>a.clientWidth||a.scrollHeight>a.clientHeight||"fixed"==c||"absolute"==c||"relative"==c))return a;return k},Jc=function(a){var b,c=K(a),d=Ec(a,"position"),e=C&&c.getBoxObjectFor&&!a.getBoundingClientRect&&
+"absolute"==d&&(b=c.getBoxObjectFor(a))&&(0>b.screenX||0>b.screenY),f=new dc(0,0),h;b=c?9==c.nodeType?c:K(c):document;if(h=B)if(h=!nb(9))h=L(b),h=!kc(h.l);h=h?b.body:b.documentElement;if(a==h)return f;if(a.getBoundingClientRect)b=Hc(a),a=zc(L(c)),f.x=b.left+a.x,f.y=b.top+a.y;else if(c.getBoxObjectFor&&!e)b=c.getBoxObjectFor(a),a=c.getBoxObjectFor(h),f.x=b.screenX-a.screenX,f.y=b.screenY-a.screenY;else{e=a;do{f.x+=e.offsetLeft;f.y+=e.offsetTop;e!=a&&(f.x+=e.clientLeft||0,f.y+=e.clientTop||0);if(D&&
+"fixed"==Ec(e,"position")){f.x+=c.body.scrollLeft;f.y+=c.body.scrollTop;break}e=e.offsetParent}while(e&&e!=a);if($a||D&&"absolute"==d)f.y-=c.body.offsetTop;for(e=a;(e=Ic(e))&&e!=c.body&&e!=h;)if(f.x-=e.scrollLeft,!$a||"TR"!=e.tagName)f.y-=e.scrollTop}return f},Kc=function(a,b,c){b instanceof J?(c=b.height,b=b.width):c==i&&g(Error("missing height argument"));a.style.width=Fc(b,j);a.style.height=Fc(c,j)},Fc=function(a,b){"number"==typeof a&&(a=(b?Math.round(a):a)+"px");return a},Mc=function(a){if("none"!=
+Ec(a,"display"))return Lc(a);var b=a.style,c=b.display,d=b.visibility,e=b.position;b.visibility="hidden";b.position="absolute";b.display="inline";a=Lc(a);b.display=c;b.position=e;b.visibility=d;return a},Lc=function(a){var b=a.offsetWidth,c=a.offsetHeight,d=D&&!b&&!c;return(b===i||d)&&a.getBoundingClientRect?(a=Hc(a),new J(a.right-a.left,a.bottom-a.top)):new J(b,c)},Nc=function(a,b){var c=a.style;if("opacity"in c)c.opacity=b;else if("MozOpacity"in c)c.MozOpacity=b;else if("filter"in c)c.filter=""===
+b?"":"alpha(opacity="+100*b+")"},P=function(a,b){a.style.display=b?"":"none"},Oc=function(a){B?a.cssText=".bidichecker-dialog-bg { position: absolute; top: 0; left: 0; }.bidichecker-dialog {font-family: arial, sans-serif}.bidichecker-dialog-buttons {display: none;}.bidichecker-dialog-title-close {position: absolute;right: 0;padding-right: 5px;padding-left: 5px;}.bidichecker-dialog-title-close:hover {background-color: #fee;}.bidichecker-dialog iframe {border: 0;height: 100%;width: 100%;background: white;}.bidichecker-dialog { position: absolute; background-color: #fcb; border: 1px solid #000; width: 800px; height: 600px; color: #000; outline: none; direction: ltr }.bidichecker-dialog-title { position: relative; padding-bottom: 5px;height: 1em;color: #000000;font-size: 16px; font-weight: bold; vertical-align: middle; }.bidichecker-dialog .bidichecker-dialog-title {cursor: pointer; cursor: hand }":
+a[D?"innerText":"innerHTML"]=".bidichecker-dialog-bg { position: absolute; top: 0; left: 0; }.bidichecker-dialog {font-family: arial, sans-serif}.bidichecker-dialog-buttons {display: none;}.bidichecker-dialog-title-close {position: absolute;right: 0;padding-right: 5px;padding-left: 5px;}.bidichecker-dialog-title-close:hover {background-color: #fee;}.bidichecker-dialog iframe {border: 0;height: 100%;width: 100%;background: white;}.bidichecker-dialog { position: absolute; background-color: #fcb; border: 1px solid #000; width: 800px; height: 600px; color: #000; outline: none; direction: ltr }.bidichecker-dialog-title { position: relative; padding-bottom: 5px;height: 1em;color: #000000;font-size: 16px; font-weight: bold; vertical-align: middle; }.bidichecker-dialog .bidichecker-dialog-title {cursor: pointer; cursor: hand }"},
+Pc=function(a){return"rtl"==Ec(a,"direction")},Qc=function(a,b,c,d){if(/^\d+px?$/.test(b))return parseInt(b,10);var e=a.style[c],f=a.runtimeStyle[c];a.runtimeStyle[c]=a.currentStyle[c];a.style[c]=b;b=a.style[d];a.style[c]=e;a.runtimeStyle[c]=f;return b},Rc=function(a,b){return Qc(a,Dc(a,b),"left","pixelLeft")},Sc={thin:2,medium:4,thick:6},Tc=function(a,b){if("none"==Dc(a,b+"Style"))return 0;var c=Dc(a,b+"Width");return c in Sc?Sc[c]:Qc(a,c,"left","pixelLeft")};var Uc=RegExp("[\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc](?:[^A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff\u202a-\u202e]*[\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc])?","g"),Vc=RegExp("(?:[\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc](?:[^A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff\u202a-\u202e]*[\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc])?)|(?:\u202e[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff](?:[^\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc\u202a-\u202e]*[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff])?\u202c[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*)+",
+"g"),Wc=RegExp("[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff](?:[^\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc\u202a-\u202e]*[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff])?","g"),Xc=RegExp("^[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff]"),
+Yc=RegExp("[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff][\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*$"),Zc=RegExp("[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*$"),
+$c=RegExp("[\x00-\u001f\u007f\u0085\u00a0\u1680\u180e\u2000-\u200f\u2028-\u202f\u205f\u3000]"),ad=RegExp("^[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\u200e]+$"),bd=RegExp("^[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\u200f]+$"),
+cd=RegExp("^[\x00-\u0008\u000e-\u001f!-@[-`{-\u0084\u0086-\u009f\u00a1-\u00bf\u00d7\u00f7\u02b9-\u02ff\u200b-\u200d\u2010-\u2027\u2030-\u205e\u2060-\u2bff\t-\r \u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*\\d"),dd=RegExp("[A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u200e\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff\u0591-\u07ff\u200f\ufb1d-\ufdff\ufe70-\ufefc]"),ed=function(a,b){this.text=a;this.index=b},fd=function(a){for(var b=[],c;c=Uc.exec(a);)b.push(new ed(c[0],
+c.index));return b},gd=function(a){for(var b=[],c;c=Vc.exec(a);){var d=c[0],e=Zc.exec(c[0]);e&&(d=d.substr(0,d.length-e[0].length));b.push(new ed(d,c.index))}return b},hd=function(a){for(var b=[],c;c=Wc.exec(a);)"\u202e"==a.charAt(c.index-1)&&"\u202c"==a.charAt(c.index+c[0].length)||b.push(new ed(c[0],c.index));return b},id=function(a,b){var c=Xc.exec(a.substr(b));return c?new ed(c[0],b):k},jd=function(a,b){var c=Yc.exec(a.substr(0,b));return c?new ed(c[0],b-c[0].length):k},kd=function(a){return(a=
+cd.exec(a))?new ed(a[0],0):k},ld={"\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t",'"':'\\"',"'":"\\'","\\":"\\\\"},md=function(a){for(var b=[],c=0;c<a.length;c++){var d=b,e=c,f;f=a.charAt(c);if(f in ld)f=ld[f];else{var h=f;if($c.test(f)){var l=f.charCodeAt(0),h="\\u";4096>l&&(h+="0",256>l&&(h+="0",16>l&&(h+="0")));h+=l.toString(16)}f=ld[f]=h}d[e]=f}return b.join("")},nd=function(a){var b=a.nodeValue;"class"!=a.nodeName&&"id"!=a.nodeName&&(b=20<b.length?b.substr(0,20)+"\u2026":b);"style"==
+a.nodeName&&(b=b.toLowerCase());return a.nodeName+"="+("'"+md(b)+"'")},od=function(a){var b=[];if(a.attributes)for(var c=0;c<a.attributes.length;++c){var d=a.attributes[c];d.nodeValue&&(d.specified===i||d.specified)&&b.push(d)}a=[a.nodeName.toLowerCase()];b=za(b,nd);b.sort();a=a.concat(b);return"<"+a.join(" ")+">"},pd=function(a){for(var b=[];a&&!(b.push(od(a)),"BODY"==a.parentNode.nodeName||"FRAMESET"==a.parentNode.nodeName);a=a.parentNode);b.reverse();return b.join("")},qd=function(a){var b=[],
+c=new N(a);Wb(c,function(){3==c.B.nodeType&&b.push(c.B.data)});return b.join("")},rd=Oa("ADDRESS","BLOCKQUOTE","BODY","CAPTION","CENTER","COL","COLGROUP","DIR","DIV","DL","DD","DT","FIELDSET","FORM","H1","H2","H3","H4","H5","H6","HR","ISINDEX","OL","LI","MAP","MENU","OPTGROUP","OPTION","P","PRE","TABLE","TBODY","TD","TFOOT","TH","THEAD","TR","TL","UL"),sd=Oa("inline","inline-block","inline-table"),td={element:k,style:k},ud=function(a){if(td.element==a)return td.style;var b=Dc(a,"display")||O(a,"display");
+td={element:a,style:b};return b},vd=function(a){var b=ud(a);return b?!sd[b]:!!rd[a.tagName]},wd=function(a){if(1==a.nodeType){if("SCRIPT"==a.nodeName||"STYLE"==a.nodeName||"NOSCRIPT"==a.nodeName)return m;if("none"==ud(a))return m;a=Dc(a,"visibility")||O(a,"visibility");return"hidden"!=a&&"collapse"!=a}return j},xd=function(a){var b={color:a.style.color||"",backgroundColor:a.style.backgroundColor||"",outline:a.style.outline||""};a.style.color="red";a.style.backgroundColor="yellow";a.style.outline=
+"medium solid red";return b};var Q=function(a,b,c,d){if("object"==typeof a){b="id,type,severity,atText,locationDescription,precededByText,followedByText".split(",");c=["id","type","severity"];for(d=0;d<b.length;++d){var e=b[d];this[e]=e in a?a[e]:k;this[e]==k&&0<=wa(c,e)&&g("Required field '"+e+"' not found in bidichecker.Error.")}}else b==i&&g("Required parameter 'opt_severity' not found in bidichecker.Error."),this.id=yd++,this.type=a,this.severity=b,zd[this.id]=c||k,this.atText=d||k};Q.prototype.precededByText=k;
+Q.prototype.followedByText=k;Q.prototype.locationDescription=k;Q.prototype.asString=k;var yd=0,zd=[];Q.prototype.nb=function(){return this.id};Q.prototype.Ia=function(){return this.type};var Ad=function(a){return a.severity};Q.prototype.xa=function(){return zd[this.id]||k};
+Q.prototype.toString=function(){var a=new cc("[",Ad(this).toString(),"] ",this.Ia()),b;if(b=this.atText)b=20<b.length?b.substr(0,20)+"\u2026":b,a.append(": ","'"+md(b)+"'");(b=this.precededByText)&&a.append(" preceded by ","'"+md(b)+"'");(b=this.followedByText)&&a.append(" followed by ","'"+md(b)+"'");(b=this.locationDescription)&&a.append(" in ",b);return a.toString()};var Bd=function(a){for(var b=0;b<a.length;++b){var c=a[b];c.asString=c.toString()}return Qb(a)};var Dd=function(a){return Cd(a||arguments.callee.caller,[])},Cd=function(a,b){var c=[];if(0<=wa(b,a))c.push("[...circular reference...]");else if(a&&50>b.length){c.push(Ed(a)+"(");for(var d=a.arguments,e=0;e<d.length;e++){0<e&&c.push(", ");var f;f=d[e];switch(typeof f){case "object":f=f?"object":"null";break;case "string":break;case "number":f=""+f;break;case "boolean":f=f?"true":"false";break;case "function":f=(f=Ed(f))?f:"[fn]";break;default:f=typeof f}40<f.length&&(f=f.substr(0,40)+"...");c.push(f)}b.push(a);
+c.push(")\n");try{c.push(Cd(a.caller,b))}catch(h){c.push("[exception trying to get caller]\n")}}else a?c.push("[...long stack...]"):c.push("[end]");return c.join("")},Ed=function(a){if(Fd[a])return Fd[a];a=""+a;if(!Fd[a]){var b=/function ([^\(]+)/.exec(a);Fd[a]=b?b[1]:"[Anonymous]"}return Fd[a]},Fd={};var Gd=function(a,b,c,d,e){this.reset(a,b,c,d,e)};Gd.prototype.Bd=0;Gd.prototype.sc=k;Gd.prototype.rc=k;var Hd=0;Gd.prototype.reset=function(a,b,c,d,e){this.Bd="number"==typeof e?e:Hd++;this.ie=d||ka();this.Ja=a;this.Ad=b;this.he=c;delete this.sc;delete this.rc};Gd.prototype.tc=function(a){this.Ja=a};Gd.prototype.getMessage=function(){return this.Ad};var S=function(a){this.Gd=a};S.prototype.G=k;S.prototype.Ja=k;S.prototype.Y=k;S.prototype.Dc=k;var Id=function(a,b){this.name=a;this.value=b};Id.prototype.toString=function(){return this.name};var Jd=new Id("SEVERE",1E3),Kd=new Id("CONFIG",700);S.prototype.getParent=function(){return this.G};S.prototype.tc=function(a){this.Ja=a};var Ld=function(a){if(a.Ja)return a.Ja;if(a.G)return Ld(a.G);va("Root logger has no level set.");return k};
+S.prototype.log=function(a,b,c){if(a.value>=Ld(this).value){a=this.Od(a,b,c);b="log:"+a.getMessage();p.console&&(p.console.timeStamp?p.console.timeStamp(b):p.console.markTimeline&&p.console.markTimeline(b));p.msWriteProfilerMark&&p.msWriteProfilerMark(b);for(b=this;b;){var c=b,d=a;if(c.Dc)for(var e=0,f=i;f=c.Dc[e];e++)f(d);b=b.getParent()}}};
+S.prototype.Od=function(a,b,c){var d=new Gd(a,""+b,this.Gd);if(c){d.sc=c;var e;var f=arguments.callee.caller;try{var h;var l=aa("window.location.href");if(s(c))h={message:c,name:"Unknown error",lineNumber:"Not available",fileName:l,stack:"Not available"};else{var o,r,v=m;try{o=c.lineNumber||c.me||"Not available"}catch(w){o="Not available",v=j}try{r=c.fileName||c.filename||c.sourceURL||l}catch(Va){r="Not available",v=j}h=v||!c.lineNumber||!c.fileName||!c.stack?{message:c.message,name:c.name,lineNumber:o,
+fileName:r,stack:c.stack||"Not available"}:c}e="Message: "+sa(h.message)+'\nUrl: <a href="view-source:'+h.fileName+'" target="_new">'+h.fileName+"</a>\nLine: "+h.lineNumber+"\n\nBrowser stack:\n"+sa(h.stack+"-> ")+"[end]\n\nJS stack traversal:\n"+sa(Dd(f)+"-> ")}catch(R){e="Exception trying to expose exception! You win, we lose. "+R}d.rc=e}return d};
+var Md={},Nd=k,Od=function(a){Nd||(Nd=new S(""),Md[""]=Nd,Nd.tc(Kd));var b;if(!(b=Md[a])){b=new S(a);var c=a.lastIndexOf("."),d=a.substr(c+1),c=Od(a.substr(0,c));if(!c.Y)c.Y={};c.Y[d]=b;b.G=c;Md[a]=b}return b};Od("goog.dom.SavedRange");var Pd=function(){};Pd.prototype.fc=function(){return m};Pd.prototype.F=function(){return K(B?this.getContainer():this.m())};Pd.prototype.Db=function(){return pc(this.F())};Pd.prototype.containsNode=function(a,b){return this.ua(Qd(Rd(a)),b)};var Sd=function(a,b){N.call(this,a,b,j)};x(Sd,N);var Td=function(a,b,c,d,e){var f;if(a){this.k=a;this.e=b;this.h=c;this.d=d;if(1==a.nodeType&&"BR"!=a.tagName)if(a=a.childNodes,b=a[b])this.k=b,this.e=0;else{if(a.length)this.k=z(a);f=j}if(1==c.nodeType)(this.h=c.childNodes[d])?this.d=0:this.h=c}Sd.call(this,e?this.h:this.k,e);if(f)try{this.next()}catch(h){h!=I&&g(h)}};x(Td,Sd);n=Td.prototype;n.k=k;n.h=k;n.e=0;n.d=0;n.m=function(){return this.k};n.w=function(){return this.h};n.xd=function(){return this.wb&&this.B==this.h&&(!this.d||1!=this.A)};
+n.next=function(){this.xd()&&g(I);return Td.g.next.call(this)};n.tb=function(){Td.g.tb.apply(this);xc(this.B,this.h)&&g(I)};var Ud=function(){};Ud.prototype.ua=function(a,b){var c=b&&!a.isCollapsed(),d=a.Ra();try{return c?0<=this.J(d,0,1)&&0>=this.J(d,1,0):0<=this.J(d,0,0)&&0>=this.J(d,1,1)}catch(e){return B||g(e),m}};Ud.prototype.containsNode=function(a,b){return this.ua(Rd(a),b)};Ud.prototype.La=function(){return new Td(this.m(),this.D(),this.w(),this.H())};var Vd=function(a){this.a=a};x(Vd,Ud);var Wd=function(a){var b=K(a).createRange();if(3==a.nodeType)b.setStart(a,0),b.setEnd(a,a.length);else if(T(a)){for(var c,d=a;(c=d.firstChild)&&T(c);)d=c;b.setStart(d,0);for(d=a;(c=d.lastChild)&&T(c);)d=c;b.setEnd(d,1==d.nodeType?d.childNodes.length:d.length)}else c=a.parentNode,a=wa(c.childNodes,a),b.setStart(c,a),b.setEnd(c,a+1);return b},Xd=function(a,b,c,d){var e=K(a).createRange();e.setStart(a,b);e.setEnd(c,d);return e};n=Vd.prototype;n.Ra=function(){return this.a};
+n.getContainer=function(){return this.a.commonAncestorContainer};n.m=function(){return this.a.startContainer};n.D=function(){return this.a.startOffset};n.w=function(){return this.a.endContainer};n.H=function(){return this.a.endOffset};n.J=function(a,b,c){return this.a.compareBoundaryPoints(1==c?1==b?p.Range.START_TO_START:p.Range.START_TO_END:1==b?p.Range.END_TO_START:p.Range.END_TO_END,a)};n.isCollapsed=function(){return this.a.collapsed};n.da=function(){return this.a.toString()};
+n.select=function(a){this.ib(pc(K(this.m())).getSelection(),a)};n.ib=function(a){a.removeAllRanges();a.addRange(this.a)};n.collapse=function(a){this.a.collapse(a)};var Yd=function(a){this.a=a};x(Yd,Vd);Yd.prototype.ib=function(a,b){var c=b?this.w():this.m(),d=b?this.H():this.D(),e=b?this.m():this.w(),f=b?this.D():this.H();a.collapse(c,d);(c!=e||d!=f)&&a.extend(e,f)};var Zd=function(a,b){this.a=a;this.ge=b};x(Zd,Ud);var $d=Od("goog.dom.browserrange.IeRange"),ae=function(a){var b=K(a).body.createTextRange();if(1==a.nodeType)b.moveToElementText(a),T(a)&&!a.childNodes.length&&b.collapse(m);else{for(var c=0,d=a;d=d.previousSibling;){var e=d.nodeType;if(3==e)c+=d.length;else if(1==e){b.moveToElementText(d);break}}d||b.moveToElementText(a.parentNode);b.collapse(!d);c&&b.move("character",c);b.moveEnd("character",a.length)}return b};n=Zd.prototype;n.ga=k;n.k=k;n.h=k;
+n.e=-1;n.d=-1;n.Ra=function(){return this.a};
+n.getContainer=function(){if(!this.ga){var a=this.a.text,b=this.a.duplicate(),c=a.replace(/ +$/,"");(c=a.length-c.length)&&b.moveEnd("character",-c);c=b.parentElement();b=b.htmlText.replace(/(\r\n|\r|\n)+/g," ").length;if(this.isCollapsed()&&0<b)return this.ga=c;for(;b>c.outerHTML.replace(/(\r\n|\r|\n)+/g," ").length;)c=c.parentNode;for(;1==c.childNodes.length&&c.innerText==(3==c.firstChild.nodeType?c.firstChild.nodeValue:c.firstChild.innerText)&&T(c.firstChild);)c=c.firstChild;0==a.length&&(c=be(this,
+c));this.ga=c}return this.ga};var be=function(a,b){for(var c=b.childNodes,d=0,e=c.length;d<e;d++){var f=c[d];if(T(f)){var h=ae(f),l=h.htmlText!=f.outerHTML;if(a.isCollapsed()&&l?0<=a.J(h,1,1)&&0>=a.J(h,1,0):a.a.inRange(h))return be(a,f)}}return b};n=Zd.prototype;n.m=function(){if(!this.k&&(this.k=ce(this,1),this.isCollapsed()))this.h=this.k;return this.k};n.D=function(){if(0>this.e&&(this.e=de(this,1),this.isCollapsed()))this.d=this.e;return this.e};
+n.w=function(){if(this.isCollapsed())return this.m();if(!this.h)this.h=ce(this,0);return this.h};n.H=function(){if(this.isCollapsed())return this.D();if(0>this.d&&(this.d=de(this,0),this.isCollapsed()))this.e=this.d;return this.d};n.J=function(a,b,c){return this.a.compareEndPoints((1==b?"Start":"End")+"To"+(1==c?"Start":"End"),a)};
+var ce=function(a,b,c){c=c||a.getContainer();if(!c||!c.firstChild)return c;for(var d=1==b,e=0,f=c.childNodes.length;e<f;e++){var h=d?e:f-e-1,l=c.childNodes[h],o;try{o=Rd(l)}catch(r){continue}var v=o.Ra();if(a.isCollapsed())if(T(l)){if(o.ua(a))return ce(a,b,l)}else{if(0==a.J(v,1,1)){a.e=a.d=h;break}}else{if(a.ua(o)){if(!T(l)){d?a.e=h:a.d=h+1;break}return ce(a,b,l)}if(0>a.J(v,1,0)&&0<a.J(v,0,1))return ce(a,b,l)}}return c},de=function(a,b){var c=1==b,d=c?a.m():a.w();if(1==d.nodeType){for(var d=d.childNodes,
+e=d.length,f=c?1:-1,h=c?0:e-1;0<=h&&h<e;h+=f){var l=d[h];if(!T(l)&&0==a.a.compareEndPoints((1==b?"Start":"End")+"To"+(1==b?"Start":"End"),Rd(l).Ra()))return c?h:h+1}return-1==h?0:h}e=a.a.duplicate();f=ae(d);e.setEndPoint(c?"EndToEnd":"StartToStart",f);e=e.text.length;return c?d.length-e:e};Zd.prototype.isCollapsed=function(){return 0==this.a.compareEndPoints("StartToEnd",this.a)};Zd.prototype.da=function(){return this.a.text};Zd.prototype.select=function(){this.a.select()};
+Zd.prototype.collapse=function(a){this.a.collapse(a);a?(this.h=this.k,this.d=this.e):(this.k=this.h,this.e=this.d)};var ee=function(a){this.a=a};x(ee,Vd);ee.prototype.ib=function(a){a.collapse(this.m(),this.D());(this.w()!=this.m()||this.H()!=this.D())&&a.extend(this.w(),this.H());0==a.rangeCount&&a.addRange(this.a)};var fe=function(a){this.a=a};x(fe,Vd);fe.prototype.J=function(a,b,c){return E("528")?fe.g.J.call(this,a,b,c):this.a.compareBoundaryPoints(1==c?1==b?p.Range.START_TO_START:p.Range.END_TO_START:1==b?p.Range.START_TO_END:p.Range.END_TO_END,a)};fe.prototype.ib=function(a,b){a.removeAllRanges();b?a.setBaseAndExtent(this.w(),this.H(),this.m(),this.D()):a.setBaseAndExtent(this.m(),this.D(),this.w(),this.H())};var Rd=function(a){if(B&&!nb(9)){var b=new Zd(ae(a),K(a));if(T(a)){for(var c,d=a;(c=d.firstChild)&&T(c);)d=c;b.k=d;b.e=0;for(d=a;(c=d.lastChild)&&T(c);)d=c;b.h=d;b.d=1==d.nodeType?d.childNodes.length:d.length;b.ga=a}else b.k=b.h=b.ga=a.parentNode,b.e=wa(b.ga.childNodes,a),b.d=b.e+1;a=b}else a=D?new fe(Wd(a)):C?new Yd(Wd(a)):$a?new ee(Wd(a)):new Vd(Wd(a));return a},T=function(a){var b;a:if(1!=a.nodeType)b=m;else{switch(a.tagName){case "APPLET":case "AREA":case "BASE":case "BR":case "COL":case "FRAME":case "HR":case "IMG":case "INPUT":case "IFRAME":case "ISINDEX":case "LINK":case "NOFRAMES":case "NOSCRIPT":case "META":case "OBJECT":case "PARAM":case "SCRIPT":case "STYLE":b=
+m;break a}b=j}return b||3==a.nodeType};var ge=function(){};x(ge,Pd);var Qd=function(a){var b=new ge;b.Ba=a;b.Va=m;return b};n=ge.prototype;n.Ba=k;n.k=k;n.e=k;n.h=k;n.d=k;n.Va=m;n.Ia=function(){return"text"};
+var U=function(a){var w;var b;if(!(b=a.Ba)){b=a.m();var c=a.D(),d=a.w(),e=a.H();if(B&&!nb(9)){var f=b,h=c,l=d,o=e,r=m;1==f.nodeType&&(h>f.childNodes.length&&$d.log(Jd,"Cannot have startOffset > startNode child count",i),h=f.childNodes[h],r=!h,f=h||f.lastChild||f,h=0);var v=ae(f);h&&v.move("character",h);f==l&&h==o?v.collapse(j):(r&&v.collapse(m),r=m,1==l.nodeType&&(o>l.childNodes.length&&$d.log(Jd,"Cannot have endOffset > endNode child count",i),w=(h=l.childNodes[o])||l.lastChild||l,l=w,o=0,r=!h),
+f=ae(l),f.collapse(!r),o&&f.moveEnd("character",o),v.setEndPoint("EndToEnd",f));o=new Zd(v,K(b));o.k=b;o.e=c;o.h=d;o.d=e;b=o}else b=D?new fe(Xd(b,c,d,e)):C?new Yd(Xd(b,c,d,e)):$a?new ee(Xd(b,c,d,e)):new Vd(Xd(b,c,d,e));b=a.Ba=b}return b};n=ge.prototype;n.getContainer=function(){return U(this).getContainer()};n.m=function(){return this.k||(this.k=U(this).m())};n.D=function(){return this.e!=k?this.e:this.e=U(this).D()};n.w=function(){return this.h||(this.h=U(this).w())};
+n.H=function(){return this.d!=k?this.d:this.d=U(this).H()};n.fc=function(){return this.Va};n.ua=function(a,b){var c=a.Ia();if("text"==c)return U(this).ua(U(a),b);return"control"==c?(c=he(a),(b?Aa:Ba)(c,function(a){return this.containsNode(a,b)},this)):m};n.isCollapsed=function(){return U(this).isCollapsed()};n.da=function(){return U(this).da()};n.La=function(){return new Td(this.m(),this.D(),this.w(),this.H())};n.select=function(){U(this).select(this.Va)};
+n.collapse=function(a){a=this.fc()?!a:a;this.Ba&&this.Ba.collapse(a);a?(this.h=this.k,this.d=this.e):(this.k=this.h,this.e=this.d);this.Va=m};var he=function(a){if(!a.Lb&&(a.Lb=[],a.a))for(var b=0;b<a.a.length;b++)a.Lb.push(a.a.item(b));return a.Lb};Od("goog.dom.MultiRange");var ie=function(){this.s=[];this.fe=M("error-text");H(window,"unload",this.sd,m,this);this.K=new ac(window.opener||window.parent,{errorList:t(this.td,this)});this.K.send("checkPage")};u("bidichecker.gui.app.ErrorPage",ie);ie.prototype.za=k;ie.prototype.sd=function(){0<this.s.length&&je(this)};ie.prototype.qd=function(a){Qd(Rd(this.oc)).select();a.preventDefault()};ie.prototype.td=function(a,b){b instanceof Array||g("Invalid data type in errorList message; expected Array.");ke(this,b.map(function(a){return new Q(a)}))};
+var le=function(a,b){if(!a)return k;var c='<span class="table-cell-ellipsize" style="'+(b?"width: "+b:"")+'">'+sa(a)+"</span>";return{v:a.toLowerCase(),f:c}},ke=function(a,b){a.s=b;for(var c=0<a.s.length,d=document.getElementsByClassName("show-on-errors"),e=0;e<d.length;e++)P(d[e],c);P(M("no-errors-container"),!c);if(c){c=new google.visualization.DataTable;c.addColumn("number","#");c.addColumn("string","Type");c.addColumn("number","Sev");c.addColumn("string","Location");c.addColumn("string","Text");
+for(d=0;d<a.s.length;d++)e=a.s[d],c.addRow([d+1,le(e.Ia()),Ad(e),le(e.locationDescription,"280px"),le(e.atText,"150px")]);a.oc=M("table-container");a.gb=new google.visualization.Table(a.oc);a.gb.draw(c,{height:"300px",allowHtml:j});google.visualization.events.addListener(a.gb,"select",t(a.rd,a));yc(M("error-count"),a.s.length+"");a.gb.setSelection([{row:0,column:k}]);me(a,a.s[0]);H(M("select-table"),"click",a.qd,m,a)}},me=function(a,b){je(a);a.za=b;a.za&&(a.K.send("highlightError",a.za),yc(M("error-text"),
+a.za.toString()))};ie.prototype.rd=function(){var a=this.gb.getSelection();0<a.length&&me(this,this.s[a[0].row])};var je=function(a){a.za&&a.K.send("unhighlightError",a.za)};var ne=function(a){a.setAttribute("role","dialog");a.oe="dialog"};var V=function(a){this.Bb=a;this.i=[]};x(V,sb);
+var oe=[],W=function(a,b,c,d,e){q(c)||(oe[0]=c,c=oe);for(var f=0;f<c.length;f++)a.i.push(H(b,c[f],d||a,e||m,a.Bb||a));return a},pe=function(a,b,c,d,e,f){if(q(c))for(var h=0;h<c.length;h++)pe(a,b,c[h],d,e,f);else a.i.push(Fb(b,c,d||a,e,f||a.Bb||a))},qe=function(a,b,c,d,e,f){if(q(c))for(var h=0;h<c.length;h++)qe(a,b,c[h],d,e,f);else{a:{d=d||a;f=f||a.Bb||a;e=!!e;if(b=Hb(b,c,e))for(c=0;c<b.length;c++)if(!b[c].ia&&b[c].sa==d&&b[c].capture==e&&b[c].Ua==f){b=b[c];break a}b=k}if(b)b=b.key,Ib(b),Ca(a.i,b)}return a};
+V.prototype.removeAll=function(){xa(this.i,Ib);this.i.length=0};V.prototype.r=function(){V.g.r.call(this);this.removeAll()};V.prototype.handleEvent=function(){g(Error("EventHandler.handleEvent not implemented"))};var re=function(){};x(re,sb);n=re.prototype;n.jc=j;n.Wa=k;n.xb=function(a){this.Wa=a};n.addEventListener=function(a,b,c,d){H(this,a,b,c,d)};n.removeEventListener=function(a,b,c,d){Gb(this,a,b,c,d)};
+n.dispatchEvent=function(a){var b=a.type||a,c=G;if(b in c){if(s(a))a=new F(a,this);else if(a instanceof F)a.target=a.target||this;else{var d=a,a=new F(b,this);Na(a,d)}var d=1,e,c=c[b],b=j in c,f;if(b){e=[];for(f=this;f;f=f.Wa)e.push(f);f=c[j];f.L=f.n;for(var h=e.length-1;!a.ka&&0<=h&&f.L;h--)a.currentTarget=e[h],d&=Mb(f,e[h],a.type,j,a)&&a.Ha!=m}if(m in c)if(f=c[m],f.L=f.n,b)for(h=0;!a.ka&&h<e.length&&f.L;h++)a.currentTarget=e[h],d&=Mb(f,e[h],a.type,m,a)&&a.Ha!=m;else for(e=this;!a.ka&&e&&f.L;e=e.Wa)a.currentTarget=
+e,d&=Mb(f,e,a.type,m,a)&&a.Ha!=m;a=Boolean(d)}else a=j;return a};n.r=function(){re.g.r.call(this);Kb(this);this.Wa=k};var se=function(a,b,c){this.target=a;this.handle=b||a;this.vb=c||new Cc(NaN,NaN,NaN,NaN);this.l=K(a);this.z=new V(this);H(this.handle,["touchstart","mousedown"],this.gc,m,this)};x(se,re);var te=B||C&&E("1.9.3");n=se.prototype;n.clientX=0;n.clientY=0;n.screenX=0;n.screenY=0;n.cc=0;n.dc=0;n.qa=0;n.ra=0;n.ac=j;n.Z=m;n.bc=0;n.Nc=0;n.Mc=m;n.U=function(){return this.z};
+n.r=function(){se.g.r.call(this);Gb(this.handle,["touchstart","mousedown"],this.gc,m,this);this.z.t();delete this.target;delete this.handle;delete this.z};
+n.gc=function(a){var b="mousedown"==a.type;if(this.ac&&!this.Z&&(!b||(pb?0==a.I.button:"click"==a.type||a.I.button&xb[0])&&(!D||!Ua||!a.ctrlKey))){ue(a);if(0==this.bc)if(ve(this,a),this.Z)a.preventDefault();else return;else a.preventDefault();var b=this.l,c=b.documentElement,d=!te;W(this.z,b,["touchmove","mousemove"],this.Lc,d);W(this.z,b,["touchend","mouseup"],this.Ta,d);te?(c.setCapture(m),W(this.z,c,"losecapture",this.Ta)):W(this.z,pc(b),"blur",this.Ta);B&&this.Mc&&W(this.z,b,"dragstart",vb);this.Pc&&
+W(this.z,this.Pc,"scroll",this.Oc,d);this.clientX=this.cc=a.clientX;this.clientY=this.dc=a.clientY;this.screenX=a.screenX;this.screenY=a.screenY;this.qa=this.target.offsetLeft;this.ra=this.target.offsetTop;this.ub=zc(L(this.l));this.Nc=ka()}else this.dispatchEvent("earlycancel")};var ve=function(a,b){if(a.dispatchEvent(new we("start",a,b.clientX,b.clientY,b))!==m)a.Z=j};
+se.prototype.Ta=function(a,b){this.z.removeAll();te&&this.l.releaseCapture();var c=xe(this,this.qa),d=ye(this,this.ra);this.Z?(ue(a),this.Z=m,this.dispatchEvent(new we("end",this,a.clientX,a.clientY,a,c,d,b||"touchcancel"==a.type))):this.dispatchEvent("earlycancel");("touchend"==a.type||"touchcancel"==a.type)&&a.preventDefault()};
+var ue=function(a){var b=a.type;"touchstart"==b||"touchmove"==b?a.ta(a.I.targetTouches[0],a.currentTarget):("touchend"==b||"touchcancel"==b)&&a.ta(a.I.changedTouches[0],a.currentTarget)};
+se.prototype.Lc=function(a){if(this.ac){ue(a);var b=a.clientX-this.clientX,c=a.clientY-this.clientY;this.clientX=a.clientX;this.clientY=a.clientY;this.screenX=a.screenX;this.screenY=a.screenY;if(!this.Z){var d=this.cc-this.clientX,e=this.dc-this.clientY;if(d*d+e*e>this.bc&&(ve(this,a),!this.Z)){this.Ta(a);return}}c=ze(this,b,c);b=c.x;c=c.y;this.Z&&this.dispatchEvent(new we("beforedrag",this,a.clientX,a.clientY,a,b,c))!==m&&(Ae(this,a,b,c),a.preventDefault())}};
+var ze=function(a,b,c){var d=zc(L(a.l)),b=b+(d.x-a.ub.x),c=c+(d.y-a.ub.y);a.ub=d;a.qa+=b;a.ra+=c;b=xe(a,a.qa);a=ye(a,a.ra);return new dc(b,a)};se.prototype.Oc=function(a){var b=ze(this,0,0);a.clientX=this.clientX;a.clientY=this.clientY;Ae(this,a,b.x,b.y)};
+var Ae=function(a,b,c,d){a.target.style.left=c+"px";a.target.style.top=d+"px";a.dispatchEvent(new we("drag",a,b.clientX,b.clientY,b,c,d))},xe=function(a,b){var c=a.vb,d=!isNaN(c.left)?c.left:k,c=!isNaN(c.width)?c.width:0;return Math.min(d!=k?d+c:Infinity,Math.max(d!=k?d:-Infinity,b))},ye=function(a,b){var c=a.vb,d=!isNaN(c.top)?c.top:k,c=!isNaN(c.height)?c.height:0;return Math.min(d!=k?d+c:Infinity,Math.max(d!=k?d:-Infinity,b))},we=function(a,b,c,d,e,f,h,l){F.call(this,a);this.clientX=c;this.clientY=
+d;this.je=e;this.left=f!==i?f:b.qa;this.top=h!==i?h:b.ra;this.le=b;this.ke=!!l};x(we,F);var Be=function(a){this.c=a;a=B?"focusout":"blur";this.Vc=H(this.c,B?"focusin":"focus",this,!B);this.Wc=H(this.c,a,this,!B)};x(Be,re);Be.prototype.handleEvent=function(a){var b=new wb(a.I);b.type="focusin"==a.type||"focus"==a.type?"focusin":"focusout";try{this.dispatchEvent(b)}finally{b.t()}};Be.prototype.r=function(){Be.g.r.call(this);Ib(this.Vc);Ib(this.Wc);delete this.c};var Ce=p.window;var De=function(){};(function(a){a.Cc=function(){return a.Pd||(a.Pd=new a)}})(De);De.prototype.Jd=0;De.Cc();var Fe=function(a){this.Ea=a||L();this.Kd=Ee};x(Fe,re);Fe.prototype.Id=De.Cc();var Ee=k;n=Fe.prototype;n.kb=k;n.P=m;n.c=k;n.Kd=k;n.Ic=k;n.G=k;n.Y=k;n.Ca=k;n.Jc=m;n.nb=function(){return this.kb||(this.kb=":"+(this.Id.Jd++).toString(36))};n.b=function(){return this.c};n.U=function(){return this.oa||(this.oa=new V(this))};n.getParent=function(){return this.G};n.xb=function(a){this.G&&this.G!=a&&g(Error("Method not supported"));Fe.g.xb.call(this,a)};n.p=function(){return this.Ea};
+n.o=function(){this.c=this.Ea.createElement("div")};n.Na=function(a){this.P&&g(Error("Component already rendered"));this.c||this.o();a?a.insertBefore(this.c,k):this.Ea.F().body.appendChild(this.c);(!this.G||this.G.P)&&this.na()};n.na=function(){this.P=j;Ge(this,function(a){!a.P&&a.b()&&a.na()})};n.fa=function(){Ge(this,function(a){a.P&&a.fa()});this.oa&&this.oa.removeAll();this.P=m};
+n.r=function(){Fe.g.r.call(this);this.P&&this.fa();this.oa&&(this.oa.t(),delete this.oa);Ge(this,function(a){a.t()});!this.Jc&&this.c&&vc(this.c);this.G=this.Ic=this.c=this.Ca=this.Y=k};n.$b=function(){return this.c};var Ge=function(a,b){a.Y&&xa(a.Y,b,i)};
+Fe.prototype.removeChild=function(a,b){if(a){var c=s(a)?a:a.nb(),a=this.Ca&&c?(c in this.Ca?this.Ca[c]:i)||k:k;if(c&&a){var d=this.Ca;c in d&&delete d[c];Ca(this.Y,a);b&&(a.fa(),a.c&&vc(a.c));c=a;c==k&&g(Error("Unable to set parent component"));c.G=k;Fe.g.xb.call(c,k)}}a||g(Error("Child is not in parent component"));return a};var He=function(a,b){Fe.call(this,b);this.Kc=!!a};x(He,Fe);n=He.prototype;n.sb=k;n.$a=m;n.u=k;n.q=k;n.R=k;n.Sa=function(){return"goog-modalpopup"};n.Ma=function(){return this.u};
+n.o=function(){He.g.o.call(this);var a=this.b();hc(a,this.Sa());a.tabIndex=0;P(a,m);if(this.Kc&&!this.q)this.q=this.p().o("iframe",{frameborder:0,style:"border:0;vertical-align:bottom;",src:'javascript:""'}),this.q.className=this.Sa()+"-bg",P(this.q,m),Nc(this.q,0);if(!this.u)this.u=this.p().o("div",this.Sa()+"-bg"),P(this.u,m);if(!this.R)this.R=this.p().createElement("span"),P(this.R,m),this.R.tabIndex=0,this.R.style.position="absolute"};
+n.na=function(){y(!!this.u,"Background element must not be null.");if(this.q){var a=this.b();a.parentNode&&a.parentNode.insertBefore(this.q,a)}a=this.b();a.parentNode&&a.parentNode.insertBefore(this.u,a);He.g.na.call(this);a=this.b();a.parentNode&&a.parentNode.insertBefore(this.R,a.nextSibling);this.sb=new Be(this.p().F());W(this.U(),this.sb,"focusin",this.Gc)};n.fa=function(){this.Oa()&&this.T(m);ub(this.sb);He.g.fa.call(this);vc(this.q);vc(this.u);vc(this.R)};
+n.T=function(a){y(this.P,"ModalPopup must be rendered first.");a!=this.$a&&(a?this.Dd():this.Cd())};n.Dd=function(){if(this.dispatchEvent("beforeshow"))this.Eb(),this.Yb(),W(this.U(),this.p().Db(),"resize",this.Eb),Ie(this,j),this.focus(),this.$a=j,this.dispatchEvent("show")};n.Cd=function(){if(this.dispatchEvent("beforehide"))qe(this.U(),this.p().Db(),"resize",this.Eb),Ie(this,m),this.$a=m,this.dispatchEvent("hide")};var Ie=function(a,b){a.q&&P(a.q,b);a.u&&P(a.u,b);P(a.b(),b);P(a.R,b)};n=He.prototype;
+n.Oa=function(){return this.$a};n.focus=function(){this.yc()};n.Eb=function(){this.q&&P(this.q,m);this.u&&P(this.u,m);var a=this.p().F(),b=oc(pc(a)||window||window),c=Math.max(a.body.scrollWidth,b.width),a=Math.max(a.body.scrollHeight,b.height);this.q&&(P(this.q,j),Kc(this.q,c,a));this.u&&(P(this.u,j),Kc(this.u,c,a))};
+n.Yb=function(){var a=this.p().F(),b=pc(a)||window;if("fixed"==Ec(this.b(),"position"))var c=a=0;else c=zc(this.p()),a=c.x,c=c.y;var d=Mc(this.b()),b=oc(b||window),a=Math.max(a+b.width/2-d.width/2,0),c=Math.max(c+b.height/2-d.height/2,0);Gc(this.b(),a,c);Gc(this.R,a,c)};n.Gc=function(a){if(a.target==this.R)a=this.yc,da(a)?this&&(a=t(a,this)):a&&"function"==typeof a.handleEvent?a=t(a.handleEvent,a):g(Error("Invalid listener argument")),Ce.setTimeout(a,0)};
+n.yc=function(){try{B&&this.p().F().body.focus(),this.b().focus()}catch(a){}};var X=function(a,b,c){He.call(this,b,c);this.Q=a||"modal-dialog";this.X=Je()};x(X,He);n=X.prototype;n.Tc=j;n.Ub=j;n.pb=j;n.Qc=j;n.qb=0.5;n.Fc="";n.Vb="";n.ja=k;n.Xb=m;n.ea=k;n.ob=k;n.Wb=k;n.Aa=k;n.rb=k;n.W=k;n.Sa=function(){return this.Q};var Ke=function(a){a.b()||a.Na()};X.prototype.$b=function(){Ke(this);return this.rb};X.prototype.Ma=function(){Ke(this);return X.g.Ma.call(this)};
+var Le=function(a){a.pb=m;if(a.P){var b=a.p(),c=a.Ma();b.removeNode(a.q);b.removeNode(c)}},Me=function(a,b){if(a.b()){var c=a.ea,d=a.Q+"-title-draggable";b?hc(c,d):ic(c,d)}if(b&&!a.ja)a.ja=new se(a.b(),a.ea),hc(a.ea,a.Q+"-title-draggable"),H(a.ja,"start",a.Xc,m,a);else if(!b&&a.ja)a.ja.t(),a.ja=k};n=X.prototype;
+n.o=function(){X.g.o.call(this);var a=this.b();y(a,"getElement() returns null");var b=this.p();this.ea=b.o("div",{className:this.Q+"-title",id:this.nb()},this.ob=b.o("span",this.Q+"-title-text",this.Fc),this.Aa=b.o("span",this.Q+"-title-close"));uc(a,this.ea,this.rb=b.o("div",this.Q+"-content"),this.W=b.o("div",this.Q+"-buttons"));this.Wb=this.ea.id;ne(a);a.setAttribute("aria-labelledby",this.Wb||"");if(this.Vb)this.rb.innerHTML=this.Vb;P(this.Aa,this.Ub);if(this.X)a=this.X,a.c=this.W,a.Na();P(this.W,
+!!this.X);this.qb=this.qb;this.b()&&(a=this.Ma())&&Nc(a,this.qb)};n.na=function(){X.g.na.call(this);W(this.U(),this,["show","hide"],this.Sc);Me(this,this.Qc);W(this.U(),this.Aa,"click",this.Rc);ne(this.b());""!==this.ob.id&&this.b().setAttribute("aria-labelledby",this.ob.id);this.pb||Le(this)};n.fa=function(){this.Oa()&&this.T(m);Me(this,m);X.g.fa.call(this)};n.T=function(a){a!=this.Oa()&&(this.P||this.Na(),X.g.T.call(this,a))};
+n.Sc=function(a){a.target==this&&(this.Oa()?(W(W(this.U(),this.b(),"keydown",this.Xa),this.b(),"keypress",this.Xa),this.dispatchEvent("aftershow"),W(this.U(),this.W,"click",this.ic)):(qe(qe(qe(this.U(),this.b(),"keydown",this.Xa),this.b(),"keypress",this.Xa),this.W,"click",this.ic),this.dispatchEvent("afterhide"),this.Xb&&this.t()))};
+n.focus=function(){X.g.focus.call(this);if(this.X){var a=this.X.Pa;if(a)for(var b=this.p().F(),c=this.W.getElementsByTagName("button"),d=0,e;e=c[d];d++)if(e.name==a){try{if(D||$a){var f=b.createElement("input");f.style.cssText="position:fixed;width:0;height:0;left:0;top:0;";this.b().appendChild(f);f.focus();this.b().removeChild(f)}e.focus()}catch(h){}break}}};
+n.Xc=function(){var a=this.p().F(),b=oc(pc(a)||window||window),c=Math.max(a.body.scrollWidth,b.width),a=Math.max(a.body.scrollHeight,b.height),d=Mc(this.b());this.ja.vb="fixed"==Ec(this.b(),"position")?new Cc(0,0,Math.max(0,b.width-d.width),Math.max(0,b.height-d.height))||new Cc(NaN,NaN,NaN,NaN):new Cc(0,0,c-d.width,a-d.height)||new Cc(NaN,NaN,NaN,NaN)};n.Rc=function(){if(this.Ub){var a=this.X,b=a&&a.yb;b?(a=a.get(b),this.dispatchEvent(new Ne(b,a))&&this.T(m)):this.T(m)}};
+n.r=function(){this.W=this.Aa=k;X.g.r.call(this)};n.ic=function(a){a:{for(a=a.target;a!=k&&a!=this.W;){if("BUTTON"==a.tagName)break a;a=a.parentNode}a=k}if(a&&!a.disabled){var a=a.name,b=this.X.get(a);this.dispatchEvent(new Ne(a,b))&&this.T(m)}};
+n.Xa=function(a){var b=m,c=m,d=this.X,e=a.target;if("keydown"==a.type)if(this.Tc&&27==a.keyCode){var f=d&&d.yb,e="SELECT"==e.tagName&&!e.disabled;f&&!e?(c=j,b=d.get(f),b=this.dispatchEvent(new Ne(f,b))):e||(b=j)}else 9==a.keyCode&&a.shiftKey&&e==this.b()&&(c=j);else if(13==a.keyCode){if("BUTTON"==e.tagName)f=e.name;else if(d){var h=d.Pa,l;if(l=h)a:{l=d.c.getElementsByTagName("BUTTON");for(var o=0,r;r=l[o];o++)if(r.name==h||r.id==h){l=r;break a}l=k}e=("TEXTAREA"==e.tagName||"SELECT"==e.tagName)&&!e.disabled;
+l&&!l.disabled&&!e&&(f=h)}f&&d&&(c=j,b=this.dispatchEvent(new Ne(f,""+d.get(f))))}if(b||c)a.stopPropagation(),a.preventDefault();b&&this.T(m)};var Ne=function(a,b){this.type="dialogselect";this.key=a;this.caption=b};x(Ne,F);var Oe=function(a){this.Ea=a||L();Zb.call(this)};x(Oe,Zb);n=Oe.prototype;n.Q="goog-buttonset";n.Pa=k;n.c=k;n.yb=k;n.set=function(a,b,c,d){Zb.prototype.set.call(this,a,b);if(c)this.Pa=a;if(d)this.yb=a;return this};var Y=function(a,b,c,d){return a.set(b.key,b.caption,c,d)};
+Oe.prototype.Na=function(){if(this.c){this.c.innerHTML="";var a=L(this.c);Yb(this,function(b,c){var d=a.o("button",{name:c},b);if(c==this.Pa)d.className=this.Q+"-default";this.c.appendChild(d)},this)}};Oe.prototype.b=function(){return this.c};Oe.prototype.p=function(){return this.Ea};
+var Pe={key:"ok",caption:"OK"},Qe={key:"cancel",caption:"Cancel"},Re={key:"yes",caption:"Yes"},Se={key:"no",caption:"No"},Te={key:"save",caption:"Save"},Ue={key:"continue",caption:"Continue"},Je=function(){return Y(Y(new Oe,Pe,j),Qe,m,j)};"undefined"!=typeof document&&(Y(new Oe,Pe,j,j),Je(),Y(Y(new Oe,Re,j),Se,m,j),Y(Y(Y(new Oe,Re),Se,j),Qe,m,j),Y(Y(Y(new Oe,Ue),Te),Qe,j,j));var Ve=function(){};Ve.prototype.wc=function(){};var We=function(){var a=new X("bidichecker-dialog");m!=a.pb&&Le(a);a.T(j);var b=a.b();b.style.zIndex=1E4;Ke(a);a.Aa.innerHTML="&times;";a.Xb=j;var c=document.createElement("iframe"),d=a.$b();d.appendChild(c);this.Qa=c.contentWindow;var c=L(d),e=k;if(B)e=c.F().createStyleSheet(),Oc(e);else{var f=lc(c.l,"head")[0];f||(e=lc(c.l,"body")[0],f=c.o("head"),e.parentNode.insertBefore(f,e));e=c.o("style");Oc(e);c.appendChild(f,e)}this.Hc=e;f=K(b);if(e=c=B&&b.currentStyle)f=L(f),e=kc(f.l)&&"auto"!=c.width&&
+"auto"!=c.height&&!c.boxSizing;if(e)f=Qc(b,c.width,"width","pixelWidth"),b=Qc(b,c.height,"height","pixelHeight"),b=new J(f,b);else{c=new J(b.offsetWidth,b.offsetHeight);if(B)var f=Rc(b,"paddingLeft"),e=Rc(b,"paddingRight"),h=Rc(b,"paddingTop"),l=Rc(b,"paddingBottom"),f=new Bc(h,e,l,f);else f=O(b,"paddingLeft"),e=O(b,"paddingRight"),h=O(b,"paddingTop"),l=O(b,"paddingBottom"),f=new Bc(parseFloat(h),parseFloat(e),parseFloat(l),parseFloat(f));B?(e=Tc(b,"borderLeft"),h=Tc(b,"borderRight"),l=Tc(b,"borderTop"),
+b=Tc(b,"borderBottom"),b=new Bc(l,h,b,e)):(e=O(b,"borderLeftWidth"),h=O(b,"borderRightWidth"),l=O(b,"borderTopWidth"),b=O(b,"borderBottomWidth"),b=new Bc(parseFloat(l),parseFloat(h),parseFloat(b),parseFloat(e)));b=new J(c.width-b.left-f.left-f.right-b.right,c.height-b.top-f.top-f.bottom-b.bottom)}b=b.height;Ke(a);d.style.height=Fc(b-a.ea.offsetHeight,j);a.Yb();this.Zb=a};x(We,Ve);We.prototype.t=function(){this.Zb.t();var a=this.Hc;vc(a.ownerNode||a.owningElement||a)};
+We.prototype.wc=function(a){var b=this.Zb.b(),c=new dc(b.offsetLeft,b.offsetTop);Gc(b,c.x,c.y+a)};var Ye=function(a){a||(a=window.open("about:blank","_blank","width=800,height=600,menubar=no,toolbar=no,location=no"))||g(Error("can't create window"));Xe(a);this.Qa=a};x(Ye,Ve);var Xe=function(a){setTimeout(function(){a.resizeTo(800,600)},1)};Ye.prototype.t=function(){try{this.Qa.close()}catch(a){}};var Ze=function(a){try{return new Ye(a)}catch(b){return new We}};var $e=function(a,b,c,d,e){var f={},h;for(h in b)f[h]=b[h];b=f;h={dir:"ltr",severity:4};for(var l in h)l in b||(b[l]=h[l]);this.dd=a;this.Fb=b;this.Za=c;this.bb=d;this.Gb=e||k},af;n=$e.prototype;n.K=k;n.start=function(){var a=this.Za.Qa;this.K=new ac(a,{checkPage:t(this.gd,this),highlightError:t(this.kd,this),unhighlightError:t(this.pd,this),getOptions:t(this.jd,this),setOptions:t(this.md,this)});a.location=this.bb};n.t=function(){ub(this.K);delete this.K;ub(this.Za);delete this.Za};
+n.jd=function(){this.K.send("options",this.Fb)};n.md=function(a,b){this.Fb=Object(b)};n.gd=function(){var a;if(this.Gb)a=this.Gb,this.Gb=k;else{a=this.Fb;var b=[];-1!=a.severity&&b.push(bf(a.severity));a=this.dd.hb("rtl"==a.dir,k,b)}this.K.send("errorList",Nb(Bd(a)))};n.kd=function(a,b){var c=(new Q(Object(b))).xa();if(c){var c=c.xc(),d=window.scrollY;window.scrollTo(0,c.y-100);this.Za.wc(window.scrollY-d)}};n.pd=function(a,b){var c=(new Q(Object(b))).xa();c&&c.Bc()};var cf=function(a){this.lb=a};var Z=function(){};u("bidichecker.FilterFactory.ComposableFilter",Z);Z.prototype.Qd=function(a){return df(this,a)};Z.prototype.and=Z.prototype.Qd;Z.prototype.$d=function(){return ef(this)};Z.prototype.not=Z.prototype.$d;Z.prototype.ae=function(a){return ff(this,a)};Z.prototype.or=Z.prototype.ae;
+var xf=function(a){var b=a.opcode;switch(b){case "AND":return new gf(a);case "AT_TEXT":return new hf(a);case "AT_TEXT_REGEXP":return new jf(a);case "FOLLOWED_BY_TEXT":return new kf(a);case "FOLLOWED_BY_TEXT_REGEXP":return new lf(a);case "LOCATION_CLASS":return new mf(a);case "LOCATION_CLASS_REGEXP":return new nf(a);case "LOCATION_ID":return new of(a);case "LOCATION_ID_REGEXP":return new pf(a);case "LOCATION_XPATH":return new qf(a);case "NOT":return new rf(a);case "OR":return new sf(a);case "PRECEDED_BY_TEXT":return new tf(a);
+case "PRECEDED_BY_TEXT_REGEXP":return new uf(a);case "SEVERITY":return new vf(a);case "TYPE":return new wf(a);default:g("Unknown filter opcode: '"+b+"'")}},yf=function(a){if(!a)return k;a=Nb(a);return za(a,function(a){return xf(a)})},df=function(a,b){return new gf({filter1:a,filter2:b})};u("bidichecker.FilterFactory.and",df);u("bidichecker.FilterFactory.atText",function(a){return new hf({atText:a||""})});u("bidichecker.FilterFactory.atTextRegexp",function(a){return new jf({atTextRegexp:a||""})});
+u("bidichecker.FilterFactory.followedByText",function(a){return new kf({followedByText:a||""})});u("bidichecker.FilterFactory.followedByTextRegexp",function(a){return new lf({followedByTextRegexp:a||""})});u("bidichecker.FilterFactory.locationClass",function(a){a||g("Empty or null argument to bidichecker.FilterFactory.locationClass");return new mf({className:a})});
+u("bidichecker.FilterFactory.locationClassRegexp",function(a){a||g("Empty or null argument to bidichecker.FilterFactory.locationClassRegexp");return new nf({classRegexp:a})});u("bidichecker.FilterFactory.locationId",function(a){a||g("Empty or null argument to bidichecker.FilterFactory.locationId");return new of({id:a})});u("bidichecker.FilterFactory.locationIdRegexp",function(a){a||g("Empty or null argument to bidichecker.FilterFactory.locationIdRegexp");return new pf({idRegexp:a})});
+u("bidichecker.FilterFactory.locationXpath",function(a){a||g("Empty or null argument to bidichecker.FilterFactory.locationXpath");return new qf({xpath:a})});var ef=function(a){return new rf({filter:a})};u("bidichecker.FilterFactory.not",ef);var ff=function(a,b){return new sf({filter1:a,filter2:b})};u("bidichecker.FilterFactory.or",ff);u("bidichecker.FilterFactory.precededByText",function(a){return new tf({precededByText:a||""})});
+u("bidichecker.FilterFactory.precededByTextRegexp",function(a){return new uf({precededByTextRegexp:a||""})});var bf=function(a){return new vf({severityThreshold:a})};u("bidichecker.FilterFactory.severityFrom",bf);u("bidichecker.FilterFactory.type",function(a){return new wf({type:a})});
+var zf=function(a,b){b in a||g("No '"+b+"' parameter found for '"+a.opcode+"' filter")},Af=function(a,b,c){zf(a,b);typeof a[b]!=c&&g("Wrong type for '"+b+"' parameter of '"+a.opcode+"' filter; expected "+c)},Bf=function(a,b){Af(a,b,"string");return a[b]},Cf=function(a,b){zf(a,b);var c=a[b],d;"string"==typeof c?d=c:c instanceof RegExp?d=c.source:g("Wrong type for '"+b+"' parameter of '"+a.opcode+"' filter; expected string or RegExp");return RegExp("^("+d+")$")},Df=function(a,b){Af(a,b,"object");var c=
+a[b];if(c instanceof Z)return c;if("string"==typeof c.opcode)return xf(c);g("Can't make a filter out of the '"+b+"' parameter of '"+a.opcode+"' filter")},gf=function(a){this.Mb=Df(a,"filter1");this.Nb=Df(a,"filter2")};x(gf,Z);gf.prototype.j=function(a,b){return this.Mb.j(a,b)&&this.Nb.j(a,b)};var hf=function(a){this.Sd=Bf(a,"atText")};x(hf,Z);hf.prototype.j=function(a){return this.Sd==(a.atText||"")};var jf=function(a){this.Rd=Cf(a,"atTextRegexp")};x(jf,Z);
+jf.prototype.j=function(a){return this.Rd.test(a.atText||"")};var kf=function(a){this.Yd=Bf(a,"followedByText")};x(kf,Z);kf.prototype.j=function(a){return this.Yd==(a.followedByText||"")};var lf=function(a){this.Xd=Cf(a,"followedByTextRegexp")};x(lf,Z);lf.prototype.j=function(a){return this.Xd.test(a.followedByText||"")};var mf=function(a){this.Ud=Bf(a,"className")};x(mf,Z);
+mf.prototype.j=function(a,b){for(var c=0;c<b.length;++c)for(var d=b[c];d;d=d.parentNode)if(d.className)for(var e=d.className.split(/\s/),f=0;f<e.length;++f)if(this.Ud==e[f])return j;return m};var nf=function(a){this.Vd=Cf(a,"classRegexp")};x(nf,Z);nf.prototype.j=function(a,b){for(var c=0;c<b.length;++c)for(var d=b[c];d;d=d.parentNode)if(d.className)for(var e=d.className.split(/\s/),f=0;f<e.length;++f)if(this.Vd.test(e[f]))return j;return m};var of=function(a){this.kb=Bf(a,"id")};x(of,Z);
+of.prototype.j=function(a,b){for(var c=0;c<b.length;++c)for(var d=b[c];d;d=d.parentNode)if(d.id&&this.kb==d.id)return j;return m};var pf=function(a){this.Zd=Cf(a,"idRegexp")};x(pf,Z);pf.prototype.j=function(a,b){for(var c=0;c<b.length;++c)for(var d=b[c];d;d=d.parentNode)if(d.id&&this.Zd.test(d.id))return j;return m};var qf=function(a){a=Bf(a,"xpath");this.Md=new cf(a)};x(qf,Z);
+qf.prototype.j=function(a,b){for(var c=0;c<b.length;++c){var d;a:{d=b[c];var e;e=this.Md;var f=d.ownerDocument,h=f._bidicheckerXpathMatcherCache_[e.lb];if(!h)try{f.evaluate||g("XPath not supported by this browser"),h=f.evaluate(e.lb,f,k,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,k),f._bidicheckerXpathMatcherCache_[e.lb]=h}catch(l){g("Error evaluating XPath expression "+e.lb+": "+l)}e=h;for(f=0;f<e.snapshotLength;++f)if(e.snapshotItem(f)==d){d=j;break a}d=m}if(d)return j}return m};
+var rf=function(a){this.yd=Df(a,"filter")};x(rf,Z);rf.prototype.j=function(a,b){return!this.yd.j(a,b)};var sf=function(a){this.Mb=Df(a,"filter1");this.Nb=Df(a,"filter2")};x(sf,Z);sf.prototype.j=function(a,b){return this.Mb.j(a,b)||this.Nb.j(a,b)};var tf=function(a){this.ce=Bf(a,"precededByText")};x(tf,Z);tf.prototype.j=function(a){return this.ce==(a.precededByText||"")};var uf=function(a){this.be=Cf(a,"precededByTextRegexp")};x(uf,Z);
+uf.prototype.j=function(a){return this.be.test(a.precededByText||"")};var vf=function(a){Af(a,"severityThreshold","number");this.ee=a.severityThreshold};x(vf,Z);vf.prototype.j=function(a){return this.ee<=Ad(a)};var wf=function(a){this.Ld=Bf(a,"type")};x(wf,Z);wf.prototype.j=function(a){return this.Ld==a.Ia()};var Ef=function(){this.va=[]};x(Ef,re);n=Ef.prototype;n.start=function(){this.dispatchEvent("StartFrames")};n.end=function(){this.dispatchEvent("EndFrames")};n.push=function(a){this.va.push(a);this.dispatchEvent("EnterFrame")};n.pop=function(){this.dispatchEvent("ExitFrame");this.va.pop()};n.zb=function(){return this.va};var Ff=function(a,b){this.$c=a;this.Zc=b||[];this.s=[]};Ff.prototype.ad=m;Ff.prototype.Jb=function(){return this.s};Ff.prototype.addError=function(a,b){var c=this.$c.zb().slice(0);b&&c.push(b);if(Ba(this.Zc,function(b){return!b.j(a,c)})){var d=Gf(c);""!=d&&(a.locationDescription=d);this.s.push(a);this.ad&&g(a.toString()+"\n")}};var Gf=function(a){var b=[];ya(a,function(a){b.push(pd(a))});return b.join(" in ")};var Hf=function(a){this.wa=new N(a);this.cd=a;this.S=[Pc(a)];this.pa=[];this.ha=[a];this.va=[]};x(Hf,re);Hf.prototype.N=k;Hf.prototype.go=function(){try{for(;;If(this));}catch(a){a!==I&&g(a),this.dispatchEvent("EndOfDom")}};
+var If=function(a){for(var b=a.wa.next();1==a.wa.A&&!wd(b);)a.wa.tb(),b=a.wa.next();a.N=b;if(1==a.wa.A){var b=a.N,c=Pc(b);a.pa.push(z(a.pa)||Jf(a,b,c));a.S.push(c);"IFRAME"==b.nodeName||"FRAME"==b.nodeName?a.va.push(b):vd(b)&&a.ha.push(b);a.dispatchEvent("StartTag")}else-1==a.wa.A?(a.dispatchEvent("EndTag"),a.S.pop(),a.pa.pop(),a.N==z(a.ha)&&a.ha.pop()):3==a.N.nodeType&&"TEXTAREA"!=a.N.parentNode.nodeName&&a.dispatchEvent("TextNode")};Hf.prototype.zb=function(){return this.va};
+var Jf=function(a,b,c){if(!b.dir&&!b.style.direction&&c==z(a.S)||b==a.cd)return m;for(a=b.firstChild;a;a=a.nextSibling)if(1==a.nodeType&&vd(a))return m;return j};var Kf=function(a){this.c=a};Kf.prototype.Ka=k;Kf.prototype.xc=function(){this.Ka=xd(this.c);return Jc(this.c)};Kf.prototype.Bc=function(){if(this.Ka)this.c.style.color=this.Ka.color,this.c.style.backgroundColor=this.Ka.backgroundColor,this.c.style.outline=this.Ka.outline};var Lf=function(a,b,c){this.ma=a;this.e=b;this.d=c;this.la=[]};Lf.prototype.xc=function(){if(0==this.la.length)for(var a=0;a<this.ma.length;++a)this.la.push(Mf(this.ma[a],0==a?this.e:0,a==this.ma.length-1?this.d:this.ma[a].length));else for(a=0;a<this.la.length;++a)wc(this.la[a],this.ma[a]);return Jc(this.la[0])};Lf.prototype.Bc=function(){if(0!=this.la.length)for(var a=0;a<this.ma.length;++a)wc(this.ma[a],this.la[a])};
+var Mf=function(a,b,c){var b=b||0,c=c||a.data.length,d=[];0<b&&d.push(a.data.substring(0,b));b=rc("span",{},a.data.substring(b,c));xd(b);d.push(b);c<a.data.length&&d.push(a.data.substring(c));b=rc("span",k,d);wc(b,a);return b};var Nf=function(a,b){this.Rb=a;this.B=b},Of=function(a){this.ya=[new Nf(0,a)];this.Ac=a};Of.prototype.append=function(a,b){if(this.Ac!=b)this.ya.push(new Nf(a,b)),this.Ac=b};var Pf=function(a,b){var c=Ha(a.ya,function(a,b){return a-b.Rb}||Ia,b);return 0<=c?c:-c-2};Of.prototype.Kb=function(a){return this.ya[Pf(this,a)].B};Of.prototype.xa=function(a,b){for(var c=Pf(this,a),d=Pf(this,a+b-1),e=[],f=c;f<=d;++f)e.push(this.ya[f].B);return new Lf(e,a-this.ya[c].Rb,a+b-this.ya[d].Rb)};
+var Qf=function(a,b,c,d,e){this.hc=b;this.ec=e;this.Uc=d;this.Pb=[a];this.Qb=a.length;this.Hb=new Of(c)};n=Qf.prototype;n.jb=k;n.Ya=function(){return Ba(this.Pb,function(a){return 0==a.length})};n.append=function(a,b){this.Hb.append(this.Qb,b);this.Qb+=a.length;this.Pb.push(a);this.jb=k};n.da=function(){if(this.jb===k)this.jb=this.Pb.join("");return this.jb};n.Kb=function(a){return this.Hb.Kb(a)};n.xa=function(a,b){return this.Hb.xa(a,b)};var Rf=new Qf("",m,k,k,m);var Sf=function(a){this.$=Rf;this.z=new V(this);W(this.z,a,"TextNode",this.Ab);pe(this.z,a,"EndOfDom",this.vd)};x(Sf,re);Sf.prototype.Ab=function(a){var a=a.target,b=a.N;z(a.S)==this.$.hc&&z(a.ha)==this.$.Uc&&z(a.pa)==this.$.ec?this.$.append(b.data,b):(this.$.Ya()||this.dispatchEvent("DirChunk"),this.$=new Qf(b.data,z(a.S),b,z(a.ha),z(a.pa)))};Sf.prototype.vd=function(){this.$.Ya()||this.dispatchEvent("DirChunk");this.dispatchEvent("EndOfChunks");this.z.removeAll()};var Tf=function(a,b){this.bd=!!b;this.Fa=new Ef;this.lc=new Ff(this.Fa,a)};Tf.prototype.O=k;Tf.prototype.Cb=k;Tf.prototype.Jb=function(){return this.lc.Jb()};
+var Yf=function(a,b,c){b.ownerDocument._bidicheckerXpathMatcherCache_={};var d,e=a.lc,f=a.Da;d=[];0!=c&&d.push(new Uf(-1==c,e));d.push(new Vf(f,e));2<=f&&d.push(new Wf(e));d.push(new Xf(e));a.O=new Hf(b);a.Cb=a.bd?new Sf(a.O):k;for(b=0;b<d.length;++b)d[b].eb(a);a.O.go();d=a.O.zb();for(b=0;b<d.length;++b){e=d[b];a.Fa.push(e);try{var h=(e.contentDocument||e.contentWindow.document).body;"IFRAME"==e.tagName&&(c=0);Yf(a,h,c)}catch(l){}a.Fa.pop()}};var Uf=function(a,b){this.pc=a;this.aa=b};Uf.prototype.eb=function(a){Fb(a.O,"StartTag",this)};Uf.prototype.handleEvent=function(a){a=a.target;this.pc!=z(a.S)&&this.aa.addError(new Q("Overall directionality not "+(this.pc?"RTL":"LTR"),1,new Kf(a.N)))};var Xf=function(a){this.aa=a;this.Ga=[]};n=Xf.prototype;n.ca=k;n.eb=function(a){var b=new V(this);W(b,a.O,"StartTag",this.Sb);W(b,a.O,"EndTag",this.zd);W(b,a.O,"TextNode",this.Ab);pe(b,a.O,"EndOfDom",b.removeAll,m,b)};n.Sb=function(a){var a=a.target,b=a.N;if(b.dir||b==z(a.ha))this.ca=k};n.zd=function(a){var a=a.target,b=a.N;if(b==z(a.ha))this.ca=k;else if(b.dir)z(a.S)==a.S[a.S.length-2]?this.ca=k:(this.ca=b,this.Ga=[])};
+n.Ab=function(a){var a=a.target,b=a.N;if(this.ca){this.Ga.push(b);var c=kd(b.data);if(c){var d=za(this.Ga,function(a){return a.data}).join(""),e=z(this.Ga).parentNode;this.aa.addError(Zf(this,d.substr(0,d.length-(b.data.length-c.text.length)),c.text.length,z(a.S),z(a.pa)),e);this.ca=k}else if(dd.test(b.data))this.ca=k}};var Zf=function(a,b,c,d,e){b=new Q("Declared "+(d?"LTR":"RTL")+" spillover to number",e?4:2,new Lf(a.Ga,0,c),b);a=qd(a.ca);b.precededByText=a;return b};var Wf=function(a){this.aa=a};Wf.prototype.eb=function(a){var b=new V(this);W(b,a.O,"StartTag",this.Sb);pe(b,a.O,"EndOfDom",b.removeAll,m,b)};
+Wf.prototype.Sb=function(a){a=a.target.N;a.title&&$f(this,a,a.title,"title text");var b=a.nodeName;"INPUT"==b?a.type.match(/^(text|search)$/)?$f(this,a,a.value,"input value"):"image"==a.type?$f(this,a,a.alt,"alt text"):a.type.match(/^(button|reset|submit)$/)?$f(this,a,a.value,"button label"):"file"==a.type&&Pc(a)&&this.aa.addError(new Q("File input not LTR",2,new Kf(a)),a):"IMG"==b?$f(this,a,a.alt,"alt text"):"TEXTAREA"==b&&$f(this,a,a.value,"textarea value")};
+var $f=function(a,b,c,d){var e=Pc(b),f=!!hd(c).length,h=!!gd(c).length;f!=h&&e!=h&&(e="Undeclared "+(e?"LTR":"RTL")+" "+d,d="input value"==d||"textarea value"==d?1:b.dir||b.style.direction||Pc(b)!=Pc(b.parentNode)?4:id(c,0)||jd(c,c.length)?2:3,a.aa.addError(new Q(e,d,new Kf(b),c),b))};var Vf=function(a,b){this.Da=a;this.aa=b};Vf.prototype.eb=function(a){var b=new V(this);W(b,a.Cb,"DirChunk",this.Nd);pe(b,a.Cb,"EndOfChunks",b.removeAll,m,b)};Vf.prototype.Nd=function(a){var b=this,c=a.target.$;c.hc?(a=hd(c.da()),xa(a,function(a){ad.exec(a.text)||ag(b,c,a,"Undeclared LTR text")})):(a=2<=this.Da?gd(c.da()):fd(c.da()),xa(a,function(a){bd.exec(a.text)||ag(b,c,a,"Undeclared RTL text")}))};
+var ag=function(a,b,c,d){var e=b.ec?4:3,f=b.xa(c.index,c.text.length),d=new Q(d,e,f,c.text),e=b.da();if(f=jd(e,c.index))3==Ad(d)&&(d.severity=2),d.precededByText=f.text;if(e=id(e,c.index+c.text.length))3==Ad(d)&&(d.severity=2),d.followedByText=e.text;b=b.Kb(c.index).parentNode;a.aa.addError(d,b)};var bg=function(a,b){Tf.call(this,b,j);this.Da=a};x(bg,Tf);var cg=function(a){this.ud=a};u("bidichecker.REVISION_1",new cg(1));var dg=new cg(2);u("bidichecker.REVISION_2",dg);u("bidichecker.LATEST",dg);var $=function(a){this.Da=a;this.s=[]};u("bidichecker.BidiChecker",$);u("bidichecker.instance",k);$.prototype.bb="https://bidichecker.googlecode.com/svn/trunk/lib/gui-app/errorpage.html";$.prototype.hb=function(a,b,c){a=a?-1:1;b=b||top.document.body;c=c||[];zd=[];yd=0;c=new bg(this.Da.ud,c);c.Fa.start();Yf(c,b,a);c.Fa.end();this.s=c.Jb();return Ea(this.s)};
+$.prototype.checkPage=$.prototype.hb;$.prototype.Td=function(a,b,c){c=(c=yf(c))||[];a=this.hb(a,b,c);return Bd(a)};$.prototype.checkPageToJson=$.prototype.Td;$.prototype.Ec=function(a){this.bb=a};$.prototype.setGuiAppUrl=$.prototype.Ec;$.prototype.de=function(a){0!=this.s.length&&eg(this,this.s,a)};$.prototype.runGui=$.prototype.de;
+var eg=function(a,b,c){if(B)if(E("8"))c=j;else{c=new We;c.Qa.document.write("Sorry, bidichecker GUI is not supported in Internet Explorer before version 8.");return}c=c?new We:Ze(k);a=new $e(a,{},c,a.bb,b);ub(af);af=a;a.start()};u("bidichecker.runBookmarkletGui",function(a,b,c){var d=new $(dg);B?(b&&b.close(),b=new We):b=Ze(b);a=new $e(d,a,b,c||"https://bidichecker.googlecode.com/svn/trunk/lib/gui-app/errorpage.html");ub(af);af=a;a.start()});
+var fg=function(a,b,c){b=b||"https://bidichecker.googlecode.com/svn/trunk/lib/bidichecker_packaged.js";c=c||"https://bidichecker.googlecode.com/svn/trunk/lib/gui-app/errorpage.html";a=Qb(a).replace(/\$/g,"$$$$");return'javascript:(function() {function run() {bidichecker.runBookmarkletGui(%OPTIONS%, g_bidicheckerBookmarkletGuiWnd, "%APPURL%");}if (typeof g_bidicheckerBookmarkletGuiWnd == "undefined") {g_bidicheckerBookmarkletGuiWnd = null;}if (g_bidicheckerBookmarkletGuiWnd &&!g_bidicheckerBookmarkletGuiWnd.closed) {g_bidicheckerBookmarkletGuiWnd.focus();} else {g_bidicheckerBookmarkletGuiWnd = window.open("about:blank", "_blank", "width=1,height=1,resizable=yes,scrollbars=yes");var scriptElemId = "_bidichecker_bookmarklet";if (document.getElementById(scriptElemId)) {if (window.bidichecker) {run();}} else {var elem = document.createElement("script");elem.src = "%SCRIPTURL%";elem.onload = run;elem.id = scriptElemId;document.getElementsByTagName("head")[0].appendChild(elem);}}})()'.replace("%SCRIPTURL%",
+b).replace("%APPURL%",c).replace("%OPTIONS%",a)};u("bidichecker.generateBookmarklet",fg);u("bidichecker.checkPage",function(a,b,c){return(new $(dg)).hb(a,b,c)});u("bidichecker.runGui",function(a,b,c){var d=new $(dg);c&&d.Ec(c);eg(d,a,b)});var gg=function(){this.V=M("severity");H(this.V,"change",this.nd,m,this);H(document,"change",this.hd,m,this);H(M("show-bookmarklet-help"),"click",this.od,m,this);this.nc=M("bookmarklet");H(this.nc,"click",this.ed,m,this);H(M("run"),"click",this.fd,m,this);this.K=new ac(window.opener||window.parent,{options:t(this.ld,this)});this.K.send("getOptions")};u("bidichecker.gui.app.OptionsPage",gg);
+var hg=function(a){for(var a=L().F().getElementsByName(a),b=0;b<a.length;b++){var c=a[b];if(c.checked)return c.value}return k},ig=function(a,b,c){for(var a=a.F().getElementsByName(b),d=m,e=0;e<a.length;e++){var f=a[e];if(f.value==c){d=f.checked=j;break}}d||g("No radio button with name "+b+" and value "+c)};n=gg.prototype;n.fd=function(){this.K.send("setOptions",jg(this));window.location="errorpage.html"};
+n.ld=function(a,b){var c=Object(b),d=c.severity;this.V.value=-1!=d?d:4;this.V.zc=this.V.value;ig(L(),"severity-filtering",-1!=d?"on":"off");ig(L(),"dir",c.dir);kg(this)};n.nd=function(a){var b=ta(this.V.value);1<=b&&4>=b?(this.V.zc=b,kg(this)):this.V.value=this.V.zc;a.stopPropagation()};n.hd=function(){kg(this)};
+n.od=function(a){alert('You can add a button (a "bookmarklet") to your browser to run BidiChecker on any web page, using the current BidiChecker settings. To do this, just drag the link labeled BidiChecker to your browser\'s bookmarks toolbar. In Google Chrome, press Ctrl-Shift-B to show the bookmarks toolbar.');a.preventDefault()};n.ed=function(a){a.preventDefault()};
+var kg=function(a){var b="on"==hg("severity-filtering");M("severity").disabled=!b;a.nc.href=fg(jg(a))},jg=function(a){var b={},c="on"==hg("severity-filtering");b.severity=c?ta(a.V.value):-1;b.dir=hg("dir");return b};
diff --git a/lib/gui-app/options.html b/lib/gui-app/options.html
new file mode 100755
index 0000000..1d87321
--- /dev/null
+++ b/lib/gui-app/options.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+  <!--
+    Copyright 2011 Google Inc. All Rights Reserved.
+
+    Use of this source code is governed by an Apache 2.0 License.
+    See the COPYING file for details.
+  -->
+
+  <head>
+    <title>BidiChecker</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
+    <link href="bidichecker.css" rel="stylesheet" type="text/css">
+    <script type="text/javascript" src="gui_compiled.js"></script>
+  </head>
+
+  <body onload="new bidichecker.gui.app.OptionsPage();">
+    <h1>BidiChecker Options</h1>
+    Expected page directionality:
+    <input type="radio" name="dir" value="ltr">LTR
+    <input type="radio" name="dir" value="rtl">RTL
+
+    <p>Suppress by severity:
+    <input type="radio" name="severity-filtering" value="on"> From level <input
+    id="severity" type="text" size="2">
+    <input type="radio" name="severity-filtering" value="off"> Off
+
+    <p>
+    <button id="run">Check Page</button>
+
+    <div id="bookmarklet-section">
+      Bookmarklet link (<a id="show-bookmarklet-help" href="#">what's this?</a>)
+      that runs BidiChecker with these settings:
+      <a id="bookmarklet">BidiChecker</a>
+    </div>
+  </body>
+</html>
+
diff --git a/samples/reviews/reviews_closure_test.html b/samples/reviews/reviews_closure_test.html
index c6e063d..5569153 100644
--- a/samples/reviews/reviews_closure_test.html
+++ b/samples/reviews/reviews_closure_test.html
@@ -68,7 +68,8 @@
 
   // Run BidiChecker on the application's element. (To run it on the entire web
   // page, use document.body instead of testDiv.)
-  var errors = bidichecker.checkPage(/* shouldBeRtl= */ false, testDiv);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(/* shouldBeRtl= */ false, testDiv);
 
   // No BiDi errors should be found.
   assertArrayEquals([], errors);
@@ -92,7 +93,8 @@
   app.render();
 
   // Run BidiChecker on the application's element.
-  var errors = bidichecker.checkPage(/* shouldBeRtl= */ true, testDiv);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(/* shouldBeRtl= */ true, testDiv);
 
   // No BiDi errors should be found.
   assertArrayEquals([], errors);
@@ -122,7 +124,8 @@
   // text" errors in the reviews panel.
   var filters = [ bidichecker.FilterFactory.type('Undeclared LTR text').and(
                       bidichecker.FilterFactory.locationId('reviews')) ];
-  var errors = bidichecker.checkPage(/* shouldBeRtl= */ true, testDiv, filters);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(/* shouldBeRtl= */ true, testDiv, filters);
 
   // No unexpected BiDi errors should be found.
   assertArrayEquals([], errors);
@@ -149,10 +152,10 @@
   // As before, we'll filter out the known BiDi errors; specifically,
   // "undeclared RTL text" errors in the reviews panel. This time, we'll try
   // the XPath-based filter.
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
   var filters = [ bidichecker.FilterFactory.type('Undeclared RTL text').and(
       bidichecker.FilterFactory.locationXpath('id("reviews")/*')) ];
-  var errors =
-      bidichecker.checkPage(/* shouldBeRtl= */ false, testDiv, filters);
+  var errors = checker.checkPage(/* shouldBeRtl= */ false, testDiv, filters);
 
   // No unexpected BiDi errors should be found.
   assertArrayEquals([], errors);
@@ -189,12 +192,11 @@
 
   // Run BidiChecker on the application's element.
   // We know this is buggy, so the error list will be non-empty.
-  var errors = bidichecker.checkPage(/* shouldBeRtl= */ true, testDiv);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(/* shouldBeRtl= */ true, testDiv);
 
   // Run the in-browser error GUI.
-  if (errors.length != 0) {
-    bidichecker.runGui(errors);
-  }
+  checker.runGui();
 
   // This assertion would fail!
 //  assertArrayEquals([], errors);
diff --git a/samples/reviews/reviews_packaged_test.html b/samples/reviews/reviews_packaged_test.html
index fe323d2..d7e8a6d 100644
--- a/samples/reviews/reviews_packaged_test.html
+++ b/samples/reviews/reviews_packaged_test.html
@@ -60,7 +60,8 @@
 
   // Run BidiChecker on the application's element. (To run it on the entire web
   // page, use document.body instead of testDiv.)
-  var errors = bidichecker.checkPage(/* shouldBeRtl= */ false, testDiv);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(/* shouldBeRtl= */ false, testDiv);
 
   // No BiDi errors should be found.
   assertArrayEquals([], errors);
@@ -85,7 +86,8 @@
   app.render();
 
   // Run BidiChecker on the application's element.
-  var errors = bidichecker.checkPage(/* shouldBeRtl= */ true, testDiv);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(/* shouldBeRtl= */ true, testDiv);
 
   // No BiDi errors should be found.
   assertArrayEquals([], errors);
@@ -114,9 +116,10 @@
   // We know this is buggy, but we're not ready to fix it yet, so we'll filter
   // out the known BiDi errors. Specifically, we'll filter out "undeclared LTR
   // text" errors in the reviews panel.
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
   var filters = [ bidichecker.FilterFactory.type('Undeclared LTR text').and(
                       bidichecker.FilterFactory.locationId('reviews')) ];
-  var errors = bidichecker.checkPage(/* shouldBeRtl= */ true, testDiv, filters);
+  var errors = checker.checkPage(/* shouldBeRtl= */ true, testDiv, filters);
 
   // No unexpected BiDi errors should be found.
   assertArrayEquals([], errors);
@@ -144,10 +147,10 @@
   // As before, we'll filter out the known BiDi errors; specifically,
   // "undeclared RTL text" errors in the reviews panel. This time, we'll try
   // the XPath-based filter.
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
   var filters = [ bidichecker.FilterFactory.type('Undeclared RTL text').and(
       bidichecker.FilterFactory.locationXpath('id("reviews")/*')) ];
-  var errors =
-      bidichecker.checkPage(/* shouldBeRtl= */ false, testDiv, filters);
+  var errors = checker.checkPage(/* shouldBeRtl= */ false, testDiv, filters);
 
   // No unexpected BiDi errors should be found.
   assertArrayEquals([], errors);
@@ -164,9 +167,11 @@
 // The function name is chosen to be last alphabetically so it's run last and
 // its results remain in the browser.
 //
-// In practice, you probably wouldn't run the GUI from an automated test suite,
-// but you might activate it manually for specific tests that are failing for
-// unclear reasons.
+// In practice, if you want to run the GUI from an automated test suite, you
+// should generally organize the tests so that each test page has just one test.
+// Otherwise, after one test has found an error, another test on the page may
+// modify or even remove the part of the DOM where the first test found the
+// error, making it impossible for the GUI to display the error.
 function testReviews_RunGui() {
   // Reviews data to display - all in English.
   var reviewsData = [
@@ -185,12 +190,11 @@
 
   // Run BidiChecker on the application's element.
   // We know this is buggy, so the error list will be non-empty.
-  var errors = bidichecker.checkPage(/* shouldBeRtl= */ true, testDiv);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(/* shouldBeRtl= */ true, testDiv);
 
   // Run the in-browser error GUI.
-  if (errors.length != 0) {
-    bidichecker.runGui(errors);
-  }
+  checker.runGui();
 
   // This assertion would fail!
 //  assertArrayEquals([], errors);
diff --git a/src/allTests.html b/src/allTests.html
index f4d5990..54a1c3f 100644
--- a/src/allTests.html
+++ b/src/allTests.html
@@ -11,11 +11,20 @@
   <head>
     <title>BidiChecker - Test All Units</title>
 
+    <style>
+      .warning {
+      font-size: 14px;
+      font-weight: bold;
+      width: 80%;
+      }
+    </style>
+
     <!-- All *_test.html files to be tested. -->
     <script type="text/javascript">
       window.allTestFiles = [
           'bidichecker_test.html',
           'bidichecker_packaged_test.html',
+          'bookmarklet_test.html',
           'dirchunk_test.html',
           'dirchunk_test.html',
           'dirchunkwalker_test.html',
@@ -23,10 +32,13 @@
           'error_test.html',
           'errorcollector_test.html',
           'filterfactory_test.html',
+          'gui/common/commchannel_test.html',
+          'gui/server/guiserver_test.html',
           'highlightableelement_test.html',
           'highlightabletext_test.html',
           'overalldirectionalitydetector_test.html',
           'spilloverdetector_test.html',
+          'undeclaredfielddetector_test.html',
           'undeclaredtextdetector_test.html',
           'utils_test.html'
           ];
@@ -38,6 +50,7 @@
     <!-- Include the closure multi-test runner. -->
     <script type="text/javascript">
       goog.require('goog.testing.MultiTestRunner');
+      goog.require('goog.userAgent.product');
     </script>
     <link rel="stylesheet"
           href="../third_party/closure-library/closure/goog/css/multitestrunner.css" type="text/css">
@@ -48,15 +61,25 @@
     </script>
   </head>
 
-  <!-- Start the runner and render it. -->
-  <body onload='runner.start();'>
+  <body>
+    <script>
+      if (goog.userAgent.product.CHROME &&
+      window.location.toString().indexOf('file:') == 0) {
+      document.write(
+      '<div class="warning">' +
+        'WARNING: Due to Chrome\'s security restrictions ' +
+        'this test will not be able to load files off your local disk ' +
+        'unless you start Chrome with:<br>' +
+        '<code>--allow-file-access-from-files<\/code><\/div><br>');
+      }
+    </script>
+
     <h1>Test All Units</h1>
 
     <script type="text/javascript">
       runner.render();
+      runner.start();
     </script>
 
-    <!-- Add any elements required by the production code.  -->
-
   </body>
 </html>
diff --git a/src/bidichecker.js b/src/bidichecker.js
index c1f0aee..1bed360 100644
--- a/src/bidichecker.js
+++ b/src/bidichecker.js
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 /**
- * @fileoverview Testing utilities to check a web page for BiDi-related errors.
+ * @fileoverview Class which checks a web page for bidi-related errors.
  * This file has the top-level entry points for use as a Javascript API, along
  * with JSON-based interface functions meant to be called from an external
  * testing framework like WebDriver.
@@ -21,22 +21,137 @@
 
 
 goog.provide('bidichecker');
+goog.provide('bidichecker.BidiChecker');
+goog.provide('bidichecker.Revision');
 
 goog.require('bidichecker.Error');
-goog.require('bidichecker.ErrorGui');
 goog.require('bidichecker.Filter');
 goog.require('bidichecker.FilterFactory');
 goog.require('bidichecker.TextErrorScanner');
+goog.require('bidichecker.gui.server.GuiContainerFactory');
+goog.require('bidichecker.gui.server.GuiServer');
 goog.require('goog.array');
 goog.require('goog.i18n.bidi');
 goog.require('goog.json');
+goog.require('goog.userAgent.product');
+
+
+/**
+ * A class representing a revision of the BidiChecker checks. Higher revisions
+ * indicate later releases, which check for more error situations.
+ * @param {number} revision The revision number.
+ * @constructor
+ */
+bidichecker.Revision = function(revision) {
+  /**
+   * @type {number}
+   */
+  this.revision = revision;
+};
+
+
+/**
+ * Currently the default revision, for backwards-compatibility with existing
+ * user tests that did not specify an explicit revision. Includes checks for
+ * overall page directionality, undeclared opposite-directionality inline text,
+ * and "spillover" which causes garbling of numbers following declared opposite-
+ * directionality text.
+ * <p>This revision is no longer recommended and will be deprecated. Tests
+ * should use {@code REVISION_2}.
+ * @type {!bidichecker.Revision}
+ * @export
+ */
+bidichecker.REVISION_1 = new bidichecker.Revision(1);
+
+
+/**
+ * Currently the latest revision. Adds checks for undeclared opposite-
+ * directionality text attributes such as input values and tooltip text.
+ * @type {!bidichecker.Revision}
+ * @export
+ */
+bidichecker.REVISION_2 = new bidichecker.Revision(2);
+
+
+/**
+ * Always points to the latest revision. Automated tests should avoid using
+ * this, as it means that newly-added checks will cause the automated tests to
+ * fail.
+ * @type {!bidichecker.Revision}
+ * @export
+ */
+bidichecker.LATEST = bidichecker.REVISION_2;
+
+
+
+
+/**
+ * Entry point of the GUI web application.
+ * @const
+ * @type {string}
+ * @private
+ */
+bidichecker.GUI_APP_URL_ =
+    'https://bidichecker.googlecode.com/svn/trunk/lib/gui-app/errorpage.html';
+
+
+/**
+ * Default location of the precompiled bidichecker package.
+ * @const
+ * @type {string}
+ * @private
+ */
+bidichecker.PACKAGE_URL_ =
+    'https://bidichecker.googlecode.com/svn/trunk/lib/bidichecker_packaged.js';
+
+
+/**
+ * Class which checks a web page for bidi-related errors. The preferred way to
+ * invoke BidiChecker is by constructing an instance of this class. The previous
+ * API, based on static methods, is no longer recommended and will be
+ * deprecated.
+ * @param {!bidichecker.Revision} revision Revision of BidiChecker checks to
+ *     run.
+ * @export
+ * @constructor
+ */
+bidichecker.BidiChecker = function(revision) {
+  /**
+   * @type {!bidichecker.Revision}
+   * @private
+   */
+  this.revision_ = revision;
+
+  /**
+   * The errors reported by the last call to {@code checkPage()}.
+   * @type {!Array.<!bidichecker.Error>}
+   * @private
+   */
+  this.errors_ = [];
+
+};
+
+
+/**
+ * A static instance of BidiChecker, for use by an external interface.
+ * @type {bidichecker.BidiChecker}
+ * @export
+ */
+bidichecker.instance = null;
+
+
+/**
+ * Root path for the GUI application.
+ * @type {string}
+ * @private
+ */
+bidichecker.BidiChecker.prototype.guiAppUrl_ = bidichecker.GUI_APP_URL_;
 
 
 /**
  * Checks the contents of the current web page, including all nested frames, for
- * BiDi-related errors. If {@code opt_element} is specified, checks only within
- * the given element of the DOM (including any nested frames). This is the main
- * entry point for the Javascript API.
+ * bidi-related errors. If {@code opt_element} is specified, checks only within
+ * the given element of the DOM (including any nested frames).
  * @param {boolean} shouldBeRtl Is the root expected to be right-to-left?
  * @param {Element=} opt_element The root element of the DOM subtree to be
  *     checked; if null, checks the entire current web page.
@@ -45,16 +160,22 @@
  *     checks.
  * @export
  */
-bidichecker.checkPage = function(shouldBeRtl, opt_element, opt_filters) {
-  bidichecker.Error.clearHighlightableAreas();
-  // {@top.document.body} always finds the top level of the current page, even
-  // if we started within a frame.
-  var element = (/** @type {!Element} */ opt_element || top.document.body);
+bidichecker.BidiChecker.prototype.checkPage = function(shouldBeRtl, opt_element,
+    opt_filters) {
   var expectedDir =
       shouldBeRtl ? goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR;
-  var scanner = new bidichecker.TextErrorScanner(opt_filters);
-  scanner.scan(element, expectedDir);
-  return scanner.getErrors();
+  // {@top.document.body} always finds the top level of the current page, even
+  // if we started within a frame.
+  var nonNullElement =
+      (/** @type {!Element} */ opt_element || top.document.body);
+  var filters = opt_filters || [];
+
+  bidichecker.Error.clearHighlightableAreas();
+  var scanner =
+      new bidichecker.TextErrorScanner(this.revision_.revision, filters);
+  scanner.scan(nonNullElement, expectedDir);
+  this.errors_ = scanner.getErrors();
+  return goog.array.clone(this.errors_);
 };
 
 
@@ -62,46 +183,256 @@
  * JSON interface to {@code checkPage}.
  * @param {boolean} shouldBeRtl Is the element/page expected to be
  *     right-to-left?
- * @param {Element=} opt_element The root element of the DOM subtree to be
- *     checked; if null, checks the entire current web page.
- * @param {string=} opt_filtersJson Error suppression filters in a JSON string.
+ * @param {Element} element The root element of the DOM subtree to be checked;
+ *     if null, checks the entire current web page.
+ * @param {string} filtersJson Error suppression filters in a JSON string,
+ *     representing a (possibly-empty) array of filter objects.
  * @return {string} Array of {@code bidichecker.Error} objects for all failing
  *     checks, in JSON format. If no errors were found, returns an empty array
  *     ("[]").
  * @export
  */
-bidichecker.checkPageToJson = function(shouldBeRtl, opt_element,
-                                       opt_filtersJson) {
-  var filters = bidichecker.FilterFactory.readFiltersFromJson(opt_filtersJson);
-  var errors = bidichecker.checkPage(shouldBeRtl, opt_element, filters);
+bidichecker.BidiChecker.prototype.checkPageToJson = function(shouldBeRtl,
+    element, filtersJson) {
+  var filters = bidichecker.FilterFactory.readFiltersFromJson(filtersJson);
+  filters = filters || [];
+  var errors = this.checkPage(shouldBeRtl, element, filters);
   return bidichecker.Error.serialize(errors);
 };
 
 
 /**
- * Runs the interactive visual error browsing mode.
- * @param {Array.<!bidichecker.Error>} errors An array of errors to be
- *     displayed.
+ * Sets the location of the GUI files.
+ * @param {string} guiAppUrl Location of the GUI files.
  * @export
  */
-bidichecker.runGui = function(errors) {
-  var gui = new bidichecker.ErrorGui(errors);
-  gui.launch();
+bidichecker.BidiChecker.prototype.setGuiAppUrl = function(guiAppUrl) {
+  this.guiAppUrl_ = guiAppUrl;
 };
 
 
 /**
- * JSON interface to {@code runGui}.
- * @param {string} errorsJson An array of errors to be displayed, in JSON
- *     format (similar to that produced by {@code checkPageJson()}).
+ * Runs the interactive visual error browsing GUI, displaying the errors
+ * reported by the last call to {@code checkPage()}. Calling {@code runGui()}
+ * before {@code checkPage()} is not supported (and is a no-op). If a GUI opened
+ * by any prior BidiChecker call in this window is still open, it will be closed
+ * and then re-opened.
+ * On IE versions 8 and above, the GUI will always be displayed in an in-page
+ * dialog box, regardless of the value of opt_noPopup.
+ * On earlier versions of IE, the GUI will not be displayed. An error message
+ * will be displayed instead.
+ * @param {boolean=} opt_noPopup Disables opening the error browser in a popup
+ *     window.
  * @export
  */
-bidichecker.runGuiFromJson = function(errorsJson) {
-  var bareErrors = (/** @type {Array.<!Object>} */ goog.json.parse(errorsJson));
+bidichecker.BidiChecker.prototype.runGui = function(opt_noPopup) {
+  if (this.errors_.length == 0) {
+    return;
+  }
+  this.runGuiWithErrors_(this.errors_, opt_noPopup);
+};
 
-  /** @type {Array.<!bidichecker.Error>} */
-  var errors = goog.array.map(bareErrors, function(bareError) {
-    return new bidichecker.Error(bareError);
-  });
-  bidichecker.runGui(errors);
+
+/**
+ * Runs the interactive visual error browsing GUI, displaying the given errors.
+ * If a GUI opened by any prior BidiChecker call in this window is still open,
+ * it will be closed and then re-opened.
+ * On IE versions 8 and above, the GUI will always be displayed in an in-page
+ * dialog box, regardless of the value of opt_noPopup.
+ * On earlier versions of IE, the GUI will not be displayed. An error message
+ * will be displayed instead.
+ * @param {!Array.<!bidichecker.Error>} errors Array of error objects to
+ *     display.
+ * @param {boolean=} opt_noPopup Disables opening the error browser in a popup
+ *     window.
+ * @private
+ */
+bidichecker.BidiChecker.prototype.runGuiWithErrors_ = function(errors,
+    opt_noPopup) {
+  if (goog.userAgent.IE) {
+    if (goog.userAgent.isVersion('8')) {
+      // IE version 8 and up, force dialog to be used.
+      opt_noPopup = true;
+    } else {
+      // IE before version 8, display error and quit.
+      var guiContainer =
+          bidichecker.gui.server.GuiContainerFactory.createFromScratch(true);
+      var msg = 'Sorry, bidichecker GUI is not supported in Internet ' +
+          'Explorer before version 8.';
+      guiContainer.getContentWindow().document.write(msg);
+      return;
+    }
+  }
+
+  var guiContainer =
+      bidichecker.gui.server.GuiContainerFactory.createFromScratch(opt_noPopup);
+  var server = new bidichecker.gui.server.GuiServer(this, {}, guiContainer,
+      this.guiAppUrl_, errors);
+  // This disposes of the last GuiServer created by BidiChecker for this window,
+  // which disposes of the GuiContainer created for it, which closes the GUI.
+  bidichecker.gui.server.GuiServer.startServer(server);
+};
+
+
+/**
+ * Runs the bookmarklet GUI with a given set of initial options. If a GUI opened
+ * by any prior BidiChecker call in this window is still open, it will be closed
+ * and then re-opened.
+ * On IE the given window is closed, and the GUI is opened in an in-page dialog.
+ * (This is relevant only for IE versions 9 and up, as the bookmarklet doesn't
+ * work on earlier versions of IE, due to URL length and other restrictions).
+ * @param {Object.<string, Object>} options The initial options.
+ *     Options are specified as an object with the following (optional) keys:
+ *     <ul>
+ *     <li>dir -- string, "rtl" or "ltr" (the default). The expected page
+ *     directionality.
+ *     <li>severity -- The severity level from which to suppress error messages,
+ *     or -1 (for no severity filtering). Default 4.
+ *     </ul>
+ * @param {Window} hostWindow The underlying browser window object
+ *     to be used by the GUI, as returned by window.open, or null to have the
+ *     function open a new window itself. If non-null, the window should be
+ *     empty. Do not pass null when calling this function in an onload handler
+ *     because pop-up blockers will not let it open a window.
+ * @param {string=} opt_guiAppUrl Location of the GUI files.
+ * @export
+ */
+bidichecker.runBookmarkletGui = function(options, hostWindow, opt_guiAppUrl) {
+  var checker = new bidichecker.BidiChecker(bidichecker.LATEST);
+  var guiContainer;
+  if (goog.userAgent.IE) {
+    if (hostWindow) {
+      hostWindow.close();
+    }
+    guiContainer =
+        bidichecker.gui.server.GuiContainerFactory.createFromScratch(true);
+  } else {
+    guiContainer =
+        bidichecker.gui.server.GuiContainerFactory.createFromWindow(hostWindow);
+  }
+  var server = new bidichecker.gui.server.GuiServer(checker, options,
+      guiContainer, opt_guiAppUrl || bidichecker.GUI_APP_URL_);
+  bidichecker.gui.server.GuiServer.startServer(server);
+};
+
+
+/**
+ * Generates a BidiChecker bookmarklet. This is a javascript: url that loads the
+ * BidiChecker package and activates the options page.
+ * @param {!Object.<string, !Object>} options The options that the options page
+ *     will be initially populated with. See OptionsPage constructor
+ *     documentation for more information.
+ * @param {string=} opt_scriptUrl Location of the BidiChecker package. Used to
+ *     install the GUI server. Must not include characters that have special
+ *     meaning inside JavaScript strings.
+ * @param {string=} opt_guiAppUrl Location of the GUI application. Must not
+ *     include characters that have special meaning inside JavaScript strings.
+ * @return {string} The generated link.
+ * @export
+ */
+bidichecker.generateBookmarklet = function(options, opt_scriptUrl,
+    opt_guiAppUrl) {
+  var scriptUrl = opt_scriptUrl || bidichecker.PACKAGE_URL_;
+  var guiAppUrl = opt_guiAppUrl || bidichecker.GUI_APP_URL_;
+
+  var template = 'javascript:' +
+    '(function() {' +
+      'function run() {' +
+        'bidichecker.runBookmarkletGui(%OPTIONS%, ' +
+            'g_bidicheckerBookmarkletGuiWnd, "%APPURL%");' +
+      '}' +
+      // The window object for the last opened window. Make sure the variable is
+      // defined.
+      'if (typeof g_bidicheckerBookmarkletGuiWnd == "undefined") {' +
+        'g_bidicheckerBookmarkletGuiWnd = null;' +
+      '}' +
+      'if (g_bidicheckerBookmarkletGuiWnd &&' +
+          '!g_bidicheckerBookmarkletGuiWnd.closed) {' +
+        // If the window is already open, there's nothing more for us to do.
+        'g_bidicheckerBookmarkletGuiWnd.focus();' +
+      '} else {' +
+        // Open a new window. Must be done as an immediate result of the
+        // bookmarklet being activated, not in the onload event; otherwise it
+        // may be blocked by the popup blocker.
+        'g_bidicheckerBookmarkletGuiWnd = window.open("about:blank", ' +
+          '"_blank", "width=1,height=1,resizable=yes,scrollbars=yes");' +
+        // ID of the element used to hold the script.
+        'var scriptElemId = "_bidichecker_bookmarklet";' +
+        // Load the script if we haven't done so already.
+        'if (document.getElementById(scriptElemId)) {' +
+          // Script element already exists. It doesn't mean that the script has
+          // been loaded yet, though, so check that bidichecker exists before
+          // proceeding. (We could probably just go ahead without checking, as
+          // normally JavaScript errors are silently ignored, but the page may
+          // have installed an error handler.)
+          'if (window.bidichecker) {' +
+            'run();' +
+          '}' +
+        '} else {' +
+          // Add script to document and call it when it's loaded.
+          'var elem = document.createElement("script");' +
+          'elem.src = "%SCRIPTURL%";' +
+          'elem.onload = run;' +
+          'elem.id = scriptElemId;' +
+          'document.getElementsByTagName("head")[0].appendChild(elem);' +
+        '}' +
+      '}' +
+    '})()';
+
+  // Substitute actual values in template. "$" is a meta character in the
+  // replace() method, so we need to escape it.
+  var optionsStr = goog.json.serialize(options).replace(/\$/g, '$$$$');
+  return template.replace('%SCRIPTURL%', scriptUrl)
+      .replace('%APPURL%', guiAppUrl)
+      .replace('%OPTIONS%', optionsStr);
+};
+
+
+/**
+ * Checks the contents of the current web page, including all nested frames, for
+ * bidi-related errors. If {@code opt_element} is specified, checks only within
+ * the given element of the DOM (including any nested frames).
+ * <p>This used to be the main entry point for the Javascript API. It is now
+ * deprecated, and is here only for compatibility with any bookmarklets created
+ * by users before the class-based API was introduced. All other code should
+ * instead construct an instance of {@code bidichecker.BidiChecker} and call its
+ * {@code checkPage()} instance method.
+ * @param {boolean} shouldBeRtl Is the root expected to be right-to-left?
+ * @param {Element=} opt_element The root element of the DOM subtree to be
+ *     checked; if null, checks the entire current web page.
+ * @param {Array.<!bidichecker.Filter>=} opt_filters Error suppression filters.
+ * @return {!Array.<!bidichecker.Error>} Array of error objects for all failing
+ *     checks.
+ * @export
+ * @deprecated Use the checkPage() instance method of the BidiChecker class.
+ */
+bidichecker.checkPage = function(shouldBeRtl, opt_element, opt_filters) {
+  var checker = new bidichecker.BidiChecker(bidichecker.LATEST);
+  return checker.checkPage(shouldBeRtl, opt_element, opt_filters);
+};
+
+
+/**
+ * Runs the interactive visual error browsing GUI. If a GUI opened by any prior
+ * BidiChecker call in this window is still open, it will be closed and then
+ * re-opened.
+ * <p>This entry point is deprecated, and is here only for compatibility with
+ * any bookmarklets created by users before the class-based API was introduced.
+ * All other code should instead construct an instance of
+ * {@code bidichecker.BidiChecker} and call its {@code checkPage()} and
+ * {@code runGui()} instance methods.
+ * @param {!Array.<!bidichecker.Error>} errors An array of errors to be
+ *     displayed.
+ * @param {boolean=} opt_noPopup Disables opening the error browser in a popup
+ *     window.
+ * @param {string=} opt_guiAppUrl Location of the GUI files.
+ * @export
+ * @deprecated Use the runGui() instance method of the BidiChecker class.
+ */
+bidichecker.runGui = function(errors, opt_noPopup, opt_guiAppUrl) {
+  var checker = new bidichecker.BidiChecker(bidichecker.LATEST);
+  if (opt_guiAppUrl) {
+    checker.setGuiAppUrl(opt_guiAppUrl);
+  }
+  checker.runGuiWithErrors_(errors, opt_noPopup);
 };
diff --git a/src/bidichecker_packaged_test.html b/src/bidichecker_packaged_test.html
index 1809b27..0f2b05e 100644
--- a/src/bidichecker_packaged_test.html
+++ b/src/bidichecker_packaged_test.html
@@ -77,7 +77,8 @@
   document.body.appendChild(testDiv);
 
   testDiv.innerHTML = '<p><span dir=\'rtl\'>friends<\/span>5,012.7 meters<\/p>';
-  var errors = bidichecker.checkPage(true, testDiv);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_1);
+  var errors = checker.checkPage(true, testDiv);
 
   var expected = [{'type': 'Overall directionality not RTL',
                    'severity': 1},
@@ -106,7 +107,8 @@
   testDiv.innerHTML = '<p><span dir=\'rtl\'>friends<\/span>5,012.7 meters<\/p>';
 
   var filters = [bidichecker.FilterFactory.atText('friends')];
-  var errors = bidichecker.checkPage(true, testDiv, filters);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_1);
+  var errors = checker.checkPage(true, testDiv, filters);
 
   var expected = [{'type': 'Overall directionality not RTL',
                    'severity': 1},
@@ -129,7 +131,8 @@
   testDiv.innerHTML =
     '<p><span dir=\'rtl\' id=\'my_id\' >friends<\/span>5,012.7 meters<\/p>';
   var filters = [bidichecker.FilterFactory.locationId('my_id')];
-  var errors = bidichecker.checkPage(true, testDiv, filters);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_1);
+  var errors = checker.checkPage(true, testDiv, filters);
 
   var expected = [{'type': 'Overall directionality not RTL',
                    'severity': 1},
@@ -152,7 +155,8 @@
     '<p><span dir=\'rtl\' id=\'my_id\' >friends<\/span>5,012.7 meters<\/p>';
   var filters = [bidichecker.FilterFactory.locationId('my_id').and(
                     bidichecker.FilterFactory.atText('friends'))];
-  var errors = bidichecker.checkPage(true, testDiv, filters);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_1);
+  var errors = checker.checkPage(true, testDiv, filters);
 
   var expected = [{'type': 'Overall directionality not RTL',
                    'severity': 1},
diff --git a/src/bidichecker_test.html b/src/bidichecker_test.html
index 8bce0a1..4e92912 100644
--- a/src/bidichecker_test.html
+++ b/src/bidichecker_test.html
@@ -34,23 +34,59 @@
 function testBidiChecker_CheckPageRunsAllCheckers() {
   var testDiv = goog.dom.createDom('div', {'id': 'test'});
   goog.dom.appendChild(document.body, testDiv);
-  testDiv.innerHTML = '<p><span dir=\'rtl\'>friends<\/span>5,012.7 meters<\/p>';
-  var errors = bidichecker.checkPage(true, testDiv);
+  testDiv.innerHTML =
+      '<p><span dir=\'rtl\'>friends<\/span>5,012.7 meters<\/p>' +
+      '<p dir=\'rtl\'><textarea>Some LTR text.<\/textarea><\/p>';
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(true, testDiv);
+  var expected = [
+      {'type': 'Overall directionality not RTL',
+       'severity': 1},
 
-  var expected = [{'type': 'Overall directionality not RTL',
-                   'severity': 1},
+      {'type': 'Undeclared LTR text',
+       'atText': 'friends',
+       'severity': 4,
+       'locationDescription': '<div id=\'test\'><p><span dir=\'rtl\'>'},
 
-                  {'type': 'Undeclared LTR text',
-                   'atText': 'friends',
-                   'severity': 4,
-                   'locationDescription':
-                       '<div id=\'test\'><p><span dir=\'rtl\'>'},
+      {'type': 'Declared RTL spillover to number',
+       'atText': '5,012.7',
+       'precededByText': 'friends',
+       'severity': 2,
+       'locationDescription': '<div id=\'test\'><p>'},
 
-                  {'type': 'Declared RTL spillover to number',
-                   'atText': '5,012.7',
-                   'precededByText': 'friends',
-                   'severity': 2,
-                   'locationDescription': '<div id=\'test\'><p>'}];
+      {'type': 'Undeclared LTR textarea value',
+       'severity': 1,
+       'atText': 'Some LTR text.',
+       'locationDescription': '<div id=\'test\'><p dir=\'rtl\'><textarea>'}
+  ];
+  assertErrorFields(expected, errors);
+}
+
+
+function testBidiChecker_CheckPageRunsAllCheckersForOldRevision() {
+  var testDiv = goog.dom.createDom('div', {'id': 'test'});
+  goog.dom.appendChild(document.body, testDiv);
+  testDiv.innerHTML =
+      '<p><span dir=\'rtl\'>friends<\/span>5,012.7 meters<\/p>' +
+      '<p dir=\'rtl\'><textarea>Some LTR text.<\/textarea><\/p>';
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_1);
+  var errors = checker.checkPage(true, testDiv);
+
+  var expected = [
+      {'type': 'Overall directionality not RTL',
+       'severity': 1},
+
+      {'type': 'Undeclared LTR text',
+       'atText': 'friends',
+       'severity': 4,
+       'locationDescription': '<div id=\'test\'><p><span dir=\'rtl\'>'},
+
+      {'type': 'Declared RTL spillover to number',
+       'atText': '5,012.7',
+       'precededByText': 'friends',
+       'severity': 2,
+       'locationDescription': '<div id=\'test\'><p>'}
+  ];
   assertErrorFields(expected, errors);
 }
 
@@ -91,35 +127,39 @@
   iframe3Doc.close();
 
   // 5. Run BidiChecker on the top-level page.
-  var errors = bidichecker.checkPage(true, testDiv);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(true, testDiv);
 
-  var expected = [{'type': 'Undeclared LTR text',
-                   'atText': 'Shalom',
-                   'severity': 3,
-                   'locationDescription': '<div dir=\'rtl\' id=\'test\'><p>'},
+  var expected =
+      [{'type': 'Undeclared LTR text',
+        'atText': 'Shalom',
+        'severity': 3,
+        'locationDescription': '<div dir=\'rtl\' id=\'test\'><p>'},
 
-                  {'type': 'Undeclared LTR text',
-                   'atText': 'hello world',
-                   'severity': 4,
-                   'locationDescription':
-                       '<body><p dir=\'rtl\'> in <iframe id=\'iframe1\'>'},
+       {'type': 'Undeclared LTR text',
+        'atText': 'hello world',
+        'severity': 4,
+        'locationDescription':
+            '<p dir=\'rtl\'> in ' +
+            '<div dir=\'rtl\' id=\'test\'><iframe id=\'iframe1\'>'},
 
-                  {'type': 'Undeclared LTR text',
-                   'atText': 'Hi',
-                   'followedByText': '!',
-                   'severity': 4,
-                   'locationDescription':
-                       '<body><p dir=\'rtl\'> in <iframe id=\'iframe2\'>'},
+       {'type': 'Undeclared LTR text',
+        'atText': 'Hi',
+        'followedByText': '!',
+        'severity': 4,
+        'locationDescription':
+            '<p dir=\'rtl\'> in ' +
+            '<div dir=\'rtl\' id=\'test\'><iframe id=\'iframe2\'>'},
 
-                  {'type': 'Undeclared LTR text',
-                   'atText': 'In a nested iframe',
-                   'followedByText': '!',
-                   'severity': 4,
-                   'locationDescription':
-                       '<p dir=\'rtl\' id=\'para\'> in ' +
-                       '<iframe id=\'iframe_nested\'> in ' +
-                       '<iframe id=\'iframe2\'>'}
-                   ];
+       {'type': 'Undeclared LTR text',
+        'atText': 'In a nested iframe',
+        'followedByText': '!',
+        'severity': 4,
+        'locationDescription':
+            '<p dir=\'rtl\' id=\'para\'> in ' +
+            '<iframe id=\'iframe_nested\'> in ' +
+            '<div dir=\'rtl\' id=\'test\'><iframe id=\'iframe2\'>'}
+      ];
   assertErrorFields(expected, errors);
 }
 
@@ -141,7 +181,8 @@
   iframeDoc.close();
 
   // 3. Run BidiChecker on the top-level page, expecting RTL directionality.
-  var errors = bidichecker.checkPage(true, testDiv);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(true, testDiv);
 
   // 4. Only expect an error at the top level.
   var expected = [{'type': 'Overall directionality not RTL',
@@ -156,7 +197,8 @@
   testDiv.innerHTML = '<p><span dir=\'rtl\'>friends<\/span>5,012.7 meters<\/p>';
 
   var filters = [bidichecker.FilterFactory.atText('friends')];
-  var errors = bidichecker.checkPage(true, testDiv, filters);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(true, testDiv, filters);
 
   var expected = [{'type': 'Overall directionality not RTL',
                    'severity': 1},
@@ -176,7 +218,8 @@
   testDiv.innerHTML =
     '<p><span dir=\'rtl\' id=\'my_id\' >friends<\/span>5,012.7 meters<\/p>';
   var filters = [bidichecker.FilterFactory.locationId('my_id')];
-  var errors = bidichecker.checkPage(true, testDiv, filters);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(true, testDiv, filters);
 
   var expected = [{'type': 'Overall directionality not RTL',
                    'severity': 1},
@@ -192,47 +235,50 @@
 
 function testBidiChecker_XpathFilterNotCachedAcrossCalls() {
   // Onlyl run this test if the browser supports XPaths.
-  // TODO(elbaum): Remove the condition block when XPath is fully supported.
-  if (document.evaluate) {
-    var testDiv = goog.dom.createDom('div', {'id': 'test'});
-    goog.dom.appendChild(document.body, testDiv);
-    testDiv.innerHTML =
+  // TODO(user): Remove the condition block when XPath is fully supported.
+  if (!document.evaluate) {
+    return;
+  }
+
+  var testDiv = goog.dom.createDom('div', {'id': 'test'});
+  goog.dom.appendChild(document.body, testDiv);
+  testDiv.innerHTML =
       '<p><span dir=\'rtl\' id=\'my_id\' >friends<\/span>5,012.7 meters<\/p>';
 
-    var filters = [bidichecker.FilterFactory.locationXpath('id("my_id")')];
-    var errors = bidichecker.checkPage(true, testDiv, filters);
+  var filters = [bidichecker.FilterFactory.locationXpath('id("my_id")')];
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(true, testDiv, filters);
 
-    var expected = [{'type': 'Overall directionality not RTL',
-                     'severity': 1},
+  var expected = [{'type': 'Overall directionality not RTL',
+                   'severity': 1},
 
-                    {'type': 'Declared RTL spillover to number',
-                     'atText': '5,012.7',
-                     'precededByText': 'friends',
-                     'severity': 2,
-                     'locationDescription': '<div id=\'test\'><p>'}];
-    assertErrorFields(expected, errors);
+                  {'type': 'Declared RTL spillover to number',
+                   'atText': '5,012.7',
+                   'precededByText': 'friends',
+                   'severity': 2,
+                   'locationDescription': '<div id=\'test\'><p>'}];
+  assertErrorFields(expected, errors);
 
-    // Create a new test div containing an element with the same id. If XPath
-    // results are cached across calls to checkPage(), this will fail, since the
-    // cache will still contain the obsolete element.
-    goog.dom.removeNode(testDiv);
-    var testDiv = goog.dom.createDom('div', {'id': 'test'});
-    goog.dom.appendChild(document.body, testDiv);
-    testDiv.innerHTML =
+  // Create a new test div containing an element with the same id. If XPath
+  // results are cached across calls to checkPage(), this will fail, since the
+  // cache will still contain the obsolete element.
+  goog.dom.removeNode(testDiv);
+  var testDiv = goog.dom.createDom('div', {'id': 'test'});
+  goog.dom.appendChild(document.body, testDiv);
+  testDiv.innerHTML =
       '<p><span dir=\'rtl\' id=\'my_id\' align=\'right\'>ends<\/span>5.7<\/p>';
 
-    errors = bidichecker.checkPage(true, testDiv, filters);
+  errors = checker.checkPage(true, testDiv, filters);
 
-    expected = [{'type': 'Overall directionality not RTL',
-                 'severity': 1},
+  expected = [{'type': 'Overall directionality not RTL',
+               'severity': 1},
 
-                {'type': 'Declared RTL spillover to number',
-                 'atText': '5.7',
-                 'precededByText': 'ends',
-                 'severity': 2,
-                 'locationDescription': '<div id=\'test\'><p>'}];
-    assertErrorFields(expected, errors);
-  }
+              {'type': 'Declared RTL spillover to number',
+               'atText': '5.7',
+               'precededByText': 'ends',
+               'severity': 2,
+               'locationDescription': '<div id=\'test\'><p>'}];
+  assertErrorFields(expected, errors);
 }
 
 
@@ -254,7 +300,8 @@
 
   // 3. Run BidiChecker on the top-level page, filtering within the iframe.
   var filters = [bidichecker.FilterFactory.locationId('iframe1')];
-  var errors = bidichecker.checkPage(true, testDiv, filters);
+  var checker = new bidichecker.BidiChecker(bidichecker.REVISION_2);
+  var errors = checker.checkPage(true, testDiv, filters);
 
   // 4. Only expect errors at the top level.
   var expected = [{'type': 'Undeclared LTR text',
@@ -265,6 +312,39 @@
   assertErrorFields(expected, errors);
 }
 
+
+function testBidiChecker_StaticCheckPageRunsAllCheckers() {
+  // This tests the deprecated static checkPage() method.
+  var testDiv = goog.dom.createDom('div', {'id': 'test'});
+  goog.dom.appendChild(document.body, testDiv);
+  testDiv.innerHTML =
+      '<p><span dir=\'rtl\'>friends<\/span>5,012.7 meters<\/p>' +
+      '<p dir=\'rtl\'><textarea>Some LTR text.<\/textarea><\/p>';
+  var errors = bidichecker.checkPage(true, testDiv);
+
+  var expected = [
+      {'type': 'Overall directionality not RTL',
+       'severity': 1},
+
+      {'type': 'Undeclared LTR text',
+       'atText': 'friends',
+       'severity': 4,
+       'locationDescription': '<div id=\'test\'><p><span dir=\'rtl\'>'},
+
+      {'type': 'Declared RTL spillover to number',
+       'atText': '5,012.7',
+       'precededByText': 'friends',
+       'severity': 2,
+       'locationDescription': '<div id=\'test\'><p>'},
+
+      {'type': 'Undeclared LTR textarea value',
+       'severity': 1,
+       'atText': 'Some LTR text.',
+       'locationDescription': '<div id=\'test\'><p dir=\'rtl\'><textarea>'}
+  ];
+  assertErrorFields(expected, errors);
+}
+
     </script>
 
   </body>
diff --git a/src/bookmarklet_test.html b/src/bookmarklet_test.html
new file mode 100644
index 0000000..cbb4ace
--- /dev/null
+++ b/src/bookmarklet_test.html
@@ -0,0 +1,248 @@
+<!DOCTYPE html>
+<html>
+  <!--
+    Copyright 2011 Google Inc. All Rights Reserved.
+
+    Use of this source code is governed by an Apache 2.0 License.
+    See the COPYING file for details.
+  -->
+
+  <!--
+  Unit tests for the generateBookmarklet method.
+  -->
+  <head>
+    <title>bidichecker - Javascript Unit Tests</title>
+    <script type="text/javascript" src="../third_party/closure-library/closure/goog/base.js">
+    </script>
+
+    <!-- Include the generated deps.js which enables goog.require of
+         the modules under test.
+    -->
+    <script type="text/javascript" src="deps.js"></script>
+    <script type="text/javascript">
+goog.require('bidichecker');
+
+goog.require('goog.testing.jsunit');
+goog.require('goog.testing.MockControl');
+goog.require('goog.userAgent.product');
+    </script>
+
+  </head>
+  <body>
+    <script type="text/javascript">
+
+/**
+ * The URLs the bookmarklet will think it's loading. Don't load and run the
+ * actual package. That would be part of an integration test.
+ */
+var SCRIPT_URL = 'http://example.com/bidichecker_packaged.js';
+var GUI_APP_URL = 'http://example.net/gui-app';
+
+/**
+ * An arbitrary set of bidichecker options, just to make sure that the generator
+ * can serialize the options correctly.
+ */
+var OPTIONS = { dir: 'rtl', severity: 2 };
+
+function setUp() {
+  g_mockControl = new goog.testing.MockControl();
+
+  // We want to test a script which loads bidichecker while using bidichecker
+  // ourselves, so rename the bidichecker namespace.
+  g_realBidichecker = bidichecker;
+  delete bidichecker;
+
+  g_mockOpen = g_mockControl.createGlobalFunctionMock('open');
+  var head = document.getElementsByTagName("head")[0];
+  g_mockAppendChild = g_mockControl.createMethodMock(head,
+      'appendChild');
+  g_mockGetElementById = g_mockControl.createMethodMock(document,
+      'getElementById');
+}
+
+function tearDown() {
+  bidichecker = g_realBidichecker;
+  g_mockControl.$tearDown();
+
+  // Delete global window object created by the bookmarklet under test.
+  delete g_bidicheckerBookmarkletGuiWnd;
+
+  delete g_bookmarkletLink;
+  delete g_initialWindowObj;
+  delete g_mockAppendChild;
+  delete g_mockControl;
+  delete g_mockGetElementById;
+  delete g_mockOpen;
+  delete g_mockRunBookmarkletGui;
+  delete g_scriptElem;
+  delete g_realBidichecker;
+}
+
+/**
+ * Adds an expectation for window.open to be called with the initial parameters
+ * for the GUI window.
+ * @return {Object} A mock Window object that will also be returned from the
+ *     window.open call.
+ */
+function expectWindowOpen() {
+  var mockWindowObj = {
+    focus: g_mockControl.createFunctionMock('focus')
+  };
+  g_mockOpen('about:blank', '_blank',
+      'width=1,height=1,resizable=yes,scrollbars=yes')
+    .$returns(mockWindowObj);
+  return mockWindowObj;
+}
+
+/**
+ * Evaluates the given script in the global scope. This is different from the
+ * built-in eval function, which evaluates the script in the caller's scope.
+ * @param {string} script The script to evaluate.
+ */
+function globalEval(script) {
+  if (window.execScript) {
+    // IE and Chrome.
+    window.execScript(script);
+  } else {
+    // Firefox.
+    eval.call(null, script);
+  }
+}
+
+function generateBookmarkletLink() {
+  g_bookmarkletLink = g_realBidichecker.generateBookmarklet(OPTIONS, SCRIPT_URL,
+      GUI_APP_URL);
+}
+
+function runBookmarkletLink() {
+  // Ideally we'd do 'window.location = link' to activate a bookmarklet.
+  // However, the browser handles this assignment only after the function
+  // returns so it wouldn't help us. Instead, we evaluate the contained JS code.
+  // So first extract the script itself from the javascript link.
+  var bookmarkletScript = g_bookmarkletLink.replace(/^javascript:/, "");
+  globalEval(bookmarkletScript);
+}
+
+/**
+ * Verifies that the link is syntactically correct.
+ */
+function testBookmarklet_syntax() {
+  generateBookmarkletLink();
+  assertTrue(/^javascript:/.test(g_bookmarkletLink));
+}
+
+function simulateInitialActivation() {
+  g_mockGetElementById(goog.testing.mockmatchers.isString).$returns(null);
+  g_initialWindowObj = expectWindowOpen();
+  var scriptElemSaver = new goog.testing.mockmatchers.SaveArgument();
+  g_mockAppendChild(scriptElemSaver);
+  g_mockControl.$replayAll();
+  runBookmarkletLink()
+  g_mockControl.$verifyAll();
+  g_mockControl.$resetAll();
+
+  // Retrieve script element that was "added" to the document.
+  g_scriptElem = scriptElemSaver.arg;
+  assertEquals(SCRIPT_URL, g_scriptElem.src);
+}
+
+function simulateScriptLoad(mockWindowObj) {
+  // Pretend that bidichecker was loaded.
+  g_mockRunBookmarkletGui = g_mockControl.createFunctionMock(
+      'runBookmarkletGui');
+  window.bidichecker = {
+    'runBookmarkletGui': g_mockRunBookmarkletGui
+  };
+
+  // Simulate the script load event.
+  g_mockControl.$resetAll();
+  g_mockRunBookmarkletGui(OPTIONS, mockWindowObj, GUI_APP_URL);
+  g_mockControl.$replayAll();
+  g_scriptElem.onload();
+  g_mockControl.$verifyAll();
+  g_mockControl.$resetAll();
+}
+
+function testBookmarklet_activateWhileScriptIsLoading() {
+  // Don't test on IE since the bookmarklet doesn't work there.
+  if (goog.userAgent.product.IE) {
+    return;
+  }
+  generateBookmarkletLink();
+  simulateInitialActivation();
+
+  // If the bookmarklet is activated while the script is loading, it should
+  // bring the new window into focus.
+  g_initialWindowObj.focus();
+  g_mockControl.$replayAll();
+  runBookmarkletLink()
+  g_mockControl.$verifyAll();
+}
+
+function testBookmarklet_activateWhileScriptIsLoadingWithWindowClosed() {
+  // Don't test on IE since the bookmarklet doesn't work there.
+  if (goog.userAgent.product.IE) {
+    return;
+  }
+  generateBookmarkletLink();
+  simulateInitialActivation();
+
+  // If the user closed the window while the script is loading, activating the
+  // bookmarklet should cause a new window to be opened.
+  g_mockGetElementById(goog.testing.mockmatchers.isString)
+      .$returns(g_scriptElem);
+  g_initialWindowObj.closed = true;
+  var newWindowObj = expectWindowOpen();
+  g_mockControl.$replayAll();
+  runBookmarkletLink()
+  g_mockControl.$verifyAll();
+  g_mockControl.$resetAll();
+
+  // When bidichecker is loaded is should use the newly opened window.
+  simulateScriptLoad(newWindowObj);
+}
+
+function testBookmarklet_reactivateAfterScriptLoaded() {
+  // Don't test on IE since the bookmarklet doesn't work there.
+  if (goog.userAgent.product.IE) {
+    return;
+  }
+  generateBookmarkletLink();
+  simulateInitialActivation();
+  simulateScriptLoad(g_initialWindowObj);
+
+  // If the bookmarklet is reactivated, it should bring the existing window into
+  // focus.
+  g_initialWindowObj.focus = g_mockControl.createFunctionMock('focus'),
+  g_initialWindowObj.focus();
+  g_mockControl.$replayAll();
+  runBookmarkletLink()
+  g_mockControl.$verifyAll();
+}
+
+function testBookmarklet_reactivateAfterScriptLoadedWithWindowClosed() {
+  // Don't test on IE since the bookmarklet doesn't work there.
+  if (goog.userAgent.product.IE) {
+    return;
+  }
+  generateBookmarkletLink();
+  simulateInitialActivation();
+  simulateScriptLoad(g_initialWindowObj);
+
+  // If the user closed the window after the script was loaded, activating the
+  // bookmarklet should cause a new window to be opened.
+  g_initialWindowObj.closed = true;
+  g_mockGetElementById(goog.testing.mockmatchers.isString)
+      .$returns(g_scriptElem);
+  var newWindowObj = expectWindowOpen();
+  g_mockRunBookmarkletGui(OPTIONS, newWindowObj, GUI_APP_URL);
+  g_mockControl.$replayAll();
+  runBookmarkletLink()
+  g_mockControl.$verifyAll();
+}
+
+
+    </script>
+
+  </body>
+</html>
diff --git a/src/deps.js b/src/deps.js
index 5541d23..9389c47 100644
--- a/src/deps.js
+++ b/src/deps.js
@@ -1,28 +1,36 @@
-// Copyright 2010 Google Inc.
+// Copyright 2011 Google Inc.
 // All Rights Reserved.
 //
 // This file has been auto-generated by GenJsDeps, please do not edit.
 
-goog.addDependency('../../../../src/bidichecker.js', ['bidichecker'], ['bidichecker.Error', 'bidichecker.ErrorGui', 'bidichecker.Filter', 'bidichecker.FilterFactory', 'bidichecker.TextErrorScanner', 'goog.array', 'goog.i18n.bidi', 'goog.json']);
+goog.addDependency('../../../../src/bidichecker.js', ['bidichecker', 'bidichecker.BidiChecker', 'bidichecker.Revision'], ['bidichecker.Error', 'bidichecker.Filter', 'bidichecker.FilterFactory', 'bidichecker.TextErrorScanner', 'bidichecker.gui.server.GuiContainerFactory', 'bidichecker.gui.server.GuiServer', 'goog.array', 'goog.i18n.bidi', 'goog.json', 'goog.userAgent.product']);
 goog.addDependency('../../../../src/detector.js', ['bidichecker.Detector'], []);
 goog.addDependency('../../../../src/dirchunk.js', ['bidichecker.DirChunk', 'bidichecker.NullDirChunk'], ['bidichecker.HighlightableArea', 'bidichecker.HighlightableText', 'bidichecker.utils', 'goog.array']);
 goog.addDependency('../../../../src/dirchunkwalker.js', ['bidichecker.DirChunkWalker'], ['bidichecker.DirChunk', 'bidichecker.DomWalker', 'bidichecker.NullDirChunk', 'goog.events.Event', 'goog.events.EventHandler', 'goog.events.EventTarget']);
 goog.addDependency('../../../../src/domwalker.js', ['bidichecker.DomWalker', 'bidichecker.DomWalker.EventTypes'], ['bidichecker.utils', 'goog.array', 'goog.dom', 'goog.dom.TagIterator', 'goog.events.EventTarget', 'goog.style']);
 goog.addDependency('../../../../src/error.js', ['bidichecker.Error'], ['bidichecker.HighlightableArea', 'bidichecker.utils', 'goog.array', 'goog.json', 'goog.string.StringBuffer']);
 goog.addDependency('../../../../src/errorcollector.js', ['bidichecker.ErrorCollector'], ['bidichecker.Error', 'bidichecker.Filter', 'bidichecker.FrameStack', 'bidichecker.utils', 'goog.array']);
-goog.addDependency('../../../../src/errorgui.js', ['bidichecker.ErrorGui'], ['bidichecker.Error', 'goog.dom', 'goog.events.Event', 'goog.string', 'goog.style', 'goog.ui.Dialog', 'goog.ui.Dialog.ButtonSet']);
 goog.addDependency('../../../../src/filter.js', ['bidichecker.Filter'], ['bidichecker.Error']);
 goog.addDependency('../../../../src/filterfactory.js', ['bidichecker.FilterFactory', 'bidichecker.FilterFactory.ComposableFilter'], ['bidichecker.Filter', 'bidichecker.XpathMatcher', 'goog.json']);
 goog.addDependency('../../../../src/framestack.js', ['bidichecker.FrameStack', 'bidichecker.FrameStack.EventTypes'], ['goog.events.EventTarget']);
+goog.addDependency('../../../../src/gui/app/errorpage.js', ['bidichecker.gui.app.ErrorPage'], ['bidichecker.Error', 'bidichecker.gui.common.CommChannel', 'goog.dom', 'goog.dom.Range', 'goog.events', 'goog.events.EventType']);
+goog.addDependency('../../../../src/gui/app/options.js', ['bidichecker.gui.app.OptionsPage'], ['bidichecker', 'bidichecker.gui.common.CommChannel', 'goog.dom', 'goog.events', 'goog.events.EventType']);
+goog.addDependency('../../../../src/gui/common/commchannel.js', ['bidichecker.gui.common.CommChannel'], ['goog.events', 'goog.events.EventType', 'goog.json', 'goog.structs.Map']);
+goog.addDependency('../../../../src/gui/server/dialogguicontainer.js', ['bidichecker.gui.server.DialogGuiContainer'], ['bidichecker.gui.server.GuiContainer', 'goog.style', 'goog.ui.Dialog']);
+goog.addDependency('../../../../src/gui/server/guicontainer.js', ['bidichecker.gui.server.GuiContainer'], []);
+goog.addDependency('../../../../src/gui/server/guicontainerfactory.js', ['bidichecker.gui.server.GuiContainerFactory'], ['bidichecker.gui.server.DialogGuiContainer', 'bidichecker.gui.server.WindowGuiContainer']);
+goog.addDependency('../../../../src/gui/server/guiserver.js', ['bidichecker.gui.server.GuiServer'], ['bidichecker.Error', 'bidichecker.gui.common.CommChannel', 'bidichecker.gui.server.GuiContainer']);
+goog.addDependency('../../../../src/gui/server/windowguicontainer.js', ['bidichecker.gui.server.WindowGuiContainer'], ['bidichecker.gui.server.GuiContainer']);
 goog.addDependency('../../../../src/highlightablearea.js', ['bidichecker.HighlightableArea'], []);
-goog.addDependency('../../../../src/highlightableelement.js', ['bidichecker.HighlightableElement'], ['bidichecker.HighlightableArea', 'goog.style']);
-goog.addDependency('../../../../src/highlightabletext.js', ['bidichecker.HighlightableText'], ['bidichecker.HighlightableArea', 'goog.dom', 'goog.style']);
+goog.addDependency('../../../../src/highlightableelement.js', ['bidichecker.HighlightableElement'], ['bidichecker.HighlightableArea', 'bidichecker.utils', 'goog.style']);
+goog.addDependency('../../../../src/highlightabletext.js', ['bidichecker.HighlightableText'], ['bidichecker.HighlightableArea', 'bidichecker.utils', 'goog.dom', 'goog.style']);
 goog.addDependency('../../../../src/overalldirectionalitydetector.js', ['bidichecker.OverallDirectionalityDetector'], ['bidichecker.Detector', 'bidichecker.DomWalker', 'bidichecker.Error', 'bidichecker.HighlightableElement', 'bidichecker.Scanner', 'goog.events', 'goog.events.Event']);
 goog.addDependency('../../../../src/samples/reviews/i18n.js', ['I18n'], []);
 goog.addDependency('../../../../src/samples/reviews/reviews.js', ['ReviewsApp'], ['I18n']);
 goog.addDependency('../../../../src/scanner.js', ['bidichecker.Scanner'], ['bidichecker.Detector', 'bidichecker.DirChunkWalker', 'bidichecker.DomWalker', 'bidichecker.ErrorCollector', 'bidichecker.XpathMatcher', 'goog.i18n.bidi']);
 goog.addDependency('../../../../src/spilloverdetector.js', ['bidichecker.SpilloverDetector'], ['bidichecker.Detector', 'bidichecker.DomWalker', 'bidichecker.Error', 'bidichecker.HighlightableText', 'bidichecker.Scanner', 'goog.array', 'goog.events', 'goog.events.EventHandler']);
-goog.addDependency('../../../../src/texterrorscanner.js', ['bidichecker.TextErrorScanner'], ['bidichecker.Detector', 'bidichecker.ErrorCollector', 'bidichecker.OverallDirectionalityDetector', 'bidichecker.Scanner', 'bidichecker.SpilloverDetector', 'bidichecker.UndeclaredTextDetector', 'goog.i18n.bidi']);
+goog.addDependency('../../../../src/texterrorscanner.js', ['bidichecker.TextErrorScanner'], ['bidichecker.Detector', 'bidichecker.ErrorCollector', 'bidichecker.OverallDirectionalityDetector', 'bidichecker.Scanner', 'bidichecker.SpilloverDetector', 'bidichecker.UndeclaredFieldDetector', 'bidichecker.UndeclaredTextDetector', 'goog.i18n.bidi']);
+goog.addDependency('../../../../src/undeclaredfielddetector.js', ['bidichecker.UndeclaredFieldDetector'], ['bidichecker.Detector', 'bidichecker.DomWalker', 'bidichecker.Error', 'bidichecker.HighlightableElement', 'bidichecker.Scanner', 'goog.array', 'goog.events', 'goog.events.EventHandler']);
 goog.addDependency('../../../../src/undeclaredtextdetector.js', ['bidichecker.UndeclaredTextDetector'], ['bidichecker.Detector', 'bidichecker.DirChunk', 'bidichecker.DirChunkWalker', 'bidichecker.Error', 'bidichecker.Scanner', 'bidichecker.utils', 'goog.array', 'goog.events', 'goog.events.Event', 'goog.events.EventHandler']);
 goog.addDependency('../../../../src/utils.js', ['bidichecker.utils', 'bidichecker.utils.Substring'], ['goog.array', 'goog.dom', 'goog.dom.TagIterator', 'goog.style']);
 goog.addDependency('../../../../src/xpathmatcher.js', ['bidichecker.XpathMatcher'], []);
diff --git a/src/dirchunkwalker_test.html b/src/dirchunkwalker_test.html
index 430d626..7f03bfb 100644
--- a/src/dirchunkwalker_test.html
+++ b/src/dirchunkwalker_test.html
@@ -381,6 +381,27 @@
   assertArrayEquals([], chunks);
 }
 
+
+function testDirChunkWalker_TextareaContentsAreIgnored() {
+  // Text nodes inside a <textarea> are not inline with the rest of the page.
+  var testDiv = goog.dom.createDom('div', {'id': 'test'});
+  goog.dom.appendChild(document.body, testDiv);
+  testDiv.innerHTML =
+      '<p>This contains <textarea>A b c d e f g<\/textarea> a textarea<\/p>';
+
+  var para = testDiv.firstChild;  // <p>...
+
+  var chunks = walkTheChunks(testDiv);
+  var chunk = chunks[0];
+  assertEquals('', DirChunkDiff_(chunk, 'This contains  a textarea', false,
+                                 [{charPos: 0, node: para},
+                                  {charPos: 14, node: para}]));
+  assertEquals(false, chunk.isDeclared());
+  assertEquals(para, chunk.getBlock());
+
+  assertEquals(1, chunks.length);
+}
+
     </script>
 
   </body>
diff --git a/src/domwalker.js b/src/domwalker.js
index e1b0688..056ccba 100644
--- a/src/domwalker.js
+++ b/src/domwalker.js
@@ -158,8 +158,7 @@
     // entered a "declared" subtree of the DOM. From that point, we stay
     // declared all the way down.
     var isDeclared = goog.array.peek(this.isDeclaredStack_) ||
-        isRtl != goog.array.peek(this.isRtlStack_) ||
-        this.declaresDir_(element);
+        this.declaresDir_(element, isRtl);
     this.isDeclaredStack_.push(isDeclared);
     this.isRtlStack_.push(isRtl);
 
@@ -185,7 +184,11 @@
       // Exiting a block.
       this.blockStack_.pop();
     }
-  } else if (this.node_.nodeType == goog.dom.NodeType.TEXT) {
+  } else if (this.node_.nodeType == goog.dom.NodeType.TEXT &&
+      this.node_.parentNode.nodeName != 'TEXTAREA') {
+    // Text nodes inside a <textarea> are not inline with the surrounding text.
+    // We ignore them completely, instead processing the textarea value property
+    // (which contains the up-to-date text) in the undeclared field detector.
     this.dispatchEvent(bidichecker.DomWalker.EventTypes.TEXT_NODE);
   }
 };
@@ -260,14 +263,27 @@
 
 /**
  * Does this element impart "declared directionality" status to the text it
- * contains? This is true for an element below the root element which has a
- * "dir" attribute, unless the element also contains a block-level element.
+ * contains? This is meant to suppress errors on a mixed-direction text that
+ * was an atomic data item for the page author. The most that the page author
+ * can do with such text data is declare its overall direction; there is no way
+ * for the page author to know what the internal directional structure of the
+ * text was intended to be.
+ * <p>We assign this status to an element below the root element which has a
+ * "dir" attribute or a "direction" style, or at which the directionality
+ * context changes (presumably by a CSS rule). We do not assign this status to
+ * any element that contains a block-level element; text data items are presumed
+ * not to contain block-level mark-up. We do allow this status for an element
+ * that contains inline elements, since page authors sometimes add some minor
+ * inline mark-up to atomic text data items, e.g. bolding "hits" in snippets.
  * @param {Element} element The element to test.
+ * @param {boolean} isRtl The directionality of the element.
  * @return {boolean} Does the element have "isDeclared" status?
  * @private
  */
-bidichecker.DomWalker.prototype.declaresDir_ = function(element) {
-  if (!element.dir || element == this.rootBlock_) {
+bidichecker.DomWalker.prototype.declaresDir_ = function(element, isRtl) {
+  if ((!element.dir && !element.style.direction &&
+      isRtl == goog.array.peek(this.isRtlStack_)) ||
+      element == this.rootBlock_) {
     return false;
   }
 
diff --git a/src/domwalker_test.html b/src/domwalker_test.html
index 4cd45fc..09fbc0a 100644
--- a/src/domwalker_test.html
+++ b/src/domwalker_test.html
@@ -283,7 +283,9 @@
   // If a block with declared directionality contains another block inside it,
   // we don't consider the outer block's contents to be "declared".
   // Note: This DOM must be built with createDom(), since the HTML parser
-  // inserts unwanted paragraph breaks.
+  // inserts unwanted paragraph breaks due to the nested paragraphs.
+  // The HTML would look like:
+  // <div id='test'><p dir='ltr'>Shalom<p dir='ltr'>BACK</p>Okay</p></div>
   var para1 = goog.dom.createDom('p', {'dir': 'ltr'}, 'BACK');
   var para2 = goog.dom.createDom('p', {'dir': 'ltr'}, 'Shalom', para1, 'Okay');
   var testDiv = goog.dom.createDom('div', {'id': 'test'}, para2);
@@ -300,6 +302,7 @@
                   {type: TEXT_NODE, text: 'Shalom',
                    inRtl: false, inDeclaredDir: false, block: para2},
 
+                  // "inDeclaredDir" is set only for the innermost paragraph.
                   {type: START_TAG, element: para1,
                    inRtl: false, inDeclaredDir: true, block: para1},
 
@@ -324,6 +327,58 @@
 }
 
 
+function testDomWalker_EmbeddedBlockCancelsDeclaredStatusViaCss() {
+  // As above, but with the paragraph directionality declared via CSS, which
+  // causes a change in the computed directionality.
+  goog.style.installStyles('.domwalker-test-ltr { direction: ltr }');
+
+  // Note: This DOM must be built with createDom(), since the HTML parser
+  // inserts unwanted paragraph breaks due to the nested paragraphs.
+  // The HTML would look like:
+  // <div dir='rtl' id='test'><p class='domwalker-test-ltr'>Shalom
+  // <p dir='ltr'>BACK</p>Okay</p></div>
+  var para1 = goog.dom.createDom('p', {'dir': 'ltr'}, 'BACK');
+  var para2 = goog.dom.createDom('p', {'class': 'domwalker-test-ltr'},
+                                 'Shalom', para1, 'Okay');
+  var testDiv = goog.dom.createDom('div', {'dir': 'rtl', 'id': 'test'}, para2);
+  goog.dom.appendChild(document.body, testDiv);
+
+  var domWalker = new bidichecker.DomWalker(testDiv);
+  var states = walkTheDom(domWalker);
+  var expected = [{type: START_TAG, element: testDiv,
+                   inRtl: true, inDeclaredDir: false, block: testDiv},
+
+                  {type: START_TAG, element: para2,
+                   inRtl: false, inDeclaredDir: false, block: para2},
+
+                  {type: TEXT_NODE, text: 'Shalom',
+                   inRtl: false, inDeclaredDir: false, block: para2},
+
+                  // "inDeclaredDir" is set only for the innermost paragraph.
+                  {type: START_TAG, element: para1,
+                   inRtl: false, inDeclaredDir: true, block: para1},
+
+                  {type: TEXT_NODE, text: 'BACK',
+                   inRtl: false, inDeclaredDir: true, block: para1},
+
+                  {type: END_TAG, element: para1,
+                   inRtl: false, inDeclaredDir: true, block: para1},
+
+                  {type: TEXT_NODE, text: 'Okay',
+                   inRtl: false, inDeclaredDir: false, block: para2},
+
+                  {type: END_TAG, element: para2,
+                   inRtl: false, inDeclaredDir: false, block: para2},
+
+                  {type: END_TAG, element: testDiv,
+                   inRtl: true, inDeclaredDir: false, block: testDiv},
+
+                  {type: END_OF_DOM, inRtl: true, block: testDiv}
+                 ];
+  assertStatesEqual(expected, states);
+}
+
+
 function testDomWalker_BlockChangesAfterExitingEmbeddedBlock() {
   var testDiv = goog.dom.createDom('div', {'id': 'test', 'dir': 'rtl'});
   goog.dom.appendChild(document.body, testDiv);
@@ -384,6 +439,55 @@
 }
 
 
+function testDomWalker_VisibilityHiddenIsIgnored() {
+  // All the contents have visibility:hidden set; they should be ignored.
+  var testDiv = goog.dom.createDom('div', {'id': 'test'});
+  goog.dom.appendChild(document.body, testDiv);
+  testDiv.innerHTML =
+      '<p dir=\'rtl\' style=\'visibility: hidden\'>Shalom!<\/p>';
+
+  var domWalker = new bidichecker.DomWalker(testDiv);
+  var states = walkTheDom(domWalker);
+  var expected = [{type: START_TAG, element: testDiv,
+                   inRtl: false, inDeclaredDir: false, block: testDiv},
+
+                  {type: END_TAG, element: testDiv,
+                   inRtl: false, inDeclaredDir: false, block: testDiv},
+
+                  {type: END_OF_DOM, inRtl: false, block: testDiv}
+                 ];
+  assertStatesEqual(expected, states);
+}
+
+
+function testDomWalker_VisibilityCollapseIsIgnored() {
+  // All the contents have visibility:collapse set; they should be ignored.
+  var testDiv = goog.dom.createDom('div', {'id': 'test'});
+  goog.dom.appendChild(document.body, testDiv);
+  testDiv.innerHTML =
+      '<p dir=\'rtl\' style=\'visibility: collapse\'>Shalom!<\/p>';
+  var para = testDiv.firstChild;
+
+  // Some browsers (in particular, IE7) do not support visiblity:collapse; skip
+  // the test in that case.
+  if (!para.style.visibility) {
+    return;
+  }
+
+  var domWalker = new bidichecker.DomWalker(testDiv);
+  var states = walkTheDom(domWalker);
+  var expected = [{type: START_TAG, element: testDiv,
+                   inRtl: false, inDeclaredDir: false, block: testDiv},
+
+                  {type: END_TAG, element: testDiv,
+                   inRtl: false, inDeclaredDir: false, block: testDiv},
+
+                  {type: END_OF_DOM, inRtl: false, block: testDiv}
+                 ];
+  assertStatesEqual(expected, states);
+}
+
+
 function testDomWalker_ScriptAndStyleAreIgnored() {
   // <style> shouldn't really appear in the body, but sometimes it does.
   var testDiv = goog.dom.createDom('div', {'id': 'test'});
@@ -405,6 +509,35 @@
 }
 
 
+function testDomWalker_TextareaContentsAreIgnored() {
+  // Text nodes inside a <textarea> are not inline with the surrounding text.
+  // We ignore them completely, instead processing the textarea value property
+  // (which contains the up-to-date text) in the undeclared field detector.
+  var testDiv = goog.dom.createDom('div', {'id': 'test'});
+  goog.dom.appendChild(document.body, testDiv);
+  testDiv.innerHTML = '<textarea>A b c d e f g<\/textarea>';
+  var textarea = testDiv.firstChild;
+
+  var domWalker = new bidichecker.DomWalker(testDiv);
+  var states = walkTheDom(domWalker);
+  var expected = [{type: START_TAG, element: testDiv,
+                   inRtl: false, inDeclaredDir: false, block: testDiv},
+
+                   {type: START_TAG, element: textarea,
+                   inRtl: false, inDeclaredDir: false, block: testDiv},
+
+                   {type: END_TAG, element: textarea,
+                   inRtl: false, inDeclaredDir: false, block: testDiv},
+
+                   {type: END_TAG, element: testDiv,
+                   inRtl: false, inDeclaredDir: false, block: testDiv},
+
+                   {type: END_OF_DOM, inRtl: false, block: testDiv}
+                 ];
+  assertStatesEqual(expected, states);
+}
+
+
 function testDomWalker_NoscriptIsIgnored() {
   var testDiv = goog.dom.createDom('div', {'id': 'test'});
   goog.dom.appendChild(document.body, testDiv);
@@ -437,8 +570,8 @@
   var iframeDoc =
       goog.dom.getFrameContentDocument(/** @type {Element} */ (iframe));
   iframeDoc.open();
-  iframeDoc.write('<div id=line1>hello world</div>' +
-                  '<div id=line2>hello world</div>');
+  iframeDoc.write('<div id=line1>hello world<\/div>' +
+                  '<div id=line2>hello world<\/div>');
   iframeDoc.close();
   var iframeRoot = iframeDoc.body;
 
@@ -508,8 +641,8 @@
   // Create two iframes in the document.
   var testDiv = goog.dom.createDom('div', {'id': 'test'});
   goog.dom.appendChild(document.body, testDiv);
-  testDiv.innerHTML = '<iframe id=\'iframe1\'></iframe>' +
-      '<iframe id=\'iframe2\'></iframe>';
+  testDiv.innerHTML = '<iframe id=\'iframe1\'><\/iframe>' +
+      '<iframe id=\'iframe2\'><\/iframe>';
   goog.dom.appendChild(document.body, testDiv);
 
   // Fill the first iframe with content.
@@ -517,7 +650,7 @@
   var iframe1Doc =
       goog.dom.getFrameContentDocument(/** @type {Element} */ (iframe1));
   iframe1Doc.open();
-  iframe1Doc.write('<p>hello world</p>');
+  iframe1Doc.write('<p>hello world<\/p>');
   iframe1Doc.close();
   var iframe1Root = iframe1Doc.body;
 
@@ -525,7 +658,7 @@
   var iframe2 = testDiv.childNodes[1];
   var iframe2Doc = goog.dom.getFrameContentDocument(iframe2);
   iframe2Doc.open();
-  iframe2Doc.write('<iframe id=\'iframe_nested\'></iframe>');
+  iframe2Doc.write('<iframe id=\'iframe_nested\'><\/iframe>');
   iframe2Doc.close();
   var iframe2Root = iframe2Doc.body;
 
@@ -534,7 +667,7 @@
   var iframe3Doc =
       goog.dom.getFrameContentDocument(/** @type {Element} */ (iframe3));
   iframe3Doc.open();
-  iframe3Doc.write('<p id=\'para\'>In a nested iframe!</p>');
+  iframe3Doc.write('<p id=\'para\'>In a nested iframe!<\/p>');
   iframe3Doc.close();
   var iframe3Root = iframe3Doc.body;
 
@@ -591,9 +724,8 @@
 
 
 function testDomWalker_CanWalkAFrameSet() {
-  // There doesnt seem to be a way to create a frameset using Javascript under
-  // IE. Disable this test; handling of framesets will be tested by the Java
-  // tests anyway.
+  // There doesn't seem to be a way to create a frameset using Javascript under
+  // IE; disable this test.
   if (goog.userAgent.IE) {
     return;
   }
diff --git a/src/error.js b/src/error.js
index c9b6b5b..c06f56e 100644
--- a/src/error.js
+++ b/src/error.js
@@ -163,6 +163,12 @@
 bidichecker.Error.highlightableAreas_ = [];
 
 
+/** @return {number} The error id. */
+bidichecker.Error.prototype.getId = function() {
+  return this['id'];
+};
+
+
 /** @return {string} The error type. */
 bidichecker.Error.prototype.getType = function() {
   return this['type'];
@@ -275,6 +281,8 @@
 
   var value;
   if ((value = this.getAtText())) {
+    var AT_TEXT_TRUNCATION_LENGTH = 20;
+    value = bidichecker.utils.truncateString(value, AT_TEXT_TRUNCATION_LENGTH);
     buffer.append(': ', bidichecker.utils.singleQuoteString(value));
   }
   if ((value = this.getPrecededByText())) {
diff --git a/src/error_test.html b/src/error_test.html
index afd4090..8625320 100644
--- a/src/error_test.html
+++ b/src/error_test.html
@@ -154,6 +154,15 @@
   assertThrows(createWithMissingId);
 }
 
+
+function testError_LongAtTextIsTruncated() {
+  var error = new bidichecker.Error('abc', 2, null,
+      'We all live in a yellow submarine, a yellow submarine, a yellow ');
+  assertEquals(
+      'We all live in a yellow submarine, a yellow submarine, a yellow ',
+       error.getAtText());
+  assertEquals('[2] abc: \'We all live in a yel\u2026\'', error.toString());
+}
     </script>
 
   </body>
diff --git a/src/errorcollector_test.html b/src/errorcollector_test.html
index b4ec310..b992598 100644
--- a/src/errorcollector_test.html
+++ b/src/errorcollector_test.html
@@ -55,6 +55,7 @@
 function testErrorCollector_AddErrorWithLocation() {
   var testDiv = goog.dom.createDom('div', {'id': 'test'});
   testDiv.innerHTML = '<div id=\'nomatch\'><p>Okay?</p></div>';
+  goog.dom.appendChild(document.body, testDiv);
 
   var collector = new bidichecker.ErrorCollector(new bidichecker.FrameStack());
   var error = new bidichecker.Error('abc', 2);
@@ -65,7 +66,8 @@
   // Check that the error now has a location description.
   var expectedFields = {'type': 'abc',
                         'severity': 2,
-                        'locationDescription': '<div id=\'nomatch\'>'};
+                        'locationDescription':
+                            '<div id=\'test\'><div id=\'nomatch\'>'};
   assertErrorFields([expectedFields], collector.getErrors());
 }
 
@@ -119,6 +121,7 @@
   var testDiv = goog.dom.createDom('div', {'id': 'test'});
   testDiv.innerHTML =
       '<div id=\'nomatch\'><p><b>Text</b></p></div>';
+  goog.dom.appendChild(document.body, testDiv);
 
   var frameStack = new bidichecker.FrameStack;
   var collector = new bidichecker.ErrorCollector(frameStack);
@@ -151,26 +154,28 @@
       'type': 'abc',
       'severity': 2,
       'locationDescription':
-          '<div id=\'nomatch\'><p><b> in <div id=\'nomatch\'>'
+          '<div id=\'test\'><div id=\'nomatch\'><p><b> in ' +
+          '<div id=\'test\'><div id=\'nomatch\'>'
   },
   {
       'type': 'abc',
       'severity': 2,
       'locationDescription':
-          '<div id=\'nomatch\'><p><b> in ' +
-          '<div id=\'nomatch\'><p> in <div id=\'nomatch\'>'
+          '<div id=\'test\'><div id=\'nomatch\'><p><b> in ' +
+          '<div id=\'test\'><div id=\'nomatch\'><p> in ' +
+          '<div id=\'test\'><div id=\'nomatch\'>'
   },
   {
       'type': 'abc',
       'severity': 2,
       'locationDescription':
-          '<div id=\'nomatch\'>'  // Just a frame location.
+          '<div id=\'test\'><div id=\'nomatch\'>'  // Just a frame location.
   },
   {
       'type': 'abc',
       'severity': 2,
       'locationDescription':
-          '<div id=\'nomatch\'><p><b>'  // No parent frame.
+          '<div id=\'test\'><div id=\'nomatch\'><p><b>'  // No parent frame.
   }];
   assertErrorFields(expectedFields, collector.getErrors());
 }
diff --git a/src/errorgui.js b/src/errorgui.js
deleted file mode 100644
index 160c161..0000000
--- a/src/errorgui.js
+++ /dev/null
@@ -1,317 +0,0 @@
-// Copyright 2009 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS-IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-/**
- * @fileoverview Browser-based UI for viewing error locations.
- */
-
-
-goog.provide('bidichecker.ErrorGui');
-
-goog.require('bidichecker.Error');
-goog.require('goog.dom');
-goog.require('goog.events.Event');
-goog.require('goog.string');
-goog.require('goog.style');
-goog.require('goog.ui.Dialog');
-goog.require('goog.ui.Dialog.ButtonSet');
-
-
-/**
- * In-browser interactive error viewer.
- * @param {Array.<!bidichecker.Error>} errors The errors to display.
- * @constructor
- */
-bidichecker.ErrorGui = function(errors) {
-  /**
-   * The errors to display.
-   * @type {Array.<!bidichecker.Error>}
-   * @private
-   */
-  this.errors_ = errors;
-
-  /**
-   * Currently displayed error number (indexed from 0).
-   * @type {number}
-   * @private
-   */
-  this.currentError_ = 0;
-
-  /**
-   * Element representing the dialog box.
-   * @type {Element}
-   * @private
-   */
-  this.dialogElement_ = null;
-
-  /**
-   * Element representing the error number input field.
-   * @type {Element}
-   * @private
-   */
-  this.errorNumField_ = null;
-
-  /**
-   * Element representing the error message display field.
-   * @type {Element}
-   * @private
-   */
-  this.errorTextElem_ = null;
-};
-
-
-/**
- * Builds and launches the error browser dialog box.
- */
-bidichecker.ErrorGui.prototype.launch = function() {
-  if (this.dialogElement_ ||  // The UI has already been launched.
-      this.errors_.length == 0) {  // Nothing to display.
-    return;
-  }
-  this.createDialogBox_();
-  this.highlightCurrentError_();
-  this.listen_();
-};
-
-
-/**
- * Style definitions for the dialog box elements.
- * @const
- * @type {string}
- * @private
- */
-bidichecker.ErrorGui.DIALOG_STYLES_ =
-    '.bidichecker-dialog-bg { position: absolute; top: 0; left: 0; }' +
-
-    '.bidichecker-dialog { position: absolute; padding: 5px;' +
-    ' background-color: #fcb; border: 1px solid #000; ' +
-    'font-family: arial, sans-serif; width: 475px; color: #000; ' +
-    'outline: none; direction: ltr }' +
-
-    '.bidichecker-dialog a, .bidichecker-dialog a:link,' +
-    '.bidichecker-dialog a:visited  { color: #0066cc; cursor: pointer; }' +
-
-    '.bidichecker-dialog-title { position: relative; ' +
-    'background-color: #f9efeb; color: #000000; padding: 10px 15px;' +
-    ' font-size: 16px; font-weight: bold; vertical-align: middle; ' +
-    'cursor: pointer; cursor: hand }' +
-
-    '.bidichecker-dialog-content { padding: 15px; font-size: 90%; ' +
-    'background-color: #fff }' +
-
-    '.bidichecker-dialog-buttons { padding: 0 15px 15px; ' +
-    'background-color: #fff }' +
-
-    '.bidichecker-dialog-error-text { font-weight: bold; font-size: 125%; ' +
-    'color: #f00; height: 80px; overflow: auto; border: 1px dotted #f00 }';
-
-
-/**
- * HTML content for the dialog box.
- * TODO(user): Use a message catalog to support internationalization of the
- * dialog box contents.
- * @const
- * @type {string}
- * @private
- */
-bidichecker.ErrorGui.DIALOG_CONTENT_ =
-    // A field for displaying the text of the error message.
-    '<div id="bidichecker-dialog-error-text" ' +
-    'class="bidichecker-dialog-error-text"> </div>' +
-
-    // An input field for displaying and changing the current error number.
-    '<p>Error <input name="current" id="bidichecker-dialog-error-num" ' +
-    'type="text" size="3" value="1" /> of ' +
-
-    // A field for displaying the total number of errors.
-    '<span id="bidichecker-dialog-error-count"></span></p>' +
-
-    '<p style="font-size:75%">Drag this box if it conceals a part of the ' +
-    'page you need.</p>';
-
-
-/**
- * Assembles the error browser dialog box.
- * @private
- */
-bidichecker.ErrorGui.prototype.createDialogBox_ = function() {
-  /**
-   * @type {goog.ui.Dialog}
-   * @private
-   */
-  this.dialog_ = new goog.ui.Dialog('bidichecker-dialog');
-  this.dialog_.setTitle('BidiChecker error browser');
-  this.dialog_.setModal(false);  // Underlying page remains accessible.
-
-  var buttonset = new goog.ui.Dialog.ButtonSet();
-  buttonset.set('prev', '< Prev');
-  buttonset.set('next', 'Next >');
-  this.dialog_.setButtonSet(buttonset);
-
-  this.dialog_.setContent(bidichecker.ErrorGui.DIALOG_CONTENT_);
-  this.dialog_.setVisible(true);
-
-  this.dialogElement_ = this.dialog_.getElement();
-  goog.style.installStyles(bidichecker.ErrorGui.DIALOG_STYLES_,
-                           this.dialogElement_);
-
-  // Prevent page elements from leaking through the dialog box.
-  this.dialogElement_.style.zIndex = 10000;
-
-  var dom = this.dialog_.getDomHelper();
-  var errorCountField = dom.getElement('bidichecker-dialog-error-count');
-  goog.dom.setTextContent(errorCountField, this.errors_.length + '');
-
-  this.errorNumField_ = dom.getElement('bidichecker-dialog-error-num');
-  this.errorTextElem_ = dom.getElement('bidichecker-dialog-error-text');
-
-  // Make sure the box is centered on the page.
-  this.dialog_.reposition();
-
-  // TODO(user): The dialog box doesn't function correctly on YouTube pages.
-  // Figure out why and fix it.
-};
-
-
-/**
- * Starts listening for user events:  button presses and changes to the error
- * number input field.
- * @private
- */
-bidichecker.ErrorGui.prototype.listen_ = function() {
-  // Listen for button presses.
-  goog.events.listen(this.dialog_, goog.ui.Dialog.EventType.SELECT,
-      this.handleButtonEvent_, false, this);
-
-  // Listen for changes to the error number input field.
-  this.errorNumField_.onchange =
-      goog.bind(this.handleErrorNumFieldChange_, this);
-};
-
-
-/**
- * Handles changes to the current error number input field.
- * @private
- */
-bidichecker.ErrorGui.prototype.handleErrorNumFieldChange_ = function() {
-  var newError = goog.string.isNumeric(this.errorNumField_.value) ?
-      goog.string.toNumber(this.errorNumField_.value) - 1 : -1;
-  if (newError >= 0 && newError < this.errors_.length &&
-      newError != this.currentError_) {
-    this.changeCurrentError_(newError);
-  } else {
-    // If the input value was invalid, reset the field contents to the current
-    // error.
-    this.setErrorNumField_();
-  }
-};
-
-
-/**
- * Handles button presses.
- * @param {!goog.events.Event} event A button press event.
- * @return {boolean} Whether the dialog box should be dismissed.
- * @private
- */
-bidichecker.ErrorGui.prototype.handleButtonEvent_ = function(event) {
-  var newError;
-  if (event.key == 'next') {
-    // Advance to next error, wrapping around the end.
-    newError = this.currentError_ == this.errors_.length - 1 ? 0 :
-        this.currentError_ + 1;
-  } else {
-    // Revert to previous error, wrapping around the start.
-    newError = this.currentError_ == 0 ? this.errors_.length - 1 :
-        this.currentError_ - 1;
-  }
-  this.changeCurrentError_(newError);
-  return false;
-};
-
-
-/**
- * Displays the current error and scrolls the window to show its position.
- * @private
- */
-bidichecker.ErrorGui.prototype.highlightCurrentError_ = function() {
-  var error = this.errors_[this.currentError_];
-  var highlightableArea = error.getHighlightableArea();
-  if (highlightableArea) {
-    var coords = highlightableArea.highlightOnPage();
-    this.scrollTo_(coords);
-  }
-  goog.dom.setTextContent(this.errorTextElem_, error.toString());
-};
-
-
-/**
- * Clears highlighting from the current error.
- * @private
- */
-bidichecker.ErrorGui.prototype.unhighlightCurrentError_ = function() {
-  var error = this.errors_[this.currentError_];
-  var highlightableArea = error.getHighlightableArea();
-  if (highlightableArea) {
-    highlightableArea.unhighlightOnPage();
-  }
-};
-
-
-/**
- * Changes the currently-displayed error.
- * @param {number} newErrorNumber The number of the new error to display.
- * @private
- */
-bidichecker.ErrorGui.prototype.changeCurrentError_ = function(newErrorNumber) {
-  this.unhighlightCurrentError_();
-  this.currentError_ = newErrorNumber;
-  this.setErrorNumField_();
-  this.highlightCurrentError_();
-};
-
-
-/**
- * Sets the error number field to display the current error number.
- * @private
- */
-bidichecker.ErrorGui.prototype.setErrorNumField_ = function() {
-  this.errorNumField_.value = this.currentError_ + 1;
-};
-
-
-/**
- * Scrolls the window so a given page position is near the top of the screen.
- * Also scrolls the dialog box by the opposite amount to keep it in the same
- * place in the viewport.
- * TODO(user): Make this do the right thing for frames and other scrollable
- * elements.
- * @param {goog.math.Coordinate} coords The coordinates to scroll to.
- * @private
- */
-bidichecker.ErrorGui.prototype.scrollTo_ = function(coords) {
-  var oldY = window.scrollY;
-  window.scrollTo(0, coords.y - 100);
-  this.scrollDialogBoxBy_(window.scrollY - oldY);
-};
-
-
-/**
- * Moves the dialog box by a given vertical amount.
- * @param {number} scrollY The distance to move it, in pixels.
- * @private
- */
-bidichecker.ErrorGui.prototype.scrollDialogBoxBy_ = function(scrollY) {
-  var coords = goog.style.getPosition(this.dialogElement_);
-  goog.style.setPosition(this.dialogElement_, coords.x, coords.y + scrollY);
-};
diff --git a/src/filterfactory.js b/src/filterfactory.js
index 07e22d6..02d7789 100644
--- a/src/filterfactory.js
+++ b/src/filterfactory.js
@@ -40,7 +40,7 @@
 bidichecker.FilterFactory.ComposableFilter = function() {};
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.ComposableFilter.prototype.isSuppressed =
     goog.abstractMethod;
 
@@ -548,7 +548,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.AndFilter_.prototype.isSuppressed = function(
     error, locationElements) {
   return this.filter1_.isSuppressed(error, locationElements) &&
@@ -578,7 +578,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.AtTextFilter_.prototype.isSuppressed = function(
     error, locationElements) {
   return this.atText_ == (error.getAtText() || '');
@@ -608,7 +608,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.AtTextRegexpFilter_.prototype.isSuppressed = function(
     error, locationElements) {
   return this.atTextRegexp_.test(error.getAtText() || '');
@@ -637,7 +637,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.FollowedByTextFilter_.prototype.isSuppressed =
     function(error, locationElements) {
   return this.followedByText_ == (error.getFollowedByText() || '');
@@ -668,7 +668,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.FollowedByTextRegexpFilter_.prototype.isSuppressed =
     function(error, locationElements) {
   return this.followedByTextRegexp_.test(error.getFollowedByText() || '');
@@ -697,7 +697,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.LocationClassFilter_.prototype.isSuppressed =
     function(error, locationElements) {
   for (var i = 0; i < locationElements.length; ++i) {
@@ -740,7 +740,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.LocationClassRegexpFilter_.prototype.isSuppressed =
     function(error, locationElements) {
   for (var i = 0; i < locationElements.length; ++i) {
@@ -781,7 +781,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.LocationIdFilter_.prototype.isSuppressed = function(
     error, locationElements) {
   for (var i = 0; i < locationElements.length; ++i) {
@@ -818,7 +818,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.LocationIdRegexpFilter_.prototype.isSuppressed =
     function(error, locationElements) {
   for (var i = 0; i < locationElements.length; ++i) {
@@ -858,7 +858,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.LocationXpathFilter_.prototype.isSuppressed =
     function(error, locationElements) {
   // TODO(user): This currently matches the path to the element in the
@@ -895,7 +895,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.NotFilter_.prototype.isSuppressed = function(
     error, locationElements) {
   return !this.filter_.isSuppressed(error, locationElements);
@@ -929,7 +929,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.OrFilter_.prototype.isSuppressed = function(
     error, locationElements) {
   return this.filter1_.isSuppressed(error, locationElements) ||
@@ -959,7 +959,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.PrecededByTextFilter_.prototype.isSuppressed =
     function(error, locationElements) {
   return this.precededByText_ == (error.getPrecededByText() || '');
@@ -990,7 +990,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.PrecededByTextRegexpFilter_.prototype.isSuppressed =
     function(error, locationElements) {
   return this.precededByTextRegexp_.test(error.getPrecededByText() || '');
@@ -1018,7 +1018,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.SeverityFilter_.prototype.isSuppressed = function(
     error, locationElements) {
   return this.severityThreshold_ <= error.getSeverity();
@@ -1044,7 +1044,7 @@
     bidichecker.FilterFactory.ComposableFilter);
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.FilterFactory.TypeFilter_.prototype.isSuppressed = function(
     error, locationElements) {
   return this.type_ == error.getType();
diff --git a/src/filterfactory_test.html b/src/filterfactory_test.html
index 61ea442..a3251b1 100644
--- a/src/filterfactory_test.html
+++ b/src/filterfactory_test.html
@@ -661,7 +661,7 @@
     assertFalse(filter.isSuppressed(error, [testDiv.firstChild]));
   } catch (except) {
     // The filter should only throw if the browser doesn't support XPaths.
-    // TODO(elbaum): Remove the try-catch block when XPath is fully supported.
+    // TODO(user): Remove the try-catch block when XPath is fully supported.
     assert(!document.evaluate);
   }
 }
@@ -680,7 +680,7 @@
     assertTrue(filter.isSuppressed(error, [testDiv.firstChild]));
   } catch (except) {
     // The filter should only throw if the browser doesn't support XPaths.
-    // TODO(elbaum): Remove the try-catch block when XPath is fully supported.
+    // TODO(user): Remove the try-catch block when XPath is fully supported.
     assert(!document.evaluate);
   }
 }
@@ -701,7 +701,7 @@
     assertTrue(filter.isSuppressed(error, [testDiv.childNodes[1]]));
   } catch (except) {
     // The filter should only throw if the browser doesn't support XPaths.
-    // TODO(elbaum): Remove the try-catch block when XPath is fully supported.
+    // TODO(user): Remove the try-catch block when XPath is fully supported.
     assert(!document.evaluate);
   }
 }
@@ -743,7 +743,7 @@
     assertTrue(filter.isSuppressed(error, [iframe, secondDiv]));
   } catch (except) {
     // The filter should only throw if the browser doesn't support XPaths.
-    // TODO(elbaum): Remove the try-catch block when XPath is fully supported.
+    // TODO(user): Remove the try-catch block when XPath is fully supported.
     assert(!document.evaluate);
   }
 }
@@ -779,7 +779,7 @@
     assertTrue(filter.isSuppressed(error, [iframe, secondDiv]));
   } catch (except) {
     // The filter should only throw if the browser doesn't support XPaths.
-    // TODO(elbaum): Remove the try-catch block when XPath is fully supported.
+    // TODO(user): Remove the try-catch block when XPath is fully supported.
     assert(!document.evaluate);
   }
 }
diff --git a/src/gui/app/errorpage.js b/src/gui/app/errorpage.js
new file mode 100644
index 0000000..2a9a2ce
--- /dev/null
+++ b/src/gui/app/errorpage.js
@@ -0,0 +1,286 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Code for the error browser, a GUI page which displays the list
+ *     of BIDI errors.
+ */
+
+goog.provide('bidichecker.gui.app.ErrorPage');
+
+goog.require('bidichecker.Error');
+goog.require('bidichecker.gui.common.CommChannel');
+goog.require('goog.dom');
+goog.require('goog.dom.Range');
+goog.require('goog.events');
+goog.require('goog.events.EventType');
+
+
+/**
+ * The error browser. The constructor sets up event listeners on the GUI page,
+ * and triggers checking of the subject page.
+ * @constructor
+ * @export
+ */
+bidichecker.gui.app.ErrorPage = function() {
+  /**
+   * The errors to display.
+   * @type {!Array.<!bidichecker.Error>}
+   * @private
+   */
+  this.errors_ = [];
+
+  this.errorTextElem_ = goog.dom.getElement('error-text');
+
+  goog.events.listen(window, goog.events.EventType.UNLOAD, this.handleClosing_,
+      false, this);
+
+  // Set up communication channel with the page being checked and send a
+  // "checkPage" message. The page is expected to reply with an "errorList"
+  // message. Most of the error page setup is done while handling the errorList
+  // message.
+  this.channel_ = new bidichecker.gui.common.CommChannel(
+      window.opener || window.parent, {
+        'errorList': goog.bind(this.handleErrorListMessage_, this)
+      });
+  this.channel_.send('checkPage');
+};
+
+
+/**
+ * Height of the errors table.
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.TABLE_HEIGHT_ = '300px';
+
+
+/**
+ * The message channel used to communicate with the subject site.
+ * @type {bidichecker.gui.common.CommChannel}
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.channel_;
+
+
+/**
+ * Currently displayed error.
+ * @type {bidichecker.Error}
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.currentError_ = null;
+
+
+/**
+ * Element representing the error message display field.
+ * @type {Element}
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.errorTextElem_;
+
+
+/**
+ * Handles a window closing event.
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.handleClosing_ = function() {
+  if (this.errors_.length > 0) {
+    this.unhighlightCurrentError_();
+  }
+};
+
+
+/**
+ * Select the table contents for easy copy-and-paste.
+ * @param {goog.events.Event} event The event.
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.handleSelectTableClick_ =
+    function(event) {
+  var range = goog.dom.Range.createFromNodeContents(this.tableContainer_);
+  range.select();
+
+  // Don't follow the link that the user clicked.
+  event.preventDefault();
+};
+
+
+/**
+ * Handles the "errorList" message from the subject site.
+ * @param {string} type The message type. Assumed to be "errorList".
+ * @param {*} data The message data. Should be an array of "raw" JSON objects
+ *     resulting from serialization of Error objects.
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.handleErrorListMessage_ = function(type,
+    data) {
+  if (!(data instanceof Array)) {
+    throw 'Invalid data type in errorList message; expected Array.';
+  }
+  var errors = data.map(function(obj) { return new bidichecker.Error(obj); });
+  this.setErrorList_(errors);
+};
+
+
+/**
+ * Creates an object to be given as a cell in the error table. The cell supports
+ * case-insensitive sorting, and clipping of long lines. This function is useful
+ * only for columns of type 'string'.
+ * @param {?string} text Text content of the cell. If null is given, the
+ *     function will simply return null.
+ * @param {string=} opt_width CSS width specifier for the cell.
+ * @return {Object} The cell object.
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.makeTableCell_ = function(text,
+    opt_width) {
+  if (!text) {
+    return null;
+  }
+
+  var style = opt_width ? 'width: ' + opt_width : '';
+  var formatted = '<span class="table-cell-ellipsize" style="' + style + '">' +
+      goog.string.htmlEscape(text) + '</span>';
+  return {
+    // The sort key. Lowercased to make sort case insensitive.
+    'v': text.toLowerCase(),
+    // Formatted HTML to display to the user.
+    'f': formatted
+  };
+};
+
+
+/**
+ * Setups the UI when there are errors to display.
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.setupErrorUi_ = function() {
+  var data = new google.visualization.DataTable();
+  data.addColumn('number', '#');  // Error number.
+  data.addColumn('string', 'Type');
+  data.addColumn('number', 'Sev');
+  data.addColumn('string', 'Location');
+  data.addColumn('string', 'Text');
+
+  for (var i = 0; i < this.errors_.length; i++) {
+    var error = this.errors_[i];
+
+    data.addRow([
+        i + 1,
+        this.makeTableCell_(error.getType()),
+        error.getSeverity(),
+        this.makeTableCell_(error.getLocationDescription(), '280px'),
+        this.makeTableCell_(error.getAtText(), '150px')
+        ]);
+  }
+
+  this.tableContainer_ = goog.dom.getElement('table-container');
+  this.table_ = new google.visualization.Table(this.tableContainer_);
+  this.table_.draw(data, {
+    'height': bidichecker.gui.app.ErrorPage.TABLE_HEIGHT_,
+    'allowHtml': true
+  });
+  google.visualization.events.addListener(this.table_, 'select',
+      goog.bind(this.handleTableSelect_, this));
+
+  var errorCountField = goog.dom.getElement('error-count');
+  goog.dom.setTextContent(errorCountField, this.errors_.length + '');
+
+  this.selectTableRow_(0);
+  this.changeCurrentError_(this.errors_[0]);
+
+  var selectTableControl = goog.dom.getElement('select-table');
+  goog.events.listen(selectTableControl, goog.events.EventType.CLICK,
+      this.handleSelectTableClick_, false, this);
+};
+
+/**
+ * Makes the given error list the current one, and update the page based on it.
+ * @param {!Array.<!bidichecker.Error>} errors The error list.
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.setErrorList_ = function(errors) {
+  this.errors_ = errors;
+
+  var displayErrors = this.errors_.length > 0;
+  var errorContainers = document.getElementsByClassName('show-on-errors');
+  for (var i = 0; i < errorContainers.length; i++) {
+    goog.style.showElement(errorContainers[i], displayErrors);
+  }
+  goog.style.showElement(goog.dom.getElement('no-errors-container'),
+      !displayErrors);
+  if (displayErrors) {
+    this.setupErrorUi_();
+  }
+};
+
+
+/**
+ * Makes the table row for the given error the only selected row in the table.
+ * @param {number} errorNum Index of the error to select.
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.selectTableRow_ =
+    function(errorNum) {
+  this.table_.setSelection([{'row': errorNum, 'column': null}]);
+};
+
+
+/**
+ * Changes the currently-displayed error.
+ * @param {!bidichecker.Error} error The new error to display.
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.changeCurrentError_ = function(error) {
+  this.unhighlightCurrentError_();
+  this.currentError_ = error;
+  this.highlightCurrentError_();
+};
+
+
+/**
+ * Called when the table selection is changed. Set the current error to a
+ * selected row, if any.
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.handleTableSelect_ = function() {
+  var selection = this.table_.getSelection();
+  if (selection.length > 0) {
+    var errorNum = selection[0]['row'];  // Anti-obfuscation bracket notation.
+    this.changeCurrentError_(this.errors_[errorNum]);
+  }
+};
+
+
+/**
+ * Highlight current error.
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.highlightCurrentError_ = function() {
+  if (this.currentError_) {
+    this.channel_.send('highlightError', this.currentError_);
+    goog.dom.setTextContent(goog.dom.getElement('error-text'),
+        this.currentError_.toString());
+  }
+};
+
+
+/**
+ * Clears highlighting from the current error.
+ * @private
+ */
+bidichecker.gui.app.ErrorPage.prototype.unhighlightCurrentError_ = function() {
+  if (this.currentError_) {
+    this.channel_.send('unhighlightError', this.currentError_);
+  }
+};
diff --git a/src/gui/app/options.js b/src/gui/app/options.js
new file mode 100644
index 0000000..17e7e6f
--- /dev/null
+++ b/src/gui/app/options.js
@@ -0,0 +1,296 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview The options page.
+ */
+
+goog.provide('bidichecker.gui.app.OptionsPage');
+
+goog.require('bidichecker');
+goog.require('bidichecker.gui.common.CommChannel');
+goog.require('goog.dom');
+goog.require('goog.events');
+goog.require('goog.events.EventType');
+
+
+
+/**
+ * The options page. The constructor sets up event listeners on the page, and
+ * queries the checked page for the current options.
+ * @constructor
+ * @export
+ */
+bidichecker.gui.app.OptionsPage = function() {
+  this.severityField_ = goog.dom.getElement('severity');
+  goog.events.listen(this.severityField_, goog.events.EventType.CHANGE,
+      this.handleSeverityFieldChange_, false, this);
+  goog.events.listen(document, goog.events.EventType.CHANGE,
+      this.handleGeneralChange_, false, this);
+
+  var helpButton = goog.dom.getElement('show-bookmarklet-help');
+  goog.events.listen(helpButton, goog.events.EventType.CLICK,
+      this.handleShowHelpClick_, false, this);
+
+  this.bookmarklet_ = goog.dom.getElement('bookmarklet');
+  goog.events.listen(this.bookmarklet_, goog.events.EventType.CLICK,
+      this.handleBookmarkletClick_, false, this);
+
+  var checkPageButton = goog.dom.getElement('run');
+  goog.events.listen(checkPageButton, goog.events.EventType.CLICK,
+      this.handleCheckPageButton_, false, this);
+
+  // Set up communication channel and send a "getOptions" message. The page
+  // being checked is expected to reply with an "options" message.
+  var otherWindow = window.opener || window.parent;
+  this.channel_ = new bidichecker.gui.common.CommChannel(otherWindow, {
+        'options': goog.bind(this.handleOptionsMessage_, this)
+      });
+  this.channel_.send('getOptions');
+};
+
+
+/**
+ * Get the value of the checked radio button in the given radio button group.
+ * @param {goog.dom.DomHelper} domHelper DOM helper used to find the group.
+ * @param {string} name The name attribute used for the group.
+ * @return {?string} Value of checked radio button, or null if there's none.
+ * @private
+ */
+bidichecker.gui.app.getRadioButtonGroupValue_ =
+    function(domHelper, name) {
+  var elems = domHelper.getDocument().getElementsByName(name);
+
+  // Find the checked element and return its value.
+  for (var i = 0; i < elems.length; i++) {
+    var elem = elems[i];
+    if (elem.checked) {
+      return elem.value;
+    }
+  }
+
+  // No checked element found.
+  return null;
+};
+
+
+/**
+ * Check the radio button with the given value in the given radio button group.
+ * @param {goog.dom.DomHelper} domHelper DOM helper used to find the group.
+ * @param {string} name The name attribute used for the group.
+ * @param {string} value Check the radio button with this value.
+ * @private
+ */
+bidichecker.gui.app.setRadioButtonGroupValue_ =
+    function(domHelper, name, value) {
+  var elems = domHelper.getDocument().getElementsByName(name);
+
+  // Find the element with the given value and check it.
+  var found = false;
+  for (var i = 0; i < elems.length; i++) {
+    var elem = elems[i];
+    if (elem.value == value) {
+      elem.checked = true;
+      found = true;
+      break;
+    }
+  }
+
+  if (!found) {
+    throw 'No radio button with name ' + name + ' and value ' + value;
+  }
+};
+
+
+/**
+ * The element containing the bookmarklet.
+ * @type {Element}
+ * @private
+ */
+bidichecker.gui.app.OptionsPage.prototype.bookmarklet_;
+
+
+/**
+ * The element showing the severity option value.
+ * @type {Element}
+ * @private
+ */
+bidichecker.gui.app.OptionsPage.prototype.severityField_;
+
+
+/**
+ * The message channel used to communicate with the page being checked.
+ * @type {bidichecker.gui.common.CommChannel}
+ * @private
+ */
+bidichecker.gui.app.OptionsPage.prototype.channel_;
+
+
+/**
+ * Sends current settings to the page being checked and then navigates to the
+ * error browser. The error browser, when loaded, will trigger error checking on
+ * the page.
+ * @private
+ */
+bidichecker.gui.app.OptionsPage.prototype.handleCheckPageButton_ = function() {
+  this.channel_.send('setOptions', this.getOptions_());
+  window.location = 'errorpage.html';
+};
+
+
+/**
+ * Handles the "options" message from the page being checked.
+ * @param {string} type The message type. Assumed to "options".
+ * @param {*} data The message data. Should be an options object.
+ * @private
+ */
+bidichecker.gui.app.OptionsPage.prototype.handleOptionsMessage_ =
+    function(type, data) {
+  // Fill in controls based on received options.
+  var options = Object(data);
+  var severity = options['severity'];
+  if (severity != -1) {
+    this.severityField_.value = severity;
+  } else {
+    // Suppression by severity is disabled, but we still need a valid value to
+    // appear in the text box.
+    this.severityField_.value = 4;
+  }
+  // Save last known valid value.
+  this.severityField_.validValue = this.severityField_.value;
+  bidichecker.gui.app.setRadioButtonGroupValue_(
+      goog.dom.getDomHelper(), 'severity-filtering',
+      (severity != -1) ? 'on' : 'off');
+
+  bidichecker.gui.app.setRadioButtonGroupValue_(
+      goog.dom.getDomHelper(), 'dir', options['dir']);
+
+  this.updateControls_();
+};
+
+
+/**
+ * Validates changes to the current severity level option. If the change is
+ * invalid it is reverted.
+ * @param {goog.events.Event} event The event that triggered this handler.
+ * @private
+ */
+bidichecker.gui.app.OptionsPage.prototype.handleSeverityFieldChange_ =
+    function(event) {
+  var newValue = goog.string.toNumber(this.severityField_.value);
+  if (1 <= newValue && newValue <= 4) {
+    // Valid input. Save it in case we need to restore later.
+    this.severityField_.validValue = newValue;
+    this.updateControls_();
+  } else {
+    // Invalid input, reset the field contents to the previous value.
+    this.severityField_.value = this.severityField_.validValue;
+  }
+
+  // Prevent bubbling of the event so that handleGeneralChange_ won't see this
+  // change.
+  event.stopPropagation();
+};
+
+
+/**
+ * Handles changes not handled by more specific listeners.
+ * Since there's no way to listen on a radio button group, we listen
+ * on the whole page element.
+ * @param {goog.events.Event} event The event that triggered this handler.
+ * @private
+ */
+bidichecker.gui.app.OptionsPage.prototype.handleGeneralChange_ =
+    function(event) {
+  this.updateControls_();
+};
+
+
+/**
+ * Describe the bookmarklet feature to the user.
+ * @param {goog.events.Event} event The event that triggered this handler.
+ * @private
+ */
+bidichecker.gui.app.OptionsPage.prototype.handleShowHelpClick_ =
+    function(event) {
+  var message =
+    'You can add a button (a "bookmarklet") to your browser to run ' +
+    'BidiChecker on any web page, using the current BidiChecker settings. ' +
+    'To do this, just drag the link labeled BidiChecker to your browser\'s ' +
+    'bookmarks toolbar. ' +
+    'In Google Chrome, press Ctrl-Shift-B to show the bookmarks toolbar.';
+  alert(message);
+  event.preventDefault();
+};
+
+
+/**
+ * Makes the browser ignore clicks on the bookmarklet link, since the user
+ * probably doesn't want to activate the bookmarklet from within the
+ * bookmarklet.
+ * @param {goog.events.Event} event The event that triggered this handler.
+ * @private
+ */
+bidichecker.gui.app.OptionsPage.prototype.handleBookmarkletClick_ =
+    function(event) {
+  event.preventDefault();
+};
+
+
+/**
+ * Updates the state of the controls using current values.
+ * @private
+ */
+bidichecker.gui.app.OptionsPage.prototype.updateControls_ = function() {
+  // Enable the severity level text box iff severity filtering is on.
+  var severityFiltering =
+      bidichecker.gui.app.getRadioButtonGroupValue_(goog.dom.getDomHelper(),
+          'severity-filtering') == 'on';
+  goog.dom.getElement('severity').disabled = !severityFiltering;
+
+  this.updateBookmarklet_();
+};
+
+
+/**
+ * Updates the bookmarklet link with the current settings.
+ * @private
+ */
+bidichecker.gui.app.OptionsPage.prototype.updateBookmarklet_ = function() {
+  var link = bidichecker.generateBookmarklet(this.getOptions_());
+  this.bookmarklet_.href = link;
+};
+
+
+/**
+ * Returns the current options.
+ * @return {!Object} The current options.
+ * @private
+ */
+bidichecker.gui.app.OptionsPage.prototype.getOptions_ = function() {
+  var options = {};
+
+  var severityFiltering =
+      bidichecker.gui.app.getRadioButtonGroupValue_(goog.dom.getDomHelper(),
+          'severity-filtering') == 'on';
+  options.severity = severityFiltering ?
+      goog.string.toNumber(this.severityField_.value) :
+      -1;
+
+  options.dir = /** @type {string} */
+      bidichecker.gui.app.getRadioButtonGroupValue_(goog.dom.getDomHelper(),
+          'dir');
+
+  return options;
+};
diff --git a/src/gui/common/commchannel.js b/src/gui/common/commchannel.js
new file mode 100644
index 0000000..3e0901a
--- /dev/null
+++ b/src/gui/common/commchannel.js
@@ -0,0 +1,124 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview A communications channel for exchanging messages with another
+ * window of the browser. Used to coordinate between the GUI window and the page
+ * being checked.
+ */
+goog.provide('bidichecker.gui.common.CommChannel');
+
+goog.require('goog.events');
+goog.require('goog.events.EventType');
+goog.require('goog.json');
+goog.require('goog.structs.Map');
+
+
+/**
+ * A communications channel for exchanging messages with another window of the
+ * browser. On receipt of a message from the window, invokes a handler function
+ * corresponding to the message type.
+ * @param {Object} otherWindow The window to communicate with.
+ * @param {bidichecker.gui.common.CommChannel.MessageMap} messageMap Which
+ *     handler to invoke for each type of message received.
+ * @constructor
+ */
+bidichecker.gui.common.CommChannel = function(otherWindow, messageMap) {
+  /**
+   * The window we communicate with.
+   * @private
+   */
+  this.otherWindow_ = otherWindow;
+
+  /**
+   * A mapping from message types to message handlers.
+   * @type {bidichecker.gui.common.CommChannel.MessageMap}
+   * @private
+   */
+  this.messageMap_ = messageMap;
+
+  /**
+   * Key used to stop listening to the event when the object is disposed.
+   * @type {?number}
+   * @private
+   */
+  this.listenerKey_ = goog.events.listen(window, goog.events.EventType.MESSAGE,
+      this.handleMessageEvent_, false, this);
+};
+
+
+/**
+ * Send a message to the other site.
+ * @param {string} type The message type.
+ * @param {?*} opt_data Optional message data. Will be serialized as JSON
+ *     so it should be a JSON compatible type. Generally an array, object, an
+ *     atomic type or combinations thereof.
+ */
+bidichecker.gui.common.CommChannel.prototype.send = function(type, opt_data) {
+  var message = {
+    'type': type,
+    'data': opt_data
+  };
+  this.otherWindow_.postMessage(goog.json.serialize(message), '*');
+};
+
+
+/**
+ * Stop listening to messages. The object shouldn't be used after calling this
+ * method.
+ */
+bidichecker.gui.common.CommChannel.prototype.dispose = function() {
+  goog.events.unlistenByKey(this.listenerKey_);
+};
+
+
+/**
+ * Handle an incoming message.
+ * @param {goog.events.Event} event The message event that triggered this
+ *     handler.
+ * @private
+ */
+bidichecker.gui.common.CommChannel.prototype.handleMessageEvent_ =
+    function(event) {
+  var underlyingEvent = event.getBrowserEvent();
+  // Parse the message data. It should be a JSON string describing an object
+  // with the following keys:
+  // * 'type' (string)
+  // * 'data' (any type)
+  var message = goog.json.parse(underlyingEvent.data);
+  var type = String(message.type);
+  var data = message.data;
+
+  // Get message handler from message map and call it. Query map using
+  // "hasOwnProperty" so we don't confuse built-in properties with map contents.
+  if (!this.messageMap_.hasOwnProperty(type)) {
+    throw 'Unknown message type received by CommChannel: ' + type;
+  }
+  var handler = this.messageMap_[type];
+  handler(type, data);
+};
+
+
+/**
+ * A message handler. Message handlers should always verify the message contents
+ * since the message may come from any site.
+ * @typedef {function(string, *)}
+ */
+bidichecker.gui.common.CommChannel.MessageHandler;
+
+/**
+ * @typedef {Object.<string, bidichecker.gui.common.CommChannel.MessageHandler>}
+ */
+bidichecker.gui.common.CommChannel.MessageMap;
+
diff --git a/src/gui/common/commchannel_test.html b/src/gui/common/commchannel_test.html
new file mode 100644
index 0000000..6f7aa37
--- /dev/null
+++ b/src/gui/common/commchannel_test.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+  <!--
+    Copyright 2011 Google Inc. All Rights Reserved.
+
+    Use of this source code is governed by an Apache 2.0 License.
+    See the COPYING file for details.
+  -->
+
+  <head>
+    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
+    <title>CommChannel: End-to-End test</title>
+    <script type="text/javascript" src="../../../third_party/closure-library/closure/goog/base.js">
+    </script>
+    <script type="text/javascript" src="../../deps.js"></script>
+    <script>
+      goog.require('bidichecker.gui.common.CommChannel');
+      goog.require('goog.dom');
+      goog.require('goog.testing.AsyncTestCase');
+      goog.require('goog.testing.jsunit');
+      goog.require('goog.userAgent.product');
+    </script>
+
+  </head>
+  <body>
+    <script>
+// Set up AsyncTestCase.
+var asyncTestCase = goog.testing.AsyncTestCase.createAndInstall(
+    document.title);
+
+// Send a message to an inner frame and wait for an acknowledgement. This
+// doesn't completely test CommChannel, since it doesn't test communications
+// between separate windows (we can't test that because opening a new window
+// would be blocked by popup blockers).
+function testCommunicationWithFrame() {
+  // Skip test since postMessage doesn't work in versions before 8. (An
+  // isVersion(X) call means version X and up).
+  if (goog.userAgent.IE && !goog.userAgent.isVersion('8')) {
+    return;
+  }
+
+  // Message that the inner page sends when it is ready to receive messages.
+  var onReadyMessage = function(type, data) {
+    assertEquals(type, 'ready');
+    assertNull(data);
+
+    // Send ping message and wait for reply.
+    asyncTestCase.waitForAsync('receive pong');
+    channel.send('ping', pingData);
+  };
+
+  // Acknowledgement message. Should have the same data that we've sent.
+  var onPongMessage = function(type, data) {
+    assertEquals(type, 'pong');
+    assertEquals(data, pingData);
+
+    // Done.
+    asyncTestCase.continueTesting();
+  };
+
+  // Arbitrary data to send to other frame, and to verify later that we get it
+  // back.
+  var pingData = 'testing 123';
+
+  // Create frame.
+  var iframe = goog.dom.createElement('iframe');
+  document.body.appendChild(iframe);
+
+  // Set up comm channel.
+  var channel = new bidichecker.gui.common.CommChannel(iframe.contentWindow, {
+    'ready': onReadyMessage,
+    'pong': onPongMessage
+  });
+
+  // Navigate frame to the test helper and wait for it to say it's ready.
+  asyncTestCase.waitForAsync('frame ready');
+  iframe.src = 'testdata/commchannel_test_innerframe.html';
+}
+
+    </script>
+  </body>
+</html>
+
diff --git a/src/gui/common/testdata/commchannel_test_innerframe.html b/src/gui/common/testdata/commchannel_test_innerframe.html
new file mode 100644
index 0000000..c5a767a
--- /dev/null
+++ b/src/gui/common/testdata/commchannel_test_innerframe.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+  <!--
+    Copyright 2011 Google Inc. All Rights Reserved.
+
+    Use of this source code is governed by an Apache 2.0 License.
+    See the COPYING file for details.
+  -->
+
+  <!--
+    Helper for commchannel_test.html. Page designed to be opened in an inner
+    frame so we can test inter-frame communication.
+  -->
+  <head>
+    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
+    <script type="text/javascript" src="../../../../third_party/closure-library/closure/goog/base.js">
+    </script>
+    <script type="text/javascript" src="../../../deps.js"></script>
+    <script>
+goog.require('bidichecker.gui.common.CommChannel');
+
+var channel;
+
+function setUpChannel() {
+  channel = new bidichecker.gui.common.CommChannel(window.parent, {
+    'ping': onPing
+  });
+
+  // Notify other side that we're ready.
+  channel.send('ready');
+}
+
+function onPing(type, data) {
+  // Send back data we've been sent.
+  channel.send('pong', data);
+}
+    </script>
+
+  </head>
+  <body onload="setUpChannel();">
+  </body>
+</html>
+
diff --git a/src/gui/server/dialogguicontainer.js b/src/gui/server/dialogguicontainer.js
new file mode 100644
index 0000000..ff41da6
--- /dev/null
+++ b/src/gui/server/dialogguicontainer.js
@@ -0,0 +1,140 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+/**
+ * @fileoverview A GuiContainer for in-page dialog.
+ */
+goog.provide('bidichecker.gui.server.DialogGuiContainer');
+
+goog.require('bidichecker.gui.server.GuiContainer');
+goog.require('goog.style');
+goog.require('goog.ui.Dialog');
+
+
+/**
+ * A dialog box used to render the GUI within the page being checked, rather
+ * than in a popup window. The dialog box contains an iframe element which
+ * contains the GUI.
+ * @constructor
+ * @extends {bidichecker.gui.server.GuiContainer}
+ */
+bidichecker.gui.server.DialogGuiContainer = function() {
+  goog.base(this);
+
+  var dialog = new goog.ui.Dialog('bidichecker-dialog');
+  dialog.setModal(false);  // Underlying page remains accessible.
+  dialog.setVisible(true);
+  var dialogElement = dialog.getElement();
+
+  // Prevent page elements from leaking through the dialog box.
+  dialogElement.style.zIndex = 10000;
+
+  // Set up the "X" button.
+  // TODO(user): Use a real image instead of a character.
+  dialog.getTitleCloseElement().innerHTML = '&times;';
+
+  // Set the disposeOnHide flag, so the dialog will really be "closed" when
+  // the close button is clicked, not merely hidden.
+  dialog.setDisposeOnHide(true);
+
+  var iframe = goog.dom.createElement('iframe');
+
+  var dialogContent = dialog.getContentElement();
+  dialogContent.appendChild(iframe);
+
+  this.setContentWindow(iframe.contentWindow);
+
+  /**
+   * The stylesheet used to style the dialog.
+   * @type {Element|StyleSheet}
+   * @private
+   */
+  this.styleSheet_ = goog.style.installStyles(
+      bidichecker.gui.server.DialogGuiContainer.DIALOG_STYLES, dialogContent);
+
+  // Resize the content element so it will fill the vertical dialog space not
+  // taken by other elements.
+  // Note that this calculation doesn't take into account the content element's
+  // padding, border, or margins. It assumes there are none.
+  var dialogInnerHeight = goog.style.getContentBoxSize(dialogElement).height;
+  var contentHeight = dialogInnerHeight - dialog.getTitleElement().offsetHeight;
+  goog.style.setHeight(dialogContent, contentHeight);
+
+  // Center dialog in the viewport.
+  dialog.reposition();
+
+  /**
+   * The underlying Dialog object.
+   * @type {!goog.ui.Dialog}
+   * @private
+   */
+  this.dialog_ = dialog;
+};
+goog.inherits(bidichecker.gui.server.DialogGuiContainer,
+    bidichecker.gui.server.GuiContainer);
+
+
+/**
+ * Style definitions for the dialog box.
+ * @const
+ * @type {string}
+ */
+bidichecker.gui.server.DialogGuiContainer.DIALOG_STYLES =
+    '.bidichecker-dialog-bg { position: absolute; top: 0; left: 0; }' +
+
+    '.bidichecker-dialog {' +
+    'font-family: arial, sans-serif' +
+    '}' +
+
+    '.bidichecker-dialog-buttons {' +
+      'display: none;' +
+    '}' +
+
+    '.bidichecker-dialog-title-close {' +
+      'position: absolute;' +
+      'right: 0;' +
+      'padding-right: 5px;' +
+      'padding-left: 5px;' +
+    '}' +
+
+    '.bidichecker-dialog-title-close:hover {' +
+      'background-color: #fee;' +
+    '}' +
+
+    '.bidichecker-dialog iframe {' +
+      'border: 0;' +
+      'height: 100%;' +
+      'width: 100%;' +
+      'background: white;' +
+    '}' +
+
+    '.bidichecker-dialog { position: absolute;' +
+    ' background-color: #fcb; border: 1px solid #000; ' +
+    'width: 800px; height: 600px; color: #000; ' +
+    'outline: none; direction: ltr }' +
+
+    '.bidichecker-dialog-title { position: relative; ' +
+    'padding-bottom: 5px;' +
+    'height: 1em;' +
+    'color: #000000;' +
+    'font-size: 16px; font-weight: bold; vertical-align: middle; }' +
+
+    '.bidichecker-dialog .bidichecker-dialog-title {' +
+    'cursor: pointer; cursor: hand }' +
+
+    '';
+
+
+/** @override */
+bidichecker.gui.server.DialogGuiContainer.prototype.dispose = function() {
+  this.dialog_.dispose();
+  goog.style.uninstallStyles(this.styleSheet_);
+};
+
+
+/** @override */
+bidichecker.gui.server.DialogGuiContainer.prototype.handleScroll =
+    function(scrollY) {
+  var dialogElement = this.dialog_.getElement();
+  var coords = goog.style.getPosition(dialogElement);
+  goog.style.setPosition(dialogElement, coords.x, coords.y + scrollY);
+};
diff --git a/src/gui/server/guicontainer.js b/src/gui/server/guicontainer.js
new file mode 100644
index 0000000..37d0c67
--- /dev/null
+++ b/src/gui/server/guicontainer.js
@@ -0,0 +1,59 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+/**
+ * @fileoverview The GuiContainer abstract class.
+ */
+goog.provide('bidichecker.gui.server.GuiContainer');
+
+
+
+/**
+ * An abstract class representing an object which can display the BidiChecker
+ * GUI web application and communicate with it. The web application is displayed
+ * in a browser window object called the "content window". The GuiContainer is
+ * responsible for managing the window chrome, e.g. disposing of it.
+ * @constructor
+ */
+bidichecker.gui.server.GuiContainer = function() {
+};
+
+
+/**
+ * The content window object where the GUI resides.
+ * @type {Window}
+ * @private
+ */
+bidichecker.gui.server.GuiContainer.prototype.contentWindow_;
+
+
+/**
+ * @param {Window} contentWindow The content window object.
+ * @protected
+ */
+bidichecker.gui.server.GuiContainer.prototype.setContentWindow =
+    function(contentWindow) {
+  this.contentWindow_ = contentWindow;
+};
+
+
+/**
+ * @return {Window} The content window object.
+ */
+bidichecker.gui.server.GuiContainer.prototype.getContentWindow = function() {
+  return this.contentWindow_;
+};
+
+
+/**
+ * Frees the resources taken by the object, closing it if necessary.
+ */
+bidichecker.gui.server.GuiContainer.prototype.dispose = goog.abstractMethod;
+
+
+/**
+ * Notifies the object that the checked document has scrolled to a given
+ * position. The default implementation is a no-op.
+ * @param {number} scrollY The distance the window moved.
+ */
+bidichecker.gui.server.GuiContainer.prototype.handleScroll = function(scrollY) {
+};
diff --git a/src/gui/server/guicontainerfactory.js b/src/gui/server/guicontainerfactory.js
new file mode 100644
index 0000000..501599e
--- /dev/null
+++ b/src/gui/server/guicontainerfactory.js
@@ -0,0 +1,55 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+/**
+ * @fileoverview Factory methods for creating GuiContainers.
+ */
+goog.provide('bidichecker.gui.server.GuiContainerFactory');
+
+goog.require('bidichecker.gui.server.DialogGuiContainer');
+goog.require('bidichecker.gui.server.WindowGuiContainer');
+
+
+/**
+ * If hostWindow != null, or a new window can be created, returns a new
+ * WindowGuiContainer. Otherwise, returns a new DialogGuiContainer. (Window
+ * creation may fail because of popup blockers.)
+ * @param {Window} hostWindow The window to be used as the container. If null, a
+ *     suitable window will be created.
+ * @return {!bidichecker.gui.server.GuiContainer} The created GuiContainer.
+ */
+bidichecker.gui.server.GuiContainerFactory.createFromWindow =
+    function(hostWindow) {
+  try {
+    return new bidichecker.gui.server.WindowGuiContainer(hostWindow);
+  } catch (e) {
+    return new bidichecker.gui.server.DialogGuiContainer();
+  }
+};
+
+
+/**
+ * If opt_noPopup isn't true, and a popup window can be created, returns a new
+ * WindowGuiContainer. Otherwise returns a new DialogGuiContainer.
+ * @param {boolean=} opt_noPopup If given and true, don't try to create a popup
+ *     window.
+ * @return {!bidichecker.gui.server.GuiContainer} The created GuiContainer.
+ */
+bidichecker.gui.server.GuiContainerFactory.createFromScratch =
+    function(opt_noPopup) {
+  return opt_noPopup ?
+    new bidichecker.gui.server.DialogGuiContainer() :
+    bidichecker.gui.server.GuiContainerFactory.createFromWindow(null);
+};
diff --git a/src/gui/server/guiserver.js b/src/gui/server/guiserver.js
new file mode 100644
index 0000000..ada7b21
--- /dev/null
+++ b/src/gui/server/guiserver.js
@@ -0,0 +1,271 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+/**
+ * @fileoverview Class which resides on the page being checked and communicates
+ * with a BidiChecker GUI, responding to its requests. See the GUI Message
+ * Protocol document for descriptions of the messages sent between the GUI and
+ * the page being checked.
+ */
+goog.provide('bidichecker.gui.server.GuiServer');
+
+goog.require('bidichecker.Error');
+goog.require('bidichecker.gui.common.CommChannel');
+goog.require('bidichecker.gui.server.GuiContainer');
+
+
+
+/**
+ * Server which communicates with a GUI and responds to its requests. To ensure
+ * that only one instance of the server will be active at any time on a
+ * particular page (being checked), and to ensure proper initialization order,
+ * call {@code bidichecker.gui.server.GuiServer.startServer} after construction.
+ * @param {!bidichecker.BidiChecker} checker A BidiChecker instance used for
+ *     checking the page.
+ * @param {Object.<string, Object>} options The initial options.
+ *     Options are specified as an object with the following (optional) keys:
+ *     <ul>
+ *     <li>dir -- string, "rtl" or "ltr" (the default). The expected page
+ *     directionality.
+ *     <li>severity -- The severity level from which to suppress error messages,
+ *     or -1 (for no severity filtering). Default 4.
+ *     </ul>
+ * @param {!bidichecker.gui.server.GuiContainer} guiContainer The object which
+ *     displays the BidiChecker GUI web application. The GuiServer will be
+ *     responsible for disposing this object.
+ * @param {string} guiAppUrl Location of the GUI files.
+ * @param {Array.<!bidichecker.Error>=} opt_errors Array of error objects for
+ *     initial checkPage request. Subsequent requests will be handled as usual
+ *     by invoking the given BidiChecker's checkPage method.
+ * @constructor
+ */
+bidichecker.gui.server.GuiServer = function(checker, options, guiContainer,
+    guiAppUrl, opt_errors) {
+  // Set defaults for unspecified options.
+  options = goog.object.clone(options);
+  var defaults = {
+    'dir': 'ltr',
+    'severity': 4
+  };
+  for (var key in defaults) {
+    if (!(key in options)) {
+      options[key] = defaults[key];
+    }
+  }
+
+  /**
+   * A BidiChecker instance used for checking the page.
+   * @type {!bidichecker.BidiChecker}
+   * @private
+   */
+  this.checker_ = checker;
+
+  /**
+   * The current options. We manage them here instead of at the GUI side because
+   * the GUI side may have trouble maintaining state (due to refreshes, etc).
+   * @type {Object}
+   * @private
+   */
+  this.options_ = options;
+
+  /**
+   * The object that manages the BidiChecker GUI web application.
+   * @type {!bidichecker.gui.server.GuiContainer}
+   * @private
+   */
+  this.guiContainer_ = guiContainer;
+
+  /**
+   * Location of the GUI files.
+   * @type {string}
+   * @private
+   */
+  this.guiAppUrl_ = guiAppUrl;
+
+  /**
+   * Errors to return as a response to the first checkPage message. Null if no
+   * initial errors were specified or the errors were already returned.
+   * @type {Array.<!bidichecker.Error>}
+   * @private
+   */
+  this.initialErrors_ = opt_errors || null;
+};
+
+
+/**
+ * Completes initialization of a new GuiServer instance and makes it the active
+ * one. Before that, disposes the running server, if any.
+ * @param {bidichecker.gui.server.GuiServer} server The GuiServer that will be
+ *     server.
+ */
+bidichecker.gui.server.GuiServer.startServer = function(server) {
+  goog.dispose(bidichecker.gui.server.GuiServer.activeServer_);
+  bidichecker.gui.server.GuiServer.activeServer_ = server;
+  server.start();
+};
+
+
+/**
+ * The communication channel.
+ * @type {bidichecker.gui.common.CommChannel}
+ * @private
+ */
+bidichecker.gui.server.GuiServer.prototype.channel_ = null;
+
+
+/**
+ * Completes initialization of the server after any existing running server is
+ * stopped, and starts the error browser.
+ * Visible for testing only.
+ */
+bidichecker.gui.server.GuiServer.prototype.start = function() {
+  var guiWindow = this.guiContainer_.getContentWindow();
+  this.channel_ = new bidichecker.gui.common.CommChannel(guiWindow, {
+      'checkPage': goog.bind(this.handleCheckPageMessage_, this),
+      'highlightError': goog.bind(this.handleHighlightErrorMessage_, this),
+      'unhighlightError': goog.bind(this.handleUnhighlightErrorMessage_, this),
+      'getOptions': goog.bind(this.handleGetOptionsMessage_, this),
+      'setOptions': goog.bind(this.handleSetOptionsMessage_, this)
+  });
+  guiWindow.location = this.guiAppUrl_;
+};
+
+
+/**
+ * Stops listening to messages and closes the GuiContainer. The object shouldn't
+ * be used after calling this method.
+ */
+bidichecker.gui.server.GuiServer.prototype.dispose = function() {
+  goog.dispose(this.channel_);
+  delete this.channel_;
+
+  goog.dispose(this.guiContainer_);
+  delete this.guiContainer_;
+};
+
+
+/**
+ * Checks the document using the current options and returns the results.
+ * @return {!Array.<!bidichecker.Error>} Array of error objects for all failing
+ *     checks.
+ * @private
+ */
+bidichecker.gui.server.GuiServer.prototype.checkPageWithCurrentOptions_ =
+    function() {
+  var options = this.options_;
+  var filters = [];
+  if (options['severity'] != -1) {
+    filters.push(bidichecker.FilterFactory.severityFrom(options['severity']));
+  }
+  return this.checker_.checkPage(options['dir'] == 'rtl', null, filters);
+};
+
+
+/**
+ * @return {Object} The current options.
+ */
+bidichecker.gui.server.GuiServer.prototype.getOptions =
+    function() {
+  return this.options_;
+};
+
+
+/**
+ * Sends back an "options" message with the current options.
+ * @private
+ */
+bidichecker.gui.server.GuiServer.prototype.handleGetOptionsMessage_ =
+    function() {
+  this.channel_.send('options', this.options_);
+};
+
+
+/**
+ * Sets the current options.
+ * @param {string} type The message type. Should be "setOptions".
+ * @param {*} data Message data. The options object to use.
+ * @private
+ */
+bidichecker.gui.server.GuiServer.prototype.handleSetOptionsMessage_ =
+    function(type, data) {
+  this.options_ = Object(data);
+};
+
+
+/**
+ * Checks the page for errors and sends back an "errorList" message with the
+ * results.
+ * @private
+ */
+bidichecker.gui.server.GuiServer.prototype.handleCheckPageMessage_ =
+    function() {
+  var errors;
+  if (this.initialErrors_) {
+    errors = this.initialErrors_;
+    this.initialErrors_ = null;
+  } else {
+    errors = this.checkPageWithCurrentOptions_();
+  }
+  // Convert the list of Error objects into a list of "raw" Objects consumable
+  // by the send method, by serializing and then deserializing them.
+  var rawObjects = goog.json.parse(bidichecker.Error.serialize(errors));
+  this.channel_.send('errorList', rawObjects);
+};
+
+
+/**
+ * Scrolls the window so a given page position is near the top of the screen.
+ * Notifies the GuiContainer so it can update its own location if necessary.
+ * @param {goog.math.Coordinate} coords The coordinates to scroll to.
+ * @private
+ */
+bidichecker.gui.server.GuiServer.prototype.scrollTo_ = function(coords) {
+  var oldY = window.scrollY;
+  window.scrollTo(0, coords.y - 100);
+  this.guiContainer_.handleScroll(window.scrollY - oldY);
+};
+
+
+/**
+ * @param {string} type The message type. Should be "highlightError".
+ * @param {*} data Message data. Should be the deserialized error object.
+ * @private
+ */
+bidichecker.gui.server.GuiServer.prototype.handleHighlightErrorMessage_ =
+    function(type, data) {
+  var error = new bidichecker.Error(Object(data));
+  var highlightableArea = error.getHighlightableArea();
+  if (highlightableArea) {
+    var coords = highlightableArea.highlightOnPage();
+    this.scrollTo_(coords);
+  }
+};
+
+
+/**
+ * @param {string} type The message type. Should be "unhighlightError".
+ * @param {*} data Message data. Should be the deserialized error object.
+ * @private
+ */
+bidichecker.gui.server.GuiServer.prototype.handleUnhighlightErrorMessage_ =
+    function(type, data) {
+  var error = new bidichecker.Error(Object(data));
+  var highlightableArea = error.getHighlightableArea();
+  if (highlightableArea) {
+    highlightableArea.unhighlightOnPage();
+  }
+};
+
+
diff --git a/src/gui/server/guiserver_test.html b/src/gui/server/guiserver_test.html
new file mode 100644
index 0000000..c78e2f7
--- /dev/null
+++ b/src/gui/server/guiserver_test.html
@@ -0,0 +1,282 @@
+<!DOCTYPE html>
+<html>
+  <!--
+    Copyright 2011 Google Inc. All Rights Reserved.
+
+    Use of this source code is governed by an Apache 2.0 License.
+    See the COPYING file for details.
+  -->
+
+  <!--
+  Unit tests for guiserver.js.
+  -->
+  <head>
+    <title>bidichecker - Javascript Unit Tests</title>
+    <script type="text/javascript" src="../../../third_party/closure-library/closure/goog/base.js">
+    </script>
+
+    <!-- Include the generated deps.js which enables goog.require of
+         the modules under test.
+    -->
+    <script type="text/javascript" src="../../deps.js"></script>
+    <script type="text/javascript">
+goog.require('bidichecker.gui.server.GuiServer');
+
+goog.require('bidichecker.BidiChecker');
+goog.require('bidichecker.Error');
+goog.require('bidichecker.gui.common.CommChannel');
+goog.require('bidichecker.gui.server.GuiContainer');
+
+goog.require('goog.json');
+goog.require('goog.testing.jsunit');
+goog.require('goog.testing.MockControl');
+    </script>
+
+  </head>
+  <body>
+    <script type="text/javascript">
+
+var GUI_APP_URL = "http://www.example.com/gui-app";
+
+function setUp() {
+  g_mockControl = new goog.testing.MockControl();
+  g_mockBidiChecker = g_mockControl.createLooseMock(bidichecker.BidiChecker);
+  g_mockChannel =
+    g_mockControl.createLooseMock(bidichecker.gui.common.CommChannel);
+  g_mockChannelConstructor =
+    g_mockControl.createConstructorMock(bidichecker.gui.common, 'CommChannel');
+  g_mockGuiContainer =
+    g_mockControl.createLooseMock(bidichecker.gui.server.GuiContainer);
+}
+
+function tearDown() {
+  g_mockControl.$tearDown();
+}
+
+function setupStartExpectations() {
+  g_mockWindow = {};
+  // Expect the mock channel constructor to be called with a message map, and
+  // save that message map so we can later use it to simulate messages.
+  g_messageMapSaver = new goog.testing.mockmatchers.SaveArgument();
+  g_mockChannelConstructor(g_mockWindow, g_messageMapSaver)
+      .$returns(g_mockChannel);
+  g_mockGuiContainer.getContentWindow().$returns(g_mockWindow);
+}
+
+function startGuiServer(opt_options, opt_errors) {
+  var server = new bidichecker.gui.server.GuiServer(g_mockBidiChecker,
+      opt_options || {}, g_mockGuiContainer, GUI_APP_URL, opt_errors);
+  server.start();
+  return server;
+}
+
+function testGuiServer_start() {
+  setupStartExpectations();
+  g_mockControl.$replayAll();
+
+  startGuiServer();
+  g_mockControl.$verifyAll();
+
+  // Check that window location was set correctly. This check can't be done by
+  // the mock because it's a property assignment, which is hard to intercept.
+  assertEquals('Location should be set to GUI app url.', GUI_APP_URL,
+      g_mockWindow.location);
+}
+
+/**
+ * Simulates a message being received by the CommChannel, by calling the
+ * callback registered on the mock CommChannel.
+ */
+function simulateMessage(type, data) {
+  var callback = g_messageMapSaver.arg[type];
+  callback(type, data);
+}
+
+function testGuiServer_checkPageWithoutInitialErrors() {
+  setupStartExpectations();
+
+  // Expect checkPage to be called.
+  var filters = [];
+  var errors = [new bidichecker.Error('my error', 1),
+      new bidichecker.Error('their error', 2)];
+  g_mockBidiChecker.checkPage(false, null, filters).$returns(errors);
+
+  // Expect the server to send back a message with the error list returned by
+  // checkPage (as raw JSON objects).
+  var rawErrors = goog.json.parse(bidichecker.Error.serialize(errors));
+  g_mockChannel.send('errorList', rawErrors);
+
+  g_mockControl.$replayAll();
+
+  var options = {
+    severity: -1  // So we won't have to deal with severity filters.
+  };
+  startGuiServer(options);
+  simulateMessage('checkPage');
+
+  g_mockControl.$verifyAll();
+}
+
+function testGuiServer_checkPageWithInitialErrors() {
+  setupStartExpectations();
+
+  var errors = [new bidichecker.Error('my error', 1),
+      new bidichecker.Error('their error', 2)];
+
+  // Expect the server to send back a message with the error list we gave it
+  // (as raw JSON objects).
+  var rawErrors = goog.json.parse(bidichecker.Error.serialize(errors));
+  g_mockChannel.send('errorList', rawErrors);
+
+  g_mockControl.$replayAll();
+
+  var options = {
+    severity: -1  // So we won't have to deal with severity filters.
+  };
+  startGuiServer(options, errors);
+  simulateMessage('checkPage');
+
+  g_mockControl.$verifyAll();
+
+  // The second time we get the message, the server should call checkPage as
+  // usual and send back a message with the returned error list.
+  g_mockControl.$resetAll();
+  var filters = [];
+  var newErrors = [new bidichecker.Error('his error', 3),
+      new bidichecker.Error('our error', 4)];
+  g_mockBidiChecker.checkPage(false, null, filters).$returns(newErrors);
+  var rawNewErrors = goog.json.parse(bidichecker.Error.serialize(newErrors));
+  g_mockChannel.send('errorList', rawNewErrors);
+  g_mockControl.$replayAll();
+  simulateMessage('checkPage');
+  g_mockControl.$verifyAll();
+}
+
+function testGuiServer_getOptions() {
+  setupStartExpectations();
+
+  // Expect the server to send back a message with the default options.
+  var defaultOptions = {
+    'dir': 'ltr',
+    'severity': 4
+  };
+  g_mockChannel.send('options', defaultOptions);
+
+  g_mockControl.$replayAll();
+
+  startGuiServer();
+  simulateMessage('getOptions');
+
+  g_mockControl.$verifyAll();
+}
+
+function testGuiServer_setOptions() {
+  setupStartExpectations();
+
+  g_mockControl.$replayAll();
+
+  var server = startGuiServer();
+  // Options which are decidedly different from the default.
+  var options = {
+    'dir': 'rtl',
+    'severity': 2
+  };
+  simulateMessage('setOptions', options);
+
+  g_mockControl.$verifyAll();
+  assertObjectEquals(options, server.getOptions());
+}
+
+function testGuiServer_highlightError() {
+  setupStartExpectations();
+  // Server is expected to create an Error object, get its HighlightableArea,
+  // and call its highlightOnPage method.
+  var rawError = {
+    'dummy': 'this is the error as an object'
+  };
+  var mockError =
+    g_mockControl.createLooseMock(bidichecker.Error);
+  var mockErrorConstructor =
+    g_mockControl.createConstructorMock(bidichecker, 'Error');
+  var mockHighlightableArea =
+    g_mockControl.createLooseMock(bidichecker.HighlightableArea);
+  mockErrorConstructor(rawError).$returns(mockError);
+  mockError.getHighlightableArea().$returns(mockHighlightableArea);
+  var coords = {
+    'y': 123
+  };
+  mockHighlightableArea.highlightOnPage().$returns(coords);
+  // Expect server to call handleScroll with *some* number that we don't know
+  // for sure since it depends on how much the (test) window was actually
+  // scrolled, an on a magic offset defined in GuiServer.
+  g_mockGuiContainer.handleScroll(goog.testing.mockmatchers.isNumber);
+
+  g_mockControl.$replayAll();
+
+  var server = startGuiServer();
+  simulateMessage('highlightError', rawError);
+
+  g_mockControl.$verifyAll();
+}
+
+function testGuiServer_unhighlightError() {
+  setupStartExpectations();
+  // Server is expected to create an Error object, get its HighlightableArea,
+  // and call its unhighlightOnPage method.
+  var rawError = {
+    'dummy': 'this is the error as an object'
+  };
+  var mockError =
+    g_mockControl.createLooseMock(bidichecker.Error);
+  var mockErrorConstructor =
+    g_mockControl.createConstructorMock(bidichecker, 'Error');
+  var mockHighlightableArea =
+    g_mockControl.createLooseMock(bidichecker.HighlightableArea);
+  mockErrorConstructor(rawError).$returns(mockError);
+  mockError.getHighlightableArea().$returns(mockHighlightableArea);
+  mockHighlightableArea.unhighlightOnPage();
+
+  g_mockControl.$replayAll();
+
+  var server = startGuiServer();
+  simulateMessage('unhighlightError', rawError);
+
+  g_mockControl.$verifyAll();
+}
+
+function testGuiServer_startServer() {
+  var mockServer1 =
+    g_mockControl.createLooseMock(bidichecker.gui.server.GuiServer);
+  mockServer1.start();
+  g_mockControl.$replayAll();
+  bidichecker.gui.server.GuiServer.startServer(mockServer1);
+  g_mockControl.$verifyAll();
+
+  // Starting another server. The first server's dispose method should be
+  // called.
+  g_mockControl.$resetAll();
+  mockServer1.dispose();
+  var mockServer2 =
+    g_mockControl.createLooseMock(bidichecker.gui.server.GuiServer);
+  mockServer2.start();
+  g_mockControl.$replayAll();
+  bidichecker.gui.server.GuiServer.startServer(mockServer2);
+  g_mockControl.$verifyAll();
+}
+
+function testGuiServer_dispose() {
+  setupStartExpectations();
+  g_mockChannel.dispose();
+  g_mockGuiContainer.dispose();
+
+  g_mockControl.$replayAll();
+
+  var server = startGuiServer();
+  server.dispose();
+  g_mockControl.$verifyAll();
+}
+
+    </script>
+
+  </body>
+</html>
diff --git a/src/gui/server/windowguicontainer.js b/src/gui/server/windowguicontainer.js
new file mode 100644
index 0000000..ace2051
--- /dev/null
+++ b/src/gui/server/windowguicontainer.js
@@ -0,0 +1,97 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+/**
+ * @fileoverview A GuiContainer for popup windows.
+ */
+goog.provide('bidichecker.gui.server.WindowGuiContainer');
+
+goog.require('bidichecker.gui.server.GuiContainer');
+
+
+/**
+ * A popup window which displays the BidiChecker GUI.
+ * @param {Window} hostWindow The window to be used as the container. If null, a
+ *     suitable window will be created.
+ * @constructor
+ * @extends {bidichecker.gui.server.GuiContainer}
+ * @throws {Error} If null was given and the window couldn't be created.
+ */
+bidichecker.gui.server.WindowGuiContainer = function(hostWindow) {
+  goog.base(this);
+
+  if (!hostWindow) {
+    hostWindow =
+        bidichecker.gui.server.WindowGuiContainer.createBrowserWindow_();
+    if (!hostWindow) {
+      throw Error('can\'t create window');
+    }
+  }
+
+  bidichecker.gui.server.WindowGuiContainer.adjustPopup_(hostWindow);
+  this.setContentWindow(hostWindow);
+};
+goog.inherits(bidichecker.gui.server.WindowGuiContainer,
+    bidichecker.gui.server.GuiContainer);
+
+
+/**
+ * Width to which the popup window will be resized.
+ * @const
+ * @private
+ */
+bidichecker.gui.server.WindowGuiContainer.WINDOW_WIDTH_ = 800;
+
+
+/**
+ * Height to which the popup window will be resized.
+ * @const
+ * @private
+ */
+bidichecker.gui.server.WindowGuiContainer.WINDOW_HEIGHT_ = 600;
+
+
+/**
+ * Adjusts the popup window's appearance, including resizing it to the
+ * appropriate size. It is our desire to relieve the bookmarklet (which must
+ * create the host window itself in order to bypass popup blockers) from having
+ * to do the adjusting correctly itself.
+ * @param {!Window} hostWindow The window to adjust.
+ * @private
+ */
+bidichecker.gui.server.WindowGuiContainer.adjustPopup_ = function(hostWindow) {
+  // Call resizeTo inside a setTimeout, to avoid a Chrome bug where, if resizeTo
+  // was called too soon the window was downsized into nothingness.
+  setTimeout(function() {
+    hostWindow.resizeTo(
+        bidichecker.gui.server.WindowGuiContainer.WINDOW_WIDTH_,
+        bidichecker.gui.server.WindowGuiContainer.WINDOW_HEIGHT_);
+  }, 1);
+};
+
+
+/**
+ * Attempts to create a blank browser window with the right settings for the
+ * GUI.
+ * @return {Window} Handle to the newly created window, or null if creation
+ *     blocked (e.g. because of popup blockers).
+ * @private
+ */
+bidichecker.gui.server.WindowGuiContainer.createBrowserWindow_ = function() {
+  var features =
+      'width=' + bidichecker.gui.server.WindowGuiContainer.WINDOW_WIDTH_ +
+      ',height=' + bidichecker.gui.server.WindowGuiContainer.WINDOW_HEIGHT_ +
+      ',menubar=no,toolbar=no,location=no';
+
+  return window.open('about:blank', '_blank', features);
+};
+
+
+/** @override */
+bidichecker.gui.server.WindowGuiContainer.prototype.dispose = function() {
+  try {
+    this.getContentWindow().close();
+  } catch (e) {
+    // The close() call may throw an exception if the user has already closed
+    // the window manually. Ignore this exception.
+  }
+};
diff --git a/src/highlightableelement.js b/src/highlightableelement.js
index 8e0a8fb..879557b 100644
--- a/src/highlightableelement.js
+++ b/src/highlightableelement.js
@@ -20,20 +20,21 @@
 goog.provide('bidichecker.HighlightableElement');
 
 goog.require('bidichecker.HighlightableArea');
+goog.require('bidichecker.utils');
 goog.require('goog.style');
 
 
 /**
  * Class representing the highlightable area of a BiDi error without associated
  * text.
- * @param {Element} element A DOM element indicating the location of the error.
+ * @param {!Element} element A DOM element indicating the location of the error.
  * @implements {bidichecker.HighlightableArea}
  * @constructor
  */
 bidichecker.HighlightableElement = function(element) {
   /**
    * The element associated with the error.
-   * @type {Element}
+   * @type {!Element}
    * @private
    */
   this.element_ = element;
@@ -41,29 +42,27 @@
 
 
 /**
- * The original background color of the element.
- * @type {?string}
+ * Contains the color, backgroundColor and outline fields of the element's
+ * original style.
+ * @type {Object}
  * @private
  */
-bidichecker.HighlightableElement.prototype.oldBackgroundColor_ = null;
+bidichecker.HighlightableElement.prototype.savedStyle_ = null;
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.HighlightableElement.prototype.highlightOnPage = function() {
-  // Change the element's background color to yellow.
-  // TODO(user): What should we do if the background is already yellow?
-  this.oldBackgroundColor_ = goog.style.getBackgroundColor(this.element_);
-  goog.style.setStyle(this.element_, 'background-color', 'yellow');
-  return goog.style.getPageOffset(/** @type {Element} */ (this.element_));
+  this.savedStyle_ = bidichecker.utils.highlightElementStyle(this.element_);
+  return goog.style.getPageOffset(this.element_);
 };
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.HighlightableElement.prototype.unhighlightOnPage = function() {
-  // Restore the original border style.
-  if (this.oldBackgroundColor_ != null) {
-    goog.style.setStyle(this.element_, 'background-color',
-        this.oldBackgroundColor_);
+  // Restore the original styles.
+  if (this.savedStyle_) {
+    this.element_.style.color = this.savedStyle_.color;
+    this.element_.style.backgroundColor = this.savedStyle_.backgroundColor;
+    this.element_.style.outline = this.savedStyle_.outline;
   }
 };
-
diff --git a/src/highlightableelement_test.html b/src/highlightableelement_test.html
index da38bfd..c401d3d 100644
--- a/src/highlightableelement_test.html
+++ b/src/highlightableelement_test.html
@@ -27,6 +27,7 @@
 
 goog.require('goog.color');
 goog.require('goog.testing.jsunit');
+goog.require('goog.userAgent.product.isVersion');
     </script>
 
   </head>
@@ -37,19 +38,23 @@
   var testDiv = goog.dom.createDom('div', {'id': 'test', 'dir': 'rtl'});
   testDiv.innerHTML = '<p>Shalom</p>';
 
-  var original = goog.style.getBackgroundColor(testDiv);
+  var originalBackgroundColor = goog.style.getBackgroundColor(testDiv) || '';
+  var originalOutline = testDiv.style.outline || '';
 
-  // Highlight the div element by changing its background color
+  // Highlight the div element by changing its background color and adding an
+  // outline.
   var location = new bidichecker.HighlightableElement(testDiv);
   location.highlightOnPage();
 
   // Check that the background color has been changed.
   assertEquals('#ffff00',
       goog.color.parse(goog.style.getBackgroundColor(testDiv)).hex);
+  assertCSSValueEquals('outline', 'medium solid red', testDiv.style.outline);
 
   // Revert the background color.
   location.unhighlightOnPage();
-  assertEquals(original, goog.style.getBackgroundColor(testDiv));
+  assertEquals(originalBackgroundColor, goog.style.getBackgroundColor(testDiv));
+  assertCSSValueEquals('outline', originalOutline, testDiv.style.outline);
 }
 
     </script>
diff --git a/src/highlightabletext.js b/src/highlightabletext.js
index ff91ab9..37486ef 100644
--- a/src/highlightabletext.js
+++ b/src/highlightabletext.js
@@ -20,6 +20,7 @@
 goog.provide('bidichecker.HighlightableText');
 
 goog.require('bidichecker.HighlightableArea');
+goog.require('bidichecker.utils');
 goog.require('goog.dom');
 goog.require('goog.style');
 
@@ -74,15 +75,14 @@
 };
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.HighlightableText.prototype.highlightOnPage = function() {
   if (this.newNodes_.length == 0) {
     // Wrap each text node in a highlighted span.
     //
     // TODO(user): What should we do if this fails to display the error, e.g.
-    // if the background color is already yellow, or if the error location is
-    // concealed behind another DOM element or scrolled out of view in a
-    // scrollable element?
+    // if the error location is concealed behind another DOM element or scrolled
+    // out of view in a scrollable element?
     for (var i = 0; i < this.nodes_.length; ++i) {
       // Adjust the boundary character positions for the first and last nodes.
       var startOffset = i == 0 ? this.startOffset_ : 0;
@@ -106,7 +106,7 @@
 };
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.HighlightableText.prototype.unhighlightOnPage = function() {
   if (this.newNodes_.length != 0) {
     // Swap back the original nodes for the highlighted ones.
@@ -138,10 +138,12 @@
     // The unhighlighted text prefix, if any.
     children.push(node.data.substring(0, start));
   }
-  // The highlighted substring, wrapped in a yellow-highlighted span.
-  children.push(goog.dom.createDom('span',
-      {style: 'color:red; background-color:yellow'},
-      node.data.substring(start, end)));
+  // The highlighted substring.
+  var highlightSpan =
+      goog.dom.createDom('span', {}, node.data.substring(start, end));
+  bidichecker.utils.highlightElementStyle(highlightSpan);
+  children.push(highlightSpan);
+
   if (end < node.data.length) {
     // The unhighlighted text suffix, if any.
     children.push(node.data.substring(end));
diff --git a/src/highlightabletext_test.html b/src/highlightabletext_test.html
index 5fbf189..6654794 100644
--- a/src/highlightabletext_test.html
+++ b/src/highlightabletext_test.html
@@ -57,6 +57,8 @@
       goog.color.parse(goog.style.getBackgroundColor(highlightSpan)).hex);
   assertEquals('#ff0000',
       goog.color.parse(goog.style.getStyle(highlightSpan, 'color')).hex);
+  assertCSSValueEquals('outline', 'medium solid red',
+      highlightSpan.style.outline);
 
   // The new text node should be the child of the inner span element.
   textNode = highlightSpan.firstChild;
@@ -89,6 +91,8 @@
       goog.color.parse(goog.style.getBackgroundColor(highlightSpan)).hex);
   assertEquals('#ff0000',
       goog.color.parse(goog.style.getStyle(highlightSpan, 'color')).hex);
+  assertCSSValueEquals('outline', 'medium solid red',
+      highlightSpan.style.outline);
 
   // The prefix part should be the only child of the highlighted span element.
   assertEquals('Shal',
@@ -125,6 +129,8 @@
       goog.color.parse(goog.style.getBackgroundColor(highlightSpan)).hex);
   assertEquals('#ff0000',
       goog.color.parse(goog.style.getStyle(highlightSpan, 'color')).hex);
+  assertCSSValueEquals('outline', 'medium solid red',
+      highlightSpan.style.outline);
 
   // The prefix part should be the first child of the wrapper span element.
   assertEquals('Sh',
diff --git a/src/install_bookmarklet.css b/src/install_bookmarklet.css
deleted file mode 100644
index 01df812..0000000
--- a/src/install_bookmarklet.css
+++ /dev/null
@@ -1,14 +0,0 @@
-body {
-  width: 600px;
-  font-family: sans-serif;
-  font-size: 13pt;
-  margin-left: 20px
-}
-
-h1 {
-  font-size: 16pt;
-}
-
-h3 {
-  font-size: 14pt;
-}
diff --git a/src/install_bookmarklet.html b/src/install_bookmarklet.html
deleted file mode 100644
index 6f49b1f..0000000
--- a/src/install_bookmarklet.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <!--
-    Copyright 2011 Google Inc. All Rights Reserved.
-
-    Use of this source code is governed by an Apache 2.0 License.
-    See the COPYING file for details.
-  -->
-  <head>
-    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-    <title>BidiChecker Bookmarklet Start Page</title>
-    <link href="install_bookmarklet.css" rel="stylesheet" type="text/css">
-  </head>
-
-  <body>
-
-    <h1>BidiChecker Bookmarklet Installation Page</h1>
-
-    <p>A "BidiChecker Bookmarklet" is a button you can add to your web browser
-      that will run
-      <a href="https://sites.google.com/a/google.com/bidichecker/home">BidiChecker</a>
-      on any web page, displaying any bidi errors in an interactive window. We'd
-      like to thank <a href="http://chris.improbable.org/">developer/blogger
-      Chris Adams</a> for
-      <a href="http://chris.improbable.org/2010/11/4/google-bidichecker-bookmarklet/">
-      demonstrating the concept</a>. His original source code can be found
-      <a href="https://gist.github.com/662454">here on GitHub</a>.</p>
-
-    <p>Below, we offer two bookmarklet links which differ a bit from Chris's
-      implementation. But the basic concept is the same: By dragging a
-      bookmarklet link to your browser's Bookmarks toolbar, you create a button
-      you can click to run BidiChecker on the current page for ad hoc
-      spot-checking. (In Google Chrome, first press Ctrl-Shift-B to show the
-      Bookmarks toolbar; other browsers have similar options.)</p>
- 
-    <p>BidiChecker does not currently support this use case very well. If no
-      errors are found, pressing the button will have no visible effect. Also,
-      pressing the button twice in succession will not work correctly. We're
-      aware of these issues and are currently working on a more sophisticated
-      bookmarklet implementation.</p>
-
-    <ul>
-      <li>This bookmarklet assumes that the page being checked has an overall
-        directionality of left-to-right (for example, an English UI):
-        <a href='javascript:(function(){var id="_bidichecker_bmlet";function run(){bidichecker.runGui(bidichecker.checkPage(false));}if(document.getElementById(id)){if(window.bidichecker){run();}}else{var elem=document.createElement("script");elem.src="http://bidichecker.googlecode.com/svn/trunk/lib/bidichecker_packaged.js";elem.onload=run;elem.id=id;document.getElementsByTagName("head")[0].appendChild(elem);}})()'><br>
-          <span style="border-style:solid; border-width:thin;">BidiChecker LTR
-        </a>
-      </li>
-      <li>And this bookmarklet assumes that the page being checked has an
-        overall directionality of right-to-left (for example, a Hebrew or
-        Arabic UI):
-        <a href='javascript:(function(){var id="_bidichecker_bmlet";function run(){bidichecker.runGui(bidichecker.checkPage(true));}if(document.getElementById(id)){if(window.bidichecker){run();}}else{var elem=document.createElement("script");elem.src="http://bidichecker.googlecode.com/svn/trunk/lib/bidichecker_packaged.js";elem.onload=run;elem.id=id;document.getElementsByTagName("head")[0].appendChild(elem);}})()'><br>
-          <span style="border-style:solid; border-width:thin;">BidiChecker RTL
-        </a>
-      </li>
-    </ul>
-
-    <p>To run BidiChecker, just navigate your browser to the page you want to
-      test, interact with the page to get it into the state you want to test,
-      and click on one of the BidiChecker bookmarklets in your browser's
-      bookmarks toolbar. If bidi errors are found, an in-page dialog box will
-      appear, allowing you to browse through the errors, which should be
-      highlighted within the page.</p>
-
-
-    <h2>Known limitations</h2>
-
-    <ul>
-      <li>The bookmarklet works on most recent browsers. Internet Explorer 9
-        is supported but not older versions.</li>
-      <li>If no errors are found, no visible changes will take place. It will
-        look as if BidiChecker has not even run.</li>
-      <li>If you launch the bookmarklet twice without reloading the page, it
-        may not function correctly.</li>
-    </ul>
-
-  </body>
-</html>
diff --git a/src/overalldirectionalitydetector.js b/src/overalldirectionalitydetector.js
index a635a18..b2d35a3 100644
--- a/src/overalldirectionalitydetector.js
+++ b/src/overalldirectionalitydetector.js
@@ -54,7 +54,7 @@
 };
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.OverallDirectionalityDetector.prototype.startListening = function(
     scanner) {
   // Listen for the start of the first tag in the DOM so we can check its
diff --git a/src/spilloverdetector.js b/src/spilloverdetector.js
index d258908..b4ee3be 100644
--- a/src/spilloverdetector.js
+++ b/src/spilloverdetector.js
@@ -75,7 +75,7 @@
 bidichecker.SpilloverDetector.prototype.candidate_ = null;
 
 
-/** @inheritDoc */
+/** @override */
 bidichecker.SpilloverDetector.prototype.startListening = function(scanner) {
 
   /**
diff --git a/src/texterrorscanner.js b/src/texterrorscanner.js
index 055baa3..63bf450 100644
--- a/src/texterrorscanner.js
+++ b/src/texterrorscanner.js
@@ -24,19 +24,27 @@
 goog.require('bidichecker.OverallDirectionalityDetector');
 goog.require('bidichecker.Scanner');
 goog.require('bidichecker.SpilloverDetector');
+goog.require('bidichecker.UndeclaredFieldDetector');
 goog.require('bidichecker.UndeclaredTextDetector');
 goog.require('goog.i18n.bidi');
 
 
 /**
  * A scanner that runs the standard text error detectors.
+ * @param {number} revision Revision of checks to run.
  * @param {Array.<!bidichecker.Filter>=} opt_filters Error suppression filters.
  * @constructor
  * @extends {bidichecker.Scanner}
  */
-bidichecker.TextErrorScanner = function(opt_filters) {
+bidichecker.TextErrorScanner = function(revision, opt_filters) {
   bidichecker.Scanner.call(this, opt_filters,
                            /* opt_needDirChunkWalker */ true);
+
+  /**
+   * @type {number}
+   * @private
+   */
+  this.revision_ = revision;
 };
 goog.inherits(bidichecker.TextErrorScanner, bidichecker.Scanner);
 
@@ -52,7 +60,7 @@
 bidichecker.TextErrorScanner.prototype.buildDetectors = function(
     element, expectedDir) {
   return bidichecker.TextErrorScanner.buildDetectors(element, expectedDir,
-                                                     this.errorCollector);
+      this.errorCollector, this.revision_);
 };
 
 
@@ -64,20 +72,26 @@
  * @param {goog.i18n.bidi.Dir} expectedDir Expected overall directionality, or
  *     {@code UNKNOWN} if not applicable.
  * @param {!bidichecker.ErrorCollector} errorCollector The error collector.
+ * @param {number} revision Revision of checks to run.
  * @return {Array.<!bidichecker.Detector>} List of detectors to run.
  */
-bidichecker.TextErrorScanner.buildDetectors = function(element, expectedDir,
-                                                       errorCollector) {
-  var detectors = [
-      new bidichecker.UndeclaredTextDetector(errorCollector),
-      new bidichecker.SpilloverDetector(errorCollector)
-  ];
+bidichecker.TextErrorScanner.buildDetectors = function(element,
+                                                       expectedDir,
+                                                       errorCollector,
+                                                       revision) {
+  var detectors = [];
   if (expectedDir != goog.i18n.bidi.Dir.UNKNOWN) {
     var shouldBeRtl = (expectedDir == goog.i18n.bidi.Dir.RTL);
-    detectors.unshift(
+    detectors.push(
         new bidichecker.OverallDirectionalityDetector(shouldBeRtl,
                                                       errorCollector));
   }
+  detectors.push(
+      new bidichecker.UndeclaredTextDetector(revision, errorCollector));
+  if (revision >= 2) {
+    detectors.push(new bidichecker.UndeclaredFieldDetector(errorCollector));
+  }
+  detectors.push(new bidichecker.SpilloverDetector(errorCollector));
 
   return detectors;
 };
diff --git a/src/undeclaredfielddetector.js b/src/undeclaredfielddetector.js
new file mode 100644
index 0000000..879bfbb
--- /dev/null
+++ b/src/undeclaredfielddetector.js
@@ -0,0 +1,216 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Detector which looks for undeclared opposite-directionality
+ * errors in text-valued attributes.
+ */
+
+
+goog.provide('bidichecker.UndeclaredFieldDetector');
+
+goog.require('bidichecker.Detector');
+goog.require('bidichecker.DomWalker');
+goog.require('bidichecker.Error');
+goog.require('bidichecker.HighlightableElement');
+goog.require('bidichecker.Scanner');
+goog.require('goog.array');
+goog.require('goog.events');
+goog.require('goog.events.EventHandler');
+
+
+/**
+ * A detector which listens for DOM node events and checks for undeclared
+ * opposite-directionality text in user-visible text-valued attributes of
+ * various elements.
+ * @param {!bidichecker.ErrorCollector} errorCollector Collects any new errors
+ *     discovered by this checker.
+ * @implements {bidichecker.Detector}
+ * @constructor
+ */
+bidichecker.UndeclaredFieldDetector = function(errorCollector) {
+  /**
+   * @type {!bidichecker.ErrorCollector}
+   * @private
+   */
+  this.errorCollector_ = errorCollector;
+};
+
+
+/**
+ * Types of fields to be checked; values are used in the error type string.
+ * @enum {string}
+ * @private
+ */
+bidichecker.UndeclaredFieldDetector.FieldType_ = {
+  ALT_TEXT: 'alt text',
+  BUTTON_LABEL: 'button label',
+  INPUT_VALUE: 'input value',
+  TEXTAREA_VALUE: 'textarea value',
+  TITLE_TEXT: 'title text'
+};
+
+
+/** @override */
+bidichecker.UndeclaredFieldDetector.prototype.startListening =
+    function(scanner) {
+
+  /**
+   * Service object to manage cleanup of event listeners.
+   * @type {goog.events.EventHandler}
+   */
+  var eventHandler = new goog.events.EventHandler(this);
+
+  // Listen for DOM elements.
+  eventHandler.listen(scanner.getDomWalker(),
+                      bidichecker.DomWalker.EventTypes.START_TAG,
+                      this.handleStartTag_);
+
+  // Listen for the end-of-DOM event; then tell event handler to stop listening
+  // to DOM events.
+  eventHandler.listenOnce(scanner.getDomWalker(),
+                          bidichecker.DomWalker.EventTypes.END_OF_DOM,
+                          eventHandler.removeAll, false, eventHandler);
+};
+
+
+/**
+ * Handles events indicating the start of a DOM element by checking relevant
+ * attributes for opposite-directionality text.
+ * @param {!goog.events.Event} event A StartTag event.
+ * @private
+ */
+bidichecker.UndeclaredFieldDetector.prototype.handleStartTag_ =
+    function(event) {
+  var domWalker = event.target;
+  var element = /** @type {!Element} */ (domWalker.getNode());
+  this.checkElement_(element);
+};
+
+
+/**
+ * Checks the directionality of text-valued attributes on an element, generating
+ * errors if appropriate.
+ * @param {!Element} element The element to check.
+ * @private
+ */
+bidichecker.UndeclaredFieldDetector.prototype.checkElement_ = function(
+    element) {
+  var FieldType = bidichecker.UndeclaredFieldDetector.FieldType_;
+
+  // All elements may have a "title" attribute.
+  if (element.title) {
+    this.checkField_(element, element.title, FieldType.TITLE_TEXT);
+  }
+  var nodeName = element.nodeName;
+  // Certain types of "input" elements have attributes to check.
+  if (nodeName == 'INPUT') {
+    if (element.type.match(/^(text|search)$/)) {
+      this.checkField_(element, element.value, FieldType.INPUT_VALUE);
+    } else if (element.type == 'image') {
+      this.checkField_(element, element.alt, FieldType.ALT_TEXT);
+    } else if (element.type.match(/^(button|reset|submit)$/)) {
+      this.checkField_(element, element.value, FieldType.BUTTON_LABEL);
+    } else if (element.type == 'file') {
+      this.checkFileInput_(element);
+    }
+  } else if (nodeName == 'IMG') {
+    // Images may have an "alt" attribute.
+    this.checkField_(element, element.alt, FieldType.ALT_TEXT);
+  } else if (nodeName == 'TEXTAREA') {
+    this.checkField_(element, element.value, FieldType.TEXTAREA_VALUE);
+  }
+};
+
+
+/**
+ * Checks the directionality of an attribute value, generating an error if
+ * appropriate.
+ * @param {!Element} element The element with the field to check.
+ * @param {string} value The value to check.
+ * @param {bidichecker.UndeclaredFieldDetector.FieldType_} fieldType The type of
+ *     the field being checked.
+ * @private
+ */
+bidichecker.UndeclaredFieldDetector.prototype.checkField_ = function(
+    element, value, fieldType) {
+  var isRtlElement = goog.style.isRightToLeft(element);
+  var hasLtrText = !!bidichecker.utils.findLtrSubstrings(value).length;
+  var hasRtlText =
+      !!bidichecker.utils.findRtlAndFakeRtlSubstrings(value).length;
+  // Has text of only one direction, but is declared as the other direction.
+  if ((hasLtrText != hasRtlText) && (isRtlElement != hasRtlText)) {
+    var fieldDirection = isRtlElement ? 'LTR' : 'RTL';
+    var errorType = 'Undeclared ' + fieldDirection + ' ' + fieldType;
+    var severity = this.getErrorSeverity_(element, value, fieldType);
+    var highlightableArea = new bidichecker.HighlightableElement(element);
+    var error = new bidichecker.Error(errorType, severity, highlightableArea,
+        value);
+    this.errorCollector_.addError(error, element);
+  }
+};
+
+
+/**
+ * Checks that input tags with type=file have LTR directionality, generating an
+ * error if appropriate.
+ * @param {!Element} element The element with the field to check.
+ * @private
+ */
+bidichecker.UndeclaredFieldDetector.prototype.checkFileInput_ = function(
+    element) {
+  var isRtlElement = goog.style.isRightToLeft(element);
+  if (isRtlElement) {
+    var errorType = 'File input not LTR';
+    var severity = 2;
+    var highlightableArea = new bidichecker.HighlightableElement(element);
+    var error = new bidichecker.Error(errorType, severity, highlightableArea);
+    this.errorCollector_.addError(error, element);
+  }
+};
+
+
+/**
+ * Determines the severity of a directionality error. Default value is 3. If the
+ * value starts or ends with neutral characters, promote it to 2 since the text
+ * will be garbled. But if the element itself has a "dir" attribute, demote it
+ * to 4 since it's apparently deliberate, to some extent. However, errors in
+ * textarea or input values always get severity 1 due to the nuisance of
+ * entering data with the wrong directionality.
+ * @param {!Element} element The element with the field with the error.
+ * @param {string} value The value with the error.
+ * @param {bidichecker.UndeclaredFieldDetector.FieldType_} fieldType The type of
+ *     the field being checked.
+ * @return {number} The severity level of the error.
+ * @private
+ */
+bidichecker.UndeclaredFieldDetector.prototype.getErrorSeverity_ = function(
+    element, value, fieldType) {
+  var FieldType = bidichecker.UndeclaredFieldDetector.FieldType_;
+  if (fieldType == FieldType.INPUT_VALUE ||
+      fieldType == FieldType.TEXTAREA_VALUE) {
+    return 1;
+  }
+  if (element.dir || element.style.direction ||
+      goog.style.isRightToLeft(element) !=
+      goog.style.isRightToLeft(/** @type {Element} */ (element.parentNode))) {
+    return 4;
+  }
+  if (bidichecker.utils.findVisibleNeutralTextAtIndex(value, 0) ||
+      bidichecker.utils.findVisibleNeutralTextBeforeIndex(value,
+                                                          value.length)) {
+    return 2;
+  }
+  return 3;
+};
diff --git a/src/undeclaredfielddetector_test.html b/src/undeclaredfielddetector_test.html
new file mode 100644
index 0000000..657b008
--- /dev/null
+++ b/src/undeclaredfielddetector_test.html
@@ -0,0 +1,368 @@
+<!DOCTYPE html>
+<html>
+  <!--
+    Copyright 2011 Google Inc. All Rights Reserved.
+
+    Use of this source code is governed by an Apache 2.0 License.
+    See the COPYING file for details.
+  -->
+
+  <!--
+  Unit tests for undeclaredfielddetector.js.
+  -->
+  <head>
+    <title>bidichecker - Javascript Unit Tests</title>
+    <script type="text/javascript" src="../third_party/closure-library/closure/goog/base.js">
+    </script>
+
+    <!-- Include the generated deps.js which enables goog.require of
+         the modules under test.
+    -->
+    <script type="text/javascript" src="deps.js"></script>
+    <script type="text/javascript">
+// This in turn pulls in the rest of the files.
+goog.require('bidichecker');
+
+goog.require('goog.testing.jsunit');
+goog.require('goog.userAgent.product.isVersion');
+    </script>
+    <script type="text/javascript" src="testutils.js"></script>
+
+  </head>
+  <body>
+    <script type="text/javascript">
+
+// IE7 doesn't report all the attributes for some unclear reason. We fix some of
+// the tests to handle this weirdness.
+var USING_IE7 = goog.userAgent.product.IE && !goog.userAgent.isVersion(8);
+
+
+/**
+ * Runs the undeclared field detector on the contents of a DOM element.
+ * @param {!Element} rootElement The root element of the DOM to be checked.
+ * @return {!Array.<!bidichecker.Error>} List of error messages.
+ */
+funct