[Catalyst-commits] r9456 - in trunk/examples: . typeface typeface/lib typeface/lib/Catalyst typeface/lib/Catalyst/Controller typeface/lib/Catalyst/Controller/FormBuilder typeface/lib/Catalyst/Engine typeface/lib/Catalyst/Plugin typeface/lib/DB typeface/lib/DB/Typeface typeface/lib/DB/Typeface/Schema typeface/lib/DBIx typeface/lib/DBIx/Class typeface/lib/HTML typeface/lib/HTML/Calendar typeface/lib/Typeface typeface/lib/Typeface/Controller typeface/lib/Typeface/Model typeface/lib/Typeface/View typeface/root typeface/root/admin typeface/root/lib typeface/root/lib/config typeface/root/lib/site typeface/root/shared typeface/root/static typeface/root/static/Scripts typeface/root/static/Styles typeface/root/static/dojo typeface/root/static/dojo/dijit typeface/root/static/dojo/dijit/_editor typeface/root/static/dojo/dijit/_tree typeface/root/static/dojo/dijit/base typeface/root/static/dojo/dijit/bench typeface/root/static/dojo/dijit/form typeface/root/static/dojo/dijit/form/nls typeface/root/static/dojo/dijit/form/nls/de typeface/root/static/dojo/dijit/form/nls/fr typeface/root/static/dojo/dijit/form/nls/it typeface/root/static/dojo/dijit/form/nls/ja typeface/root/static/dojo/dijit/form/nls/zh-cn typeface/root/static/dojo/dijit/form/templates typeface/root/static/dojo/dijit/layout typeface/root/static/dojo/dijit/layout/templates typeface/root/static/dojo/dijit/nls typeface/root/static/dojo/dijit/nls/de typeface/root/static/dojo/dijit/templates typeface/root/static/dojo/dijit/tests typeface/root/static/dojo/dijit/tests/css typeface/root/static/dojo/dijit/tests/form typeface/root/static/dojo/dijit/tests/form/images typeface/root/static/dojo/dijit/tests/images typeface/root/static/dojo/dijit/tests/layout typeface/root/static/dojo/dijit/tests/util typeface/root/static/dojo/dijit/themes typeface/root/static/dojo/dijit/themes/blackie typeface/root/static/dojo/dijit/themes/blackie/images typeface/root/static/dojo/dijit/themes/tundra typeface/root/static/dojo/dijit/themes/tundra/images typeface/root/static/dojo/dijit/util typeface/root/static/dojo/dojo typeface/root/static/dojo/dojo/_firebug typeface/root/static/dojo/dojo/cldr typeface/root/static/dojo/dojo/cldr/nls typeface/root/static/dojo/dojo/cldr/nls/de typeface/root/static/dojo/dojo/cldr/nls/de-de typeface/root/static/dojo/dojo/cldr/nls/en typeface/root/static/dojo/dojo/cldr/nls/en-au typeface/root/static/dojo/dojo/cldr/nls/en-ca typeface/root/static/dojo/dojo/cldr/nls/en-gb typeface/root/static/dojo/dojo/cldr/nls/en-us typeface/root/static/dojo/dojo/cldr/nls/es typeface/root/static/dojo/dojo/cldr/nls/es-es typeface/root/static/dojo/dojo/cldr/nls/fr typeface/root/static/dojo/dojo/cldr/nls/it typeface/root/static/dojo/dojo/cldr/nls/it-it typeface/root/static/dojo/dojo/cldr/nls/ja typeface/root/static/dojo/dojo/cldr/nls/ja-jp typeface/root/static/dojo/dojo/cldr/nls/ko typeface/root/static/dojo/dojo/cldr/nls/ko-kr typeface/root/static/dojo/dojo/cldr/nls/pt typeface/root/static/dojo/dojo/cldr/nls/pt-br typeface/root/static/dojo/dojo/cldr/nls/zh typeface/root/static/dojo/dojo/cldr/nls/zh-cn typeface/root/static/dojo/dojo/cldr/nls/zh-tw typeface/root/static/dojo/dojo/data typeface/root/static/dojo/dojo/data/api typeface/root/static/dojo/dojo/data/util typeface/root/static/dojo/dojo/date typeface/root/static/dojo/dojo/dnd typeface/root/static/dojo/dojo/io typeface/root/static/dojo/dojo/resources typeface/root/static/dojo/dojo/rpc typeface/root/static/dojo/dojo/tests typeface/root/static/dojo/dojo/tests/_base typeface/root/static/dojo/dojo/tests/_base/_loader typeface/root/static/dojo/dojo/tests/data typeface/root/static/dojo/dojo/tests/date typeface/root/static/dojo/dojo/tests/dnd typeface/root/static/dojo/dojo/tests/io typeface/root/static/dojo/dojo/tests/nls typeface/root/static/dojo/dojo/tests/nls/ar typeface/root/static/dojo/dojo/tests/nls/cs typeface/root/static/dojo/dojo/tests/nls/de typeface/root/static/dojo/dojo/tests/nls/el typeface/root/static/dojo/dojo/tests/nls/en-au typeface/root/static/dojo/dojo/tests/nls/en-us-hawaii typeface/root/static/dojo/dojo/tests/nls/en-us-new_york-brooklyn typeface/root/static/dojo/dojo/tests/nls/en-us-texas typeface/root/static/dojo/dojo/tests/nls/es typeface/root/static/dojo/dojo/tests/nls/fa typeface/root/static/dojo/dojo/tests/nls/fr typeface/root/static/dojo/dojo/tests/nls/he typeface/root/static/dojo/dojo/tests/nls/hi typeface/root/static/dojo/dojo/tests/nls/it typeface/root/static/dojo/dojo/tests/nls/ja typeface/root/static/dojo/dojo/tests/nls/ko typeface/root/static/dojo/dojo/tests/nls/pl typeface/root/static/dojo/dojo/tests/nls/pt typeface/root/static/dojo/dojo/tests/nls/ru typeface/root/static/dojo/dojo/tests/nls/sw typeface/root/static/dojo/dojo/tests/nls/th typeface/root/static/dojo/dojo/tests/nls/tr typeface/root/static/dojo/dojo/tests/nls/yi typeface/root/static/dojo/dojo/tests/nls/zh-cn typeface/root/static/dojo/dojo/tests/nls/zh-tw typeface/root/static/dojo/dojo/tests/resources typeface/root/static/dojo/dojox typeface/root/static/dojo/dojox/_cometd typeface/root/static/dojo/dojox/collections typeface/root/static/dojo/dojox/collections/tests typeface/root/static/dojo/dojox/crypto typeface/root/static/dojo/dojox/crypto/tests typeface/root/static/dojo/dojox/data typeface/root/static/dojo/dojox/data/tests typeface/root/static/dojo/dojox/data/tests/stores typeface/root/static/dojo/dojox/date typeface/root/static/dojo/dojox/gfx typeface/root/static/dojo/dojox/gfx/demos typeface/root/static/dojo/dojox/gfx/demos/images typeface/root/static/dojo/dojox/gfx/tests typeface/root/static/dojo/dojox/gfx/tests/images typeface/root/static/dojo/dojox/resources typeface/root/static/dojo/dojox/rpc typeface/root/static/dojo/dojox/string typeface/root/static/dojo/dojox/string/tests typeface/root/static/dojo/dojox/tests typeface/root/static/dojo/dojox/tests/date typeface/root/static/dojo/dojox/tests/widget typeface/root/static/dojo/dojox/widget typeface/root/static/dojo/dojox/wire typeface/root/static/dojo/dojox/wire/ml typeface/root/static/dojo/dojox/wire/tests typeface/root/static/dojo/dojox/wire/tests/markup typeface/root/static/dojo/dojox/wire/tests/markup/Service typeface/root/static/dojo/dojox/wire/tests/programmatic typeface/root/static/dojo/dojox/xml typeface/root/static/dojo/util typeface/root/static/dojo/util/doh typeface/root/static/dojo/util/doh/_sounds typeface/root/static/images typeface/root/static/images/icons typeface/root/static/javascripts typeface/root/static/stylesheets typeface/root/templates typeface/root/templates/chaoticsoul typeface/root/templates/chaoticsoul/static typeface/root/templates/chaoticsoul/static/images typeface/root/templates/chaoticsoul/static/stylesheets typeface/root/templates/connections typeface/root/templates/connections/static typeface/root/templates/connections/static/images typeface/root/templates/connections/static/stylesheets typeface/root/templates/default typeface/root/templates/default/static typeface/root/templates/default/static/images typeface/root/templates/default/static/stylesheets typeface/schema typeface/script typeface/t

zarquon at dev.catalyst.perl.org zarquon at dev.catalyst.perl.org
Sun Mar 8 09:49:15 GMT 2009


Author: zarquon
Date: 2009-03-08 09:49:12 +0000 (Sun, 08 Mar 2009)
New Revision: 9456

Added:
   trunk/examples/typeface/
   trunk/examples/typeface/Changes
   trunk/examples/typeface/INSTALL
   trunk/examples/typeface/LICENSE
   trunk/examples/typeface/META.yml
   trunk/examples/typeface/Makefile.PL
   trunk/examples/typeface/Makefile.old
   trunk/examples/typeface/README
   trunk/examples/typeface/create_login.pl
   trunk/examples/typeface/create_sql.pl
   trunk/examples/typeface/deploy.pl
   trunk/examples/typeface/dumper.pl
   trunk/examples/typeface/lib/
   trunk/examples/typeface/lib/Catalyst/
   trunk/examples/typeface/lib/Catalyst/Controller/
   trunk/examples/typeface/lib/Catalyst/Controller/FormBuilder/
   trunk/examples/typeface/lib/Catalyst/Controller/FormBuilder/DBIC.pm
   trunk/examples/typeface/lib/Catalyst/Engine/
   trunk/examples/typeface/lib/Catalyst/Engine/SCGI.pm
   trunk/examples/typeface/lib/Catalyst/Plugin/
   trunk/examples/typeface/lib/Catalyst/Plugin/Nifty.pm
   trunk/examples/typeface/lib/Catalyst/Plugin/ProxyReplyAs.pm
   trunk/examples/typeface/lib/DB/
   trunk/examples/typeface/lib/DB/Typeface/
   trunk/examples/typeface/lib/DB/Typeface/Schema.pm
   trunk/examples/typeface/lib/DB/Typeface/Schema/
   trunk/examples/typeface/lib/DB/Typeface/Schema/Articles.pm
   trunk/examples/typeface/lib/DB/Typeface/Schema/Categories.pm
   trunk/examples/typeface/lib/DB/Typeface/Schema/CategoriesArticles.pm
   trunk/examples/typeface/lib/DB/Typeface/Schema/Comments.pm
   trunk/examples/typeface/lib/DB/Typeface/Schema/Links.pm
   trunk/examples/typeface/lib/DB/Typeface/Schema/Pages.pm
   trunk/examples/typeface/lib/DB/Typeface/Schema/Users.pm
   trunk/examples/typeface/lib/DBIx/
   trunk/examples/typeface/lib/DBIx/Class/
   trunk/examples/typeface/lib/DBIx/Class/FormBuilder.pm
   trunk/examples/typeface/lib/HTML/
   trunk/examples/typeface/lib/HTML/Calendar/
   trunk/examples/typeface/lib/HTML/Calendar/Simple.pm
   trunk/examples/typeface/lib/HTML/CalendarMonthSimple.pm
   trunk/examples/typeface/lib/Typeface.pm
   trunk/examples/typeface/lib/Typeface/
   trunk/examples/typeface/lib/Typeface/Controller/
   trunk/examples/typeface/lib/Typeface/Controller/Admin.pm
   trunk/examples/typeface/lib/Typeface/Controller/Ajax.pm
   trunk/examples/typeface/lib/Typeface/Controller/Feed.pm
   trunk/examples/typeface/lib/Typeface/Controller/Login.pm
   trunk/examples/typeface/lib/Typeface/Controller/MetaBond.pm
   trunk/examples/typeface/lib/Typeface/Controller/MetaWeblogRPC.pm
   trunk/examples/typeface/lib/Typeface/Controller/Root.pm
   trunk/examples/typeface/lib/Typeface/Controller/Search.pm
   trunk/examples/typeface/lib/Typeface/Controller/Submit.pm
   trunk/examples/typeface/lib/Typeface/Model/
   trunk/examples/typeface/lib/Typeface/Model/Typeface.pm
   trunk/examples/typeface/lib/Typeface/View/
   trunk/examples/typeface/lib/Typeface/View/ADMIN.pm
   trunk/examples/typeface/lib/Typeface/View/JSON.pm
   trunk/examples/typeface/lib/Typeface/View/REMOTE.pm
   trunk/examples/typeface/lib/Typeface/View/TT.pm
   trunk/examples/typeface/lighttpd.conf
   trunk/examples/typeface/loader.pl
   trunk/examples/typeface/log/
   trunk/examples/typeface/root/
   trunk/examples/typeface/root/admin/
   trunk/examples/typeface/root/admin/category.tt2
   trunk/examples/typeface/root/admin/commit.tt2
   trunk/examples/typeface/root/admin/entry.tt2
   trunk/examples/typeface/root/admin/fix.tt2
   trunk/examples/typeface/root/admin/index.tt2
   trunk/examples/typeface/root/admin/link.tt2
   trunk/examples/typeface/root/admin/login_as.tt2
   trunk/examples/typeface/root/admin/login_pane.tt2
   trunk/examples/typeface/root/admin/message.tt2
   trunk/examples/typeface/root/admin/page.tt2
   trunk/examples/typeface/root/admin/user.tt2
   trunk/examples/typeface/root/favicon.ico
   trunk/examples/typeface/root/lib/
   trunk/examples/typeface/root/lib/config/
   trunk/examples/typeface/root/lib/config/main
   trunk/examples/typeface/root/lib/config/url
   trunk/examples/typeface/root/lib/site/
   trunk/examples/typeface/root/lib/site/admin
   trunk/examples/typeface/root/lib/site/admin_wrapper
   trunk/examples/typeface/root/lib/site/html
   trunk/examples/typeface/root/lib/site/remote
   trunk/examples/typeface/root/lib/site/remote_wrapper
   trunk/examples/typeface/root/lib/site/wrapper
   trunk/examples/typeface/root/shared/
   trunk/examples/typeface/root/shared/archives_list.tt2
   trunk/examples/typeface/root/shared/calendar_list.tt2
   trunk/examples/typeface/root/shared/categories_list.tt2
   trunk/examples/typeface/root/shared/links_list.tt2
   trunk/examples/typeface/root/shared/login_list.tt2
   trunk/examples/typeface/root/shared/message.tt2
   trunk/examples/typeface/root/shared/page.tt2
   trunk/examples/typeface/root/shared/search_list.tt2
   trunk/examples/typeface/root/shared/syndicate_list.tt2
   trunk/examples/typeface/root/static/
   trunk/examples/typeface/root/static/Scripts/
   trunk/examples/typeface/root/static/Scripts/shBrushCSharp.js
   trunk/examples/typeface/root/static/Scripts/shBrushCpp.js
   trunk/examples/typeface/root/static/Scripts/shBrushCss.js
   trunk/examples/typeface/root/static/Scripts/shBrushDelphi.js
   trunk/examples/typeface/root/static/Scripts/shBrushJScript.js
   trunk/examples/typeface/root/static/Scripts/shBrushJava.js
   trunk/examples/typeface/root/static/Scripts/shBrushPerl.js
   trunk/examples/typeface/root/static/Scripts/shBrushPhp.js
   trunk/examples/typeface/root/static/Scripts/shBrushPython.js
   trunk/examples/typeface/root/static/Scripts/shBrushRuby.js
   trunk/examples/typeface/root/static/Scripts/shBrushSql.js
   trunk/examples/typeface/root/static/Scripts/shBrushVb.js
   trunk/examples/typeface/root/static/Scripts/shBrushXml.js
   trunk/examples/typeface/root/static/Scripts/shCore.js
   trunk/examples/typeface/root/static/Scripts/shCore.uncompressed.js
   trunk/examples/typeface/root/static/Styles/
   trunk/examples/typeface/root/static/Styles/SyntaxHighlighter.css
   trunk/examples/typeface/root/static/Styles/TestPages.css
   trunk/examples/typeface/root/static/dojo/
   trunk/examples/typeface/root/static/dojo/dijit/
   trunk/examples/typeface/root/static/dojo/dijit/ColorPalette.js
   trunk/examples/typeface/root/static/dojo/dijit/Declaration.js
   trunk/examples/typeface/root/static/dojo/dijit/Menu.js
   trunk/examples/typeface/root/static/dojo/dijit/ProgressBar.js
   trunk/examples/typeface/root/static/dojo/dijit/TitlePane.js
   trunk/examples/typeface/root/static/dojo/dijit/Tooltip.js
   trunk/examples/typeface/root/static/dojo/dijit/Tree.js
   trunk/examples/typeface/root/static/dojo/dijit/_Calendar.js
   trunk/examples/typeface/root/static/dojo/dijit/_editor/
   trunk/examples/typeface/root/static/dojo/dijit/_editor/RichText.js
   trunk/examples/typeface/root/static/dojo/dijit/_editor/selection.js
   trunk/examples/typeface/root/static/dojo/dijit/_tree/
   trunk/examples/typeface/root/static/dojo/dijit/_tree/Controller.js
   trunk/examples/typeface/root/static/dojo/dijit/_tree/Node.html
   trunk/examples/typeface/root/static/dojo/dijit/_tree/Tree.html
   trunk/examples/typeface/root/static/dojo/dijit/base/
   trunk/examples/typeface/root/static/dojo/dijit/base/Container.js
   trunk/examples/typeface/root/static/dojo/dijit/base/FormElement.js
   trunk/examples/typeface/root/static/dojo/dijit/base/Layout.js
   trunk/examples/typeface/root/static/dojo/dijit/base/Showable.js
   trunk/examples/typeface/root/static/dojo/dijit/base/TemplatedWidget.js
   trunk/examples/typeface/root/static/dojo/dijit/base/Widget.js
   trunk/examples/typeface/root/static/dojo/dijit/bench/
   trunk/examples/typeface/root/static/dojo/dijit/bench/create_widgets.html
   trunk/examples/typeface/root/static/dojo/dijit/bench/parse_widgets.php
   trunk/examples/typeface/root/static/dojo/dijit/bench/test_Button-parse.html
   trunk/examples/typeface/root/static/dojo/dijit/bench/test_Button-parse.php
   trunk/examples/typeface/root/static/dojo/dijit/bench/test_Button-programmatic.html
   trunk/examples/typeface/root/static/dojo/dijit/bench/test_button-results.html
   trunk/examples/typeface/root/static/dojo/dijit/bench/widget_construction_test.php
   trunk/examples/typeface/root/static/dojo/dijit/changes.txt
   trunk/examples/typeface/root/static/dojo/dijit/dijit.js
   trunk/examples/typeface/root/static/dojo/dijit/dijit.js.uncompressed.js
   trunk/examples/typeface/root/static/dojo/dijit/form/
   trunk/examples/typeface/root/static/dojo/dijit/form/AutoCompleter.js
   trunk/examples/typeface/root/static/dojo/dijit/form/Button.js
   trunk/examples/typeface/root/static/dojo/dijit/form/Checkbox.js
   trunk/examples/typeface/root/static/dojo/dijit/form/CurrencyTextbox.js
   trunk/examples/typeface/root/static/dojo/dijit/form/DateTextbox.js
   trunk/examples/typeface/root/static/dojo/dijit/form/InlineEditBox.js
   trunk/examples/typeface/root/static/dojo/dijit/form/NumberSpinner.js
   trunk/examples/typeface/root/static/dojo/dijit/form/NumberTextbox.js
   trunk/examples/typeface/root/static/dojo/dijit/form/Select.js
   trunk/examples/typeface/root/static/dojo/dijit/form/Textarea.js
   trunk/examples/typeface/root/static/dojo/dijit/form/Textbox.js
   trunk/examples/typeface/root/static/dojo/dijit/form/ValidationTextbox.js
   trunk/examples/typeface/root/static/dojo/dijit/form/_DropDownTextBox.js
   trunk/examples/typeface/root/static/dojo/dijit/form/_Spinner.js
   trunk/examples/typeface/root/static/dojo/dijit/form/nls/
   trunk/examples/typeface/root/static/dojo/dijit/form/nls/de/
   trunk/examples/typeface/root/static/dojo/dijit/form/nls/de/validate.js
   trunk/examples/typeface/root/static/dojo/dijit/form/nls/fr/
   trunk/examples/typeface/root/static/dojo/dijit/form/nls/fr/validate.js
   trunk/examples/typeface/root/static/dojo/dijit/form/nls/it/
   trunk/examples/typeface/root/static/dojo/dijit/form/nls/it/validate.js
   trunk/examples/typeface/root/static/dojo/dijit/form/nls/ja/
   trunk/examples/typeface/root/static/dojo/dijit/form/nls/ja/validate.js
   trunk/examples/typeface/root/static/dojo/dijit/form/nls/validate.js
   trunk/examples/typeface/root/static/dojo/dijit/form/nls/zh-cn/
   trunk/examples/typeface/root/static/dojo/dijit/form/nls/zh-cn/validate.js
   trunk/examples/typeface/root/static/dojo/dijit/form/templates/
   trunk/examples/typeface/root/static/dojo/dijit/form/templates/AutoCompleter.html
   trunk/examples/typeface/root/static/dojo/dijit/form/templates/Button.html
   trunk/examples/typeface/root/static/dojo/dijit/form/templates/Checkbox.html
   trunk/examples/typeface/root/static/dojo/dijit/form/templates/ComboButton.html
   trunk/examples/typeface/root/static/dojo/dijit/form/templates/DropDownButton.html
   trunk/examples/typeface/root/static/dojo/dijit/form/templates/InlineEditBox.html
   trunk/examples/typeface/root/static/dojo/dijit/form/templates/Spinner.html
   trunk/examples/typeface/root/static/dojo/dijit/form/templates/Textbox.html
   trunk/examples/typeface/root/static/dojo/dijit/form/templates/blank.gif
   trunk/examples/typeface/root/static/dojo/dijit/layout/
   trunk/examples/typeface/root/static/dojo/dijit/layout/AccordionContainer.js
   trunk/examples/typeface/root/static/dojo/dijit/layout/ContentPane.js
   trunk/examples/typeface/root/static/dojo/dijit/layout/Dialog.js
   trunk/examples/typeface/root/static/dojo/dijit/layout/LayoutContainer.js
   trunk/examples/typeface/root/static/dojo/dijit/layout/LinkPane.js
   trunk/examples/typeface/root/static/dojo/dijit/layout/PageContainer.js
   trunk/examples/typeface/root/static/dojo/dijit/layout/SplitContainer.js
   trunk/examples/typeface/root/static/dojo/dijit/layout/TabContainer.js
   trunk/examples/typeface/root/static/dojo/dijit/layout/templates/
   trunk/examples/typeface/root/static/dojo/dijit/layout/templates/AccordionPane.html
   trunk/examples/typeface/root/static/dojo/dijit/layout/templates/Dialog.html
   trunk/examples/typeface/root/static/dojo/dijit/layout/templates/TabContainer.html
   trunk/examples/typeface/root/static/dojo/dijit/nls/
   trunk/examples/typeface/root/static/dojo/dijit/nls/common.js
   trunk/examples/typeface/root/static/dojo/dijit/nls/de/
   trunk/examples/typeface/root/static/dojo/dijit/nls/de/common.js
   trunk/examples/typeface/root/static/dojo/dijit/templates/
   trunk/examples/typeface/root/static/dojo/dijit/templates/Calendar.html
   trunk/examples/typeface/root/static/dojo/dijit/templates/ColorPalette.html
   trunk/examples/typeface/root/static/dojo/dijit/templates/ProgressBar.html
   trunk/examples/typeface/root/static/dojo/dijit/templates/TitlePane.html
   trunk/examples/typeface/root/static/dojo/dijit/templates/Tooltip.html
   trunk/examples/typeface/root/static/dojo/dijit/templates/blank.gif
   trunk/examples/typeface/root/static/dojo/dijit/templates/colors3x4.png
   trunk/examples/typeface/root/static/dojo/dijit/templates/colors7x10.png
   trunk/examples/typeface/root/static/dojo/dijit/tests/
   trunk/examples/typeface/root/static/dojo/dijit/tests/countries.json
   trunk/examples/typeface/root/static/dojo/dijit/tests/css/
   trunk/examples/typeface/root/static/dojo/dijit/tests/css/dijitTests.css
   trunk/examples/typeface/root/static/dojo/dijit/tests/form/
   trunk/examples/typeface/root/static/dojo/dijit/tests/form/autoCompleterData.json
   trunk/examples/typeface/root/static/dojo/dijit/tests/form/images/
   trunk/examples/typeface/root/static/dojo/dijit/tests/form/images/Alabama.jpg
   trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_AutoCompleter.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_AutoCompleter_destroy.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Button.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Checkbox.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_InlineEditBox.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Select.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Spinner.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Textarea.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_validate.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/images/
   trunk/examples/typeface/root/static/dojo/dijit/tests/images/arrowSmall.gif
   trunk/examples/typeface/root/static/dojo/dijit/tests/images/flatScreen.gif
   trunk/examples/typeface/root/static/dojo/dijit/tests/images/note.gif
   trunk/examples/typeface/root/static/dojo/dijit/tests/images/plus.gif
   trunk/examples/typeface/root/static/dojo/dijit/tests/images/testsBodyBg.gif
   trunk/examples/typeface/root/static/dojo/dijit/tests/images/tube.gif
   trunk/examples/typeface/root/static/dojo/dijit/tests/images/tubeTall.gif
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/doc0.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/doc1.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/doc2.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/tab1.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/tab2.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_AccordionContainer.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_ContentPane.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_Dialog.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_Layout.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_LayoutContainer.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_PageContainer.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_SplitContainer.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_TabContainer.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/module.js
   trunk/examples/typeface/root/static/dojo/dijit/tests/parser.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/runTests.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/test.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/testBidi.js
   trunk/examples/typeface/root/static/dojo/dijit/tests/test_Calendar.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/test_ColorPalette.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/test_Declaration.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/test_Menu.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/test_Menu_Debuggable.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/test_ProgressBar.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/test_RichText.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/test_Table.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/test_TitlePane.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/test_Tooltip.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/test_Tree.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/util/
   trunk/examples/typeface/root/static/dojo/dijit/tests/util/test_FocusManager.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/util/test_placeStrict.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/util/test_typematic.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/widgetsInTemplate.html
   trunk/examples/typeface/root/static/dojo/dijit/tests/widgetsInTemplate.js
   trunk/examples/typeface/root/static/dojo/dijit/themes/
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/blackie.css
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/blackie.html
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/blackie.psd
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonActive-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonActive-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonActive-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonDisabled-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonDisabled-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonDisabled-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonEnabled-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonEnabled-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonEnabled-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonHover-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonHover-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonHover-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/close.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/closeActive.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/closeHover.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowActive-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowActive-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowActive-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowHover-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowHover-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowHover-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnActive-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnActive-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnActive-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnHover-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnHover-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnHover-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonDisabled-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonDisabled-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonDisabled-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonEnabled-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonEnabled-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonEnabled-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonActive-center.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonActive-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonActive-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonActive-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonDisabled-center.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonDisabled-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonDisabled-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonDisabled-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonEnabled-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonEnabled-right-06.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonEnabled-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonEnabled-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonHover-center.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonHover-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonHover-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonHover-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/images.css
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectActive-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectActive-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectActive-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectDisabled-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectDisabled-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectDisabled-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectEnabled-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectEnabled-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectEnabled-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectHover-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectHover-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectHover-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerActive-bottom.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerActive-top.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerDisabled-bottom.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerDisabled-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerDisabled-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerDisabled-top.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerEnabled-bottom.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerEnabled-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerEnabled-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerEnabled-top.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerHover-bottom.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerHover-top.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabActive-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabActive-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabActive-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabDisabled-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabDisabled-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabDisabled-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabEnabled-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabEnabled-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabEnabled-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabHover-left.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabHover-right.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabHover-stretch.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/dijit.css
   trunk/examples/typeface/root/static/dojo/dijit/themes/templateThemeTest.html
   trunk/examples/typeface/root/static/dojo/dijit/themes/themeTester.html
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/bar.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/bubble.html
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/checkmark.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/decrementMonth.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/dojoTundraGradientBg.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/dojoTundraGradientBgActive.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/dojoTundraTabActiveBg.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/dojoUITundra06.psd
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/expand_leaf.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/expand_loading.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/expand_minus.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/expand_plus.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/h-bar.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/i.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/i_half.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/arrowDown.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/arrowLeft.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/arrowRight.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/arrowUp.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/buttonActive.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/buttonDisabled.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/buttonEnabled.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/buttonHover.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/calendarDayLabel.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/calendarMonthLabel.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/calendarYearLabel.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkboxActive.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkboxDisabled.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkboxEnabled.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkboxHover.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkmark.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/dijitProgressBarAnim.psd
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/doubleArrowDown.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/doubleArrowUp.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/menu.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/preciseSliderThumb.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-1.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-2.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-3.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-4.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-5.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-6.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-7.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-8.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-9.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim.psd
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarEmpty.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarFull.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonActive.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonActiveDisabled.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonActiveHover.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonDisabled.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonEnabled.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonHover.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/sliderEmpty.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/sliderFull.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/sliderThumb.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/smallArrowDown.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/smallArrowUp.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/splitContainerSizerH-thumb.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/splitContainerSizerH.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/splitContainerSizerV-thumb.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/splitContainerSizerV.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabActive.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabClose.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabCloseHover.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabDisabled.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabEnabled.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabHover.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/titleBar.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/incrementMonth.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/index.html
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/no.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/popupMenuBg.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/shadow.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/splitContainerHBg.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/splitContainerVBg.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tab_close.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tab_close_h.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/titleBarBg.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tooltipConnector.gif
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tooltipConnector.png
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tundra.css
   trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/validationInputBg.png
   trunk/examples/typeface/root/static/dojo/dijit/util/
   trunk/examples/typeface/root/static/dojo/dijit/util/BackgroundIframe.js
   trunk/examples/typeface/root/static/dojo/dijit/util/FocusManager.js
   trunk/examples/typeface/root/static/dojo/dijit/util/PopupManager.js
   trunk/examples/typeface/root/static/dojo/dijit/util/manager.js
   trunk/examples/typeface/root/static/dojo/dijit/util/parser.js
   trunk/examples/typeface/root/static/dojo/dijit/util/place.js
   trunk/examples/typeface/root/static/dojo/dijit/util/scroll.js
   trunk/examples/typeface/root/static/dojo/dijit/util/sniff.js
   trunk/examples/typeface/root/static/dojo/dijit/util/typematic.js
   trunk/examples/typeface/root/static/dojo/dijit/util/wai.js
   trunk/examples/typeface/root/static/dojo/dijit/util/window.js
   trunk/examples/typeface/root/static/dojo/dojo/
   trunk/examples/typeface/root/static/dojo/dojo/AdapterRegistry.js
   trunk/examples/typeface/root/static/dojo/dojo/_firebug/
   trunk/examples/typeface/root/static/dojo/dojo/_firebug/LICENSE
   trunk/examples/typeface/root/static/dojo/dojo/_firebug/errorIcon.png
   trunk/examples/typeface/root/static/dojo/dojo/_firebug/firebug.html
   trunk/examples/typeface/root/static/dojo/dojo/_firebug/firebug.js
   trunk/examples/typeface/root/static/dojo/dojo/_firebug/infoIcon.png
   trunk/examples/typeface/root/static/dojo/dojo/_firebug/warningIcon.png
   trunk/examples/typeface/root/static/dojo/dojo/back.js
   trunk/examples/typeface/root/static/dojo/dojo/behavior.js
   trunk/examples/typeface/root/static/dojo/dojo/build.txt
   trunk/examples/typeface/root/static/dojo/dojo/cldr/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/README
   trunk/examples/typeface/root/static/dojo/dojo/cldr/monetary.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de-de/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de-de/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-au/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-au/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-au/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-ca/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-ca/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-ca/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-ca/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-gb/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-gb/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-us/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-us/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-us/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es-es/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es-es/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es-es/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/fr/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/fr/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/fr/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/fr/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it-it/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it-it/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja-jp/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja-jp/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko-kr/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko-kr/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko-kr/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt-br/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt-br/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-cn/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-cn/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-cn/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-tw/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-tw/number.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh/
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh/gregorian.js
   trunk/examples/typeface/root/static/dojo/dojo/cldr/supplemental.js
   trunk/examples/typeface/root/static/dojo/dojo/cookie.js
   trunk/examples/typeface/root/static/dojo/dojo/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/data/
   trunk/examples/typeface/root/static/dojo/dojo/data/JsonItemStore.js
   trunk/examples/typeface/root/static/dojo/dojo/data/api/
   trunk/examples/typeface/root/static/dojo/dojo/data/api/Identity.js
   trunk/examples/typeface/root/static/dojo/dojo/data/api/Notification.js
   trunk/examples/typeface/root/static/dojo/dojo/data/api/Read.js
   trunk/examples/typeface/root/static/dojo/dojo/data/api/Request.js
   trunk/examples/typeface/root/static/dojo/dojo/data/api/Write.js
   trunk/examples/typeface/root/static/dojo/dojo/data/util/
   trunk/examples/typeface/root/static/dojo/dojo/data/util/filter.js
   trunk/examples/typeface/root/static/dojo/dojo/data/util/simpleFetch.js
   trunk/examples/typeface/root/static/dojo/dojo/data/util/sorter.js
   trunk/examples/typeface/root/static/dojo/dojo/date.js
   trunk/examples/typeface/root/static/dojo/dojo/date/
   trunk/examples/typeface/root/static/dojo/dojo/date/locale.js
   trunk/examples/typeface/root/static/dojo/dojo/date/stamp.js
   trunk/examples/typeface/root/static/dojo/dojo/dnd/
   trunk/examples/typeface/root/static/dojo/dojo/dnd/avatar.js
   trunk/examples/typeface/root/static/dojo/dojo/dnd/common.js
   trunk/examples/typeface/root/static/dojo/dojo/dnd/container.js
   trunk/examples/typeface/root/static/dojo/dojo/dnd/manager.js
   trunk/examples/typeface/root/static/dojo/dojo/dnd/move.js
   trunk/examples/typeface/root/static/dojo/dojo/dnd/selector.js
   trunk/examples/typeface/root/static/dojo/dojo/dnd/source.js
   trunk/examples/typeface/root/static/dojo/dojo/dojo.js
   trunk/examples/typeface/root/static/dojo/dojo/dojo.js.uncompressed.js
   trunk/examples/typeface/root/static/dojo/dojo/fx.js
   trunk/examples/typeface/root/static/dojo/dojo/i18n.js
   trunk/examples/typeface/root/static/dojo/dojo/io/
   trunk/examples/typeface/root/static/dojo/dojo/io/script.js
   trunk/examples/typeface/root/static/dojo/dojo/number.js
   trunk/examples/typeface/root/static/dojo/dojo/regexp.js
   trunk/examples/typeface/root/static/dojo/dojo/resources/
   trunk/examples/typeface/root/static/dojo/dojo/resources/LICENSE
   trunk/examples/typeface/root/static/dojo/dojo/resources/dojo.css
   trunk/examples/typeface/root/static/dojo/dojo/resources/iframe_history.html
   trunk/examples/typeface/root/static/dojo/dojo/rpc/
   trunk/examples/typeface/root/static/dojo/dojo/rpc/JsonPService.js
   trunk/examples/typeface/root/static/dojo/dojo/rpc/JsonService.js
   trunk/examples/typeface/root/static/dojo/dojo/rpc/RpcService.js
   trunk/examples/typeface/root/static/dojo/dojo/string.js
   trunk/examples/typeface/root/static/dojo/dojo/tests.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/
   trunk/examples/typeface/root/static/dojo/dojo/tests/AdapterRegistry.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/TODO
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/Deferred.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/NodeList.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/bootstrap.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/getText.txt
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/hostenv_browser.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/hostenv_rhino.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/hostenv_spidermonkey.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/loader.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/array.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/connect.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/declare.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/fx.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/fx.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/html.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/html.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/html_quirks.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/json.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/lang.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/query.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/query.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/xhr.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/_base/xhr.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/back-bookmark.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/back.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/back.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/behavior.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/behavior.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/cldr.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/cookie.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/cookie.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/currency.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/data.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/data/
   trunk/examples/typeface/root/static/dojo/dojo/tests/data/JsonItemStore.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries.json
   trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_commentFiltered.json
   trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_idcollision.json
   trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_withBoolean.json
   trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_withNull.json
   trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_withattributes.json
   trunk/examples/typeface/root/static/dojo/dojo/tests/data/utils.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/date.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/date/
   trunk/examples/typeface/root/static/dojo/dojo/tests/date/locale.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/date/stamp.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/
   trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_container.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_dnd.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_moveable.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_selector.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/i18n.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/io/
   trunk/examples/typeface/root/static/dojo/dojo/tests/io/script.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/io/script.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/io/scriptJsonp.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/io/scriptSimple.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/module.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ar/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ar/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/cs/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/cs/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/de/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/de/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/el/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/el/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-au/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-au/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-hawaii/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-hawaii/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-new_york-brooklyn/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-new_york-brooklyn/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-texas/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-texas/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/es/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/es/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/fa/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/fa/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/fr/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/fr/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/he/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/he/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/hi/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/hi/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/it/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/it/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ja/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ja/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ko/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ko/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/pl/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/pl/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/pt/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/pt/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ru/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ru/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/sw/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/sw/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/th/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/th/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/tr/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/tr/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/yi/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/yi/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/zh-cn/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/zh-cn/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/zh-tw/
   trunk/examples/typeface/root/static/dojo/dojo/tests/nls/zh-tw/salutations.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/number.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/resources/
   trunk/examples/typeface/root/static/dojo/dojo/tests/resources/ApplicationState.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/resources/JSON.php
   trunk/examples/typeface/root/static/dojo/dojo/tests/resources/testClass.php
   trunk/examples/typeface/root/static/dojo/dojo/tests/resources/testClass.smd
   trunk/examples/typeface/root/static/dojo/dojo/tests/resources/test_JsonRPCMediator.php
   trunk/examples/typeface/root/static/dojo/dojo/tests/resources/test_css.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/rpc.js
   trunk/examples/typeface/root/static/dojo/dojo/tests/runTests.html
   trunk/examples/typeface/root/static/dojo/dojo/tests/string.js
   trunk/examples/typeface/root/static/dojo/dojox/
   trunk/examples/typeface/root/static/dojo/dojox/_cometd/
   trunk/examples/typeface/root/static/dojo/dojox/_cometd/README
   trunk/examples/typeface/root/static/dojo/dojox/_cometd/cometd.js
   trunk/examples/typeface/root/static/dojo/dojox/collections.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/
   trunk/examples/typeface/root/static/dojo/dojox/collections/ArrayList.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/BinaryTree.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/Dictionary.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/Queue.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/README
   trunk/examples/typeface/root/static/dojo/dojox/collections/Set.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/SortedList.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/Stack.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/_base.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/tests/
   trunk/examples/typeface/root/static/dojo/dojox/collections/tests/ArrayList.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/tests/BinaryTree.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Dictionary.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Queue.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Set.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/tests/SortedList.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Stack.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/tests/_base.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/tests/collections.js
   trunk/examples/typeface/root/static/dojo/dojox/collections/tests/runTests.html
   trunk/examples/typeface/root/static/dojo/dojox/cometd.js
   trunk/examples/typeface/root/static/dojo/dojox/crypto.js
   trunk/examples/typeface/root/static/dojo/dojox/crypto/
   trunk/examples/typeface/root/static/dojo/dojox/crypto/Blowfish.js
   trunk/examples/typeface/root/static/dojo/dojox/crypto/LICENSE
   trunk/examples/typeface/root/static/dojo/dojox/crypto/MD5.js
   trunk/examples/typeface/root/static/dojo/dojox/crypto/README
   trunk/examples/typeface/root/static/dojo/dojox/crypto/_base.js
   trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/
   trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/Blowfish.js
   trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/MD5.js
   trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/crypto.js
   trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/runTests.html
   trunk/examples/typeface/root/static/dojo/dojox/data/
   trunk/examples/typeface/root/static/dojo/dojox/data/CsvStore.js
   trunk/examples/typeface/root/static/dojo/dojox/data/OpmlStore.js
   trunk/examples/typeface/root/static/dojo/dojox/data/README
   trunk/examples/typeface/root/static/dojo/dojox/data/XmlStore.js
   trunk/examples/typeface/root/static/dojo/dojox/data/dom.js
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/dom.js
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/module.js
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/runTests.html
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/CsvStore.js
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/OpmlStore.js
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/XmlStore.js
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books.xml
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books2.xml
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books3.xml
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books_isbnAttr.xml
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books_isbnAttr2.xml
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/geography.xml
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/movies.csv
   trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/patterns.csv
   trunk/examples/typeface/root/static/dojo/dojox/date/
   trunk/examples/typeface/root/static/dojo/dojox/date/php.js
   trunk/examples/typeface/root/static/dojo/dojox/date/posix.js
   trunk/examples/typeface/root/static/dojo/dojox/gfx.js
   trunk/examples/typeface/root/static/dojo/dojox/gfx/
   trunk/examples/typeface/root/static/dojo/dojox/gfx/_base.js
   trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/
   trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/butterfly.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/circles.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/clock.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/images/
   trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/images/clock_face.jpg
   trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/lion.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/tiger.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/matrix.js
   trunk/examples/typeface/root/static/dojo/dojox/gfx/path.js
   trunk/examples/typeface/root/static/dojo/dojox/gfx/shape.js
   trunk/examples/typeface/root/static/dojo/dojox/gfx/svg.js
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/images/
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/images/error.png
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/images/placeholder.png
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/images/rect.png
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_arc.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_bezier.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_gfx.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_group.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_image.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_linearGradient.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_linestyle.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_matrix.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_pattern.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_poly.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_setPath.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_tbbox.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_text.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_textpath.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_transform.html
   trunk/examples/typeface/root/static/dojo/dojox/gfx/vml.js
   trunk/examples/typeface/root/static/dojo/dojox/resources/
   trunk/examples/typeface/root/static/dojo/dojox/resources/README.template
   trunk/examples/typeface/root/static/dojo/dojox/rpc/
   trunk/examples/typeface/root/static/dojo/dojox/rpc/yahoo.smd
   trunk/examples/typeface/root/static/dojo/dojox/string/
   trunk/examples/typeface/root/static/dojo/dojox/string/Builder.js
   trunk/examples/typeface/root/static/dojo/dojox/string/README
   trunk/examples/typeface/root/static/dojo/dojox/string/tests/
   trunk/examples/typeface/root/static/dojo/dojox/string/tests/Builder.js
   trunk/examples/typeface/root/static/dojo/dojox/string/tests/runTests.html
   trunk/examples/typeface/root/static/dojo/dojox/string/tests/string.js
   trunk/examples/typeface/root/static/dojo/dojox/tests/
   trunk/examples/typeface/root/static/dojo/dojox/tests/date/
   trunk/examples/typeface/root/static/dojo/dojox/tests/date/posix.js
   trunk/examples/typeface/root/static/dojo/dojox/tests/module.js
   trunk/examples/typeface/root/static/dojo/dojox/tests/runTests.html
   trunk/examples/typeface/root/static/dojo/dojox/tests/widget/
   trunk/examples/typeface/root/static/dojo/dojox/tests/widget/test_Toaster.html
   trunk/examples/typeface/root/static/dojo/dojox/widget/
   trunk/examples/typeface/root/static/dojo/dojox/widget/Toaster.js
   trunk/examples/typeface/root/static/dojo/dojox/wire.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/
   trunk/examples/typeface/root/static/dojo/dojox/wire/CompositeWire.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/DataWire.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/README
   trunk/examples/typeface/root/static/dojo/dojox/wire/TableAdapter.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/TextAdapter.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/TreeAdapter.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/Wire.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/XmlWire.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/_base.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/ml/
   trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Action.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Data.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/ml/DataStore.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Invocation.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Service.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Transfer.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/ml/util.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Action.html
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Data.html
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/DataStore.html
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/DataStore.xml
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Invocation.html
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service.html
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/JSON.smd
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/XML.smd
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/a.json
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/a.xml
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Transfer.html
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/module.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/CompositeWire.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/DataWire.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/TableAdapter.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/TextAdapter.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/TreeAdapter.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/Wire.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/XmlWire.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/_base.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/runTests.html
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/wire.js
   trunk/examples/typeface/root/static/dojo/dojox/wire/tests/wireml.js
   trunk/examples/typeface/root/static/dojo/dojox/xml/
   trunk/examples/typeface/root/static/dojo/dojox/xml/DomParser.js
   trunk/examples/typeface/root/static/dojo/dojox/xml/README
   trunk/examples/typeface/root/static/dojo/util/
   trunk/examples/typeface/root/static/dojo/util/doh/
   trunk/examples/typeface/root/static/dojo/util/doh/_browserRunner.js
   trunk/examples/typeface/root/static/dojo/util/doh/_rhinoRunner.js
   trunk/examples/typeface/root/static/dojo/util/doh/_sounds/
   trunk/examples/typeface/root/static/dojo/util/doh/_sounds/LICENSE
   trunk/examples/typeface/root/static/dojo/util/doh/_sounds/doh.wav
   trunk/examples/typeface/root/static/dojo/util/doh/_sounds/dohaaa.wav
   trunk/examples/typeface/root/static/dojo/util/doh/_sounds/woohoo.wav
   trunk/examples/typeface/root/static/dojo/util/doh/runner.html
   trunk/examples/typeface/root/static/dojo/util/doh/runner.js
   trunk/examples/typeface/root/static/dojo/util/doh/small_logo.png
   trunk/examples/typeface/root/static/images/
   trunk/examples/typeface/root/static/images/RSS.gif
   trunk/examples/typeface/root/static/images/bg.jpg
   trunk/examples/typeface/root/static/images/btn_120x50_built.png
   trunk/examples/typeface/root/static/images/btn_120x50_built_shadow.png
   trunk/examples/typeface/root/static/images/btn_120x50_powered.png
   trunk/examples/typeface/root/static/images/btn_120x50_powered_shadow.png
   trunk/examples/typeface/root/static/images/btn_88x31_built.png
   trunk/examples/typeface/root/static/images/btn_88x31_built_shadow.png
   trunk/examples/typeface/root/static/images/btn_88x31_powered.png
   trunk/examples/typeface/root/static/images/btn_88x31_powered_shadow.png
   trunk/examples/typeface/root/static/images/catalyst_logo.png
   trunk/examples/typeface/root/static/images/catalyst_small.gif
   trunk/examples/typeface/root/static/images/comments.gif
   trunk/examples/typeface/root/static/images/icons/
   trunk/examples/typeface/root/static/images/icons/delicious.png
   trunk/examples/typeface/root/static/images/icons/digg.png
   trunk/examples/typeface/root/static/images/icons/furl.png
   trunk/examples/typeface/root/static/images/icons/google.png
   trunk/examples/typeface/root/static/images/icons/newsvine.png
   trunk/examples/typeface/root/static/images/icons/reddit.png
   trunk/examples/typeface/root/static/images/icons/technorati.png
   trunk/examples/typeface/root/static/images/icons/yahoo.png
   trunk/examples/typeface/root/static/images/ntbg.png
   trunk/examples/typeface/root/static/images/rails.jpg
   trunk/examples/typeface/root/static/images/rss.png
   trunk/examples/typeface/root/static/images/search.png
   trunk/examples/typeface/root/static/javascripts/
   trunk/examples/typeface/root/static/javascripts/application.js
   trunk/examples/typeface/root/static/javascripts/nicetitles.js
   trunk/examples/typeface/root/static/javascripts/niftycube.js
   trunk/examples/typeface/root/static/javascripts/niftydates.js
   trunk/examples/typeface/root/static/javascripts/niftytricks.js
   trunk/examples/typeface/root/static/stylesheets/
   trunk/examples/typeface/root/static/stylesheets/admin.css
   trunk/examples/typeface/root/static/stylesheets/default.css
   trunk/examples/typeface/root/static/stylesheets/nicetitles.css
   trunk/examples/typeface/root/static/stylesheets/niftyCorners.css
   trunk/examples/typeface/root/templates/
   trunk/examples/typeface/root/templates/chaoticsoul/
   trunk/examples/typeface/root/templates/chaoticsoul/index.tt2
   trunk/examples/typeface/root/templates/chaoticsoul/layout.tt2
   trunk/examples/typeface/root/templates/chaoticsoul/sidebar.tt2
   trunk/examples/typeface/root/templates/chaoticsoul/static/
   trunk/examples/typeface/root/templates/chaoticsoul/static/images/
   trunk/examples/typeface/root/templates/chaoticsoul/static/images/content_bkg.gif
   trunk/examples/typeface/root/templates/chaoticsoul/static/images/image_left.jpg
   trunk/examples/typeface/root/templates/chaoticsoul/static/images/image_right.jpg
   trunk/examples/typeface/root/templates/chaoticsoul/static/javascripts/
   trunk/examples/typeface/root/templates/chaoticsoul/static/stylesheets/
   trunk/examples/typeface/root/templates/chaoticsoul/static/stylesheets/style.css
   trunk/examples/typeface/root/templates/connections/
   trunk/examples/typeface/root/templates/connections/index.tt2
   trunk/examples/typeface/root/templates/connections/layout.tt2
   trunk/examples/typeface/root/templates/connections/sidebar.tt2
   trunk/examples/typeface/root/templates/connections/static/
   trunk/examples/typeface/root/templates/connections/static/images/
   trunk/examples/typeface/root/templates/connections/static/images/blockquote.gif
   trunk/examples/typeface/root/templates/connections/static/images/bullet.gif
   trunk/examples/typeface/root/templates/connections/static/images/comments_bottom.jpg
   trunk/examples/typeface/root/templates/connections/static/images/content_bg.gif
   trunk/examples/typeface/root/templates/connections/static/images/contentbg.jpg
   trunk/examples/typeface/root/templates/connections/static/images/divider.gif
   trunk/examples/typeface/root/templates/connections/static/images/rap.jpg
   trunk/examples/typeface/root/templates/connections/static/images/sidenav_bottom.jpg
   trunk/examples/typeface/root/templates/connections/static/images/sidenav_top.jpg
   trunk/examples/typeface/root/templates/connections/static/images/sub-bullet.gif
   trunk/examples/typeface/root/templates/connections/static/images/subcat_bullet.gif
   trunk/examples/typeface/root/templates/connections/static/images/top.jpg
   trunk/examples/typeface/root/templates/connections/static/javascripts/
   trunk/examples/typeface/root/templates/connections/static/stylesheets/
   trunk/examples/typeface/root/templates/connections/static/stylesheets/style.css
   trunk/examples/typeface/root/templates/default/
   trunk/examples/typeface/root/templates/default/error.tt2
   trunk/examples/typeface/root/templates/default/footer.tt2
   trunk/examples/typeface/root/templates/default/index.tt2
   trunk/examples/typeface/root/templates/default/layout.tt2
   trunk/examples/typeface/root/templates/default/sidebar.tt2
   trunk/examples/typeface/root/templates/default/static/
   trunk/examples/typeface/root/templates/default/static/images/
   trunk/examples/typeface/root/templates/default/static/images/arrow.gif
   trunk/examples/typeface/root/templates/default/static/images/bgback.jpg
   trunk/examples/typeface/root/templates/default/static/images/bgnew.jpg
   trunk/examples/typeface/root/templates/default/static/images/bullet.png
   trunk/examples/typeface/root/templates/default/static/images/search_grad.png
   trunk/examples/typeface/root/templates/default/static/images/topbg.jpg
   trunk/examples/typeface/root/templates/default/static/javascripts/
   trunk/examples/typeface/root/templates/default/static/stylesheets/
   trunk/examples/typeface/root/templates/default/static/stylesheets/master.css
   trunk/examples/typeface/root/templates/default/test.tt2
   trunk/examples/typeface/schema/
   trunk/examples/typeface/schema/DB-Typeface::Schema-1.x-MySQL.sql
   trunk/examples/typeface/schema/DB-Typeface::Schema-1.x-PostgreSQL.sql
   trunk/examples/typeface/schema/DB-Typeface::Schema-1.x-SQLite.sql
   trunk/examples/typeface/script/
   trunk/examples/typeface/script/typeface_cgi.pl
   trunk/examples/typeface/script/typeface_create.pl
   trunk/examples/typeface/script/typeface_fastcgi.pl
   trunk/examples/typeface/script/typeface_scgi.pl
   trunk/examples/typeface/script/typeface_server.pl
   trunk/examples/typeface/script/typeface_test.pl
   trunk/examples/typeface/t/
   trunk/examples/typeface/t/01app.t
   trunk/examples/typeface/t/02pod.t
   trunk/examples/typeface/t/03podcoverage.t
   trunk/examples/typeface/tmp/
   trunk/examples/typeface/typeface-page.html
   trunk/examples/typeface/typeface.yml
Log:
copy of typeface from svn co svn://fabulously40.com/public/trunk/typeface as of Sun  8 Mar 2009 09:38:52 UTC

Added: trunk/examples/typeface/Changes
===================================================================
--- trunk/examples/typeface/Changes	                        (rev 0)
+++ trunk/examples/typeface/Changes	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,188 @@
+This file documents the revision history for Perl extension Typeface.
+
+0.72 Sun Jan 28 20:29:18 PST 2007
+
+        Major memory leak fixes, no with Typeface specifically but the projects it depends on.
+        
+        Changed:
+                Cache::Store::FastMmap to Cache::FileCache
+                Removal of local PageCache
+                Session::Store::FastMmap to Session::Store::File
+                
+        Fixed:
+                Fixed memory leak with syntax highlighting.
+                Lowered memory footprint.
+                Fixed conflict between code highlighter and textile.
+                Fixed memory leak with formbuilder + bundled with fix.
+                Fixed memory leak with c::c::formbuilder + bundled with fix
+        
+
+0.71 Sat Jan 20 21:12:21 PST 2007
+
+        Minor fixes and improvements.
+        
+        New: 
+                Added a category editor in the admin backend. 
+                 - oops forgot about this one when transitioning to the Dojo powered backend.
+                 
+        Changed:
+                Minor code cleanup still much to do.
+                
+        Fixed:
+                Fixed possible memory leak?
+                Fixed order of how Archived lists display.
+                Set Page titles depending on subject or page name. (SEO optimization)
+                Added Catalyst::View::JSON as a dependency
+                Added Text::Highlight as a dependency
+                
+
+0.7 2007-1-16 04:28:44
+
+	Lots of optimizations and miscellaneous fixes. 
+	
+	New:
+		Two new ported Wordpress templates, Connections and ChaoticSoul.
+		Created dedicated site for Typeface - http://typeface-project.org/
+		Included ProxyReplyAs Catalyst plugin if you wish to deploy Typeface through 
+		HTTP proxy.
+		Two new ported Wordpress themes, chaotic soul and connections.
+
+	Changed:
+		Refactored template support for easier Wordpress theme porting.
+		Switched back to Server::XMLRPC since they fixed their circular memory leak. 
+		(thanks mst)
+		
+	Fixed:
+		All dependencies are accounted for thanks to Kevin Old.
+		Dojo optimizations.
+		Improved syntax highlighter.
+		Switch to Catalyst::Controller::FormBuilder
+
+0.6 2006-12-16 03:06:45
+
+	Fixed:
+		Lots of issues got stomped out that were in the previous release.
+		Memory leak with C::P::Server::XMLRPC (thanks MST)
+		Rendering issues in various places.
+		
+	New:
+		Standardized admin back-end that is not constrained by the loaded template.
+		Live Search
+		Live Sort of the category list
+		Ability to add and delete links.
+		Experimental SCGI implementation for Catalyst.
+		
+	Changes:
+		New Streamlined layout.
+		Switch from C::P::Server::XMLRPC to C::P::XMLRPC for now till all memory leaks get resolved with the former.
+		
+	BUGS:
+		Safari can't generate the WYSIWYG Editor on the fly in the back-end. 
+		
+
+0.5 2006-12-02 07:14:00
+- Fourth release, a bit more user friendly than before.
+
+	Fixed:
+		Fixed all remaining IE render issues.
+		Cleaned up CSS.
+		Fixed caching issues with cache::store::fastmmap.
+		Code clean up.
+		Fixed miscellaneous metaweblog xmlrpc issues.
+		Fixed time in words to not be dependent on a single time zone.
+		Cleaned up documentation.
+		
+	New Features:
+		Added install script to bootstrap the initial user.
+
+0.4 2006-11-17 08:00:00
+- Third public release of typeface.
+
+	Fixed: 
+		IE render width issue.
+		Removed all traces of lets get dugg.
+	
+	New Features:
+		Template support.
+		Site title configurable in YAML
+
+0.3 2006-11-20 04:55:00
+- Second public release of typeface.
+
+	Fixed:
+		Create new page link fixed.
+		Modification of pages fixed.
+		Code cleanups.
+		
+	New Features:
+		Ability to create pages not in the tab drawer.
+		
+
+0.2  2006-11-01 03:59:00
+- First public release of typeface.
+
+Features:
+	XML-RPC MetaWeblog edit and submission
+	Captcha image verification
+	Categories
+	Human readable *cachable* time information.
+	Human readable URLs			ex: /view/<article_subject>
+	Structured archive URLs   	ex: /archive/<year>/<month>/<day>
+	Self contained on-site search
+	By-the-month Calendar
+	Tabbed Pages
+	RSS Syndication throughout the site 
+	Code highlight tags [code syntax="Perl"] [/code]
+		Valid syntax:
+			CPP
+			CSS
+			HTML
+			Java
+			PHP
+			Perl
+			SQL
+
+TODO:
+	Code clean up
+	XML-RPC site pinging on article post
+	Implement my idea "MetaBonds"
+	
+
+Who is this release for?
+	Skillful users and developers who might be interested in contributing. 
+
+Why make yet another blog?
+	Why not? I am not pleased with wordpress due to its lack of caching. It can't hold up to a good old slashdotting! This blog takes advantage of caching through out to minimize server resource usage and produce the best visit/connection throughout put. The other reason I made this was to learn the wonderful Catalyst web framework.  
+
+What makes this blog so special?
+	This blog is geared toward developers who wish to blog about their development cycle! I am completely gearing this toward the OSS developer demographic. This blog makes it easy at conveying your thoughts and ideas by posting syntax highlighted code snippets. Second of all, Caching Caching and some more caching! Almost every page is cached, for the best performance possible!  
+	
+Installation
+
+	1) Install all the dependencies from cpan.
+	2) import the SQL schema.
+	3) create your initial user: INSERT INTO users (name,password) values ('myuser','mypass');
+	4) Login!
+	
+Dependency list:
+	ConfigLoader 
+	Static::Simple 
+	PageCache 
+	Cache::FastMmap 
+	FormBuilder 
+	Session 
+	Session::Store::FastMmap 
+	Cache Session::State::Cookie 
+	Textile DateTime 
+	Authentication 
+	Authentication::Store::DBIC 
+	Authentication::Credential::Password 
+	Prototype 
+	Captcha 
+	Server 
+	Server::XMLRPC
+	Text::Highlight
+	XML::Feed
+
+0.1  2006-10-18 10:41:39
+        - initial revision, generated by Catalyst

Added: trunk/examples/typeface/INSTALL
===================================================================
--- trunk/examples/typeface/INSTALL	                        (rev 0)
+++ trunk/examples/typeface/INSTALL	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,15 @@
+Installation:
+	1) Run MakeFile.PL to install all dependencies.
+	2) Rim create_sql.pl and import the generated SQL schema.
+	3) Edit typeface.yml to suit your needs.
+	4) Run create_login.pl
+	5) Run script/typeface_server.pl -p 8080
+	6) Login into http://localhost:8080/
+	7) There is no step 7.
+
+
+Use CPAN it's your friend! The only dependency you might have an issue with is Captcha. Captcha depends on GD which is problematic on OSX. If you already have Catalyst installed everything should go smooth as butter.
+
+If you can't get this working you suck at the internet! [sic]
+
+-Victor
\ No newline at end of file

Added: trunk/examples/typeface/LICENSE
===================================================================
--- trunk/examples/typeface/LICENSE	                        (rev 0)
+++ trunk/examples/typeface/LICENSE	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

Added: trunk/examples/typeface/META.yml
===================================================================
--- trunk/examples/typeface/META.yml	                        (rev 0)
+++ trunk/examples/typeface/META.yml	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,40 @@
+abstract: ~
+distribution_type: module
+generated_by: Module::Install version 0.640
+license: unknown
+name: Typeface
+no_index: 
+  directory: 
+    - inc
+    - t
+requires: 
+  Catalyst: 5.7006
+  Catalyst::Action::RenderView: 0
+  Catalyst::Controller::FormBuilder: 0
+  Catalyst::Plugin::Authentication: 0
+  Catalyst::Plugin::Authentication::Credential::Password: 0
+  Catalyst::Plugin::Authentication::Store::DBIC: 0
+  Catalyst::Plugin::Cache: 0
+  Catalyst::Plugin::Cache::Store::FastMmap: 0
+  Catalyst::Plugin::Captcha: 0
+  Catalyst::Plugin::ConfigLoader: 0
+  Catalyst::Plugin::PageCache: 0
+  Catalyst::Plugin::Server: 0
+  Catalyst::Plugin::Server::XMLRPC: 0
+  Catalyst::Plugin::Session: 0
+  Catalyst::Plugin::Session::State::Cookie: 0
+  Catalyst::Plugin::Session::Store::FastMmap: 0
+  Catalyst::Plugin::Static::Simple: 0
+  Catalyst::Plugin::Textile: 0
+  Config::Any::YAML: 0
+  DateTime: 0
+  DateTime::Format::MySQL: 0
+  DateTime::Format::Pg: 0
+  HTML::CalendarMonthSimple: 0
+  JSON::Syck: 0
+  SCGI: 0
+  SQL::Translator: 0
+  Switch: 0
+  XML::Feed: 0
+  YAML: 0
+version: 0.71

Added: trunk/examples/typeface/Makefile.PL
===================================================================
--- trunk/examples/typeface/Makefile.PL	                        (rev 0)
+++ trunk/examples/typeface/Makefile.PL	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,45 @@
+use inc::Module::Install;
+
+name 'Typeface';
+all_from 'lib/Typeface.pm';
+
+requires 'Catalyst' => '5.7006';
+requires 'Catalyst::Plugin::ConfigLoader';
+requires 'Catalyst::Plugin::Static::Simple';
+requires 'Catalyst::Action::RenderView';
+requires 'Catalyst::Plugin::Cache';
+requires 'Catalyst::Plugin::Cache::FileCache';
+requires 'Catalyst::Plugin::PageCache';
+requires 'Catalyst::Controller::FormBuilder';
+requires 'Catalyst::Plugin::Session';
+requires 'Catalyst::Plugin::Session::Store::File';
+requires 'Catalyst::Plugin::Session::State::Cookie';
+requires 'Catalyst::Plugin::Authentication';
+requires 'Catalyst::Plugin::Authentication::Store::DBIC';
+requires 'Catalyst::Plugin::Authentication::Credential::Password';
+requires 'Catalyst::Plugin::Captcha';
+requires 'Catalyst::View::JSON';
+requires 'Text::Highlight';
+# requires 'Syntax::Highlight::Engine::Kate';
+# requires 'Syntax::Highlight::Engine::Kate:All';
+requires 'Text::Textile';
+requires 'JSON::Syck';
+requires 'Scalar::Util::Clone';
+requires 'DateTime::Format::Pg';
+requires 'DateTime::Format::MySQL';
+requires 'SQL::Translator';
+requires 'SCGI';
+requires 'Catalyst::Plugin::Server';
+requires 'Catalyst::Plugin::Server::XMLRPC';
+requires 'Config::Any::YAML';
+requires 'XML::Feed';
+requires 'HTML::CalendarMonthSimple';
+requires 'Switch';
+requires 'DateTime';
+requires 'YAML'; # This should reflect the config file format you've chosen
+                 # See Catalyst::Plugin::ConfigLoader for supported formats
+catalyst;
+
+install_script glob('script/*.pl');
+auto_install;
+WriteAll;

Added: trunk/examples/typeface/Makefile.old
===================================================================
--- trunk/examples/typeface/Makefile.old	                        (rev 0)
+++ trunk/examples/typeface/Makefile.old	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,1034 @@
+# This Makefile is for the Typeface extension to perl.
+#
+# It was generated automatically by MakeMaker version
+# 6.30 (Revision: Revision: 4535 ) from the contents of
+# Makefile.PL. Don't edit this file, edit Makefile.PL instead.
+#
+#       ANY CHANGES MADE HERE WILL BE LOST!
+#
+#   MakeMaker ARGV: ()
+#
+#   MakeMaker Parameters:
+
+#     DIR => []
+#     DISTNAME => q[Typeface]
+#     EXE_FILES => [q[script/typeface_cgi.pl], q[script/typeface_create.pl], q[script/typeface_fastcgi.pl], q[script/typeface_server.pl], q[script/typeface_test.pl]]
+#     NAME => q[Typeface]
+#     NO_META => q[1]
+#     PL_FILES => {  }
+#     PREREQ_PM => { YAML=>q[0], Catalyst::Plugin::Authentication::Credential::Password=>q[0], Catalyst::Plugin::ConfigLoader=>q[0], Catalyst::Plugin::Prototype=>q[0], Catalyst::Plugin::Cache::FastMmap=>q[0], Catalyst::Plugin::Server::XMLRPC=>q[0], Catalyst::Plugin::DateTime=>q[0], Catalyst::Plugin::Session::Store::FastMmap=>q[0], Catalyst::Plugin::FormBuilder=>q[0], Catalyst::Plugin::Authentication::Store::DBIC=>q[0], Catalyst::Plugin::Session::State::Cookie=>q[0], Catalyst::Plugin::Textile=>q[0], Catalyst=>q[5.7005], Catalyst::Plugin::Static::Simple=>q[0], Catalyst::Action::RenderView=>q[0], Catalyst::Plugin::Session=>q[0], Catalyst::Plugin::Cache=>q[0], Catalyst::Plugin::Authentication=>q[0], Config::Any::YAML=>q[0], Catalyst::Plugin::PageCache=>q[0], Catalyst::Plugin::Captcha=>q[0], Catalyst::Plugin::Server=>q[0] }
+#     VERSION => q[0.03]
+#     dist => { PREOP=>q[$(PERL) -I. -MModule::Install::Admin -e "dist_preop(q($(DISTVNAME)))"] }
+#     test => { TESTS=>q[t/01app.t t/02pod.t t/03podcoverage.t t/controller_Admin.t t/controller_Feed.t t/controller_Login.t t/controller_Main.t t/controller_MetaBond.t t/controller_MetaWeblogRPC.t t/controller_Search.t t/controller_submit.t t/model_LetsGetDugg-LetsGetDugg.t t/model_LetsGetDugg.t t/view_REMOTE.t] }
+
+# --- MakeMaker post_initialize section:
+
+
+# --- MakeMaker const_config section:
+
+# These definitions are from config.sh (via /opt/local/lib/perl5/5.8.8/darwin-thread-multi-2level/Config.pm)
+
+# They may have been overridden via Makefile.PL or on the command line
+AR = ar
+CC = /usr/bin/gcc-4.0
+CCCDLFLAGS =  
+CCDLFLAGS =  
+DLEXT = bundle
+DLSRC = dl_dlopen.xs
+LD = env MACOSX_DEPLOYMENT_TARGET=10.3 cc
+LDDLFLAGS = -L/opt/local/lib -bundle -undefined dynamic_lookup -L/usr/local/lib
+LDFLAGS = -L/opt/local/lib -L/usr/local/lib
+LIBC = /usr/lib/libc.dylib
+LIB_EXT = .a
+OBJ_EXT = .o
+OSNAME = darwin
+OSVERS = 8.4.1
+RANLIB = ranlib
+SITELIBEXP = /opt/local/lib/perl5/site_perl/5.8.8
+SITEARCHEXP = /opt/local/lib/perl5/site_perl/5.8.8/darwin-thread-multi-2level
+SO = dylib
+EXE_EXT = 
+FULL_AR = /usr/bin/ar
+VENDORARCHEXP = /opt/local/lib/perl5/vendor_perl/5.8.8/darwin-thread-multi-2level
+VENDORLIBEXP = /opt/local/lib/perl5/vendor_perl/5.8.8
+
+
+# --- MakeMaker constants section:
+AR_STATIC_ARGS = cr
+DIRFILESEP = /
+DFSEP = $(DIRFILESEP)
+NAME = Typeface
+NAME_SYM = Typeface
+VERSION = 0.03
+VERSION_MACRO = VERSION
+VERSION_SYM = 0_03
+DEFINE_VERSION = -D$(VERSION_MACRO)=\"$(VERSION)\"
+XS_VERSION = 0.03
+XS_VERSION_MACRO = XS_VERSION
+XS_DEFINE_VERSION = -D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\"
+INST_ARCHLIB = blib/arch
+INST_SCRIPT = blib/script
+INST_BIN = blib/bin
+INST_LIB = blib/lib
+INST_MAN1DIR = blib/man1
+INST_MAN3DIR = blib/man3
+MAN1EXT = 1
+MAN3EXT = 3
+INSTALLDIRS = site
+DESTDIR = 
+PREFIX = $(SITEPREFIX)
+PERLPREFIX = /opt/local
+SITEPREFIX = /opt/local
+VENDORPREFIX = /opt/local
+INSTALLPRIVLIB = /opt/local/lib/perl5/5.8.8
+DESTINSTALLPRIVLIB = $(DESTDIR)$(INSTALLPRIVLIB)
+INSTALLSITELIB = /opt/local/lib/perl5/site_perl/5.8.8
+DESTINSTALLSITELIB = $(DESTDIR)$(INSTALLSITELIB)
+INSTALLVENDORLIB = /opt/local/lib/perl5/vendor_perl/5.8.8
+DESTINSTALLVENDORLIB = $(DESTDIR)$(INSTALLVENDORLIB)
+INSTALLARCHLIB = /opt/local/lib/perl5/5.8.8/darwin-thread-multi-2level
+DESTINSTALLARCHLIB = $(DESTDIR)$(INSTALLARCHLIB)
+INSTALLSITEARCH = /opt/local/lib/perl5/site_perl/5.8.8/darwin-thread-multi-2level
+DESTINSTALLSITEARCH = $(DESTDIR)$(INSTALLSITEARCH)
+INSTALLVENDORARCH = /opt/local/lib/perl5/vendor_perl/5.8.8/darwin-thread-multi-2level
+DESTINSTALLVENDORARCH = $(DESTDIR)$(INSTALLVENDORARCH)
+INSTALLBIN = /opt/local/bin
+DESTINSTALLBIN = $(DESTDIR)$(INSTALLBIN)
+INSTALLSITEBIN = /opt/local/bin
+DESTINSTALLSITEBIN = $(DESTDIR)$(INSTALLSITEBIN)
+INSTALLVENDORBIN = /opt/local/bin
+DESTINSTALLVENDORBIN = $(DESTDIR)$(INSTALLVENDORBIN)
+INSTALLSCRIPT = /opt/local/bin
+DESTINSTALLSCRIPT = $(DESTDIR)$(INSTALLSCRIPT)
+INSTALLMAN1DIR = /opt/local/share/man/man1
+DESTINSTALLMAN1DIR = $(DESTDIR)$(INSTALLMAN1DIR)
+INSTALLSITEMAN1DIR = /opt/local/share/man/man1
+DESTINSTALLSITEMAN1DIR = $(DESTDIR)$(INSTALLSITEMAN1DIR)
+INSTALLVENDORMAN1DIR = /opt/local/share/man/man1
+DESTINSTALLVENDORMAN1DIR = $(DESTDIR)$(INSTALLVENDORMAN1DIR)
+INSTALLMAN3DIR = /opt/local/share/man/man3
+DESTINSTALLMAN3DIR = $(DESTDIR)$(INSTALLMAN3DIR)
+INSTALLSITEMAN3DIR = /opt/local/share/man/man3
+DESTINSTALLSITEMAN3DIR = $(DESTDIR)$(INSTALLSITEMAN3DIR)
+INSTALLVENDORMAN3DIR = /opt/local/share/man/man3
+DESTINSTALLVENDORMAN3DIR = $(DESTDIR)$(INSTALLVENDORMAN3DIR)
+PERL_LIB =
+PERL_ARCHLIB = /opt/local/lib/perl5/5.8.8/darwin-thread-multi-2level
+LIBPERL_A = libperl.a
+FIRST_MAKEFILE = Makefile
+MAKEFILE_OLD = Makefile.old
+MAKE_APERL_FILE = Makefile.aperl
+PERLMAINCC = $(CC)
+PERL_INC = /opt/local/lib/perl5/5.8.8/darwin-thread-multi-2level/CORE
+PERL = /opt/local/bin/perl "-Iinc"
+FULLPERL = /opt/local/bin/perl "-Iinc"
+ABSPERL = $(PERL)
+PERLRUN = $(PERL)
+FULLPERLRUN = $(FULLPERL)
+ABSPERLRUN = $(ABSPERL)
+PERLRUNINST = $(PERLRUN) "-I$(INST_ARCHLIB)" "-Iinc" "-I$(INST_LIB)"
+FULLPERLRUNINST = $(FULLPERLRUN) "-I$(INST_ARCHLIB)" "-Iinc" "-I$(INST_LIB)"
+ABSPERLRUNINST = $(ABSPERLRUN) "-I$(INST_ARCHLIB)" "-Iinc" "-I$(INST_LIB)"
+PERL_CORE = 0
+PERM_RW = 644
+PERM_RWX = 755
+
+MAKEMAKER   = /opt/local/lib/perl5/5.8.8/ExtUtils/MakeMaker.pm
+MM_VERSION  = 6.30
+MM_REVISION = Revision: 4535 
+
+# FULLEXT = Pathname for extension directory (eg Foo/Bar/Oracle).
+# BASEEXT = Basename part of FULLEXT. May be just equal FULLEXT. (eg Oracle)
+# PARENT_NAME = NAME without BASEEXT and no trailing :: (eg Foo::Bar)
+# DLBASE  = Basename part of dynamic library. May be just equal BASEEXT.
+FULLEXT = Typeface
+BASEEXT = Typeface
+PARENT_NAME = 
+DLBASE = $(BASEEXT)
+VERSION_FROM = 
+OBJECT = 
+LDFROM = $(OBJECT)
+LINKTYPE = dynamic
+BOOTDEP = 
+
+# Handy lists of source code files:
+XS_FILES = 
+C_FILES  = 
+O_FILES  = 
+H_FILES  = 
+MAN1PODS = script/typeface_cgi.pl \
+	script/typeface_create.pl \
+	script/typeface_fastcgi.pl \
+	script/typeface_server.pl \
+	script/typeface_test.pl
+MAN3PODS = lib/HTML/Calendar/Simple.pm \
+	lib/HTML/CalendarMonthSimple.pm \
+	lib/Typeface/Model/Typeface.pm \
+	lib/Typeface/View/REMOTE.pm \
+	lib/Typeface/View/TT.pm
+
+# Where is the Config information that we are using/depend on
+CONFIGDEP = $(PERL_ARCHLIB)$(DFSEP)Config.pm $(PERL_INC)$(DFSEP)config.h
+
+# Where to build things
+INST_LIBDIR      = $(INST_LIB)
+INST_ARCHLIBDIR  = $(INST_ARCHLIB)
+
+INST_AUTODIR     = $(INST_LIB)/auto/$(FULLEXT)
+INST_ARCHAUTODIR = $(INST_ARCHLIB)/auto/$(FULLEXT)
+
+INST_STATIC      = 
+INST_DYNAMIC     = 
+INST_BOOT        = 
+
+# Extra linker info
+EXPORT_LIST        = 
+PERL_ARCHIVE       = 
+PERL_ARCHIVE_AFTER = 
+
+
+TO_INST_PM = create_sql.pl \
+	lib/.DS_Store \
+	lib/Catalyst/Plugin/Nifty.pm \
+	lib/DB/.DS_Store \
+	lib/DB/Typeface/.DS_Store \
+	lib/DB/Typeface/Schema.pm \
+	lib/DB/Typeface/Schema/.DS_Store \
+	lib/DB/Typeface/Schema/Articles.pm \
+	lib/DB/Typeface/Schema/Blogs.pm \
+	lib/DB/Typeface/Schema/BlogsUsers.pm \
+	lib/DB/Typeface/Schema/Categories.pm \
+	lib/DB/Typeface/Schema/CategoriesArticles.pm \
+	lib/DB/Typeface/Schema/Comments.pm \
+	lib/DB/Typeface/Schema/Links.pm \
+	lib/DB/Typeface/Schema/Pages.pm \
+	lib/DB/Typeface/Schema/Users.pm \
+	lib/HTML/Calendar/Simple.pm \
+	lib/HTML/CalendarMonthSimple.pm \
+	lib/Typeface.pm \
+	lib/Typeface/.DS_Store \
+	lib/Typeface/Controller/Admin.pm \
+	lib/Typeface/Controller/Feed.pm \
+	lib/Typeface/Controller/Login.pm \
+	lib/Typeface/Controller/MetaBond.pm \
+	lib/Typeface/Controller/MetaWeblogRPC.pm \
+	lib/Typeface/Controller/Root.pm \
+	lib/Typeface/Controller/Search.pm \
+	lib/Typeface/Controller/Submit.pm \
+	lib/Typeface/Model/.DS_Store \
+	lib/Typeface/Model/Typeface.pm \
+	lib/Typeface/View/REMOTE.pm \
+	lib/Typeface/View/TT.pm
+
+PM_TO_BLIB = lib/Typeface/Model/Typeface.pm \
+	blib/lib/Typeface/Model/Typeface.pm \
+	lib/Typeface/View/TT.pm \
+	blib/lib/Typeface/View/TT.pm \
+	lib/DB/Typeface/Schema/Articles.pm \
+	blib/lib/DB/Typeface/Schema/Articles.pm \
+	lib/DB/.DS_Store \
+	blib/lib/DB/.DS_Store \
+	lib/DB/Typeface/Schema.pm \
+	blib/lib/DB/Typeface/Schema.pm \
+	lib/Typeface/Controller/Search.pm \
+	blib/lib/Typeface/Controller/Search.pm \
+	lib/Typeface/Controller/Feed.pm \
+	blib/lib/Typeface/Controller/Feed.pm \
+	lib/Typeface/.DS_Store \
+	blib/lib/Typeface/.DS_Store \
+	lib/HTML/Calendar/Simple.pm \
+	blib/lib/HTML/Calendar/Simple.pm \
+	lib/DB/Typeface/Schema/Pages.pm \
+	blib/lib/DB/Typeface/Schema/Pages.pm \
+	lib/DB/Typeface/Schema/Blogs.pm \
+	blib/lib/DB/Typeface/Schema/Blogs.pm \
+	lib/DB/Typeface/Schema/Users.pm \
+	blib/lib/DB/Typeface/Schema/Users.pm \
+	lib/Typeface/Controller/Admin.pm \
+	blib/lib/Typeface/Controller/Admin.pm \
+	lib/DB/Typeface/Schema/Comments.pm \
+	blib/lib/DB/Typeface/Schema/Comments.pm \
+	lib/HTML/CalendarMonthSimple.pm \
+	blib/lib/HTML/CalendarMonthSimple.pm \
+	lib/.DS_Store \
+	blib/lib/.DS_Store \
+	lib/DB/Typeface/Schema/CategoriesArticles.pm \
+	blib/lib/DB/Typeface/Schema/CategoriesArticles.pm \
+	lib/DB/Typeface/.DS_Store \
+	blib/lib/DB/Typeface/.DS_Store \
+	lib/Typeface/View/REMOTE.pm \
+	blib/lib/Typeface/View/REMOTE.pm \
+	create_sql.pl \
+	$(INST_LIB)/create_sql.pl \
+	lib/DB/Typeface/Schema/Links.pm \
+	blib/lib/DB/Typeface/Schema/Links.pm \
+	lib/Typeface/Controller/Submit.pm \
+	blib/lib/Typeface/Controller/Submit.pm \
+	lib/Typeface/Controller/MetaWeblogRPC.pm \
+	blib/lib/Typeface/Controller/MetaWeblogRPC.pm \
+	lib/DB/Typeface/Schema/BlogsUsers.pm \
+	blib/lib/DB/Typeface/Schema/BlogsUsers.pm \
+	lib/DB/Typeface/Schema/Categories.pm \
+	blib/lib/DB/Typeface/Schema/Categories.pm \
+	lib/Typeface/Controller/Login.pm \
+	blib/lib/Typeface/Controller/Login.pm \
+	lib/Typeface/Model/.DS_Store \
+	blib/lib/Typeface/Model/.DS_Store \
+	lib/Catalyst/Plugin/Nifty.pm \
+	blib/lib/Catalyst/Plugin/Nifty.pm \
+	lib/Typeface/Controller/MetaBond.pm \
+	blib/lib/Typeface/Controller/MetaBond.pm \
+	lib/Typeface/Controller/Root.pm \
+	blib/lib/Typeface/Controller/Root.pm \
+	lib/DB/Typeface/Schema/.DS_Store \
+	blib/lib/DB/Typeface/Schema/.DS_Store \
+	lib/Typeface.pm \
+	blib/lib/Typeface.pm
+
+
+# --- MakeMaker platform_constants section:
+MM_Unix_VERSION = 1.50
+PERL_MALLOC_DEF = -DPERL_EXTMALLOC_DEF -Dmalloc=Perl_malloc -Dfree=Perl_mfree -Drealloc=Perl_realloc -Dcalloc=Perl_calloc
+
+
+# --- MakeMaker tool_autosplit section:
+# Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto
+AUTOSPLITFILE = $(ABSPERLRUN)  -e 'use AutoSplit;  autosplit($$ARGV[0], $$ARGV[1], 0, 1, 1)'
+
+
+
+# --- MakeMaker tool_xsubpp section:
+
+
+# --- MakeMaker tools_other section:
+SHELL = /bin/sh
+CHMOD = chmod
+CP = cp
+MV = mv
+NOOP = $(SHELL) -c true
+NOECHO = @
+RM_F = rm -f
+RM_RF = rm -rf
+TEST_F = test -f
+TOUCH = touch
+UMASK_NULL = umask 0
+DEV_NULL = > /dev/null 2>&1
+MKPATH = $(ABSPERLRUN) "-MExtUtils::Command" -e mkpath
+EQUALIZE_TIMESTAMP = $(ABSPERLRUN) "-MExtUtils::Command" -e eqtime
+ECHO = echo
+ECHO_N = echo -n
+UNINST = 0
+VERBINST = 0
+MOD_INSTALL = $(ABSPERLRUN) -MExtUtils::Install -e 'install({@ARGV}, '\''$(VERBINST)'\'', 0, '\''$(UNINST)'\'');'
+DOC_INSTALL = $(ABSPERLRUN) "-MExtUtils::Command::MM" -e perllocal_install
+UNINSTALL = $(ABSPERLRUN) "-MExtUtils::Command::MM" -e uninstall
+WARN_IF_OLD_PACKLIST = $(ABSPERLRUN) "-MExtUtils::Command::MM" -e warn_if_old_packlist
+MACROSTART = 
+MACROEND = 
+USEMAKEFILE = -f
+FIXIN = $(PERLRUN) "-MExtUtils::MY" -e "MY->fixin(shift)"
+
+
+# --- MakeMaker makemakerdflt section:
+makemakerdflt: all
+	$(NOECHO) $(NOOP)
+
+
+# --- MakeMaker dist section:
+TAR = tar
+TARFLAGS = cvf
+ZIP = zip
+ZIPFLAGS = -r
+COMPRESS = gzip --best
+SUFFIX = .gz
+SHAR = shar
+PREOP = $(PERL) -I. -MModule::Install::Admin -e "dist_preop(q($(DISTVNAME)))"
+POSTOP = $(NOECHO) $(NOOP)
+TO_UNIX = $(NOECHO) $(NOOP)
+CI = ci -u
+RCS_LABEL = rcs -Nv$(VERSION_SYM): -q
+DIST_CP = best
+DIST_DEFAULT = tardist
+DISTNAME = Typeface
+DISTVNAME = Typeface-0.03
+
+
+# --- MakeMaker macro section:
+
+
+# --- MakeMaker depend section:
+
+
+# --- MakeMaker cflags section:
+
+
+# --- MakeMaker const_loadlibs section:
+
+
+# --- MakeMaker const_cccmd section:
+
+
+# --- MakeMaker post_constants section:
+
+
+# --- MakeMaker pasthru section:
+
+PASTHRU = LIBPERL_A="$(LIBPERL_A)"\
+	LINKTYPE="$(LINKTYPE)"\
+	PREFIX="$(PREFIX)"
+
+
+# --- MakeMaker special_targets section:
+.SUFFIXES : .xs .c .C .cpp .i .s .cxx .cc $(OBJ_EXT)
+
+.PHONY: all config static dynamic test linkext manifest blibdirs clean realclean disttest distdir
+
+
+
+# --- MakeMaker c_o section:
+
+
+# --- MakeMaker xs_c section:
+
+
+# --- MakeMaker xs_o section:
+
+
+# --- MakeMaker top_targets section:
+all :: pure_all manifypods
+	$(NOECHO) $(NOOP)
+
+
+pure_all :: config pm_to_blib subdirs linkext
+	$(NOECHO) $(NOOP)
+
+subdirs :: $(MYEXTLIB)
+	$(NOECHO) $(NOOP)
+
+config :: $(FIRST_MAKEFILE) blibdirs
+	$(NOECHO) $(NOOP)
+
+help :
+	perldoc ExtUtils::MakeMaker
+
+
+# --- MakeMaker blibdirs section:
+blibdirs : $(INST_LIBDIR)$(DFSEP).exists $(INST_ARCHLIB)$(DFSEP).exists $(INST_AUTODIR)$(DFSEP).exists $(INST_ARCHAUTODIR)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists $(INST_SCRIPT)$(DFSEP).exists $(INST_MAN1DIR)$(DFSEP).exists $(INST_MAN3DIR)$(DFSEP).exists
+	$(NOECHO) $(NOOP)
+
+# Backwards compat with 6.18 through 6.25
+blibdirs.ts : blibdirs
+	$(NOECHO) $(NOOP)
+
+$(INST_LIBDIR)$(DFSEP).exists :: Makefile.PL
+	$(NOECHO) $(MKPATH) $(INST_LIBDIR)
+	$(NOECHO) $(CHMOD) 755 $(INST_LIBDIR)
+	$(NOECHO) $(TOUCH) $(INST_LIBDIR)$(DFSEP).exists
+
+$(INST_ARCHLIB)$(DFSEP).exists :: Makefile.PL
+	$(NOECHO) $(MKPATH) $(INST_ARCHLIB)
+	$(NOECHO) $(CHMOD) 755 $(INST_ARCHLIB)
+	$(NOECHO) $(TOUCH) $(INST_ARCHLIB)$(DFSEP).exists
+
+$(INST_AUTODIR)$(DFSEP).exists :: Makefile.PL
+	$(NOECHO) $(MKPATH) $(INST_AUTODIR)
+	$(NOECHO) $(CHMOD) 755 $(INST_AUTODIR)
+	$(NOECHO) $(TOUCH) $(INST_AUTODIR)$(DFSEP).exists
+
+$(INST_ARCHAUTODIR)$(DFSEP).exists :: Makefile.PL
+	$(NOECHO) $(MKPATH) $(INST_ARCHAUTODIR)
+	$(NOECHO) $(CHMOD) 755 $(INST_ARCHAUTODIR)
+	$(NOECHO) $(TOUCH) $(INST_ARCHAUTODIR)$(DFSEP).exists
+
+$(INST_BIN)$(DFSEP).exists :: Makefile.PL
+	$(NOECHO) $(MKPATH) $(INST_BIN)
+	$(NOECHO) $(CHMOD) 755 $(INST_BIN)
+	$(NOECHO) $(TOUCH) $(INST_BIN)$(DFSEP).exists
+
+$(INST_SCRIPT)$(DFSEP).exists :: Makefile.PL
+	$(NOECHO) $(MKPATH) $(INST_SCRIPT)
+	$(NOECHO) $(CHMOD) 755 $(INST_SCRIPT)
+	$(NOECHO) $(TOUCH) $(INST_SCRIPT)$(DFSEP).exists
+
+$(INST_MAN1DIR)$(DFSEP).exists :: Makefile.PL
+	$(NOECHO) $(MKPATH) $(INST_MAN1DIR)
+	$(NOECHO) $(CHMOD) 755 $(INST_MAN1DIR)
+	$(NOECHO) $(TOUCH) $(INST_MAN1DIR)$(DFSEP).exists
+
+$(INST_MAN3DIR)$(DFSEP).exists :: Makefile.PL
+	$(NOECHO) $(MKPATH) $(INST_MAN3DIR)
+	$(NOECHO) $(CHMOD) 755 $(INST_MAN3DIR)
+	$(NOECHO) $(TOUCH) $(INST_MAN3DIR)$(DFSEP).exists
+
+
+
+# --- MakeMaker linkext section:
+
+linkext :: $(LINKTYPE)
+	$(NOECHO) $(NOOP)
+
+
+# --- MakeMaker dlsyms section:
+
+
+# --- MakeMaker dynamic section:
+
+dynamic :: $(FIRST_MAKEFILE) $(INST_DYNAMIC) $(INST_BOOT)
+	$(NOECHO) $(NOOP)
+
+
+# --- MakeMaker dynamic_bs section:
+
+BOOTSTRAP =
+
+
+# --- MakeMaker dynamic_lib section:
+
+
+# --- MakeMaker static section:
+
+## $(INST_PM) has been moved to the all: target.
+## It remains here for awhile to allow for old usage: "make static"
+static :: $(FIRST_MAKEFILE) $(INST_STATIC)
+	$(NOECHO) $(NOOP)
+
+
+# --- MakeMaker static_lib section:
+
+
+# --- MakeMaker manifypods section:
+
+POD2MAN_EXE = $(PERLRUN) "-MExtUtils::Command::MM" -e pod2man "--"
+POD2MAN = $(POD2MAN_EXE)
+
+
+manifypods : pure_all  \
+	script/typeface_fastcgi.pl \
+	script/typeface_test.pl \
+	script/typeface_cgi.pl \
+	script/typeface_server.pl \
+	script/typeface_create.pl \
+	lib/Typeface/Model/Typeface.pm \
+	lib/HTML/Calendar/Simple.pm \
+	lib/Typeface/View/TT.pm \
+	lib/Typeface/View/REMOTE.pm \
+	lib/HTML/CalendarMonthSimple.pm \
+	lib/Typeface/Model/Typeface.pm \
+	lib/HTML/Calendar/Simple.pm \
+	lib/Typeface/View/TT.pm \
+	lib/Typeface/View/REMOTE.pm \
+	lib/HTML/CalendarMonthSimple.pm
+	$(NOECHO) $(POD2MAN) --section=1 --perm_rw=$(PERM_RW) \
+	  script/typeface_fastcgi.pl $(INST_MAN1DIR)/typeface_fastcgi.pl.$(MAN1EXT) \
+	  script/typeface_test.pl $(INST_MAN1DIR)/typeface_test.pl.$(MAN1EXT) \
+	  script/typeface_cgi.pl $(INST_MAN1DIR)/typeface_cgi.pl.$(MAN1EXT) \
+	  script/typeface_server.pl $(INST_MAN1DIR)/typeface_server.pl.$(MAN1EXT) \
+	  script/typeface_create.pl $(INST_MAN1DIR)/typeface_create.pl.$(MAN1EXT) 
+	$(NOECHO) $(POD2MAN) --section=3 --perm_rw=$(PERM_RW) \
+	  lib/Typeface/Model/Typeface.pm $(INST_MAN3DIR)/Typeface::Model::Typeface.$(MAN3EXT) \
+	  lib/HTML/Calendar/Simple.pm $(INST_MAN3DIR)/HTML::Calendar::Simple.$(MAN3EXT) \
+	  lib/Typeface/View/TT.pm $(INST_MAN3DIR)/Typeface::View::TT.$(MAN3EXT) \
+	  lib/Typeface/View/REMOTE.pm $(INST_MAN3DIR)/Typeface::View::REMOTE.$(MAN3EXT) \
+	  lib/HTML/CalendarMonthSimple.pm $(INST_MAN3DIR)/HTML::CalendarMonthSimple.$(MAN3EXT) 
+
+
+
+
+# --- MakeMaker processPL section:
+
+
+# --- MakeMaker installbin section:
+
+EXE_FILES = script/typeface_cgi.pl script/typeface_create.pl script/typeface_fastcgi.pl script/typeface_server.pl script/typeface_test.pl
+
+pure_all :: $(INST_SCRIPT)/typeface_fastcgi.pl $(INST_SCRIPT)/typeface_test.pl $(INST_SCRIPT)/typeface_cgi.pl $(INST_SCRIPT)/typeface_server.pl $(INST_SCRIPT)/typeface_create.pl
+	$(NOECHO) $(NOOP)
+
+realclean ::
+	$(RM_F) \
+	  $(INST_SCRIPT)/typeface_fastcgi.pl $(INST_SCRIPT)/typeface_test.pl \
+	  $(INST_SCRIPT)/typeface_cgi.pl $(INST_SCRIPT)/typeface_server.pl \
+	  $(INST_SCRIPT)/typeface_create.pl 
+
+$(INST_SCRIPT)/typeface_fastcgi.pl : script/typeface_fastcgi.pl $(FIRST_MAKEFILE) $(INST_SCRIPT)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists
+	$(NOECHO) $(RM_F) $(INST_SCRIPT)/typeface_fastcgi.pl
+	$(CP) script/typeface_fastcgi.pl $(INST_SCRIPT)/typeface_fastcgi.pl
+	$(FIXIN) $(INST_SCRIPT)/typeface_fastcgi.pl
+	-$(NOECHO) $(CHMOD) $(PERM_RWX) $(INST_SCRIPT)/typeface_fastcgi.pl
+
+$(INST_SCRIPT)/typeface_test.pl : script/typeface_test.pl $(FIRST_MAKEFILE) $(INST_SCRIPT)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists
+	$(NOECHO) $(RM_F) $(INST_SCRIPT)/typeface_test.pl
+	$(CP) script/typeface_test.pl $(INST_SCRIPT)/typeface_test.pl
+	$(FIXIN) $(INST_SCRIPT)/typeface_test.pl
+	-$(NOECHO) $(CHMOD) $(PERM_RWX) $(INST_SCRIPT)/typeface_test.pl
+
+$(INST_SCRIPT)/typeface_cgi.pl : script/typeface_cgi.pl $(FIRST_MAKEFILE) $(INST_SCRIPT)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists
+	$(NOECHO) $(RM_F) $(INST_SCRIPT)/typeface_cgi.pl
+	$(CP) script/typeface_cgi.pl $(INST_SCRIPT)/typeface_cgi.pl
+	$(FIXIN) $(INST_SCRIPT)/typeface_cgi.pl
+	-$(NOECHO) $(CHMOD) $(PERM_RWX) $(INST_SCRIPT)/typeface_cgi.pl
+
+$(INST_SCRIPT)/typeface_server.pl : script/typeface_server.pl $(FIRST_MAKEFILE) $(INST_SCRIPT)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists
+	$(NOECHO) $(RM_F) $(INST_SCRIPT)/typeface_server.pl
+	$(CP) script/typeface_server.pl $(INST_SCRIPT)/typeface_server.pl
+	$(FIXIN) $(INST_SCRIPT)/typeface_server.pl
+	-$(NOECHO) $(CHMOD) $(PERM_RWX) $(INST_SCRIPT)/typeface_server.pl
+
+$(INST_SCRIPT)/typeface_create.pl : script/typeface_create.pl $(FIRST_MAKEFILE) $(INST_SCRIPT)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists
+	$(NOECHO) $(RM_F) $(INST_SCRIPT)/typeface_create.pl
+	$(CP) script/typeface_create.pl $(INST_SCRIPT)/typeface_create.pl
+	$(FIXIN) $(INST_SCRIPT)/typeface_create.pl
+	-$(NOECHO) $(CHMOD) $(PERM_RWX) $(INST_SCRIPT)/typeface_create.pl
+
+
+
+# --- MakeMaker subdirs section:
+
+# none
+
+# --- MakeMaker clean_subdirs section:
+clean_subdirs :
+	$(NOECHO) $(NOOP)
+
+
+# --- MakeMaker clean section:
+
+# Delete temporary files but do not touch installed files. We don't delete
+# the Makefile here so a later make realclean still has a makefile to use.
+
+clean :: clean_subdirs
+	- $(RM_F) \
+	  *$(LIB_EXT) core \
+	  core.[0-9] $(INST_ARCHAUTODIR)/extralibs.all \
+	  core.[0-9][0-9] $(BASEEXT).bso \
+	  pm_to_blib.ts core.[0-9][0-9][0-9][0-9] \
+	  $(BASEEXT).x $(BOOTSTRAP) \
+	  perl$(EXE_EXT) tmon.out \
+	  *$(OBJ_EXT) pm_to_blib \
+	  $(INST_ARCHAUTODIR)/extralibs.ld blibdirs.ts \
+	  core.[0-9][0-9][0-9][0-9][0-9] *perl.core \
+	  core.*perl.*.? $(MAKE_APERL_FILE) \
+	  perl $(BASEEXT).def \
+	  core.[0-9][0-9][0-9] mon.out \
+	  lib$(BASEEXT).def perlmain.c \
+	  perl.exe so_locations \
+	  $(BASEEXT).exp 
+	- $(RM_RF) \
+	  blib 
+	- $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) $(DEV_NULL)
+
+
+# --- MakeMaker realclean_subdirs section:
+realclean_subdirs :
+	$(NOECHO) $(NOOP)
+
+
+# --- MakeMaker realclean section:
+# Delete temporary files (via clean) and also delete dist files
+realclean purge ::  clean realclean_subdirs
+	- $(RM_F) \
+	  $(MAKEFILE_OLD) $(FIRST_MAKEFILE) 
+	- $(RM_RF) \
+	  $(DISTVNAME) 
+
+
+# --- MakeMaker metafile section:
+metafile:
+	$(NOECHO) $(NOOP)
+
+
+# --- MakeMaker signature section:
+signature :
+	cpansign -s
+
+
+# --- MakeMaker dist_basics section:
+distclean :: realclean distcheck
+	$(NOECHO) $(NOOP)
+
+distcheck :
+	$(PERLRUN) "-MExtUtils::Manifest=fullcheck" -e fullcheck
+
+skipcheck :
+	$(PERLRUN) "-MExtUtils::Manifest=skipcheck" -e skipcheck
+
+manifest :
+	$(PERLRUN) "-MExtUtils::Manifest=mkmanifest" -e mkmanifest
+
+veryclean : realclean
+	$(RM_F) *~ *.orig */*~ */*.orig
+
+
+
+# --- MakeMaker dist_core section:
+
+dist : $(DIST_DEFAULT) $(FIRST_MAKEFILE)
+	$(NOECHO) $(ABSPERLRUN) -l -e 'print '\''Warning: Makefile possibly out of date with $(VERSION_FROM)'\''' \
+	  -e '    if -e '\''$(VERSION_FROM)'\'' and -M '\''$(VERSION_FROM)'\'' < -M '\''$(FIRST_MAKEFILE)'\'';'
+
+tardist : $(DISTVNAME).tar$(SUFFIX)
+	$(NOECHO) $(NOOP)
+
+uutardist : $(DISTVNAME).tar$(SUFFIX)
+	uuencode $(DISTVNAME).tar$(SUFFIX) $(DISTVNAME).tar$(SUFFIX) > $(DISTVNAME).tar$(SUFFIX)_uu
+
+$(DISTVNAME).tar$(SUFFIX) : distdir
+	$(PREOP)
+	$(TO_UNIX)
+	$(TAR) $(TARFLAGS) $(DISTVNAME).tar $(DISTVNAME)
+	$(RM_RF) $(DISTVNAME)
+	$(COMPRESS) $(DISTVNAME).tar
+	$(POSTOP)
+
+zipdist : $(DISTVNAME).zip
+	$(NOECHO) $(NOOP)
+
+$(DISTVNAME).zip : distdir
+	$(PREOP)
+	$(ZIP) $(ZIPFLAGS) $(DISTVNAME).zip $(DISTVNAME)
+	$(RM_RF) $(DISTVNAME)
+	$(POSTOP)
+
+shdist : distdir
+	$(PREOP)
+	$(SHAR) $(DISTVNAME) > $(DISTVNAME).shar
+	$(RM_RF) $(DISTVNAME)
+	$(POSTOP)
+
+
+# --- MakeMaker distdir section:
+create_distdir :
+	$(RM_RF) $(DISTVNAME)
+	$(PERLRUN) "-MExtUtils::Manifest=manicopy,maniread" \
+		-e "manicopy(maniread(),'$(DISTVNAME)', '$(DIST_CP)');"
+
+distdir : create_distdir  
+	$(NOECHO) $(NOOP)
+
+
+
+# --- MakeMaker dist_test section:
+disttest : distdir
+	cd $(DISTVNAME) && $(ABSPERLRUN) Makefile.PL 
+	cd $(DISTVNAME) && $(MAKE) $(PASTHRU)
+	cd $(DISTVNAME) && $(MAKE) test $(PASTHRU)
+
+
+
+# --- MakeMaker dist_ci section:
+
+ci :
+	$(PERLRUN) "-MExtUtils::Manifest=maniread" \
+	  -e "@all = keys %{ maniread() };" \
+	  -e "print(qq{Executing $(CI) @all\n}); system(qq{$(CI) @all});" \
+	  -e "print(qq{Executing $(RCS_LABEL) ...\n}); system(qq{$(RCS_LABEL) @all});"
+
+
+# --- MakeMaker distmeta section:
+distmeta : create_distdir metafile
+	$(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'eval { maniadd({q{META.yml} => q{Module meta-data (added by MakeMaker)}}) } ' \
+	  -e '    or print "Could not add META.yml to MANIFEST: $${'\''@'\''}\n"'
+
+
+
+# --- MakeMaker distsignature section:
+distsignature : create_distdir
+	$(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'eval { maniadd({q{SIGNATURE} => q{Public-key signature (added by MakeMaker)}}) } ' \
+	  -e '    or print "Could not add SIGNATURE to MANIFEST: $${'\''@'\''}\n"'
+	$(NOECHO) cd $(DISTVNAME) && $(TOUCH) SIGNATURE
+	cd $(DISTVNAME) && cpansign -s
+
+
+
+# --- MakeMaker install section:
+
+install :: all pure_install doc_install
+	$(NOECHO) $(NOOP)
+
+install_perl :: all pure_perl_install doc_perl_install
+	$(NOECHO) $(NOOP)
+
+install_site :: all pure_site_install doc_site_install
+	$(NOECHO) $(NOOP)
+
+install_vendor :: all pure_vendor_install doc_vendor_install
+	$(NOECHO) $(NOOP)
+
+pure_install :: pure_$(INSTALLDIRS)_install
+	$(NOECHO) $(NOOP)
+
+doc_install :: doc_$(INSTALLDIRS)_install
+	$(NOECHO) $(NOOP)
+
+pure__install : pure_site_install
+	$(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site
+
+doc__install : doc_site_install
+	$(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site
+
+pure_perl_install ::
+	$(NOECHO) $(MOD_INSTALL) \
+		read $(PERL_ARCHLIB)/auto/$(FULLEXT)/.packlist \
+		write $(DESTINSTALLARCHLIB)/auto/$(FULLEXT)/.packlist \
+		$(INST_LIB) $(DESTINSTALLPRIVLIB) \
+		$(INST_ARCHLIB) $(DESTINSTALLARCHLIB) \
+		$(INST_BIN) $(DESTINSTALLBIN) \
+		$(INST_SCRIPT) $(DESTINSTALLSCRIPT) \
+		$(INST_MAN1DIR) $(DESTINSTALLMAN1DIR) \
+		$(INST_MAN3DIR) $(DESTINSTALLMAN3DIR)
+	$(NOECHO) $(WARN_IF_OLD_PACKLIST) \
+		$(SITEARCHEXP)/auto/$(FULLEXT)
+
+
+pure_site_install ::
+	$(NOECHO) $(MOD_INSTALL) \
+		read $(SITEARCHEXP)/auto/$(FULLEXT)/.packlist \
+		write $(DESTINSTALLSITEARCH)/auto/$(FULLEXT)/.packlist \
+		$(INST_LIB) $(DESTINSTALLSITELIB) \
+		$(INST_ARCHLIB) $(DESTINSTALLSITEARCH) \
+		$(INST_BIN) $(DESTINSTALLSITEBIN) \
+		$(INST_SCRIPT) $(DESTINSTALLSCRIPT) \
+		$(INST_MAN1DIR) $(DESTINSTALLSITEMAN1DIR) \
+		$(INST_MAN3DIR) $(DESTINSTALLSITEMAN3DIR)
+	$(NOECHO) $(WARN_IF_OLD_PACKLIST) \
+		$(PERL_ARCHLIB)/auto/$(FULLEXT)
+
+pure_vendor_install ::
+	$(NOECHO) $(MOD_INSTALL) \
+		read $(VENDORARCHEXP)/auto/$(FULLEXT)/.packlist \
+		write $(DESTINSTALLVENDORARCH)/auto/$(FULLEXT)/.packlist \
+		$(INST_LIB) $(DESTINSTALLVENDORLIB) \
+		$(INST_ARCHLIB) $(DESTINSTALLVENDORARCH) \
+		$(INST_BIN) $(DESTINSTALLVENDORBIN) \
+		$(INST_SCRIPT) $(DESTINSTALLSCRIPT) \
+		$(INST_MAN1DIR) $(DESTINSTALLVENDORMAN1DIR) \
+		$(INST_MAN3DIR) $(DESTINSTALLVENDORMAN3DIR)
+
+doc_perl_install ::
+	$(NOECHO) $(ECHO) Appending installation info to $(DESTINSTALLARCHLIB)/perllocal.pod
+	-$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB)
+	-$(NOECHO) $(DOC_INSTALL) \
+		"Module" "$(NAME)" \
+		"installed into" "$(INSTALLPRIVLIB)" \
+		LINKTYPE "$(LINKTYPE)" \
+		VERSION "$(VERSION)" \
+		EXE_FILES "$(EXE_FILES)" \
+		>> $(DESTINSTALLARCHLIB)/perllocal.pod
+
+doc_site_install ::
+	$(NOECHO) $(ECHO) Appending installation info to $(DESTINSTALLARCHLIB)/perllocal.pod
+	-$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB)
+	-$(NOECHO) $(DOC_INSTALL) \
+		"Module" "$(NAME)" \
+		"installed into" "$(INSTALLSITELIB)" \
+		LINKTYPE "$(LINKTYPE)" \
+		VERSION "$(VERSION)" \
+		EXE_FILES "$(EXE_FILES)" \
+		>> $(DESTINSTALLARCHLIB)/perllocal.pod
+
+doc_vendor_install ::
+	$(NOECHO) $(ECHO) Appending installation info to $(DESTINSTALLARCHLIB)/perllocal.pod
+	-$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB)
+	-$(NOECHO) $(DOC_INSTALL) \
+		"Module" "$(NAME)" \
+		"installed into" "$(INSTALLVENDORLIB)" \
+		LINKTYPE "$(LINKTYPE)" \
+		VERSION "$(VERSION)" \
+		EXE_FILES "$(EXE_FILES)" \
+		>> $(DESTINSTALLARCHLIB)/perllocal.pod
+
+
+uninstall :: uninstall_from_$(INSTALLDIRS)dirs
+	$(NOECHO) $(NOOP)
+
+uninstall_from_perldirs ::
+	$(NOECHO) $(UNINSTALL) $(PERL_ARCHLIB)/auto/$(FULLEXT)/.packlist
+
+uninstall_from_sitedirs ::
+	$(NOECHO) $(UNINSTALL) $(SITEARCHEXP)/auto/$(FULLEXT)/.packlist
+
+uninstall_from_vendordirs ::
+	$(NOECHO) $(UNINSTALL) $(VENDORARCHEXP)/auto/$(FULLEXT)/.packlist
+
+
+# --- MakeMaker force section:
+# Phony target to force checking subdirectories.
+FORCE:
+	$(NOECHO) $(NOOP)
+
+
+# --- MakeMaker perldepend section:
+
+
+# --- MakeMaker makefile section:
+# We take a very conservative approach here, but it's worth it.
+# We move Makefile to Makefile.old here to avoid gnu make looping.
+$(FIRST_MAKEFILE) : Makefile.PL $(CONFIGDEP)
+	$(NOECHO) $(ECHO) "Makefile out-of-date with respect to $?"
+	$(NOECHO) $(ECHO) "Cleaning current config before rebuilding Makefile..."
+	-$(NOECHO) $(RM_F) $(MAKEFILE_OLD)
+	-$(NOECHO) $(MV)   $(FIRST_MAKEFILE) $(MAKEFILE_OLD)
+	- $(MAKE) $(USEMAKEFILE) $(MAKEFILE_OLD) clean $(DEV_NULL)
+	$(PERLRUN) Makefile.PL 
+	$(NOECHO) $(ECHO) "==> Your Makefile has been rebuilt. <=="
+	$(NOECHO) $(ECHO) "==> Please rerun the $(MAKE) command.  <=="
+	false
+
+
+
+# --- MakeMaker staticmake section:
+
+# --- MakeMaker makeaperl section ---
+MAP_TARGET    = perl
+FULLPERL      = /opt/local/bin/perl
+
+$(MAP_TARGET) :: static $(MAKE_APERL_FILE)
+	$(MAKE) $(USEMAKEFILE) $(MAKE_APERL_FILE) $@
+
+$(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib
+	$(NOECHO) $(ECHO) Writing \"$(MAKE_APERL_FILE)\" for this $(MAP_TARGET)
+	$(NOECHO) $(PERLRUNINST) \
+		Makefile.PL DIR= \
+		MAKEFILE=$(MAKE_APERL_FILE) LINKTYPE=static \
+		MAKEAPERL=1 NORECURS=1 CCCDLFLAGS=
+
+
+# --- MakeMaker test section:
+
+TEST_VERBOSE=0
+TEST_TYPE=test_$(LINKTYPE)
+TEST_FILE = test.pl
+TEST_FILES = t/01app.t t/02pod.t t/03podcoverage.t t/controller_Admin.t t/controller_Feed.t t/controller_Login.t t/controller_Main.t t/controller_MetaBond.t t/controller_MetaWeblogRPC.t t/controller_Search.t t/controller_submit.t t/model_LetsGetDugg-LetsGetDugg.t t/model_LetsGetDugg.t t/view_REMOTE.t
+TESTDB_SW = -d
+
+testdb :: testdb_$(LINKTYPE)
+
+test :: $(TEST_TYPE)
+
+test_dynamic :: pure_all
+	PERL_DL_NONLAZY=1 $(FULLPERLRUN) "-MExtUtils::Command::MM" "-e" "test_harness($(TEST_VERBOSE), 'inc', '$(INST_LIB)', '$(INST_ARCHLIB)')" $(TEST_FILES)
+
+testdb_dynamic :: pure_all
+	PERL_DL_NONLAZY=1 $(FULLPERLRUN) $(TESTDB_SW) "-Iinc" "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE)
+
+test_ : test_dynamic
+
+test_static :: test_dynamic
+testdb_static :: testdb_dynamic
+
+
+# --- MakeMaker ppd section:
+# Creates a PPD (Perl Package Description) for a binary distribution.
+ppd:
+	$(NOECHO) $(ECHO) '<SOFTPKG NAME="$(DISTNAME)" VERSION="0,03,0,0">' > $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '    <TITLE>$(DISTNAME)</TITLE>' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '    <ABSTRACT></ABSTRACT>' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '    <AUTHOR></AUTHOR>' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '    <IMPLEMENTATION>' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst" VERSION="5,7005,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Action-RenderView" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Authentication" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Authentication-Credential-Password" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Authentication-Store-DBIC" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Cache" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Cache-FastMmap" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Captcha" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-ConfigLoader" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-DateTime" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-FormBuilder" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-PageCache" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Prototype" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Server" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Server-XMLRPC" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Session" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Session-State-Cookie" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Session-Store-FastMmap" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Static-Simple" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Catalyst-Plugin-Textile" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="Config-Any-YAML" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <DEPENDENCY NAME="YAML" VERSION="0,0,0,0" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <OS NAME="$(OSNAME)" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <ARCHITECTURE NAME="darwin-thread-multi-2level" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '        <CODEBASE HREF="" />' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '    </IMPLEMENTATION>' >> $(DISTNAME).ppd
+	$(NOECHO) $(ECHO) '</SOFTPKG>' >> $(DISTNAME).ppd
+
+
+# --- MakeMaker pm_to_blib section:
+
+pm_to_blib : $(TO_INST_PM)
+	$(NOECHO) $(ABSPERLRUN) -MExtUtils::Install -e 'pm_to_blib({@ARGV}, '\''$(INST_LIB)/auto'\'', '\''$(PM_FILTER)'\'')' \
+	  lib/Typeface/Model/Typeface.pm blib/lib/Typeface/Model/Typeface.pm \
+	  lib/Typeface/View/TT.pm blib/lib/Typeface/View/TT.pm \
+	  lib/DB/Typeface/Schema/Articles.pm blib/lib/DB/Typeface/Schema/Articles.pm \
+	  lib/DB/.DS_Store blib/lib/DB/.DS_Store \
+	  lib/DB/Typeface/Schema.pm blib/lib/DB/Typeface/Schema.pm \
+	  lib/Typeface/Controller/Search.pm blib/lib/Typeface/Controller/Search.pm \
+	  lib/Typeface/Controller/Feed.pm blib/lib/Typeface/Controller/Feed.pm \
+	  lib/Typeface/.DS_Store blib/lib/Typeface/.DS_Store \
+	  lib/HTML/Calendar/Simple.pm blib/lib/HTML/Calendar/Simple.pm \
+	  lib/DB/Typeface/Schema/Pages.pm blib/lib/DB/Typeface/Schema/Pages.pm \
+	  lib/DB/Typeface/Schema/Blogs.pm blib/lib/DB/Typeface/Schema/Blogs.pm \
+	  lib/DB/Typeface/Schema/Users.pm blib/lib/DB/Typeface/Schema/Users.pm \
+	  lib/Typeface/Controller/Admin.pm blib/lib/Typeface/Controller/Admin.pm \
+	  lib/DB/Typeface/Schema/Comments.pm blib/lib/DB/Typeface/Schema/Comments.pm \
+	  lib/HTML/CalendarMonthSimple.pm blib/lib/HTML/CalendarMonthSimple.pm \
+	  lib/.DS_Store blib/lib/.DS_Store \
+	  lib/DB/Typeface/Schema/CategoriesArticles.pm blib/lib/DB/Typeface/Schema/CategoriesArticles.pm \
+	  lib/DB/Typeface/.DS_Store blib/lib/DB/Typeface/.DS_Store \
+	  lib/Typeface/View/REMOTE.pm blib/lib/Typeface/View/REMOTE.pm \
+	  create_sql.pl $(INST_LIB)/create_sql.pl \
+	  lib/DB/Typeface/Schema/Links.pm blib/lib/DB/Typeface/Schema/Links.pm \
+	  lib/Typeface/Controller/Submit.pm blib/lib/Typeface/Controller/Submit.pm \
+	  lib/Typeface/Controller/MetaWeblogRPC.pm blib/lib/Typeface/Controller/MetaWeblogRPC.pm \
+	  lib/DB/Typeface/Schema/BlogsUsers.pm blib/lib/DB/Typeface/Schema/BlogsUsers.pm \
+	  lib/DB/Typeface/Schema/Categories.pm blib/lib/DB/Typeface/Schema/Categories.pm \
+	  lib/Typeface/Controller/Login.pm blib/lib/Typeface/Controller/Login.pm \
+	  lib/Typeface/Model/.DS_Store blib/lib/Typeface/Model/.DS_Store \
+	  lib/Catalyst/Plugin/Nifty.pm blib/lib/Catalyst/Plugin/Nifty.pm \
+	  lib/Typeface/Controller/MetaBond.pm blib/lib/Typeface/Controller/MetaBond.pm \
+	  lib/Typeface/Controller/Root.pm blib/lib/Typeface/Controller/Root.pm \
+	  lib/DB/Typeface/Schema/.DS_Store blib/lib/DB/Typeface/Schema/.DS_Store \
+	  lib/Typeface.pm blib/lib/Typeface.pm 
+	$(NOECHO) $(TOUCH) pm_to_blib
+
+
+# --- MakeMaker selfdocument section:
+
+
+# --- MakeMaker postamble section:
+
+
+# End.
+# Postamble by Module::Install 0.64
+# --- Module::Install::Admin::Makefile section:
+
+realclean purge ::
+	$(RM_F) $(DISTVNAME).tar$(SUFFIX)
+	$(RM_RF) inc MANIFEST.bak _build
+	$(PERL) -I. -MModule::Install::Admin -e "remove_meta()"
+
+reset :: purge
+
+upload :: test dist
+	cpan-upload -verbose $(DISTVNAME).tar$(SUFFIX)
+
+grok ::
+	perldoc Module::Install
+
+distsign ::
+	cpansign -s
+
+catalyst_par :: all
+	$(NOECHO) $(PERL) -Ilib -Minc::Module::Install -MModule::Install::Catalyst -e"Catalyst::Module::Install::_catalyst_par( '', 'Typeface', { CLASSES => [], CORE => 0, ENGINE => 'CGI', MULTIARCH => 0, SCRIPT => '', USAGE => q## } )"
+# --- Module::Install::AutoInstall section:
+
+config :: installdeps
+	$(NOECHO) $(NOOP)
+
+checkdeps ::
+	$(PERL) Makefile.PL --checkdeps
+
+installdeps ::
+	$(NOECHO) $(NOOP)
+

Added: trunk/examples/typeface/README
===================================================================
--- trunk/examples/typeface/README	                        (rev 0)
+++ trunk/examples/typeface/README	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,42 @@
+Installation:
+	1) Run MakeFile.PL to install all dependencies.
+	2) Import the SQL schema.
+	3) Edit typeface.yml to suit your needs.
+	4) Run create_login.pl
+	5) Run script/typeface_server.pl -p 8080
+	6) Login into http://localhost:8080/!
+
+
+Features:
+	XML-RPC MetaWeblog support (MarsEdit supported http://ranchero.com/marsedit/)
+	Captcha image verification
+	Categories
+	Human readable URLs
+	Live ajax search
+	On site calendar
+	Tabbed static pages
+	Templates
+	SEO Optimized
+	RSS Syndication throughout the site 
+	Robust backend for posting.
+	Code highlight tags [code syntax="Perl"] print "hello world!"; [/code]
+		Valid syntax: CPP,CSS,HTML,Java,PHP,Perl.SQL
+
+TODO:
+	Code clean up
+	XML-RPC site pinging on article post
+	Implement my idea "MetaBonds"
+	
+
+BUGS:
+	Safari can't generate the WYSIWYG Editor on the fly in the back-end.
+	
+FAQ:
+Who is this release for?
+	 Everyone
+
+Why make yet another blog?
+	Why not? I am not pleased with wordpress due to its lack of caching. It can't hold up to a good old slashdotting! This blog takes advantage of extensive caching to benefit load times. I am tired of blogs going down due to high traffic! I want something that looks nice, pleasant to use and easy to deploy. 
+
+What makes this blog so special?
+	Fast,Free,Feature-full and easily deployable. Need I say more? 
\ No newline at end of file

Added: trunk/examples/typeface/create_login.pl
===================================================================
--- trunk/examples/typeface/create_login.pl	                        (rev 0)
+++ trunk/examples/typeface/create_login.pl	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,42 @@
+use lib './lib';
+use DB::Typeface::Schema;
+use Data::Dumper;
+use Config::Any::YAML;
+
+my $cfg = Config::Any::YAML->load('typeface.yml');
+
+my $db = DB::Typeface::Schema->connect($cfg->{'Model::Typeface'}->{connect_info}->[0]);
+
+if(!defined $db) {
+	print "Can't connect to database!\n";
+	exit(0);
+}
+
+$login = question('login');
+$password = question('password');
+
+my $user = $db->resultset('Users')->new({});
+$user->name($login);
+$user->password($password);
+$user->insert();
+
+print "Your ready to rock and roll now.\n";
+
+sub question {
+	my ($what)=@_;
+	while(1) {
+		print "What $what do you want? ";
+		$input = <STDIN>;
+		chomp($input);
+		if ($login =~ / /) {
+			print "\n\nNo spaces in $what\n\n";
+		}
+		else {
+			last;
+		}
+	}	
+	
+	return $input;
+}
+
+

Added: trunk/examples/typeface/create_sql.pl
===================================================================
--- trunk/examples/typeface/create_sql.pl	                        (rev 0)
+++ trunk/examples/typeface/create_sql.pl	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,12 @@
+use lib './lib';
+use DB::Typeface::Schema;
+use Data::Dumper;
+use Config::Any::YAML;
+
+my $cfg = Config::Any::YAML->load('typeface.yml');
+
+my $db = DB::Typeface::Schema->connect($cfg->{Typeface}->{connect_info});
+
+#$db->deploy();
+$db->create_ddl_dir();
+

Added: trunk/examples/typeface/deploy.pl
===================================================================
--- trunk/examples/typeface/deploy.pl	                        (rev 0)
+++ trunk/examples/typeface/deploy.pl	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,18 @@
+use lib './lib';
+use DB::Typeface::Schema;
+use Data::Dumper;
+use Config::Any::YAML;
+
+my $db = DB::Typeface::Schema->connect('dbi:SQLite:./mydb.db');
+
+if(!defined $db) {
+	print "Can't connect to database!\n";
+	exit(0);
+}
+
+eval { $db->deploy({add_drop_table => 1}); };
+
+if($@) {
+    print "\n\nOk failed to re-deploy, trying fresh deployment!\n\n";
+    $db->deploy();
+}
\ No newline at end of file

Added: trunk/examples/typeface/dumper.pl
===================================================================
--- trunk/examples/typeface/dumper.pl	                        (rev 0)
+++ trunk/examples/typeface/dumper.pl	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,16 @@
+use lib './lib';
+use DB::Typeface::Schema;
+
+my $db = DB::Typeface::Schema->connect('dbi:Pg:dbname=letsgetdugg;host=fab40;user=victori;password=cool123');
+
+if(!defined $db) {
+  print "Can't connect to database!\n";
+  exit(0);
+}
+
+use lib './lib';
+use DBIC::Dumper::YAML;
+use Data::Dumper;
+
+my $dumper = DBIC::Dumper::YAML->new();
+$dumper->dump_all($db,'fixtures');
\ No newline at end of file

Added: trunk/examples/typeface/lib/Catalyst/Controller/FormBuilder/DBIC.pm
===================================================================
--- trunk/examples/typeface/lib/Catalyst/Controller/FormBuilder/DBIC.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Catalyst/Controller/FormBuilder/DBIC.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,143 @@
+package Catalyst::Controller::FormBuilder::DBIC;
+
+use strict;
+use base qw/Catalyst::Controller::FormBuilder/;
+
+sub create_form {
+    my ( $self, $args ) = @_;
+	
+	$self->{_db_rset}=$args->{object};
+	$self->{_db}=$self->{_db_rset}->result_source;
+	$self->{_table}=$self->{_db_rset}->result_source->from;
+	$self->{_table_info}=$self->{_db}->storage->columns_info_for($self->{_table});
+	$self->{_columns}=$args->{columns};
+	$self->{_action}=$args->{action};
+	$self->{_size}=20;
+	
+	$self->_process_table_columns() if !defined $self->{_columns};
+	$self->_process_field_lengths();
+	$self->_process_form();
+}
+
+
+sub _process_field_lengths {
+	my ($self)=@_;
+	
+	while (my ($key,$col) = each(%{$self->{_table_info}}) ) {
+		if ($col->{data_type} eq "character varying") {
+			if(length($self->{_db_rset}->$key)>$self->{_size}) {
+				$self->{_size} = length($self->{_db_rset}->$key)+5;
+			}
+		}
+	}
+}
+
+sub accept_form {
+	my ($self,$args)=@_;
+
+	if (defined $args->{id}) {
+		# edit existing record
+	}
+	else {
+		# must be a new record if no ID
+		$self->{_db_rset}=$self->model("$args->{class}")->new({});
+		$self->{_db}=$self->{_target}->result_source;
+		$self->{_table}=$self->{_db_rset}->result_source->from;
+		$self->{_table_info}=$self->{_db}->storage->columns_info_for($self->{_table});
+	}
+
+	$self->_process_table_columns();
+	
+	
+	for my $col ( @{$self->{_columns}} ) {
+		$self->{_db_rset}->$col($self->req->params->{$col});
+	}
+	
+	return $self->{_db_rset};
+} 
+
+sub _process_form {
+	my ($self)=@_;
+	
+	for my $col ( @{$self->{_columns}} ) {
+		# default settings
+        my $type     = "text";
+		my $disabled = undef;
+        my @options  = undef;
+        my $required = 0;
+		my $value	 = "";
+		
+		next if $col eq "created_at";
+        next if $col eq "id";
+
+        $type = "password" if ( $col =~ /^password$|^passwd$|^pass$/i );
+
+        $required = 1 unless $self->{_table_info}->{$col}->{is_nullable};
+
+		eval { $value=$self->{_db_rset}->$col; };
+		
+		if($@) {
+		    # table not found
+		    next;
+		}
+
+        if ( $self->{_table_info}->{$col}->{data_type} eq "smallint" ) {
+            $type    = "radio";
+            @options = [qw/Yes No/];
+        }
+
+        $type = "textarea" if ( $self->{_table_info}->{$col}->{data_type} eq "text" );
+
+		# handle types fix up DateTime inflated objects
+		$value = $value->mdy('/') if ref($value) eq 'DateTime';
+				
+        $self->formbuilder->field(
+            name     => $col,
+            label    => $self->_process_name($col),
+            type     => $type,
+            rows     => 10,
+            cols     => 50,
+			disabled => $disabled,
+            required => $required,
+            options  => @options,
+			value	 => $value,
+			size	 => $self->{_size},
+        );
+
+    }
+
+	$self->formbuilder->method('POST');
+	$self->formbuilder->action($self->{_action}) if defined $self->{_action};
+	$self->formbuilder->submit('Commit ' . $self->_process_name($self->{_table}));
+}
+
+sub _process_name {
+    my ( $self, $name ) = @_;
+    my $label = ucfirst( lc($name) );
+    $label =~ s/_/ /g;
+
+	$label =~ s/^fname$/First Name/ig;
+	$label =~ s/^lname$/Last Name/ig;
+	$label =~ s/^mname$/Middle Name/ig;
+	$label =~ s/dlicense/Drivers License/ig;
+	$label =~ s/^dob$/Date of Birth/ig;
+
+    return $label;
+}
+
+sub _process_table_columns {
+    my ( $self ) = @_;
+
+    my $dbh = $self->{_db}->schema->storage->dbh;
+
+    my $table;
+    if ( $self->{_db}->{db_schema} ) {
+        $table = $self->{_db}->{db_schema} . $self->{_db}->{_namesep} . $table;
+    }
+
+    my $sth = $dbh->prepare("SELECT * FROM $self->{_table} WHERE 1=0");
+    $sth->execute;
+    $self->{_columns} = \@{ $sth->{NAME_lc} };
+}
+
+1;

Added: trunk/examples/typeface/lib/Catalyst/Engine/SCGI.pm
===================================================================
--- trunk/examples/typeface/lib/Catalyst/Engine/SCGI.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Catalyst/Engine/SCGI.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,198 @@
+package Catalyst::Engine::SCGI;
+
+use strict;
+use base 'Catalyst::Engine::CGI';
+eval "use SCGI";
+die "Please install SCGI\n" if $@;
+use IO::Socket;
+use Data::Dumper;
+
+
+my $uri_proto=URI->new();
+
+=head1 NAME
+
+Catalyst::Engine::SCGI - SCGI Engine
+
+=head1 DESCRIPTION
+
+This is the SCGI engine.
+
+=head1 OVERLOADED METHODS
+
+This class overloads some methods from C<Catalyst::Engine::CGI>.
+
+=head2 $self->run($c, $port, $detach)
+ 
+Start the SCGI server.  If $port is not set default to port 9000. If $detach is set, server will go into the background.
+
+=cut
+
+sub run {
+    my ( $self, $class, $port, $detach ) = @_;
+
+    my $sock = 0;
+    $port = 9000 unless defined $port;
+    my $socket = IO::Socket::INET->new(
+        Listen    => 5,
+        ReuseAddr => 1,
+        LocalPort => $port,
+    ) or die "cannot bind to port $port: $!";
+    $sock = SCGI->new( $socket, blocking => 1 )
+      or die "Failed to open SCGI socket; $!";
+
+    $self->daemon_fork()   if defined $detach;
+    $self->daemon_detach() if defined $detach;
+    while ( my $request = $sock->accept ) {
+        eval { $request->read_env };
+        if ($@) {
+
+            # some error
+        }
+        else {
+            $self->{_request} = $request;
+            # local %ENV = %{ $request->env };
+            # local *STDIN = $request->connection();
+            # local *STDOUT = $request->connection();
+            # warn ref($request->connection);
+            $class->handle_request( env => $request->env );
+            # make sure to close once we are done.
+            $request->close();
+        }
+    }
+}
+
+=head2 $self->finalize_headers ( $c )
+ 
+ Write finalized headers to socket
+
+=cut
+sub finalize_headers {
+    my ( $self, $c ) = @_;
+    $c->response->header( Status => $c->response->status );
+    $self->{_request}->connection->print(
+        $c->response->headers->as_string("\015\012") . "\015\012" );
+}
+
+=head2 $self->write ( $c, $buffer )
+ 
+ Write directly to socket
+
+=cut
+sub write {
+    my ( $self, $c, $buffer ) = @_;
+
+    unless ( $self->{_prepared_write} ) {
+        $self->prepare_write($c);
+        $self->{_prepared_write} = 1;
+    }
+
+    $self->{_request}->connection->print($buffer);
+}
+
+=head2 $self->prepare_path($c)
+
+=cut
+sub prepare_path {
+    my ( $self, $c ) = @_;
+    local (*ENV) = $self->env || \%ENV;
+
+    my $scheme = $c->request->secure ? 'https' : 'http';
+    my $host      = $ENV{HTTP_HOST}   || $ENV{SERVER_NAME};
+    my $port      = $ENV{SERVER_PORT} || 80;
+    my $base_path;
+    if ( exists $ENV{REDIRECT_URL} ) {
+        $base_path = $ENV{REDIRECT_URL};
+        $base_path =~ s/$ENV{PATH_INFO}$//;
+    }
+    else {
+        $base_path = $ENV{SCRIPT_NAME} || '/';
+    }
+
+    # If we are running as a backend proxy, get the true hostname
+  PROXY_CHECK:
+    {
+        unless ( $c->config->{using_frontend_proxy} ) {
+            last PROXY_CHECK if $host !~ /localhost|127.0.0.1/;
+            last PROXY_CHECK if $c->config->{ignore_frontend_proxy};
+        }
+        last PROXY_CHECK unless $ENV{HTTP_X_FORWARDED_HOST};
+
+        $host = $ENV{HTTP_X_FORWARDED_HOST};
+
+        # backend could be on any port, so
+        # assume frontend is on the default port
+        $port = $c->request->secure ? 443 : 80;
+    }
+
+    my $path = $base_path . ( $ENV{PATH_INFO} || '' );
+    $path =~ s{^/+}{};
+
+    my $uri = $uri_proto->clone;
+    $uri->scheme($scheme);
+    $uri->host($host);
+    $uri->port($port);
+    $uri->path($path);
+    $uri->query( $ENV{QUERY_STRING} ) if $ENV{QUERY_STRING};
+
+    # sanitize the URI
+    $uri = $uri->canonical;
+    $c->request->uri($uri);
+
+    # set the base URI
+    # base must end in a slash
+    $base_path .= '/' unless ( $base_path =~ /\/$/ );
+    my $base = $uri->clone;
+    
+    my ($base_uri) = $base_path=~ /(.*?)\//;
+    $base_uri .= '/' unless ($base_uri =~/\/$/ );
+    
+    $base->path_query($base_uri);
+    $c->request->base($base);
+}
+
+=head2 $self->read_chunk ( $c, $buffer, $readlen )
+ 
+ Read Body content to $_[3]'s set length and direct output to $_[2].
+
+=cut
+sub read_chunk {
+    my ( $self, $c ) = @_;
+    my $rc = read( $self->{_request}->connection, $_[2], $_[3] );
+    return $rc;
+}
+
+=head2 $self->daemon_fork()
+
+Performs the first part of daemon initialisation.  Specifically,
+forking.  STDERR, etc are still connected to a terminal.
+
+=cut
+
+sub daemon_fork {
+    require POSIX;
+    fork && exit;
+}
+
+=head2 $self->daemon_detach( )
+
+Performs the second part of daemon initialisation.  Specifically,
+disassociates from the terminal.
+
+However, this does B<not> change the current working directory to "/",
+as normal daemons do.  It also does not close all open file
+descriptors (except STDIN, STDOUT and STDERR, which are re-opened from
+F</dev/null>).
+
+=cut
+
+sub daemon_detach {
+    my $self = shift;
+    print "SCGI daemon started (pid $$)\n";
+    open STDIN,  "+</dev/null" or die $!;
+    open STDOUT, ">&STDIN"     or die $!;
+    open STDERR, ">&STDIN"     or die $!;
+    POSIX::setsid();
+}
+
+1;

Added: trunk/examples/typeface/lib/Catalyst/Plugin/Nifty.pm
===================================================================
--- trunk/examples/typeface/lib/Catalyst/Plugin/Nifty.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Catalyst/Plugin/Nifty.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,178 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+
+package Catalyst::Plugin::Nifty;
+use DateTime;
+use strict;
+use Text::Highlight;
+# use Syntax::Highlight::Engine::Kate;
+
+
+sub render_nifty_date {
+    my $self = shift;
+    my $date = shift;
+    
+    return "<span class=\"nifty_date\" title=\""
+      . $self->datetime_to_nifty_time($date)
+      . "\"></span>";
+}
+
+sub set_nifty_params {
+    my $self = shift;
+    if (@_) { $self->{nifty_args} = shift; }
+    else {
+        return $self->{nifty_args};
+    }
+}
+
+sub render_nifty_headers {
+    my $self = shift;
+	return $self->render_nifty_edges_and_dates;
+}
+
+sub nifty_txt_to_url {
+    my $self = shift;
+
+    my ( $txt, $id ) = @_;
+
+    $txt =~ s/(\'|\!|\`|\?)//g;
+    $txt =~ s/ /\_/g;
+
+    return $txt;
+}
+
+sub nifty_url_to_query {
+    my $self = shift;
+
+    my ($txt) = shift;
+
+    $txt =~ s/\_/ /g;
+    $txt =~ s/s /\%/g;
+    return ( "%" . $txt . "%" );
+}
+
+sub datetime_to_nifty_time {
+    my $self = shift;
+
+    my ($d) = shift;
+    # $d =~ /(.*)-(.*)-(.*) (.*):(.*):(.*)/;
+    # my $dt = DateTime->new(
+    #     year   => $1,
+    #     month  => $2,
+    #     day    => $3,
+    #     hour   => $4,
+    #     minute => $5,
+    #     second => $6
+    # );
+    my $ext =
+        $d->day_abbr() . ", "
+      . $d->day() . " "
+      . $d->month_abbr() . " "
+      . $d->year() . " "
+      . $d->hour . ":"
+      . $d->minute . ":"
+      . $d->second();
+    return $ext;
+}
+
+#use Scalar::Util qw( weaken );
+sub nifty_highlight_code {
+	my $self = shift;
+	my $html = shift;
+
+	$html =~ s/\[code syntax\=[\'|\"](.*?)[\'|\"]\](.*?)\[\/code\]/$self->process_code($1,$2)/egs;
+	return $html;
+}
+
+
+sub process_code {
+	my ($self,$lang,$code)=@_;
+	
+    # $lang =~ s/CPP/C/g;
+	
+            #     my $hl = new Syntax::Highlight::Engine::Kate(
+            #        language => $lang,
+            #        substitutions => {
+            #           "<" => "&lt;",
+            #           ">" => "&gt;",
+            #           "&" => "&amp;",
+            #           " " => "&nbsp;",
+            #           "\t" => "&nbsp;&nbsp;&nbsp;",
+            #           "\n" => "<br/>",
+            #        },
+            #        format_table => { Alert => ['<span class="Alert">', '</span>'],
+            #  BaseN => ['<span class="BaseN">', '</span>'],
+            #  BString => ['<span class="BString">', '</span>'],
+            #  Char => ['<span class="Char">', '</span>'],
+            #  Comment => ['<span class="Comment">', '</span>'],
+            #  DataType => ['<span class="DataType">', '</span>'],
+            #  DecVal => ['<span class="DecVal">', '</span>'],
+            #  Error => ['<span class="Error">', '</span>'],
+            #  Float => ['<span class="Float">', '</span>'],
+            #  Function => ['<span class="Function">', '</span>'],
+            #  IString => ['<span class="IString">', '</span>'],
+            #  Keyword => ['<span class="Keyword">', '</span>'],
+            #  Normal => ['<span class="Normal">', '</span>'],
+            #  Operator => ['<span class="Operator">', '</span>'],
+            #  Others => ['<span class="Others">', '</span>'],
+            #  RegionMarker => ['<span class="RegionMarker">', '</span>'],
+            #  Reserved => ['<span class="Reserved">', '</span>'],
+            #  String => ['<span class="String">', '</span>'],
+            #  Variable => ['<span class="Variable">', '</span>'],
+            #  Warning => ['<span class="Warning">', '</span>'],
+            #  
+            # },
+            #     );
+	
+    my $high = new Text::Highlight(wrapper=>"<div class='code'>%s</div>\n");
+    my $final=$high->highlight($lang,$code);
+    $final =~ s/  /&nbsp;&nbsp;/g;
+    $final =~ s/\n/<br\/>/g;
+    # my $final = '<div class="code">' . $hl->highlightText($code) . '</div>';
+    
+    return $final;
+}
+
+sub render_nifty_edges_and_dates {
+    my $self = shift;
+
+    my ($tags) = $self->{nifty_args};
+    my $nifty_tags = "<script type=\"text/javascript\">\n";
+    $nifty_tags = $nifty_tags . "window.onload=function(){ \n";
+    $nifty_tags = $nifty_tags . "show_dates_as_local_time(); \n";
+    for my $tag ( @{$tags} ) {
+        $nifty_tags = $nifty_tags . "Nifty(";
+        for my $element ( @{$tag} ) {
+            $nifty_tags = $nifty_tags . "'$element',";
+        }
+        chop($nifty_tags);
+        $nifty_tags = $nifty_tags . ");\n";
+    }
+
+    $nifty_tags = $nifty_tags . "} \n </script> \n";
+
+    return $nifty_tags;
+}
+
+sub push_into_nifty_params {
+    my $self = shift;
+    my ( $current_list, $tags_to_add ) = @_;
+    push @$current_list, $tags_to_add;
+    return $current_list;
+}
+
+1;

Added: trunk/examples/typeface/lib/Catalyst/Plugin/ProxyReplyAs.pm
===================================================================
--- trunk/examples/typeface/lib/Catalyst/Plugin/ProxyReplyAs.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Catalyst/Plugin/ProxyReplyAs.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,14 @@
+package Catalyst::Plugin::ProxyReplyAs;
+use strict;
+ 
+sub uri_for {
+    my $class = shift;
+    if( $class->config->{proxy_reply_as} ) {
+        my $u = URI->new($class->config->{proxy_reply_as});
+        $class->req->base($u);
+    }
+    my $result = $class->NEXT::uri_for( @_ );
+    return $result;
+}
+
+1;
\ No newline at end of file

Added: trunk/examples/typeface/lib/DB/Typeface/Schema/Articles.pm
===================================================================
--- trunk/examples/typeface/lib/DB/Typeface/Schema/Articles.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/DB/Typeface/Schema/Articles.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,183 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package DB::Typeface::Schema::Articles;
+
+# Created by DBIx::Class::Schema::Loader v0.03007 @ 2006-10-18 15:02:47
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class';
+
+__PACKAGE__->load_components( "PK::Auto", "InflateColumn::DateTime" , "Core" );
+__PACKAGE__->table("articles");
+__PACKAGE__->add_columns(
+    "id",
+    {
+        data_type         => 'integer',
+        is_auto_increment => 1,
+        default_value     => undef,
+        is_nullable       => 0,
+    },
+    "subject",
+    {
+        data_type     => "character varying",
+        default_value => undef,
+        is_nullable   => 1,
+        size          => 255,
+    },
+    "body",
+    {
+        data_type     => "text",
+        default_value => undef,
+        is_nullable   => 1,
+        size          => undef,
+    },
+    "created_at",
+    {
+        data_type     => "datetime",
+        default_value => "now()",
+        is_nullable   => 1,
+        size          => undef,
+    },
+    "user_id",
+    {
+        data_type     => "integer",
+        default_value => undef,
+        is_nullable   => 1,
+        size          => 4,
+    },
+);
+
+__PACKAGE__->set_primary_key("id");
+__PACKAGE__->has_many(
+    'comments' => 'DB::Typeface::Schema::Comments',
+    'article_id'
+);
+
+__PACKAGE__->belongs_to(
+    'user' => 'DB::Typeface::Schema::Users',
+    'user_id'
+);
+
+__PACKAGE__->has_many(
+    'categories_articles' =>
+      'DB::Typeface::Schema::CategoriesArticles',
+    'article_id'
+);
+__PACKAGE__->many_to_many( 'categories' => 'categories_articles', 'category' );
+
+# Yes this is a hack since we need to textilize first then process code highlight
+use Text::Textile qw(textile);
+sub textilize {
+    my $self = shift;
+    my $what = shift;
+    
+    my $temp = $self->$what;
+    $temp =~ s/<textarea/==<textarea/g;
+    $temp =~ s/<\/textarea>/<\/textarea>==/g;
+    # $temp =~ s/\[code (.*?)\]/==\[code $1\]/g;
+    # $temp =~ s/\[\/code\]/\[\/code\]==/g;
+    return textile($temp);
+}
+
+sub insert {
+	 my $self = shift; 
+	 $self->created_at(DateTime->now());
+	 $self->next::method( @_ ); 
+}
+
+__PACKAGE__->resultset_class('DB::Typeface::Schema::ResultSet::Articles');
+package DB::Typeface::Schema::ResultSet::Articles;
+use base 'DBIx::Class::ResultSet';
+
+sub get_latest_articles {
+    my ($self,$number_of_posts) = @_;
+    my $rows = 10;
+    $rows = $number_of_posts if defined $number_of_posts;
+    return $self->search( undef, { rows => $rows, order_by => 'id desc' } )->all;
+}
+
+sub archived  {
+    my ( $self, $year, $month, $day ) = @_;
+
+    my $dt   = DateTime->now();
+    my $hour = $dt->hour();
+
+	if (defined $day && $day != $dt->day )
+	{
+		$hour = '24';
+	}
+
+    if ( defined $day ) {
+        return $self->search(
+            {
+                created_at => {
+                    -between => [
+                        "$year-$month-$day 00:00:00",
+                        "$year-$month-$day $hour:00:00"
+                    ]
+                }
+            },
+            { order_by => 'id desc' }
+        )->all();
+    }
+    else {
+        my $lastday =
+          DateTime->last_day_of_month( year => $year, month => $month )
+          ->day;
+
+        return $self->search(
+            {
+                    created_at => {
+                        -between => [
+                            "$year-$month-1",
+                            "$year-$month-$lastday"
+                        ]
+                    }
+            },
+            { order_by => 'id desc' }
+        )->all();
+    }
+}
+
+sub from_month  {
+    my ( $self, $month, $year ) = @_;
+    
+    $year = DateTime->now()->year() unless defined $year;
+
+    my $dt = DateTime->now();
+    my $lastday =
+      DateTime->last_day_of_month( year => $year, month => $month )
+      ->day;
+    my $hour = $dt->hour();
+
+    return $self->search(
+        {
+            created_at => {
+                -between => [
+                    "$year-$month-1",
+                    "$year-$month-$lastday"
+                ]
+            }
+        },
+        { order_by => 'id desc' }
+    )->all();
+}
+
+1;
+

Added: trunk/examples/typeface/lib/DB/Typeface/Schema/Categories.pm
===================================================================
--- trunk/examples/typeface/lib/DB/Typeface/Schema/Categories.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/DB/Typeface/Schema/Categories.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,50 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package DB::Typeface::Schema::Categories;
+
+# Created by DBIx::Class::Schema::Loader v0.03007 @ 2006-10-18 15:02:47
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class';
+
+__PACKAGE__->load_components("PK::Auto","Core");
+__PACKAGE__->table("categories");
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type => 'integer', 
+	is_auto_increment => 1,
+    default_value => undef,
+	is_nullable => 0,
+  },
+  "name",
+  {
+    data_type => "character varying",
+    default_value => undef,
+    is_nullable => 1,
+    size => 255,
+  },
+);
+__PACKAGE__->set_primary_key("id");
+
+__PACKAGE__->has_many( 'categories_articles' => 'DB::Typeface::Schema::CategoriesArticles', 'category_id');
+__PACKAGE__->many_to_many( 'articles' => 'categories_articles', 'article');
+
+1;
+

Added: trunk/examples/typeface/lib/DB/Typeface/Schema/CategoriesArticles.pm
===================================================================
--- trunk/examples/typeface/lib/DB/Typeface/Schema/CategoriesArticles.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/DB/Typeface/Schema/CategoriesArticles.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,49 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package DB::Typeface::Schema::CategoriesArticles;
+
+# Created by DBIx::Class::Schema::Loader v0.03007 @ 2006-10-18 15:02:47
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class';
+
+__PACKAGE__->load_components("PK::Auto","Core");
+__PACKAGE__->table("categories_articles");
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type => 'integer', 
+	is_auto_increment => 1,
+    default_value => undef,
+    is_nullable => 0,
+  },
+  "category_id",
+  { data_type => "integer", default_value => undef, is_nullable => 1, size => 4 },
+  "article_id",
+  { data_type => "integer", default_value => undef, is_nullable => 1, size => 4 },
+);
+__PACKAGE__->set_primary_key("id");
+
+__PACKAGE__->belongs_to('category',
+		'DB::Typeface::Schema::Categories','category_id');
+__PACKAGE__->belongs_to('article',
+		'DB::Typeface::Schema::Articles','article_id');
+
+1;
+

Added: trunk/examples/typeface/lib/DB/Typeface/Schema/Comments.pm
===================================================================
--- trunk/examples/typeface/lib/DB/Typeface/Schema/Comments.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/DB/Typeface/Schema/Comments.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,133 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package DB::Typeface::Schema::Comments;
+
+# Created by DBIx::Class::Schema::Loader v0.03007 @ 2006-10-18 15:02:47
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class';
+
+__PACKAGE__->load_components("PK::Auto", "InflateColumn::DateTime","Core");
+__PACKAGE__->table("comments");
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type => 'integer', 
+	is_auto_increment => 1,
+    default_value => undef,
+    is_nullable => 0,
+  },
+  "name",
+  {
+    data_type => "character varying",
+    default_value => undef,
+    is_nullable => 1,
+    size => 255,
+  },
+  "email",
+  {
+    data_type => "character varying",
+    default_value => undef,
+    is_nullable => 1,
+    size => 255,
+  },
+  "url",
+  {
+    data_type => "character varying",
+    default_value => undef,
+    is_nullable => 1,
+    size => 255,
+  },
+  "comment",
+  {
+    data_type => "text",
+    default_value => undef,
+    is_nullable => 1,
+    size => undef,
+  },
+  "created_at",
+  {
+    data_type => "datetime",
+    default_value => "now()",
+    is_nullable => 1,
+    size => undef,
+  },
+  "article_id",
+  { data_type => "integer", default_value => undef, is_nullable => 1, size => 4 },
+);
+
+use Text::Textile qw(textile);
+sub textilize {
+    my $self = shift;
+    my $what = shift;
+    
+    my $temp = $self->$what;
+    $temp =~ s/\[code (.*?)\]/==<pre>\[code $1\]/g;
+    $temp =~ s/\[\/code\]/\[\/code\]<\/pre>==/g;
+    return textile($temp);
+}
+
+sub insert {
+	 my $self = shift; 
+	 $self->created_at(DateTime->now());
+	 $self->next::method( @_ ); 
+}
+
+sub form {
+    my ($self,$from) = @_;
+    
+    $self->{formbuilder}->field(
+        name     => 'name',
+        required => 1,
+        label    => 'Name',
+        size     => 25
+    );
+    $self->{formbuilder}->field( name => 'email', label => 'Email',   size => 25, validate => 'EMAIL' );
+    $self->{formbuilder}->field( name => 'url',   label => 'Website', size => 25 );
+  
+  	$self->{formbuilder}->field(
+        name     => 'comment',
+        type     => 'textarea',
+        required => 1,
+        label    => 'Body',
+        cols     => 30,
+        rows     => 10
+    );
+
+    $self->{formbuilder}->field(
+        name     => 'verification',
+        label    => 'Verification',
+        size     => 25,
+        required => 1
+    );
+    # make sure no trailing slashes happen.
+    $from = '/' . $from;
+    $self->{formbuilder}->action( '/submit/comment' . $from );
+    $self->{formbuilder}->method('post');
+    
+    return $self->{formbuilder};
+}
+
+__PACKAGE__->set_primary_key("id");
+
+__PACKAGE__->belongs_to('article',
+		'DB::Typeface::Schema::Articles','article_id');
+
+1;
+

Added: trunk/examples/typeface/lib/DB/Typeface/Schema/Links.pm
===================================================================
--- trunk/examples/typeface/lib/DB/Typeface/Schema/Links.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/DB/Typeface/Schema/Links.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,63 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+
+package DB::Typeface::Schema::Links;
+
+# Created by DBIx::Class::Schema::Loader v0.03007 @ 2006-10-18 15:02:47
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class';
+
+__PACKAGE__->load_components("PK::Auto", "Core");
+__PACKAGE__->table("links");
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type => 'integer', 
+	is_auto_increment => 1,
+    default_value => undef,
+    is_nullable => 0,
+  },
+  "url",
+  {
+    data_type => "character varying",
+    default_value => undef,
+    is_nullable => 1,
+    size => 255,
+  },
+  "name",
+  {
+    data_type => "character varying",
+    default_value => undef,
+    is_nullable => 1,
+    size => 255,
+  }, 
+  "description",
+  {
+    data_type => "character varying",
+    default_value => undef,
+    is_nullable => 1,
+    size => 255,
+  },
+);
+
+__PACKAGE__->set_primary_key("id");
+		
+1;
+

Added: trunk/examples/typeface/lib/DB/Typeface/Schema/Pages.pm
===================================================================
--- trunk/examples/typeface/lib/DB/Typeface/Schema/Pages.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/DB/Typeface/Schema/Pages.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,76 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package DB::Typeface::Schema::Pages;
+
+# Created by DBIx::Class::Schema::Loader v0.03007 @ 2006-10-18 15:02:47
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class';
+
+__PACKAGE__->load_components("PK::Auto","Core");
+__PACKAGE__->table("pages");
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type => 'integer', 
+	is_auto_increment => 1,
+    default_value => undef,
+	is_nullable => 0,
+  },
+  "name",
+  {
+    data_type => "character varying",
+    default_value => undef,
+    is_nullable => 1,
+    size => 255,
+  },
+  "body",
+  {
+    data_type => "text",
+    default_value => undef,
+    is_nullable => 1,
+  },
+  "display_sidebar",
+  {
+	data_type => 'smallint',
+	default_value => 1,
+	is_nullable => 0,
+   },
+  "display_in_drawer",
+  {
+	data_type => 'smallint',
+	default_value => 1,
+	is_nullable => 0,
+  }
+);
+__PACKAGE__->set_primary_key("id");
+
+use Text::Textile qw(textile);
+sub textilize {
+    my $self = shift;
+    my $what = shift;
+    
+    my $temp = $self->$what;
+    $temp =~ s/\[code (.*?)\]/==<pre>\[code $1\]/g;
+    $temp =~ s/\[\/code\]/\[\/code\]<\/pre>==/g;
+    return textile($temp);
+}
+
+1;
+

Added: trunk/examples/typeface/lib/DB/Typeface/Schema/Users.pm
===================================================================
--- trunk/examples/typeface/lib/DB/Typeface/Schema/Users.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/DB/Typeface/Schema/Users.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,88 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package DB::Typeface::Schema::Users;
+
+# Created by DBIx::Class::Schema::Loader v0.03007 @ 2006-10-18 15:02:47
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class';
+
+__PACKAGE__->load_components("PK::Auto", "Core");
+__PACKAGE__->table("users");
+__PACKAGE__->add_columns(
+  "id",
+  {
+    data_type => 'integer', 
+	is_auto_increment => 1,
+    default_value => undef,
+    is_nullable => 0,
+  },
+  "name",
+  {
+    data_type => "character varying",
+    default_value => undef,
+    is_nullable => 1,
+    size => 255,
+  },
+  "password",
+  {
+    data_type => "character varying",
+    default_value => undef,
+    is_nullable => 1,
+    size => 255,
+  },
+  "website",
+  {
+    data_type => "character varying",
+    default_value => undef,
+    is_nullable => 1,
+    size => 255,
+  },
+  "email",
+  {
+    data_type => "character varying",
+    default_value => undef,
+    is_nullable => 1,
+    size => 255,
+  },
+  "created_at",
+  {
+    data_type => "datetime",
+    default_value => "now()",
+    is_nullable => 1,
+    size => undef,
+  },
+);
+
+__PACKAGE__->set_primary_key("id");
+
+__PACKAGE__->has_many('articles'=>
+	'DB::Typeface::Schema::Articles','user_id');
+
+#__PACKAGE__->has_many('blogs_users'=>'DB::Typeface::Schema::BlogsUsers', 'user_id');
+#__PACKAGE__->many_to_many('blogs' => 'blogs_users' , 'blog');
+
+sub insert {
+	 my $self = shift; 
+	 $self->created_at(DateTime->now());
+	 $self->next::method( @_ ); 
+}
+
+1;
+

Added: trunk/examples/typeface/lib/DB/Typeface/Schema.pm
===================================================================
--- trunk/examples/typeface/lib/DB/Typeface/Schema.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/DB/Typeface/Schema.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,29 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package DB::Typeface::Schema;
+
+# Created by DBIx::Class::Schema::Loader v0.03007 @ 2006-10-18 15:02:47
+
+use strict;
+use warnings;
+use DateTime;
+
+use base 'DBIx::Class::Schema';
+__PACKAGE__->load_classes;
+
+1;
+

Added: trunk/examples/typeface/lib/DBIx/Class/FormBuilder.pm
===================================================================
--- trunk/examples/typeface/lib/DBIx/Class/FormBuilder.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/DBIx/Class/FormBuilder.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,43 @@
+package DBIx::Class::FormBuilder;
+
+use strict;
+use warnings;
+use base 'DBIx::Class';
+use CGI::FormBuilder;
+use Data::Dumper;
+
+sub new {
+    my ($class, $attrs, @rest) = @_;
+    my $ret = $class->next::method($attrs, @rest);
+    
+    #setup formbuilder + form
+    $ret->{formbuilder} = CGI::FormBuilder->new();
+    $ret->form();
+    
+    return $ret;
+}
+
+sub form {
+    my ($self, at rest) = @_;
+    return $self->{formbuilder};
+}
+
+sub insert {
+    my ($self, at rest) = @_;
+    
+    foreach my $name ( $self->result_source->columns ) {
+        $self->{formbuilder}->field(name=>$name , value => $self->get_column($name)) 
+            if defined $self->get_column($name);
+    }
+    if($self->{formbuilder}->validate) {
+        #$self->next::method(@_);
+    } else {
+        print $self->{formbuilder}->render;
+    }
+}
+
+sub update {
+    my ($self, at rest) = @_;
+}
+
+1;
\ No newline at end of file

Added: trunk/examples/typeface/lib/HTML/Calendar/Simple.pm
===================================================================
--- trunk/examples/typeface/lib/HTML/Calendar/Simple.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/HTML/Calendar/Simple.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,454 @@
+package HTML::Calendar::Simple; 
+
+$HTML::Calendar::Simple::VERSION = "0.04";
+
+=pod
+
+=head1 NAME
+
+HTML::Calendar::Simple - A simple html calendar
+
+=head1 SYNOPSIS
+
+  use HTML::Calendar::Simple;
+
+  my $cal = HTML::Calendar::Simple->new; # This month, this year
+     $cal = HTML::Calendar::Simple->new({ 'month' => $month }); # This year
+     $cal = HTML::Calendar::Simple->new({ 'month' => $month, 
+                                          'year'  => $year});
+
+  my $month = $cal->month;
+  my $year  = $cal->year;
+
+  $cal->pin_up(a_picture_location);  
+  $cal->daily_info({ 'day'      => $day,
+                     'day_link' => $location,
+                     $type1     => $info1,
+                     $type2     => $info2,
+                     'link'     => [$link, $tag],
+  });
+
+  print $cal; # stringifies to something like the output of cal
+
+  my $html = $cal->calendar_month;
+
+  my $html = HTML::Calendar::Simple->calendar_year;
+     $html = HTML::Calendar::Simple->calendar_year({ 'year' => $year });
+     $html = HTML::Calendar::Simple->calendar_year(
+               { 'pin_up' => $where_to_find_the_picture,
+                 'year'   => $year, 
+                 $month   => { $day1 => $link1,
+                               $day2 => $link2, }
+               });
+
+=head1 DESCRIPTION
+
+This is a simple module which will make an HTML representation of a 
+given month. You can add links to individual days, or in fact, any 
+sort of information you want.
+
+Yes, the inspiration for this came out of me looking at 
+HTML::CalendarMonthSimple, and thinking 'Hmmm. A bit too complicated
+for what I want. I know, I will write a simplified version.' So I did. 
+
+=cut
+
+use strict;
+use Date::Simple;
+use CGI;
+
+use overload 
+  '""' => '_stringify';
+
+my %days   = ( 'Sun' => 0, 'Mon' => 1, 
+               'Tue' => 2, 'Wed' => 3, 
+               'Thu' => 4, 'Fri' => 5, 
+               'Sat' => 6 );
+
+my %months = (  1 => 'Jan', 2  => 'Feb', 3  => 'Mar',
+                4 => 'Apr', 5  => 'May', 6  => 'Jun',
+                7 => 'Jul', 8  => 'Aug', 9  => 'Sep',
+               10 => 'Oct', 11 => 'Nov', 12 => 'Dec' );
+
+=head2 new
+
+  my $cal = HTML::Calendar::Simple->new;
+  my $cal = HTML::Calendar::Simple->new({ 'month' => $month });
+  my $cal = HTML::Calendar::Simple->new({ 'month' => $month, 
+                                          'year'  => $year });
+
+This will make a new HTML::Calendar::Simple object.
+
+=cut
+
+sub new {
+  my $self = {};
+  bless $self, shift;
+  $self->_init(@_);
+  return $self;
+}
+
+sub _init {
+  my $self = shift;
+  # validate the args passed to new, if there were any.
+  my $valid_day = Date::Simple->new;
+  my $ref = shift;
+  if (defined $ref && ref $ref eq 'HASH') {
+    my $month = exists $ref->{month} ? $ref->{month} : $valid_day->month;
+    my $year  = exists $ref->{year}  ? $ref->{year}  : $valid_day->year; 
+    $valid_day = $self->_date_obj($year, $month, 1);
+    $valid_day = defined $valid_day ? $valid_day : Date::Simple->new;
+  }
+  $self->{month} = $valid_day->month;
+  $self->{year}  = $valid_day->year;
+  $self->{the_month} = $self->_days_list($self->{month}, $self->{year});
+  $self;
+}
+
+=head2 month
+
+  my $month = $cal->month;
+
+This will return the numerical value of the month.
+
+=head2 year
+
+  my $year = $cal->year;
+
+This will return the four-digit year of the calendar
+
+=cut
+
+sub month      { $_[0]->{month}          } # month in numerical format
+sub year       { $_[0]->{year}           } # year in YYYY form
+sub _spacer    { return ""               } # the filler for the first few entries
+sub _the_month { @{ $_[0]->{the_month} } } # this is the list of hashrefs.
+
+sub _cgi {
+  my $self = shift;
+  unless (exists $self->{cgi}) { $self->{cgi} = CGI->new; }
+  return $self->{cgi};
+}
+
+=head2 daily_info
+
+  $cal->daily_info({ 'day'      => $day,
+                     'day_link' => $location, # puts an href on the day
+                     $type1     => $info1,
+                     $type2     => $info2,
+                     'link'     => [$link, $tag],
+  });
+
+This will record that fact that $info of $type happen(s|ed) on $day.
+
+Now, if there is no method defined to cope with $type, then the information
+pased as $info will just be text printed in the cell of $day. So, if you want
+something special to happen to (say) a type of 'meeting', you would have to 
+define a method called _meeting.
+
+For example: 
+  
+  $cal->daily_info({ 'day'     => 12, 
+                     'meeting' => 'Meet swm' });
+
+and somewhere else in this module...
+
+  sub _meeting {
+    my $self = shift;
+    return $self->_cgi->h1( shift );
+  }
+
+So any day that had a meeting key in its hash would be displayed as 
+an <h1>$info</h1>
+
+Note: If you call daily_info again with the same day with the same type
+      BUT with different info, then the old info will get clobbered.
+
+There is already one method in here, and that is _link. So, you can do:
+
+  $cal->daily_info({ 'day'  => $day,
+                     'link' => [$link, $tag],
+  });
+
+Note that the key 'link' takes an array ref.
+
+Also, if you don't pass valid uris as values of the keys 'link' and
+'day_link', well, that is your out if they don't work!
+
+=cut
+
+sub daily_info {
+  my $self = shift;
+  my $ref  = shift or return;
+  ref $ref eq 'HASH' or return;
+  my $day  = $self->_date_obj($self->year, $self->month, $ref->{'day'})
+    or return;
+  my %info = %{ $ref };
+  delete $info{'day'};
+  foreach my $day_ref ($self->_the_month) {
+    next unless $day_ref && $day_ref->{date} == $day;
+    $day_ref->{$_} = $info{$_} foreach keys %info;
+    last;
+  }
+}
+
+# Glerg. Make each cell in the calendar table a table of its own. And each row
+# of this table will contain a little snippet of information.
+
+sub _row_elem {
+  my $self = shift;
+  my $ref  = shift or return $self->_spacer;
+  return $ref if $ref eq $self->_spacer;
+  my $q = $self->_cgi;
+  my $day = exists $ref->{day_link} 
+          ? $q->a({ -href => $ref->{day_link} }, $ref->{date}->day)
+          : $ref->{date}->day;
+  my $elem = $q->start_table . $q->Tr($q->td($day));
+  my %info = %{ $ref };
+  foreach my $key (keys %info) {
+    next if ($key eq 'date' or $key eq 'day_link');
+    my $method = "_$key";
+    $elem .= $self->can($method) 
+           ? $q->Tr($q->td($self->$method($info{$key})))
+           : $q->Tr($q->td($info{$key}));
+  }
+  $elem .= $q->end_table;
+  return $elem;
+}
+
+sub _link {
+  my $self = shift;
+  my $ref  = shift or return;
+  ref $ref eq 'ARRAY' or return;
+  my ($link, $tag) = @$ref;
+  return $self->_cgi->a({ -href => $link }, $tag);
+}
+
+sub _table_row {
+  my $self = shift;
+  my @week = @_; my @row;
+  push @row, $self->_row_elem($_) foreach @week;
+  return @row;
+}
+
+=head2 pin_up
+
+  $cal->pin_up(a_picture_with_location);
+
+This will add a picture above the calendar month, just like the 
+calendar I have hanging up in my kitchen, (It is a cat calendar, if
+you are interested, as my second son loves cats. As do I!)
+
+This could be used to have a mechanic's garage Pirelli-style pr0n
+calendar, but that would be your call. Mine would be something including
+a Triumph Daytona 955i. Mmmm, nice.
+
+=cut
+
+sub pin_up {
+  my ($self, $pic) = @_;
+  return unless $pic;
+  $self->{picture} = $pic;
+}
+
+sub picture {
+  my $self = shift;
+  return exists $self->{picture} ? $self->{picture} : 0;
+}
+
+=head2 calendar_month
+
+  my $html = $cal->calendar_month;
+
+This will return an html string of the calendar month in question.
+
+=head2 html
+
+  my $html = $cal->html;
+
+This will return an html string of the calendar month in question.
+
+THIS CALL HAS BEEN DEPRECATED.
+
+=cut
+
+sub html { $_[0]->calendar_month }
+
+sub calendar_month {
+  my $self = shift;
+  my @seq  = $self->_the_month;
+  my $q    = $self->_cgi;
+  my $mnth = $q->h3($months{$self->month} . " " . $self->year);
+  my $cal  = $q->start_table({-border => 0}) 
+           . $q->th([sort { $days{$a} <=> $days{$b} } keys %days]);
+  while (@seq) {
+    my @week_row = $self->_table_row(splice @seq, 0, 7);
+    $cal .= $q->Tr($q->td([@week_row]));
+  }
+  $cal .= $q->end_table;
+  $cal = $q->start_table . $q->Tr($q->td({ align => 'center' }, $mnth)) 
+       . $q->Tr($q->td($cal)) . $q->end_table;
+  $cal = $self->_add_pic($cal) if $self->picture;
+  return $cal;
+}
+
+=head2 calendar_year
+  
+  my $html = HTML::Calendar::Simple->calendar_year;
+     $html = HTML::Calendar::Simple->calendar_year({ 'year' => $year });
+     $html = HTML::Calendar::Simple->calendar_year(
+               { 'pin_up' => $where_to_find_the_picture,
+                 'year'   => $year, 
+                 $month   => { $day1 => $link1,
+                               $day2 => $link2, }
+               });
+
+This will return the an html string for every month in the year passed,
+or the current year if nothing passed in.
+
+This key of the hashref month is *another* hashref, where the key here 
+is the day in that month, and the value a link.
+
+This is icky, I know, and now puts me in mind of making HTML::Calendar::Day, 
+HTML::Calendar::Month and HTML::Calendar::Year, and having an overarching
+HTML::Calendar.
+
+=cut
+
+sub _generate_months {
+  my ($class, $year, $ref) = @_;
+  my @year;
+  for my $month  (1 .. 12) {
+    my $cal = $class->new({ 'month' => $month, 'year'  => $year });
+    if (defined $ref->{$month}) {
+      my %links = %{ $ref->{$month} };
+      foreach my $day (keys %links) {
+        $cal->daily_info({ 'day'      => $day,
+                           'day_link' => $links{$day},
+        });
+      }
+    }
+    push @year, $cal;
+  }
+  return @year;
+}
+
+sub calendar_year {
+  my ($class, $ref) = @_;
+  my $year = $ref->{year};
+  my $when = defined $year 
+           ? Date::Simple->new($year, 1, 1)
+           : Date::Simple->new;
+     $when = defined $when ? $when : Date::Simple->new;
+  $year = $when->year;
+  my @year = $class->_generate_months($year, $ref);
+  my $year_string;
+  my $q = CGI->new;
+  while (@year) {
+    my @qrtr = map { $_->calendar_month } splice @year, 0, 3;
+    s/$year//g for @qrtr;
+    $year_string .= $q->start_table . $q->Tr($q->td({valign => 'top'}, [@qrtr])) 
+                 .  $q->end_table   . $q->br;
+  }
+  my $pic = defined $ref->{'pin_up'} ? $ref->{'pin_up'} : "";
+  $pic = $q->Tr($q->td({ align => 'center' }, $q->img({ src  => $pic }))) if $pic; 
+  $year_string = $q->start_table . $pic . $q->th($year)
+               . $q->Tr($q->td($year_string)) 
+               . $q->end_table;
+  return $year_string;
+}
+
+sub _add_pic {
+  my ($self, $cal) = @_;
+  my $q = $self->_cgi;
+  return $q->start_table 
+       . $q->Tr($q->td({ align => 'center' }, 
+                $q->img({ src  => $self->picture }))) 
+       . $q->Tr($q->td($cal)) 
+       . $q->end_table;
+}
+
+sub _date_obj { Date::Simple->new($_[1], $_[2], $_[3]) }
+
+# here is the format of what is returned from this call. Let us say a list of 
+# hashrefs, so that I can tag lots of things in with it. Ick, I know, but this
+# is just a messing-about at the mo. And a hashref, mmmm, makes me think of 
+# an object is needed here. A Day object if I thieved an idea from somewhere else.
+
+sub _days_list {
+  my $self = shift;
+  # Fill in a Date::Simple object for every day, Why not Date::Range object? 
+  # Because I haven't installed it yet, and not sure it would be appropriate
+  # for the way I have set this up.
+  my ($month, $year) = @_;
+  my $start = $self->_date_obj($year, $month, 1);
+  my $end   = $start + 31;
+     $end   = $self->_date_obj($end->year, $end->month, 1);
+  my @seq   = map $self->_spacer, (1 .. $days{$start->format("%a")});
+  push @seq, { 'date' => $start++ } while ($start < $end);
+  return \@seq;
+}
+
+sub _stringify {
+  my $self   = shift;
+  my @month  = $self->_the_month;
+  my $string =  "\t\t\t" . $months{ $self->month } . " " . $self->year . "\n\n";
+     $string .= join "\t", sort { $days{$a} <=> $days{$b} } keys %days;
+     $string .= "\n";
+  while (@month) {
+    $string .= join "\t", map { $_  eq $self->_spacer ? "" : $_->{date}->day } 
+                          splice @month, 0, 7;
+    $string .= "\n";
+  }
+  return $string;
+}
+
+=head1 BUGS
+
+None known
+
+=head2 TODO
+
+Oh....lots of things.
+
+  o Rip out the CGI stuff and put all the HTML in a template, so the user
+    can decide on the format of the calendar themselves.
+  o Allow for the setting of borders etc like HTML::CalendarMonthSimple.
+  o Format the output better if there is info in a daily cell.
+  o Perhaps overload '.' so you could add two calendars. Not sure.
+  o Check the links passed in are of format http://www.stray-toaster.co.uk
+    or something.
+  o Get rid of the days and months hashes and replace with something better.
+  o And if all that happens, it may as well be HTML::CalendarMonthSimple!!
+  o Make HTML::Calendar::Day, HTML::Calendar::Month and HTML::Calendar::Year
+
+=head1 SHOWING YOUR APPRECIATION
+
+There was a thread on london.pm mailing list about working in a vacumn
+- that it was a bit depressing to keep writing modules but never get
+any feedback. So, if you use and like this module then please send me
+an email and make my day.
+
+All it takes is a few little bytes.
+
+(Leon wrote that, not me!)
+
+=head1 AUTHOR
+
+Stray Toaster E<lt>F<coder at stray-toaster.co.uk>E<gt>
+
+=head2 With Thanks
+
+ o To swm E<lt>F<swm at swmcc.com>E<gt> for some roadtesting!
+ o To <lt>F<Simon Young><gt> for the pin-up idea
+
+=head1 COPYRIGHT
+
+Copyright (C) 2002, mwk
+
+This module is free software; you can redistribute it or modify it
+under the same terms as Perl itself.
+
+=cut
+
+return qw/Now beat it you bother me/;

Added: trunk/examples/typeface/lib/HTML/CalendarMonthSimple.pm
===================================================================
--- trunk/examples/typeface/lib/HTML/CalendarMonthSimple.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/HTML/CalendarMonthSimple.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,1275 @@
+# HTML::CalendarMonthSimple.pm
+# Generate HTML calendars. An alternative to HTML::CalendarMonth
+# Herein, the symbol $self is used to refer to the object that's being passed around.
+
+package HTML::CalendarMonthSimple;
+$HTML::CalendarMonthSimple::VERSION = "1.25";
+use strict;
+use Date::Calc;
+
+
+# Within the constructor is the only place where values are access directly.
+# Methods are provided for accessing/changing values, and those methods
+# are used even internally.
+# Most of the constructor is assigning default values.
+sub new {
+   my $class = shift; $class = ref($class) || $class;
+   my $self = {}; %$self = @_; # Load ourselves up from the args
+
+   # figure out the current date (which may be specified as today_year, et al
+   # then figure out which year+month we're supposed to display
+   {
+      my($year,$month,$date) = Date::Calc::Today();
+      $self->{'today_year'}  = $self->{'today_year'} || $year;
+      $self->{'today_month'} = $self->{'today_month'} || $month;
+      $self->{'today_date'}  = $self->{'today_date'} || $date;
+      $self->{'month'}       = $self->{'month'} || $self->{'today_month'};
+      $self->{'year'}        = $self->{'year'}  || $self->{'today_year'};
+      $self->{'monthname'}   = Date::Calc::Month_to_Text($self->{'month'});
+   }
+
+   # Some defaults
+   $self->{'border'}             = 5;
+   $self->{'width'}              = '100%';
+   $self->{'showdatenumbers'}    = 1;
+   $self->{'showweekdayheaders'} = 1;
+   $self->{'cellalignment'}      = 'left';
+   $self->{'vcellalignment'}     = 'top';
+   $self->{'weekdayheadersbig'}  = 1;
+   $self->{'nowrap'}             = 0;
+
+   $self->{'weekdays'} = [qw/Monday Tuesday Wednesday Thursday Friday/];
+   $self->{'sunday'}   = "Sunday";
+   $self->{'saturday'} = "Saturday";
+
+   # Set the default calendar header
+   $self->{'header'} = sprintf("<h1 class='month_date'>%s %d</h1>",
+                               Date::Calc::Month_to_Text($self->{'month'}),$self->{'year'});
+
+   # Initialize the (empty) cell content so the keys are representative of the month
+   foreach my $datenumber ( 1 .. Date::Calc::Days_in_Month($self->{'year'},$self->{'month'}) ) {
+      $self->{'content'}->{$datenumber}          = '';
+      $self->{'datecellclass'}->{$datenumber}    = '';
+      $self->{'datecolor'}->{$datenumber}        = '';
+      $self->{'datebordercolor'}->{$datenumber}  = '';
+      $self->{'datecontentcolor'}->{$datenumber} = '';
+      $self->{'href'}->{$datenumber}             = '';
+   }
+
+   # All done!
+   bless $self,$class; return $self;
+}
+
+
+sub as_HTML {
+   my $self = shift;
+   my %params = @_; 
+   my $html = '';
+   my(@days,$weeks,$WEEK,$DAY);
+
+   # To make the grid even, pad the start of the series with 0s
+   @days = (1 .. Date::Calc::Days_in_Month($self->year(),$self->month() ) );
+   if ($self->weekstartsonmonday()) {
+       foreach (1 .. (Date::Calc::Day_of_Week($self->year(),
+                                              $self->month(),1) -1 )) {
+          unshift(@days,0);
+       }
+   }
+   else {
+       foreach (1 .. (Date::Calc::Day_of_Week($self->year(),
+                                              $self->month(),1)%7) ) {
+          unshift(@days,0);
+       }
+   }
+   $weeks = int((scalar(@days)+6)/7);
+   # And pad the end as well, to avoid "uninitialized value" warnings
+   foreach (scalar(@days)+1 .. $weeks*7) {
+      push(@days,0);
+   }
+
+   # Define some scalars for generating the table
+   my $border = $self->border();
+   my $tablewidth = $self->width();
+   $tablewidth =~ m/^(\d+)(\%?)$/; my $cellwidth = (int($1/7))||'14'; if ($2) { $cellwidth .= '%'; }
+   my $header = $self->header();
+   my $cellalignment = $self->cellalignment();
+   my $vcellalignment = $self->vcellalignment();
+   my $contentfontsize = $self->contentfontsize();
+   my $bgcolor = $self->bgcolor();
+   my $weekdaycolor = $self->weekdaycolor() || $self->bgcolor();
+   my $weekendcolor = $self->weekendcolor() || $self->bgcolor();
+   my $todaycolor = $self->todaycolor() || $self->bgcolor();
+   my $contentcolor = $self->contentcolor() || $self->contentcolor();
+   my $weekdaycontentcolor = $self->weekdaycontentcolor() || $self->contentcolor();
+   my $weekendcontentcolor = $self->weekendcontentcolor() || $self->contentcolor();
+   my $todaycontentcolor = $self->todaycontentcolor() || $self->contentcolor();
+   my $bordercolor = $self->bordercolor() || $self->bordercolor();
+   my $weekdaybordercolor = $self->weekdaybordercolor() || $self->bordercolor();
+   my $weekendbordercolor = $self->weekendbordercolor() || $self->bordercolor();
+   my $todaybordercolor = $self->todaybordercolor() || $self->bordercolor();
+   my $weekdayheadercolor = $self->weekdayheadercolor() || $self->bgcolor();
+   my $weekendheadercolor = $self->weekendheadercolor() || $self->bgcolor();
+   my $headercontentcolor = $self->headercontentcolor() || $self->contentcolor();
+   my $weekdayheadercontentcolor = $self->weekdayheadercontentcolor() || $self->contentcolor();
+   my $weekendheadercontentcolor = $self->weekendheadercontentcolor() || $self->contentcolor();
+   my $headercolor = $self->headercolor() || $self->bgcolor();
+   my $cellpadding = $self->cellpadding();
+   my $cellspacing = $self->cellspacing();
+   my $sharpborders = $self->sharpborders();
+   my $cellheight = $self->cellheight();
+   my $cellclass = $self->cellclass();
+   my $tableclass = $self->tableclass();
+   my $weekdaycellclass = $self->weekdaycellclass() || $self->cellclass();
+   my $weekendcellclass = $self->weekendcellclass() || $self->cellclass();
+   my $todaycellclass = $self->todaycellclass() || $self->cellclass();
+   my $headerclass = $self->headerclass() || $self->cellclass();
+   my $nowrap = $self->nowrap();
+
+   # Get today's date, in case there's a todaycolor()
+   my($todayyear,$todaymonth,$todaydate) = ($self->today_year(),$self->today_month(),$self->today_date());
+
+   # the table declaration - sharpborders wraps the table inside a table cell
+   if ($sharpborders) {
+      $html .= "<table border=\"0\"";
+      $html .= " class=\"$tableclass\"" if defined $tableclass;
+      $html .= " width=\"$tablewidth\"" if defined $tablewidth;
+      $html .= " cellpadding=\"0\" cellspacing=\"0\">\n";
+      $html .= "<tr valign=\"top\" align=\"left\">\n";
+      $html .= "<td align=\"left\" valign=\"top\"";
+      $html .= " bgcolor=\"$bordercolor\"" if defined $bordercolor;
+      $html .= ">";
+      $html .= "<table border=\"0\" cellpadding=\"3\" cellspacing=\"1\" width=\"100%\">";
+   }
+   else {
+      $html .= "<table";
+      $html .= " class=\"$tableclass\"" if defined $tableclass;
+      $html .= " border=\"$border\"" if defined $border;
+      $html .= " width=\"$tablewidth\"" if defined $tablewidth;
+      $html .= " bgcolor=\"$bgcolor\"" if defined $bgcolor;
+      $html .= " bordercolor=\"$bordercolor\"" if defined $bordercolor;
+      $html .= " cellpadding=\"$cellpadding\"" if defined $cellpadding;
+      $html .= " cellspacing=\"$cellspacing\""  if defined $cellspacing;
+      $html .= ">\n";
+   }
+   # the header
+   if ($header) {
+      $html .= "<tr><td colspan=\"7\"";
+      $html .= " bgcolor=\"$headercolor\"" if defined $headercolor;
+      $html .= " class=\"$headerclass\"" if defined $headerclass;
+      $html .= ">";
+      $html .= "<font color=\"$headercontentcolor\">" if defined $headercontentcolor;
+      $html .= $header;
+      $html .= "</font>"  if defined $headercontentcolor;
+      $html .= "</td></tr>\n";
+   }
+   # the names of the days of the week
+   if ($self->showweekdayheaders) {
+      my $celltype = $self->weekdayheadersbig() ? "th" : "td";
+      my @weekdays = $self->weekdays();
+
+      my $saturday_html = "<$celltype"
+                        . ( defined $weekendheadercolor 
+                            ? qq| bgcolor="$weekendheadercolor"| 
+                            : '' )
+                        . ( defined $weekendcellclass 
+                            ? qq| class="$weekendcellclass"| 
+                            : '' ) 
+                        . ">"
+                        . ( defined $weekendheadercontentcolor 
+                            ? qq|<font color="$weekendheadercontentcolor">| 
+                            : '' ) 
+                        . $self->saturday()
+                        . ( defined $weekendheadercontentcolor 
+                            ? qq|</font>|
+                            : '' )
+                        . "</$celltype>\n";
+
+      my $sunday_html   = "<$celltype"
+                        . ( defined $weekendheadercolor 
+                            ? qq| bgcolor="$weekendheadercolor"| 
+                            : '' )
+                        . ( defined $weekendcellclass 
+                            ? qq| class="$weekendcellclass"| 
+                            : '' ) 
+                        . ">"
+                        . ( defined $weekendheadercontentcolor 
+                            ? qq|<font color="$weekendheadercontentcolor">| 
+                            : '' ) 
+                        . $self->sunday()
+                        . ( defined $weekendheadercontentcolor 
+                            ? qq|</font>|
+                            : '' )
+                        . "</$celltype>\n";
+      
+      my $weekday_html = '';
+      foreach (@weekdays) { # draw the weekday headers
+
+         $weekday_html  .= "<$celltype"
+                        . ( defined $weekendheadercolor 
+                            ? qq| bgcolor="$weekdayheadercolor"| 
+                            : '' )
+                        . ( defined $weekendcellclass 
+                            ? qq| class="$weekdaycellclass"| 
+                            : '' ) 
+                        . ">"
+                        . ( defined $weekdayheadercontentcolor 
+                            ? qq|<font color="$weekdayheadercontentcolor">| 
+                            : '' ) 
+                        . $_
+                        . ( defined $weekdayheadercontentcolor 
+                            ? qq|</font>|
+                            : '' )
+                        . "</$celltype>\n";
+      }
+
+      $html .= "<tr>\n";
+      if ($self->weekstartsonmonday()) {
+        $html .= $weekday_html
+              .  $saturday_html
+              .  $sunday_html;
+      }
+      else {
+        $html .= $sunday_html
+              .  $weekday_html
+              .  $saturday_html;
+      }
+      $html .= "</tr>\n";
+   }
+
+   my $_saturday_index = 6;
+   my $_sunday_index   = 0;
+   if ($self->weekstartsonmonday()) {
+       $_saturday_index = 5;
+       $_sunday_index   = 6;
+   }
+   # now do each day, the actual date-content-containing cells
+   foreach $WEEK (0 .. ($weeks-1)) {
+      $html .= "<tr>\n";
+
+      
+      foreach $DAY ( 0 .. 6 ) {
+         my($thiscontent,$thisday,$thisbgcolor,$thisbordercolor,$thiscontentcolor,$thiscellclass);
+         $thisday = $days[((7*$WEEK)+$DAY)];
+
+         # Get the cell content
+         if (! $thisday) { # If it's a dummy cell, no content
+            $thiscontent = '&nbsp;'; }
+         else { # A real date cell with potential content
+            # Get the content
+            if ($self->showdatenumbers()) { 
+              if ( $self->getdatehref( $thisday )) {
+                $thiscontent = "<span><a href=\"".$self->getdatehref($thisday);
+                $thiscontent .= "\">$thisday</a></span>\n";
+              } else {
+                $thiscontent = "<span>$thisday</span>\n";
+              }
+            }
+            $thiscontent .= $self->{'content'}->{$thisday};
+            $thiscontent ||= '&nbsp;';
+         }
+
+         # Get the cell's coloration and CSS class
+         if ($self->year == $todayyear && $self->month == $todaymonth && $thisday == $todaydate)
+                                              { $thisbgcolor = $self->datecolor($thisday) || $todaycolor;
+                                                $thisbordercolor = $self->datebordercolor($thisday) || $todaybordercolor;
+                                                $thiscontentcolor = $self->datecontentcolor($thisday) || $todaycontentcolor;
+                                                $thiscellclass = $self->datecellclass($thisday) || $todaycellclass;
+                                              }
+         elsif (($DAY == $_sunday_index) || ($DAY == $_saturday_index))   { $thisbgcolor = $self->datecolor($thisday) || $weekendcolor;
+                                                $thisbordercolor = $self->datebordercolor($thisday) || $weekendbordercolor;
+                                                $thiscontentcolor = $self->datecontentcolor($thisday) || $weekendcontentcolor;
+                                                $thiscellclass = $self->datecellclass($thisday) || $weekendcellclass;
+                                              }
+         else                                 { $thisbgcolor = $self->datecolor($thisday) || $weekdaycolor;
+                                                $thisbordercolor = $self->datebordercolor($thisday) || $weekdaybordercolor;
+                                                $thiscontentcolor = $self->datecontentcolor($thisday) || $weekdaycontentcolor;
+                                                $thiscellclass = $self->datecellclass($thisday) || $weekdaycellclass;
+                                              }
+
+         # Done with this cell - push it into the table
+         $html .= "<td";
+         $html .= " nowrap" if $nowrap;
+         $html .= " class=\"$thiscellclass\"" if defined $thiscellclass;
+         $html .= " height=\"$cellheight\"" if defined $cellheight;
+         $html .= " width=\"$cellwidth\"" if defined $cellwidth;
+         $html .= " valign=\"$vcellalignment\"" if defined $vcellalignment;
+         $html .= " align=\"$cellalignment\"" if defined $cellalignment;
+         $html .= " bgcolor=\"$thisbgcolor\"" if defined $thisbgcolor;
+         $html .= " bordercolor=\"$thisbordercolor\"" if defined $thisbordercolor;
+         $html .= ">";
+         $html .= "<font" if (defined $thiscontentcolor ||
+                              defined $contentfontsize);
+         $html .= " color=\"$thiscontentcolor\"" if defined $thiscontentcolor;
+         $html .= " size=\"$contentfontsize\""  if defined $contentfontsize;
+         $html .= ">" if (defined $thiscontentcolor ||
+                          defined $contentfontsize);
+         $html .= $thiscontent;
+         $html .= "</font>" if (defined $thiscontentcolor ||
+                                defined $contentfontsize);
+         $html .= "</td>\n";
+      }
+      $html .= "</tr>\n";
+   }
+   $html .= "</table>\n";
+
+   # if sharpborders, we need to break out of the enclosing table cell
+   if ($sharpborders) {
+      $html .= "</td>\n</tr>\n</table>\n";
+   }
+
+   return $html;
+}
+
+
+
+sub sunday {
+   my $self = shift;
+   my $newvalue = shift;
+   $self->{'sunday'} = $newvalue if defined($newvalue);
+   return $self->{'sunday'};
+}
+
+sub saturday {
+   my $self = shift;
+   my $newvalue = shift;
+   $self->{'saturday'} = $newvalue if defined($newvalue);
+   return $self->{'saturday'};
+}
+
+sub weekdays {
+   my $self = shift;
+   my @days = @_;
+   $self->{'weekdays'} = \@days if (scalar(@days)==5);
+   return @{$self->{'weekdays'}};
+}
+
+sub getdatehref {
+   my $self = shift;
+   my @dates = $self->_date_string_to_numeric(shift); return() unless @dates;
+   return $self->{'href'}->{$dates[0]};
+}
+
+sub setdatehref {
+   my $self = shift;
+   my @dates = $self->_date_string_to_numeric(shift); return() unless @dates;
+   my $datehref = shift || '';
+
+   foreach my $date (@dates) {
+      $self->{'href'}->{$date} = $datehref if defined($self->{'href'}->{$date});
+   }
+
+   return(1);
+}
+
+sub weekendcolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'weekendcolor'} = $newvalue; }
+   return $self->{'weekendcolor'};
+}
+
+sub weekendheadercolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'weekendheadercolor'} = $newvalue; }
+   return $self->{'weekendheadercolor'};
+}
+
+sub weekdayheadercolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'weekdayheadercolor'} = $newvalue; }
+   return $self->{'weekdayheadercolor'};
+}
+
+sub weekdaycolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'weekdaycolor'} = $newvalue; }
+   return $self->{'weekdaycolor'};
+}
+
+sub headercolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'headercolor'} = $newvalue; }
+   return $self->{'headercolor'};
+}
+
+sub bgcolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'bgcolor'} = $newvalue; }
+   return $self->{'bgcolor'};
+}
+
+sub todaycolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'todaycolor'} = $newvalue; }
+   return $self->{'todaycolor'};
+}
+
+sub bordercolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'bordercolor'} = $newvalue; }
+   return $self->{'bordercolor'};
+}
+
+sub weekdaybordercolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'weekdaybordercolor'} = $newvalue; }
+   return $self->{'weekdaybordercolor'};
+}
+
+sub weekendbordercolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'weekendbordercolor'} = $newvalue; }
+   return $self->{'weekendbordercolor'};
+}
+
+sub todaybordercolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'todaybordercolor'} = $newvalue; }
+   return $self->{'todaybordercolor'};
+}
+
+sub contentcolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'contentcolor'} = $newvalue; }
+   return $self->{'contentcolor'};
+}
+
+sub headercontentcolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'headercontentcolor'} = $newvalue; }
+   return $self->{'headercontentcolor'};
+}
+
+sub weekdayheadercontentcolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'weekdayheadercontentcolor'} = $newvalue; }
+   return $self->{'weekdayheadercontentcolor'};
+}
+
+sub weekendheadercontentcolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'weekendheadercontentcolor'} = $newvalue; }
+   return $self->{'weekendheadercontentcolor'};
+}
+
+sub weekdaycontentcolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'weekdaycontentcolor'} = $newvalue; }
+   return $self->{'weekdaycontentcolor'};
+}
+
+sub weekendcontentcolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'weekendcontentcolor'} = $newvalue; }
+   return $self->{'weekendcontentcolor'};
+}
+
+sub todaycontentcolor {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'todaycontentcolor'} = $newvalue; }
+   return $self->{'todaycontentcolor'};
+}
+
+sub datecolor {
+   my $self = shift;
+   my @dates = $self->_date_string_to_numeric(shift); return() unless @dates;
+   my $newvalue = shift;
+
+   if (defined($newvalue)) {
+      foreach my $date (@dates) {
+         $self->{'datecolor'}->{$date} = $newvalue if defined($self->{'datecolor'}->{$date});
+      }
+   }
+
+   return $self->{'datecolor'}->{$dates[0]};
+}
+
+sub datebordercolor {
+   my $self = shift;
+   my @dates = $self->_date_string_to_numeric(shift); return() unless @dates;
+   my $newvalue = shift;
+
+   if (defined($newvalue)) {
+      foreach my $date (@dates) {
+         $self->{'datebordercolor'}->{$date} = $newvalue if defined($self->{'datebordercolor'}->{$date});
+      }
+   }
+
+   return $self->{'datebordercolor'}->{$dates[0]};
+}
+
+sub datecontentcolor {
+   my $self = shift;
+   my @dates = $self->_date_string_to_numeric(shift); return() unless @dates;
+   my $newvalue = shift;
+
+   if (defined($newvalue)) {
+      foreach my $date (@dates) {
+         $self->{'datecontentcolor'}->{$date} = $newvalue if defined($self->{'datecontentcolor'}->{$date});
+      }
+   }
+
+   return $self->{'datecontentcolor'}->{$dates[0]};
+}
+
+sub getcontent {
+   my $self = shift;
+   my @dates = $self->_date_string_to_numeric(shift); return() unless @dates;
+   return $self->{'content'}->{$dates[0]};
+}
+
+sub setcontent {
+   my $self = shift;
+   my @dates = $self->_date_string_to_numeric(shift); return() unless @dates;
+   my $newcontent = shift || '';
+
+   foreach my $date (@dates) {
+      $self->{'content'}->{$date} = $newcontent if defined($self->{'content'}->{$date});
+   }
+
+   return(1);
+}
+
+sub addcontent {
+   my $self = shift;
+   my @dates = $self->_date_string_to_numeric(shift); return() unless @dates;
+   my $newcontent = shift || return();
+
+   foreach my $date (@dates) {
+      $self->{'content'}->{$date} .= $newcontent if defined($self->{'content'}->{$date});
+   }
+
+   return(1);
+}
+
+sub border {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'border'} = int($newvalue); }
+   return $self->{'border'};
+}
+
+
+sub cellpadding {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'cellpadding'} = $newvalue; }
+   return $self->{'cellpadding'};
+}
+
+sub cellspacing {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'cellspacing'} = $newvalue; }
+   return $self->{'cellspacing'};
+}
+
+sub width {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'width'} = $newvalue; }
+   return $self->{'width'};
+}
+
+sub showdatenumbers {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'showdatenumbers'} = $newvalue; }
+   return $self->{'showdatenumbers'};
+}
+sub showweekdayheaders {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'showweekdayheaders'} = $newvalue; }
+   return $self->{'showweekdayheaders'};
+}
+
+sub cellalignment {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'cellalignment'} = $newvalue; }
+   return $self->{'cellalignment'};
+}
+
+sub vcellalignment {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'vcellalignment'} = $newvalue; }
+   return $self->{'vcellalignment'};
+}
+
+sub contentfontsize {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'contentfontsize'} = $newvalue; }
+   return $self->{'contentfontsize'};
+}
+
+sub weekdayheadersbig {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'weekdayheadersbig'} = $newvalue; }
+   return $self->{'weekdayheadersbig'};
+}
+
+sub year {
+   my $self = shift;
+   return $self->{'year'};
+}
+
+sub month {
+   my $self = shift;
+   return $self->{'month'};
+}
+
+sub monthname {
+   my $self = shift;
+   return $self->{'monthname'};
+}
+
+sub today_year {
+   my $self = shift;
+   return $self->{'today_year'};
+}
+
+sub today_month {
+   my $self = shift;
+   return $self->{'today_month'};
+}
+
+sub today_date {
+   my $self = shift;
+   return $self->{'today_date'};
+}
+
+
+sub header {
+   my $self = shift;
+   my $newvalue = shift;
+   if (defined($newvalue)) { $self->{'header'} = $newvalue; }
+   return $self->{'header'};
+}
+
+sub nowrap {
+    my $self = shift;
+    my $newvalue = shift;
+    if (defined($newvalue)) { $self->{'nowrap'} = $newvalue; }
+    return $self->{'nowrap'};
+}
+
+sub sharpborders {
+    my $self = shift;
+    my $newvalue = shift;
+    if (defined($newvalue)) { $self->{'sharpborders'} = $newvalue; }
+    return $self->{'sharpborders'};
+}
+
+sub cellheight {
+    my $self = shift;
+    my $newvalue = shift;
+    if (defined($newvalue)) { $self->{'cellheight'} = $newvalue; }
+    return $self->{'cellheight'};
+}
+
+sub cellclass {
+    my $self = shift;
+    my $newvalue = shift;
+    if (defined($newvalue)) { $self->{'cellclass'} = $newvalue; }
+    return $self->{'cellclass'};
+}
+
+sub tableclass {
+    my $self = shift;
+    my $newvalue = shift;
+    if (defined($newvalue)) { $self->{'tableclass'} = $newvalue; }
+    return $self->{'tableclass'};
+}
+
+sub weekdaycellclass {
+    my $self = shift;
+    my $newvalue = shift;
+    if (defined($newvalue)) { $self->{'weekdaycellclass'} = $newvalue; }
+    return $self->{'weekdaycellclass'};
+}
+
+sub weekendcellclass {
+    my $self = shift;
+    my $newvalue = shift;
+    if (defined($newvalue)) { $self->{'weekendcellclass'} = $newvalue; }
+    return $self->{'weekendcellclass'};
+}
+
+sub todaycellclass {
+    my $self = shift;
+    my $newvalue = shift;
+    if (defined($newvalue)) { $self->{'todaycellclass'} = $newvalue; }
+    return $self->{'todaycellclass'};
+}
+
+sub datecellclass {
+    my $self = shift;
+    my $date = lc(shift) || return(); $date = int($date) if $date =~ m/^[\d\.]+$/;
+    my $newvalue = shift;
+    if (defined($newvalue)) { $self->{'datecellclass'}->{$date} = $newvalue; }
+    return $self->{'datecellclass'}->{$date};
+}
+
+sub headerclass {
+    my $self = shift;
+    my $newvalue = shift;
+    if (defined($newvalue)) { $self->{'headerclass'} = $newvalue; }
+    return $self->{'headerclass'};
+}
+
+sub weekstartsonmonday {
+    my $self = shift;
+    my $newvalue = shift;
+    if (defined($newvalue)) { $self->{'weekstartsonmonday'} = $newvalue; }
+    return $self->{'weekstartsonmonday'} ? 1 : 0;
+}
+
+
+### the following methods are internal-use-only methods
+
+# _date_string_to_numeric() takes a date string (e.g. 5, 'wednesdays', or '3friday')
+# and returns the corresponding numeric date. For numerics, this sounds meaningless,
+# but for the strings it's useful to have this all in one place.
+# If it's a plural weekday (e.g. 'sundays') then an array of numeric dates is returned.
+sub _date_string_to_numeric {
+   my $self = shift;
+   my $date = shift || return ();
+
+   my($which,$weekday);
+   if ($date =~ m/^\d\.*\d*$/) { # first and easiest, simple numerics
+      return int($date);
+   }
+   elsif (($which,$weekday) = ($date =~ m/^(\d)([a-zA-Z]+)$/)) {
+      my($y,$m,$d) = Date::Calc::Nth_Weekday_of_Month_Year($self->year(),$self->month(),Date::Calc::Decode_Day_of_Week($weekday),$which);
+      return $d;
+   }
+   elsif (($weekday) = ($date =~ m/^(\w+)s$/i)) {
+      $weekday = Date::Calc::Decode_Day_of_Week($weekday); # now it's the numeric weekday
+      my @dates;
+      foreach my $which (1..5) {
+         my $thisdate = Date::Calc::Nth_Weekday_of_Month_Year($self->year(),$self->month(),$weekday,$which);
+         push(@dates,$thisdate) if $thisdate;
+      }
+      return @dates;
+   }
+}
+
+
+
+__END__;
+#################################################################################
+
+
+=head1 NAME
+
+HTML::CalendarMonthSimple - Perl Module for Generating HTML Calendars
+
+
+=head1 SYNOPSIS
+
+   use HTML::CalendarMonthSimple;
+   $cal = new HTML::CalendarMonthSimple('year'=>2001,'month'=>2);
+   $cal->width('50%');
+   $cal->border(10);
+   $cal->header('Text at the top of the Grid');
+   $cal->setcontent(14,"Valentine's Day");
+   $cal->setdatehref(14, 'http://localhost/');
+   $cal->addcontent(14,"<p>Don't forget to buy flowers.");
+   $cal->addcontent(13,"Guess what's tomorrow?");
+   $cal->bgcolor('pink');
+   print $cal->as_HTML;
+
+
+=head1 DESCRIPTION
+
+HTML::CalendarMonthSimple is a Perl module for generating, manipulating, and printing a HTML calendar grid for a specified month. It is intended as a faster and easier-to-use alternative to HTML::CalendarMonth.
+
+This module requires the Date::Calc module, which is available from CPAN if you don't already have it.
+
+
+=head1 INTERFACE METHODS
+
+
+=head1 new(ARGUMENTS)
+
+Naturally, new() returns a newly constructed calendar object.
+
+The optional constructor arguments 'year' and 'month' can specify which month's calendar will be used. If either is omitted, the current value (e.g. "today") is used. An important note is that the month and the year are NOT the standard C or Perl -- use a month in the range 1-12 and a real year, e.g. 2001.
+
+The arguments 'today_year', 'today_month', and 'today_date' may also be specified, to specify what "today" is. If not specified, the system clock will be used. This is particularly useful when the todaycolor() et al methods are used, and/or if you're dealing with multiple timezones. Note that these arguments change what "today" is, which means that if you specify a today_year and a today_month then you are effectively specifying a 'year' and 'month' argument as well, though you can also specify a year and month argument and override the "today" behavior.
+
+   # Examples:
+   # Create a calendar for this month.
+   $cal = new HTML::CalendarMonthSimple();
+   # A calendar for a specific month/year
+   $cal = new HTML::CalendarMonthSimple('month'=>2,'year'=>2000);
+   # Pretend that today is June 10, 2000 and display the "current" calendar
+   $cal = new HTML::CalendarMonthSimple('today_year'=>2000,'today_month'=>6,'today_date'=>10);
+
+
+=head1 year()
+
+=head1 month()
+
+=head1 today_year()
+
+=head1 today_month()
+
+=head1 today_date()
+
+=head1 monthname()
+
+These methods simply return the year/month/date of the calendar, as specified in the constructor.
+
+monthname() returns the text name of the month, e.g. "December".
+
+
+
+=head1 setcontent(DATE,STRING)
+
+=head1 addcontent(DATE,STRING)
+
+=head1 getcontent(DATE)
+
+These methods are used to control the content of date cells within the calendar grid. The DATE argument may be a numeric date or it may be a string describing a certain occurrence of a weekday, e.g. "3MONDAY" to represent "the third Monday of the month being worked with", or it may be the plural of a weekday name, e.g. "wednesdays" to represent all occurrences of the given weekday. The weekdays are case-insensitive.
+
+Since plural weekdays (e.g. 'wednesdays') is not a single date, getcontent() will return the content only for the first occurrence of that day within a month.
+
+   # Examples:
+   # The cell for the 15th of the month will now say something.
+   $cal->setcontent(15,"An Important Event!");
+   # Later down the program, we want the content to be boldfaced.
+   $cal->setcontent(15,"<b>" . $cal->getcontent(15) . "</b>");
+
+   # addcontent() does not clobber existing content.
+   # Also, if you setcontent() to '', you've deleted the content.
+   $cal->setcontent(16,'');
+   $cal->addcontent(16,"<p>Hello World</p>");
+   $cal->addcontent(16,"<p>Hello Again</p>");
+   print $cal->getcontent(16); # Prints 2 sentences
+
+   # Padded and decimal numbers may be used, as well:
+   $cal->setcontent(3.14159,'Third of the month');
+   $cal->addcontent('00003.0000','Still the third');
+   $cal->getcontent('3'); # Gets the 2 sentences
+
+   # The second Sunday of May is some holiday or another...
+   $cal->addcontent('2sunday','Some Special Day') if ($cal->month() == 5);
+
+   # Every Wednesday is special...
+   $cal->addcontent('wednesdays','Every Wednesday!');
+
+   # either of these will return the content for the 1st Friday of the month
+   $cal->getcontent('1friday');
+   $cal->getcontent('Fridays'); # you really should use '1friday' for the first Friday
+
+Note: A change in 1.21 is that all content is now stored in a single set of date-indexed buckets. Previously, the content for weekdays, plural weekdays, and numeric dates were stored separately and could be fetched and set independently. This led to buggy behavior, so now a single storage set is used.
+
+   # Example:
+   # if the 9th of the month is the second Wednesday...
+   $cal->setcontent(9,'ninth');
+   $cal->addcontent('2wednesday','second wednesday');
+   $cal->addcontent('wednesdays','every wednesday');
+   print $cal->getcontent(9);
+
+In version 1.20 and previous, this would print 'ninth' but in 1.21 and later, this will print all three items (since the 9th is not only the 9th but also a Wednesday and the second Wednesday). This could have implications if you use setcontent() on a set of days, since other content may be overwritten:
+
+   # Example:
+   # the second setcontent() effectively overwrites the first one
+   $cal->setcontent(9,'ninth');
+   $cal->setcontent('2wednesday','second wednesday');
+   $cal->setcontent('wednesdays','every wednesday');
+   print $cal->getcontent(9); # returns 'every wednesday' because that was the last assignment!
+
+
+
+=head1 as_HTML()
+
+This method returns a string containing the HTML table for the month.
+
+   # Example:
+   print $cal->as_HTML();
+
+It's okay to continue modifying the calendar after calling as_HTML(). My guess is that you'd want to call as_HTML() again to print the further-modified calendar, but that's your business...
+
+
+
+=head1 weekstartsonmonday([1|0])
+
+By default, calendars are displayed with Sunday as the first day of the week (American style). Most of the world prefers for calendars to start the week on Monday. This method selects which type is used: 1 specifies that the week starts on Monday, 0 specifies that the week starts on Sunday (the default). If no value is given at all, the current value (1 or 0) is returned.
+
+   # Example:
+   $cal->weekstartsonmonday(1); # switch over to weeks starting on Monday
+   $cal->weekstartsonmonday(0); # switch back to the default, where weeks start on Sunday
+
+   # Example:
+   print "The week starts on " . ($cal->weekstartsonmonday() ? 'Sunday' : 'Monday') . "\n";
+
+
+=head1 setdatehref(DATE,URL_STRING)
+
+=head1 getdatehref(DATE)
+
+These allow the date-number in a calendar cell to become a hyperlink to the specified URL. The DATE may be either a numeric date or any of the weekday formats described in setcontent(), et al. If plural weekdays (e.g. 'wednesdays') are used with getdatehref() the URL of the first occurrence of that weekday in the month will be returned (since 'wednesdays' is not a single date).
+
+   # Example:
+   # The date number in the cell for the 15th of the month will be a link
+   # then we change our mind and delete the link by assigning a null string
+   $cal->setdatehref(15,"http://sourceforge.net/");
+   $cal->setdatehref(15,'');
+
+   # Example:
+   # the second Wednesday of the month goes to some website
+   $cal->setdatehref('2wednesday','http://www.second-wednesday.com/');
+
+   # Example:
+   # every Wednesday goes to a website
+   # note that this will effectively undo the '2wednesday' assignment we just did!
+   # if we wanted the second Wednesday to go to that special URL, we should've done that one after this!
+   $cal->setdatehref('wednesdays','http://every-wednesday.net/');
+
+
+
+=head1 contentfontsize([STRING])
+
+contentfontsize() sets the font size for the contents of the cell, overriding the browser's default. Can be expressed as an absolute (1 .. 6) or relative (-3 .. +3) size.
+
+
+=head1 border([INTEGER])
+
+This specifies the value of the border attribute to the <TABLE> declaration for the calendar. As such, this controls the thickness of the border around the calendar table. The default value is 5.
+
+If a value is not specified, the current value is returned. If a value is specified, the border value is changed and the new value is returned.
+
+
+=head1 width([INTEGER][%])
+
+This sets the value of the width attribute to the <TABLE> declaration for the calendar. As such, this controls the horizintal width of the calendar.
+
+The width value can be either an integer (e.g. 600) or a percentage string (e.g. "80%"). Most web browsers take an integer to be the table's width in pixels and a percentage to be the table width relative to the screen's width. The default width is "100%".
+
+If a value is not specified, the current value is returned. If a value is specified, the border value is changed and the new value is returned.
+
+   # Examples:
+   $cal->width(600);    # absolute pixel width
+   $cal->width("100%"); # percentage of screen size
+
+
+=head1 showdatenumbers([1 or 0])
+
+If showdatenumbers() is set to 1, then the as_HTML() method will put date labels in each cell (e.g. a 1 on the 1st, a 2 on the 2nd, etc.) If set to 0, then the date labels will not be printed. The default is 1.
+
+If no value is specified, the current value is returned.
+
+The date numbers are shown in boldface, normal size font. If you want to change this, consider setting showdatenumbers() to 0 and using setcontent()/addcontent() instead.
+
+
+=head1 showweekdayheaders([1 or 0])
+
+=head1 weekdayheadersbig([1 or 0])
+
+If showweekdayheaders() is set to 1 (the default) then calendars rendered via as_HTML() will display the names of the days of the week. If set to 0, the days' names will not be displayed.
+
+If weekdayheadersbig() is set to 1 (the default) then the weekday headers will be in <th> cells. The effect in most web browsers is that they will be boldfaced and centered. If set to 0, the weekday headers will be in <td> cells and in normal text.
+
+For both functions, if no value is specified, the current value is returned.
+
+
+=head1 cellalignment([STRING])
+
+=head1 vcellalignment([STRING])
+
+cellalignment() sets the value of the align attribute to the <TD> tag for each day's cell. This controls how text will be horizontally centered/aligned within the cells. vcellalignment() does the same for vertical alignment. By default, content is aligned horizontally "left" and vertically "top"
+
+Any value can be used, if you think the web browser will find it interesting. Some useful alignments are: left, right, center, top, and bottom.
+
+
+=head1 header([STRING])
+
+By default, the current month and year are displayed at the top of the calendar grid. This is called the "header".
+
+The header() method allows you to set the header to whatever you like. If no new header is specified, the current header is returned.
+
+If the header is set to an empty string, then no header will be printed at all. (No, you won't be stuck with a big empty cell!)
+
+   # Example:
+   # Set the month/year header to something snazzy.
+   my($y,$m) = ( $cal->year() , $cal->monthname() );
+   $cal->header("<center><font size=+2 color=red>$m $y</font></center>\n\n");
+
+
+
+=head1 bgcolor([STRING])
+
+=head1 weekdaycolor([STRING])
+
+=head1 weekendcolor([STRING])
+
+=head1 todaycolor([STRING])
+
+=head1 bordercolor([STRING])
+
+=head1 weekdaybordercolor([STRING])
+
+=head1 weekendbordercolor([STRING])
+
+=head1 todaybordercolor([STRING])
+
+=head1 contentcolor([STRING])
+
+=head1 weekdaycontentcolor([STRING])
+
+=head1 weekendcontentcolor([STRING])
+
+=head1 todaycontentcolor([STRING])
+
+=head1 headercolor([STRING])
+
+=head1 headercontentcolor([STRING])
+
+=head1 weekdayheadercolor([STRING])
+
+=head1 weekdayheadercontentcolor([STRING])
+
+=head1 weekendheadercolor([STRING])
+
+=head1 weekendheadercontentcolor([STRING])
+
+These define the colors of the cells. If a string (which should be either a HTML color-code like '#000000' or a color-word like 'yellow') is supplied as an argument, then the color is set to that specified. Otherwise, the current value is returned. To un-set a value, try assigning the null string as a value.
+
+The bgcolor defines the color of all cells. The weekdaycolor overrides the bgcolor for weekdays (Monday through Friday), the weekendcolor overrides the bgcolor for weekend days (Saturday and Sunday), and the todaycolor overrides the bgcolor for today's date. (Which may not mean a lot if you're looking at a calendar other than the current month.)
+
+The weekdayheadercolor overrides the bgcolor for the weekday headers that appear at the top of the calendar if showweekdayheaders() is true, and weekendheadercolor does the same thing for the weekend headers. The headercolor overrides the bgcolor for the month/year header at the top of the calendar. The headercontentcolor(), weekdayheadercontentcolor(), and weekendheadercontentcolor() methods affect the color of the corresponding headers' contents and default to the contentcolor().
+
+The colors of the cell borders may be set: bordercolor determines the color of the calendar grid's outside border, and is the default color of the inner border for individual cells. The inner bordercolor may be overridden for the various types of cells via weekdaybordercolor, weekendbordercolor, and todaybordercolor.
+
+Finally, the color of the cells' contents may be set with contentcolor, weekdaycontentcolor, weekendcontentcolor, and todaycontentcolor. The contentcolor is the default color of cell content, and the other methods override this for the appropriate days' cells.
+
+   # Example:
+   $cal->bgcolor('white');                  # Set the default cell bgcolor
+   $cal->bordercolor('green');              # Set the default border color
+   $cal->contentcolor('black');             # Set the default content color
+   $cal->headercolor('yellow');             # Set the bgcolor of the Month+Year header
+   $cal->headercontentcolor('yellow');      # Set the content color of the Month+Year header
+   $cal->weekdayheadercolor('orange');      # Set the bgcolor of weekdays' headers
+   $cal->weekendheadercontentcolor('blue'); # Set the color of weekday headers' contents
+   $cal->weekendheadercolor('pink');        # Set the bgcolor of weekends' headers
+   $cal->weekdayheadercontentcolor('blue'); # Set the color of weekend headers' contents
+   $cal->weekendcolor('palegreen');         # Override weekends' cell bgcolor
+   $cal->weekendcontentcolor('blue');       # Override weekends' content color
+   $cal->todaycolor('red');                 # Override today's cell bgcolor
+   $cal->todaycontentcolor('yellow');       # Override today's content color
+   print $cal->as_HTML;                     # Print a really ugly calendar!
+
+
+=head1 datecolor(DATE,[STRING])
+
+=head1 datecontentcolor(DATE,[STRING])
+
+=head1 datebordercolor(DATE,[STRING])
+
+These methods set the cell color and the content color for the specified date, and will return the current value if STRING is not specified. These color settings will override any of the settings mentioned above, even todaycolor() and todaycontentcolor().
+
+The date may be a numeric date or a weekday string as described in setcontent() et al. Note that if a plural weekday is used (e.g. 'sundays') then, since it's not a single date, the value for the first occurrence of that weekday will be returned (e.g. the first Sunday's color).
+
+   # Example: a red-letter day!
+   $cal->datecolor(3,'pink');
+   $cal->datecontentcolor(3,'red');
+
+   # Example:
+   # Every Tuesday is a Soylent Green day...
+   # Note that if the 3rd was a Tuesday, this later assignment would override the previous one.
+   # see the docs for setcontent() et all for more information.
+   $cal->datecolor('tuesdays','green');
+   $cal->datecontentcolor('tuesdays','yellow');
+
+
+
+=head1 nowrap([1 or 0])
+
+If set to 1, then calendar cells will have the NOWRAP attribute set, preventing their content from wrapping. If set to 0 (the default) then NOWRAP is not used and very long content may cause cells to become stretched out.
+
+
+
+=head1 sharpborders([1 or 0])
+
+If set to 1, this gives very crisp edges between the table cells. If set to 0 (the default) standard HTML cells are used. If neither value is specified, the current value is returned.
+
+FYI: To accomplish the crisp border, the entire calendar table is wrapped inside a table cell.
+
+
+
+=head1 cellheight([NUMBER])
+
+This specifies the height in pixels of each cell in the calendar. By default, no height is defined and the web browser usually chooses a reasonable default.
+
+If no value is given, the current value is returned.
+
+To un-specify a height, try specifying a height of 0 or undef.
+
+
+
+=head1 tableclass([STRING])
+
+=head1 cellclass([STRING])
+
+=head1 weekdaycellclass([STRING])
+
+=head1 weekendcellclass([STRING])
+
+=head1 todaycellclass([STRING])
+
+=head1 datecellclass(DATE,[STRING])
+
+=head1 headerclass([STRING])
+
+
+These specify which CSS class will be attributed to the calendar's table and the calendar's cells. By default, no classes are specified or used.
+
+tableclass() sets the CSS class for the calendar table.
+
+cellclass() is used for all calendar cells. weekdaycellclass(), weekendcellclass(), and todaycellclass() override the cellclass() for the corresponding types of cells. headerclass() is used for the calendar's header.
+
+datecellclass() sets the CSS class for the cell for the specified date. This setting will override any of the other cell class settings, even todaycellclass()  This date must be numeric; it cannot be a string such as "2wednesday"
+
+If no value is given, the current value is returned.
+
+To un-specify a class, try specifying an empty string, e.g. cellclass('')
+
+
+
+=head1 sunday([STRING])
+
+=head1 saturday([STRING])
+
+=head1 weekdays([MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY])
+
+These functions allow the days of the week to be "renamed", which is useful for displaying the weekday headers in another language.
+
+   # show the days of the week in Spanish
+   $cal->saturday('Sábado');
+   $cal->sunday('Domingo');
+   $cal->weekdays('Lunes','Martes','Miércoles','Jueves','Viernes');
+
+   # show the days of the week in German
+   $cal->saturday('Samstag');
+   $cal->sunday('Sonntag');
+   $cal->weekdays('Montag','Dienstag','Mittwoch','Donnerstag','Freitag');
+
+If no value is specified (or, for weekdays() if exactly 5 arguments aren't given) then the current value is returned.
+
+
+
+=head1 BUGS, TODO, CHANGES
+
+Changes in 1.01: Added VALIGN to cells, to make alignment work with browsers better. Added showweekdayheaders(). Corrected a bug that results in the month not fitting on the grid (e.g. March 2003).  Added getdatehref() and setdatehref(). Corrected a bug that causes a blank week to be printed at the beginning of some months.
+
+Changes in 1.02: Added the color methods.
+
+Changes in 1.03: More color methods!
+
+Changes in 1.04: Added the "which weekday" capability to addcontent(), setcontent(), and getcontent()
+
+Changes in 1.05: addcontent(), et al can now take strings such as '06' or decimals such as '3.14' and will handle them correctly.
+
+Changes in 1.06: Changed the "which weekday" interface a bit; truncations such as "2Tue" no longer work, and must be spelled out entirely ("2Tuesday"). Added "plural weekdays" support (e.g. "wednesdays" for "every wednesday").
+
+Changes in 1.07: Fixed a typo that caused an entirely empty calendar to be displayed very small.
+
+Changes in 1.08: Re-did the bugfixes described in 1.05, handling padded and non-integer dates.
+
+Changes in 1.09: Fixed the "2Monday", et al support; a bug was found by Dale Wellman <dwellman at bpnetworks.com> where the 7th, 14th, 21st, and 28th days weren't properly computing which Nth weekday they were so "1Monday" wouldn't work if the first Monday was the 7th of the month.
+
+Changes in 1.10: Added the headercontentcolor(), weekendheadercontentcolor(), and weekdayheadercontentcolor() methods, and made content headers use bgcolors, etc properly.
+
+Changes in 1.11: The module's VERSION is now properly specified, so "use" statements won't barf if they specify a minimum version. Added the vcellalignment() method so vertical content alignment is independent of horizontal alignment.
+
+Changes in 1.12: Fixed lots of warnings that were generated if B<-w> was used, due to many values defaulting to undef/blank. Added the sharpborders(), nowrap(), cellheight(), cellclass(), and weekdayheadersbig() methods. cellclass(), the beginning of CSS support. Thanks, Bray!
+
+Changes in 1.13: Added more CSS methods: headerclass(), weekdaycellclass(), weekndcellclass(), todaycellclass(). Added a test to the module distribution at the urging of CPAN testers.
+
+Changes in 1.14: Added the contentfontsize() method.
+
+Changes in 1.15: Added the datecolor(), datecontentcolor(), datebordercolor(), and datecellclass() methods, allowind cosmetic attributes to be changed on a per-date basis.
+
+Changes in 1.16: Fixed a very stupid bug that made addcontent() and setcontent() not work. Sorry!
+
+Changes in 1.17: Corrected B<-w> warnings about uninitialized values in as_HTML().
+
+Changes in 1.18: Added methods: tableclass(), sunday(), saturday(), weekdays(). Now day names can be internationalized!
+
+Changes in 1.19: Fixed as_HTML() such that blank/0 values can be used for various values, e.g. border size, colors, etc. Previously, values had to be non-zero or they were assumed to be undefined.
+
+Ver 1.20 was a mistake on my part and was immediately superseded by 1.21.
+
+Changes in 1.21: Fixed the internals of setcontent() et al (see the method's doc for details). Made getdatehref(), setdatehref(), and datecolor() et al, able to handle weekdays in addition to numeric dates.
+
+Changes in 1.22: Added the much-desired weekstartsonmonday() method. Now weeks can start on Monday and end with the weekend, instead of the American style of starting on Sunday.
+
+Changes in 1.23: Added today_year() et al. "Today" can now be overridden in the constructor.
+
+Changes in 1.24: Minor corrections to the HTML so it passes XML validation. Thanks a bundle, Peter!
+
+Changes in 1.25: A minor typo correction. Nothing big.
+
+
+
+=head1 AUTHORS, CREDITS, COPYRIGHTS
+
+This Perl module is freeware. It may be copied, derived, used, and distributed without limitation.
+
+HTML::CalendarMonth was written and is copyrighted by Matthew P. Sisk <sisk at mojotoad.com> and provided inspiration for the module's interface and features. None of Matt Sisk's code appears herein.
+
+HTML::CalendarMonthSimple was written by Gregor Mosheh <stigmata at blackangel.net> Frankly, the major inspiration was the difficulty and unnecessary complexity of HTML::CalendarMonth. (Laziness is a virtue.)
+
+This would have been extremely difficult if not for Date::Calc. Many thanks to Steffen Beyer <sb at engelschall.com> for a very fine set of date-related functions!
+
+Dave Fuller <dffuller at yahoo.com> added the getdatehref() and setdatehref() methods, and pointed out the bugs that were corrected in 1.01.
+
+Danny J. Sohier <danny at gel.ulaval.ca> provided many of the color functions.
+
+Bernie Ledwick <bl at man.fwltech.com> provided base code for the today*() functions, and for the handling of cell borders.
+
+Justin Ainsworth <jrainswo at olemiss.edu> provided the vcellalignment() concept and code.
+
+Jessee Porter <porterje at us.ibm.com> provided fixes for 1.12 to correct those warnings.
+
+Bray Jones <bjones at vialogix.com> supplied the sharpborders(), nowrap(), cellheight(), cellclass() methods.
+
+Bill Turner <b at brilliantcorners.org> supplied the headerclass() method and the rest of the methods added to 1.13
+
+Bill Rhodes <wrhodes at 27.org> provided the contentfontsize() method for version 1.14
+
+Alberto Simões <albie at alfarrabio.di.uminho.pt> provided the tableclass() function and the saturday(), sunday(), and weekdays() functions for version 1.18. Thanks, Alberto, I've been wanting this since the beginning!
+
+Blair Zajac <blair at orcaware.com> provided the fixes for 1.19
+
+Thanks to Kurt <kurt at otown.com> for the bug report that made all the new stuff in 1.21 possible.
+
+Many thanks to Stefano Rodighiero <larsen at libero.it> for the code that made weekstartsonmonday() possible. This was a much-requested feature that will make many people happy!
+
+Dan Boitnott <dboitnot at yahoo.com> provided today_year() et al in 1.23
+
+Peter Venables <pvenables at rogers.com> provided the XML validation fixes for 1.24
+


Property changes on: trunk/examples/typeface/lib/HTML/CalendarMonthSimple.pm
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/lib/Typeface/Controller/Admin.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/Controller/Admin.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/Controller/Admin.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,573 @@
+# Copyright (C) 2006  name of Victor Igumnov
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package Typeface::Controller::Admin;
+
+use strict;
+use warnings;
+use base 'Catalyst::Controller::FormBuilder';
+
+sub auto : Private {
+    my ( $self, $c ) = @_;
+    $c->res->redirect('/') unless ( $c->user );
+
+    return 0 unless ( $c->user );
+}
+
+sub clear : Local {
+    my ( $self, $c, $id ) = @_;
+
+    my $article = $c->model('Typeface::Articles')->find($id);
+    $c->forward( 'submit', 'cache_refresh', [$article] );
+    $c->res->body( '<p>cleared cache for ' . $article->subject . '</p>' );
+}
+
+sub clear_page : Local {
+    my ( $self, $c, $id ) = @_;
+    
+    my $page = $c->model('Typeface::Pages')->find($id);
+    $c->forward( 'submit', 'cache_refresh', [$page] );
+    $c->res->body( '<p>cleared cache for ' . $page->name . '</p>' );
+}
+
+
+sub create_page_form : Local Form {
+    my ( $self, $c  , $form ) = @_;
+
+    my ( $name, $id, $body, $display_sidebar, $display_in_drawer ) = "";
+    if ( defined $c->stash->{page} ) {
+        $name = $c->stash->{page}->name();
+        $id   = $c->stash->{page}->id();
+        if ( $c->stash->{page}->display_sidebar() == 1 ) {
+            $display_sidebar = 'Yes';
+        }
+        else {
+            $display_sidebar = 'No';
+        }
+        if ( $c->stash->{page}->display_in_drawer() == 1 ) {
+            $display_in_drawer = 'Yes';
+        }
+        else {
+            $display_in_drawer = 'No';
+        }
+
+        $body = $c->stash->{page}->body();
+    }
+
+    $form->field(
+        name     => 'name',
+        required => 1,
+        label    => 'Page Name',
+        size     => 40,
+        value    => $name
+    );
+
+    $form->field(
+        name     => 'display_sidebar',
+        required => 1,
+        label    => 'Display the sidebar?',
+        type     => 'radio',
+        options  => [qw/Yes No/],
+        value    => $display_sidebar,
+    );
+
+    $form->field(
+        name     => 'display_in_drawer',
+        required => 1,
+        label    => 'Display in the drawer?',
+        type     => 'radio',
+        options  => [qw/Yes No/],
+        value    => $display_in_drawer,
+    );
+
+    $form->field(
+        name     => 'body',
+        required => 1,
+        label    => 'Page Content',
+        type     => 'textarea',
+        cols     => 60,
+        rows     => 20,
+        value    => $body,
+    );
+
+    # make sure no trailing slashes happen.
+    $id = '/' . $id if length($id)>0;
+    $form->action( '/admin/page_commit' . $id );
+    $form->method('post');
+
+}
+
+sub create_category_form : Local Form {
+    my ( $self, $c, $form ) = @_;
+
+    my ( $name, $id ) = "";
+    if ( defined $c->stash->{category} ) {
+        $name = $c->stash->{category}->name;
+        $id   = $c->stash->{category}->id;
+    }
+
+    $form->field(
+        name     => 'name',
+        required => 1,
+        label    => 'Category Name',
+        size     => 40,
+        value    => $name
+    );
+
+    # make sure no trailing slashes happen.
+    $id = '/' . $id if length($id)>0;
+    $form->action( '/admin/category_commit' . $id );
+    $form->method('post');
+}
+
+sub create_link_form : Local Form {
+    my ( $self, $c , $form ) = @_;
+
+    my ( $name, $id,$url,$description ) = "";
+    if ( defined $c->stash->{link} ) {
+        $name = $c->stash->{link}->name;
+        $url  = $c->stash->{link}->url;
+        $description = $c->stash->{link}->description;
+        $id   = $c->stash->{link}->id;
+    }
+
+    $form->field(
+        name     => 'name',
+        required => 1,
+        label    => 'Displayed Name',
+        size     => 40,
+        value    => $name
+    );
+    
+    $form->field(
+        name     => 'url',
+        required => 1,
+        label    => 'Url',
+        size     => 40,
+        value    => $url
+    );
+    
+    $form->field(
+        name     => 'description',
+        required => 1,
+        label    => 'Description',
+        size     => 40,
+        value    => $description
+    );
+
+    # make sure no trailing slashes happen.
+    
+    $id = '/' . $id if length($id)>0;
+    $form->action( '/admin/link_commit' . $id );
+    $form->method('post');
+}
+
+
+sub create_user_form : Local Form {
+    my ( $self, $c , $form ) = @_;
+    my ( $name, $password, $website, $email, $id ) = "";
+    if ( defined $c->stash->{user} ) {
+        $name     = $c->stash->{user}->name;
+        $password = $c->stash->{user}->password;
+        $website  = $c->stash->{user}->website;
+        $email    = $c->stash->{user}->email;
+        $id       = $c->stash->{user}->id;
+    }
+
+    # $self->formbuilder->field(
+    # 	name		=> 'picture',
+    # 	required 	=> 0,
+    # 	label		=> 'User Picture',
+    # 	type		=> 'file',
+    # );
+    $form->field(
+        name     => 'name',
+        required => 1,
+        label    => 'User Name',
+        size     => 25,
+        value    => $name
+    );
+    $form->field(
+        name     => 'password',
+        required => 1,
+        type     => 'password',
+        label    => 'Password',
+        size     => 25,
+        value    => $password
+    );
+    $form->field(
+        name     => 'website',
+        required => 1,
+        label    => 'Website',
+        size     => 25,
+        value    => $website
+    );
+    $form->field(
+        name     => 'email',
+        required => 1,
+        label    => 'E-Mail',
+        validate => 'EMAIL',
+        size     => 25,
+        value    => $email
+    );
+    $form->enctype('multipart/form-data');
+    # make sure no trailing slashes happen.
+    $id = '/' . $id if length($id)>0;
+    $form->action( '/admin/user_commit' . $id );
+    $form->method('post');
+}
+
+sub create_submit_form : Local Form {
+    my ( $self, $c , $form ) = @_;
+
+    my ( $subject, $body, $id, @selected_cat, @selected_blog ) = "";
+    if ( defined $c->stash->{article} ) {
+        $subject = $c->stash->{article}->subject();
+        $body    = $c->stash->{article}->body();
+        $id      = $c->stash->{article}->id();
+        foreach my $cat ( $c->stash->{article}->categories ) {
+            push @selected_cat, $cat->name;
+        }
+    }
+
+    my @cats = ();
+    foreach my $cat ( @{ $c->stash->{categories} } ) {
+        push @cats, $cat->name;
+    }
+
+    # my @blogs = ();
+    # foreach my $blog ( $c->user->blogs ) {
+    #     push @blogs, $blog->name;
+    # }
+
+    $form->field(
+        name     => 'subject',
+        label    => 'Subject',
+        size     => 40,
+		required => 1,
+        value    => $subject,
+    );
+    $form->field(
+        name     => 'categories',
+        required => 1,
+        label    => 'Categories',
+        multiple => 1,
+        options  => \@cats,
+        value    => \@selected_cat,
+    );
+
+    #     $self->formbuilder->field(
+    #         name     => 'blogs',
+    #         required => 1,
+    #         label    => 'Blogs',
+    #         multiple => 1,
+    #         options  => \@blogs,
+    # value 	 => \@selected_blog,
+    #     );
+    $form->field(
+        name                 => 'body',
+        required             => 1,
+        type                 => 'textarea',
+        label                => 'Body',
+        value                => $body
+    );
+    # make sure no trailing slashes happen.
+    $id = '/' . $id if length($id)>0;
+    $form->action( '/admin/commit' . $id );
+    $form->method('post');
+}
+
+sub category : Local Form {
+    my ( $self, $c, $id ) = @_;
+    if ( defined $id ) {
+        $c->stash->{category} = $c->model('Typeface::Categories')->find($id);
+    }
+    $c->forward('/admin/create_category_form',[$self->formbuilder]);
+    $c->stash->{template} = 'category.tt2';
+}
+
+sub page_commit : Local Form {
+    my ( $self, $c, $id ) = @_;
+
+    if ( $self->formbuilder->validate ) {
+        my $page;
+        if ( defined $id ) {
+            $page = $c->model('Typeface::Pages')->find($id);
+        }
+        else {
+            $page = $c->model('Typeface::Pages')->new( {} );
+        }
+        $page->name( $c->req->params->{name} );
+        $page->body( $c->req->params->{body} );
+
+        if ( $c->req->params->{display_sidebar} eq "Yes" ) {
+            $page->display_sidebar(1);
+        }
+        else {
+            $page->display_sidebar(0);
+        }
+
+        if ( $c->req->params->{display_in_drawer} eq "Yes" ) {
+            $page->display_in_drawer(1);
+        }
+        else {
+            $page->display_in_drawer(0);
+        }
+
+        $page->insert_or_update();
+
+        $c->res->redirect('/admin');
+    }
+}
+
+sub category_commit : Local Form {
+    my ( $self, $c, $id ) = @_;
+
+    if ( $self->formbuilder->validate && $self->formbuilder->submitted ) {
+        my $category;
+        if ( defined $id ) {
+            $category = $c->model('Typeface::Categories')->find($id);
+        }
+        else {
+            $category = $c->model('Typeface::Categories')->new( {} );
+        }
+        $category->name( $c->req->params->{name} );
+        $category->insert_or_update();
+
+        $c->res->redirect('/admin');
+    }
+}
+
+sub link_commit : Local Form {
+    my ( $self, $c, $id ) = @_;
+
+    if ( $self->formbuilder->validate && $self->formbuilder->submitted ) {
+        my $link;
+        if ( defined $id ) {
+            $link = $c->model('Typeface::Links')->find($id);
+        }
+        else {
+            $link = $c->model('Typeface::Links')->new( {} );
+        }
+        $link->name( $c->req->params->{name} );
+        $link->url( $c->req->params->{url} );
+        $link->description( $c->req->params->{description} );
+        $link->insert_or_update();
+
+        $c->res->redirect('/admin');
+    }
+}
+
+sub page : Local Form {
+    my ( $self, $c, $id ) = @_;
+    if ( defined $id ) {
+        $c->stash->{page} = $c->model('Typeface::Pages')->find($id);
+    }
+
+    $c->forward('/admin/create_page_form',[$self->formbuilder]);
+    $c->stash->{template} = 'page.tt2';
+}
+
+sub link : Local Form {
+    my ( $self, $c, $id ) = @_;
+    if ( defined $id ) {
+        $c->stash->{link} = $c->model('Typeface::Links')->find($id);
+    }
+
+    $c->forward('/admin/create_link_form',[$self->formbuilder]);
+    $c->stash->{template} = 'link.tt2';
+}
+
+sub user : Local Form {
+    my ( $self, $c, $id ) = @_;
+    if ( defined $id ) {
+        $c->stash->{user} = $c->model('Typeface::Users')->find($id);
+    }
+    
+    $c->forward('/admin/create_user_form',[$self->formbuilder]);
+    $c->stash->{template} = 'user.tt2';
+}
+
+sub user_commit : Local Form {
+    my ( $self, $c, $id ) = @_;
+
+    if ( $self->formbuilder->validate && $self->formbuilder->submitted ) {
+        my $user;
+
+# my $home = $c->config->{home};
+# my $file = $c->req->params->{picture};
+# my $username = $c->user->name;
+# $c->req->uploads->{picture}->copy_to("$home/root/static/users/$username.jpg");
+#
+#
+# my $t = new Image::Thumbnail(
+#                 module     => 'GD',
+#                 size       => 55,
+#                 create     => 1,
+#                 input      => "$home/root/static/users/$username.jpg",
+#                 outputpath => "$home/root/static/users/thumb_$username.jpg",
+#         );
+#
+
+        if ( defined $id ) {
+            $user = $c->model('Typeface::Users')->find($id);
+        }
+        else {
+            $user = $c->model('Typeface::Users')->new( {} );
+        }
+        $user->name( $c->req->params->{name} );
+        $user->password( $c->req->params->{password} );
+        $user->email( $c->req->params->{email} );
+        $user->website( $c->req->params->{website} );
+        $user->insert_or_update();
+
+        $c->res->redirect('/admin');
+    }
+}
+
+sub index : Local Form {
+    my ( $self, $c ) = @_;
+
+    #$c->log->info('HOME ' . $c->config->{home});
+    my @articles = $c->model('Typeface::Articles')->get_latest_articles();
+    my @categories =
+      $c->model('Typeface::Categories')->all();
+    my @users = $c->model('Typeface::Users')->all();
+    my @pages = $c->model('Typeface::Pages')->all();
+    my @links = $c->model('Typeface::Links')->all();
+
+    #my @blogs = $c->user->blogs->all();
+
+    $c->stash->{articles}   = [@articles];
+    $c->stash->{categories} = [@categories];
+    $c->stash->{users}      = [@users];
+    $c->stash->{alinks} = [@links];
+    $c->stash->{apages} = [@pages];
+
+    # $c->stash->{blogs}      = [@blogs];
+
+    $c->forward('/admin/create_submit_form',[$self->formbuilder]);
+    $c->stash->{template} = 'index.tt2';
+}
+
+sub edit : Local Form {
+    my ( $self, $c, $id ) = @_;
+
+    $c->stash->{article} = $c->model('Typeface::Articles')->find($id);
+    $c->stash->{categories} =
+      [ $c->model('Typeface::Categories')->all() ];
+
+    $c->forward('/admin/create_submit_form',[$self->formbuilder]);
+    $c->stash->{template} = 'entry.tt2';
+}
+
+sub destroy : Local {
+    my ( $self, $c, $obj, $id ) = @_;
+
+    $c->model( 'Typeface::' . $obj )->find($id)->delete();
+    $c->forward( 'submit', 'cache_refresh' );
+
+    $c->flash->{notice} = "Deleted.";
+    $c->res->redirect('/admin');
+    $c->stash->{template} = 'index.tt2';
+}
+
+sub commit : Local Form {
+    my ( $self, $c, $id ) = @_;
+    if ( $self->formbuilder->validate && $self->formbuilder->submitted) {
+        $c->stash->{template} = 'commit.tt2';
+        $self->save_article(
+            $c,
+            {
+                id         => $id,
+                subject    => $c->req->params->{subject},
+                body       => $c->req->params->{body},
+                categories => $c->req->params->{categories},
+            }
+        );
+        $c->res->redirect('/admin');
+    }
+    else {
+        $c->res->redirect('/admin');
+    }
+
+    $c->res->body('stub');
+}
+
+sub attach_article_to_categories {
+    my ( $self, $c, $article, $categories ) = @_;
+
+    my @final_list = ();
+
+    # if its an array do a scan if not , just grab the name
+    if ( ref($categories) eq 'ARRAY' ) {
+        for my $a (@$categories) {
+            for my $cat ($a) {
+                my $category =
+                  $c->model('Typeface::Categories')->search( name => $cat )
+                  ->first();
+                push @final_list, $category;
+
+               #$article->add_to_categories($category) if ( defined $category );
+            }
+        }
+    }
+    else {
+        my $category =
+          $c->model('Typeface::Categories')->search( name => $categories )
+          ->first();
+        push @final_list, $category if ( defined $category );
+    }
+    $article->set_categories(@final_list) if scalar(@final_list);
+}
+
+sub save_article : Local {
+    my ( $self, $c, $contents ) = @_;
+
+    my $commit;
+    if ( defined $contents->{id} ) {
+        $commit = $c->model('Typeface::Articles')->find( $contents->{id} );
+    }
+    else {
+        $commit = $c->model('Typeface::Articles')->new( {} );
+    }
+    $commit->subject( $contents->{subject} );
+    $commit->body( $contents->{body} );
+    my $user =
+      $c->model('Typeface::User')->search( { name => $c->user->name } )
+      ->first();
+    $commit->user($user);
+    $commit->insert_or_update();
+    $self->attach_article_to_categories( $c, $commit, $contents->{categories} );
+
+    $c->forward( 'submit', 'cache_refresh', [$commit] );
+
+    return $commit;
+}
+
+sub end : Private {
+    my ( $self, $c ) = @_;
+    
+    return 1 if $c->req->method eq 'HEAD';
+    return 1 if length( $c->response->body );
+    return 1 if scalar @{ $c->error } && !$c->stash->{template};
+    return 1 if $c->response->status =~ /^(?:204|3\d\d)$/;
+    
+    $c->forward('ADMIN');
+}
+
+
+1;

Added: trunk/examples/typeface/lib/Typeface/Controller/Ajax.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/Controller/Ajax.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/Controller/Ajax.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,108 @@
+package Typeface::Controller::Ajax;
+
+use strict;
+use warnings;
+use base 'Catalyst::Controller';
+
+=head1 NAME
+
+Typeface::Controller::Ajax - Catalyst Controller
+
+=head1 DESCRIPTION
+
+Catalyst Controller.
+
+=head1 METHODS
+
+=cut
+
+=head2 index 
+
+=cut
+
+sub check_articles : Local {
+    my ( $self, $c ) = @_;
+
+    my @articles = $c->model('Typeface::Articles')->search(
+        {
+            -or => {
+                subject => { 'ilike' => '%' . $c->req->params->{field} . '%' },
+                body    => { 'ilike' => '%' . $c->req->params->{field} . '%' }
+            }
+        }
+    )->all();
+
+    my @out = ();
+    push @out, '<div align="center">';
+    foreach my $article (@articles) {
+        push @out,
+          '<a href="/view/'
+          . $c->nifty_txt_to_url( $article->subject() ) . '">'
+          . $article->subject()
+          . '</a><br/>';
+    }
+    push @out, '</div>';
+
+    $c->res->body( join( ' ', @out ) );
+}
+
+sub sort_by : Local {
+    my ( $self, $c ) = @_;
+
+	my @cats;
+    my @out = ();
+	if($c->req->params->{field} =~ /alpha/) {
+    @cats =
+      $c->model('Typeface::Categories')->search( undef, { order_by => 'name' } )
+      ->all();
+	}
+	else {
+	    @cats =
+	      $c->model('Typeface::Categories')->search( undef, { order_by => 'id' } )
+	      ->all();		
+	}
+
+    push @out, '<ul>';
+    foreach my $cat (@cats) {
+        push @out,
+          "<li><a title='"
+          . $cat->name()
+          . "' href='/category/"
+          . $c->nifty_txt_to_url( $cat->name() ) . "'>"
+          . $cat->name()
+          . "</a></li>";
+    }
+    push @out, '</ul>';
+
+    $c->res->body( join( '', @out ) );
+}
+
+sub help_complete_combobox : Local {
+    my ( $self, $c, $class_name, $field_name ) = @_;
+
+    my @class_instances =
+      $c->model( 'Typeface::' . $class_name )
+      ->search(
+        { $field_name => { 'ilike' => $c->req->params->{field} . '%' } } )
+      ->all();
+
+    my @out;
+    foreach my $item (@class_instances) {
+        push @out, [ '' . $item->$field_name . '' ];
+    }
+    $c->stash->{result} = [@out];
+    $c->forward('JSON');
+}
+
+=head1 AUTHOR
+
+Victor Igumnov
+
+=head1 LICENSE
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+1;

Added: trunk/examples/typeface/lib/Typeface/Controller/Feed.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/Controller/Feed.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/Controller/Feed.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,96 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package Typeface::Controller::Feed;
+
+use strict;
+use warnings;
+use base 'Catalyst::Controller';
+use XML::Feed;
+use Text::Textile qw(textile);
+
+sub comments : Local {
+    my ( $self, $c, $subject ) = @_;
+
+    my $feed = XML::Feed->new('RSS');
+    $feed->title( $c->config->{name} . ' RSS' );
+    $feed->link( $c->uri_for('/') );
+    $feed->description($c->config->{name} . ' RSS Feed');
+
+    my @comments;
+    if ( !defined $subject ) {
+        @comments =
+          $c->model('Typeface::Comments')->all();
+    }
+    else {
+        @comments =
+          $c->model('Typeface::Articles')
+          ->search(
+            { subject => { like => $c->nifty_url_to_query($subject) } } )
+          ->first()->comments();
+    }
+
+    for ( my $i = 0 ; $i < scalar(@comments) ; $i++ ) {
+        my $feed_entry = XML::Feed::Entry->new('RSS');
+        $feed_entry->title( $comments[$i]->name()
+              . "'s comment "
+              . $comments[$i]->created_at->ymd() );
+        my $url = $c->nifty_txt_to_url( $comments[$i]->article()->subject() );
+        $feed_entry->link( $c->uri_for('/view/' . $url . '#comments') );
+        $feed_entry->summary(
+            textile( $comments[$i]->comment() ) );
+        $feed_entry->issued( $comments[$i]->created_at() );
+        $feed->add_entry($feed_entry);
+    }
+
+    $c->res->content_type('application/rss+xml');
+    $c->res->body( $feed->as_xml );
+}
+
+sub articles : Local {
+    my ( $self, $c, $cat ) = @_;
+
+    my $feed = XML::Feed->new('RSS');
+    $feed->title( $c->config->{name} . ' RSS' );
+    $feed->link( $c->uri_for('/') );
+    $feed->description($c->config->{name} . ' RSS Feed');
+
+    my @articles;
+    if ( !defined $cat ) {
+        @articles = $c->model('Typeface::Articles')->get_latest_articles();
+    }
+    else {
+        @articles =
+          $c->model('Typeface::Categories')
+          ->search( { name => { like => $c->nifty_url_to_query($cat) } } )
+          ->first()->articles();
+    }
+
+    for ( my $i = 0 ; $i < scalar(@articles) ; $i++ ) {
+        my $feed_entry = XML::Feed::Entry->new('RSS');
+        $feed_entry->title( $articles[$i]->subject() );
+        my $url = $c->nifty_txt_to_url( $articles[$i]->subject() );
+        $feed_entry->link( $c->uri_for( '/view', $url ) );
+        $feed_entry->summary( textile( $articles[$i]->body() ) );
+        $feed_entry->issued( $articles[$i]->created_at() );
+        $feed->add_entry($feed_entry);
+    }
+
+    $c->res->content_type('application/rss+xml');
+    $c->res->body( $feed->as_xml );
+}
+
+1;

Added: trunk/examples/typeface/lib/Typeface/Controller/Login.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/Controller/Login.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/Controller/Login.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,74 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package Typeface::Controller::Login;
+
+use strict;
+use warnings;
+use base 'Catalyst::Controller';
+use Data::Dumper;
+
+
+#since this will be forwarded to a method with a form
+sub login_as : Local {
+    my ( $self, $c ) = @_;
+
+    my $login    = $c->req->params->{login};
+    my $password = $c->req->params->{password};
+
+	$c->log->info('logging in!');
+    if ( $c->login( $login, $password ) ) {
+        $c->res->redirect('/admin/index');
+		return;
+    }
+    else {
+        $c->flash->{notice} = "Wrong password or name.";
+        $c->res->redirect('/login');
+		return;
+    }
+}
+
+sub index : Local {
+    my ( $self, $c ) = @_;
+	$c->stash->{template} = 'login_as.tt2';
+}
+
+sub logout : Local {
+    my ( $self, $c ) = @_;
+
+    $c->logout;
+    $c->res->redirect('/');
+    $c->res->body('stub');
+}
+
+sub info : Local {
+    my ( $self, $c ) = @_;
+	$c->stash->{template} = 'shared/info.tt2';
+}
+
+sub end : Private {
+    my ( $self, $c ) = @_;
+    
+    return 1 if $c->req->method eq 'HEAD';
+    return 1 if length( $c->response->body );
+    return 1 if scalar @{ $c->error } && !$c->stash->{template};
+    return 1 if $c->response->status =~ /^(?:204|3\d\d)$/;
+    
+    $c->forward('ADMIN');
+}
+
+
+1;

Added: trunk/examples/typeface/lib/Typeface/Controller/MetaBond.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/Controller/MetaBond.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/Controller/MetaBond.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,23 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package Typeface::Controller::MetaBond;
+
+use strict;
+use warnings;
+use base 'Catalyst::Controller';
+
+1;

Added: trunk/examples/typeface/lib/Typeface/Controller/MetaWeblogRPC.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/Controller/MetaWeblogRPC.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/Controller/MetaWeblogRPC.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,193 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package Typeface::Controller::MetaWeblogRPC;
+
+use strict;
+use warnings;
+use base 'Catalyst::Controller';
+
+sub getBlogPosts : XMLRPCPath('/metaWeblog/getRecentPosts') {
+    my ( $self, $c, $blogid, $login, $password, $number_of_posts ) = @_;
+
+    if ( $c->login( $login, $password ) ) {
+
+        my @articles =
+          $c->model('Typeface::Articles')->get_latest_articles($number_of_posts);
+
+        my @returnXML;
+        for ( my $i = 0 ; $i < scalar(@articles) ; $i++ ) {
+            my $url = $c->nifty_txt_to_url( $articles[$i]->subject() );
+            $url = $c->uri_for( 'view', $url );
+
+            my @cats = ();
+            foreach my $cat ( $articles[$i]->categories ) {
+                push @cats, $cat->name;
+            }
+
+            my %post = (
+                title       => $articles[$i]->subject,
+                description => $articles[$i]->body,
+                userid      => $articles[$i]->user->name,
+                'link'      => $url,
+                categories  => [@cats],
+                postid      => $articles[$i]->id,
+                dateCreated => $articles[$i]->created_at->datetime,
+            );
+
+            push @returnXML, \%post;
+        }
+        $c->stash->{xmlrpc} = [@returnXML];
+    }
+
+    $c->res->body('stub');
+}
+
+sub getBlogCategories : XMLRPCPath('/metaWeblog/getCategories') {
+    my ( $self, $c, $blogid, $login, $password ) = @_;
+
+    my @returnXML;
+    if ( $c->login( $login, $password ) ) {
+        my @cat =
+          $c->model('Typeface::Categories')->search( undef, {} )->all();
+        for ( my $i = 0 ; $i < scalar(@cat) ; $i++ ) {
+            my $url = $cat[$i]->name();
+            $url = $c->nifty_txt_to_url($url);
+
+            # FIXME: $url = $c->uri_for( 'view', $url ); clean it up
+            $url = $c->uri_for ("category/" . $url);
+
+            my %category = (
+                categoryId   => $cat[$i]->id,
+                categoryName => $cat[$i]->name,
+                description  => $cat[$i]->name,
+                htmlUrl      => $url,
+            );
+            push @returnXML, \%category;
+        }
+
+        $c->stash->{xmlrpc} = [@returnXML];
+    }
+
+    $c->res->body('stub');
+}
+
+sub getUsersBlogs : XMLRPCPath('/blogger/getUsersBlogs') {
+    my ( $self, $c, $hash, $login, $password ) = @_;
+
+    $c->stash->{xmlrpc} = [
+        {
+            url      => $c->uri_for('/'),
+            blogid   => 1,
+            blogName => $c->uri_for('/'),
+            isAdmin  => 1
+        }
+    ];
+
+    $c->res->body('stub');
+}
+
+sub deletePost : XMLRPCPath('/blogger/deletePost') {
+    my ( $self, $c, $hash, $post_to_delete, $login, $password, $blogid ) = @_;
+    if ( $c->login( $login, $password ) ) {
+        $c->log->info( 'post to delete: ' . $post_to_delete );
+        $c->model('Typeface::Articles')->find($post_to_delete)->delete();
+        $c->forward( 'submit', 'cache_refresh' );   # send it off to clear cache
+    }
+    $c->res->body('stub');
+}
+
+sub newPost : XMLRPCPath('/metaWeblog/newPost') {
+    my ( $self, $c, $blogid, $login, $password, $post ) = @_;
+
+    if ( $c->login( $login, $password ) ) {
+        $c->log->info('Posting...');
+        my $article = $c->forward(
+            'admin',
+            'save_article',
+            [
+                {
+                    subject    => $post->{title},
+                    body       => $post->{description},
+                    categories => $post->{categories},
+                }
+            ]
+        );
+        $c->stash->{xmlrpc} = $article->id();
+    }
+
+    $c->res->body('stub');
+}
+
+sub getPost : XMLRPCPath('/metaWeblog/getPost') {
+    my ( $self, $c, $postid, $login, $password ) = @_;
+
+    if ( $c->login( $login, $password ) ) {
+        my $article = $c->model('Typeface::Articles')->find($postid);
+
+        my $url = $c->nifty_txt_to_url( $article->subject() );
+        $url = $c->uri_for( 'view', $url );
+        $c->stash->{xmlrpc} = {
+            title       => $article->subject,
+            description => $article->body,
+            userid      => $article->user->name,
+            'link'      => $url,
+            postid      => $article->id,
+            dateCreated => $article->created_at->datetime
+        };
+    }
+    $c->res->body('stub');
+}
+
+sub getUserInfo : XMLRPCPath('/blogger/getUserInfo') {
+    my ( $self, $c, $appkey, $login, $password ) = @_;
+
+    if ( $c->login( $login, $password ) ) {
+        $c->stash->{xmlrpc} = {
+            nickname  => $c->user->name,
+            userid    => $c->user->id,
+            email     => $c->user->name,
+            url       => $c->uri_for($c->user->name),
+            lastname  => $c->user->name,
+            firstname => $c->user->name,
+        };
+    }
+    $c->res->body('stub');
+}
+
+sub editPost : XMLRPCPath('/metaWeblog/editPost') {
+    my ( $self, $c, $postid, $login, $password, $post ) = @_;
+
+    if ( $c->login( $login, $password ) ) {
+        my $article = $c->forward(
+            'admin',
+            'save_article',
+            [
+                {
+                    id         => $postid,
+                    subject    => $post->{title},
+                    body       => $post->{description},
+                    categories => $post->{categories},
+                }
+            ]
+        );
+		$c->stash->{xmlrpc} = $article->id();
+    }
+
+    $c->res->body('stub');
+}
+
+1;

Added: trunk/examples/typeface/lib/Typeface/Controller/Root.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/Controller/Root.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/Controller/Root.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,229 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package Typeface::Controller::Root;
+use strict;
+use warnings;
+use base 'Catalyst::Controller::FormBuilder';
+use HTML::CalendarMonthSimple;
+
+__PACKAGE__->config->{namespace} = '';
+
+sub begin : Private {
+    my ( $self, $c ) = @_;
+
+    $c->stash->{pages} =
+       [ $c->model('Typeface::Pages')->search( display_in_drawer => 1 )->all() ];
+    $c->stash->{activelink} =
+      { home => 'activelink' };    # set it to home unless overridden.
+
+	$c->stash->{sidebar} = 1;
+	
+	$c->stash->{xmlrpc}=undef;
+}
+
+
+sub category : Local {
+    my ( $self, $c, $category ) = @_;
+
+    my $cat =
+      $c->model('Typeface::Categories')
+      ->search( { name => { like => $c->nifty_url_to_query($category) } } )
+      ->first();
+    $c->stash->{articles} = [ $cat->articles() ];
+	$c->stash->{template} = 'index.tt2';
+    $c->stash->{rss}      = $cat->name();
+}
+
+sub page : Local {
+    my ( $self, $c, $what ) = @_;
+
+    my $page =
+      $c->model('Typeface::Pages')
+      ->search( { name => { like => $c->nifty_url_to_query($what) } } )
+      ->first();
+
+    $c->stash->{sidebar} = undef unless $page->display_sidebar();
+    $c->stash->{page} = $page;
+    $c->stash->{title} = $page->name;
+    my $name = $c->nifty_txt_to_url( $page->name );
+    $c->stash->{activelink} = { $name => 'activelink' };
+	$c->stash->{template} = 'page.tt2';
+}
+
+sub blog : Local {
+    my ( $self, $c, $blog ) = @_;
+
+    #TODO add blog/some_group_blog
+    $c->res->body('Not implemented yet.');
+}
+
+sub blogs : Local {
+    my ( $self, $c ) = @_;
+
+    my @blogs = $c->model('Typeface::Blogs')->all();
+    $c->stash->{blogs}    = [@blogs];
+	$c->stash->{template} = 'blogs.tt2';
+    $c->forward( $c->view('REMOTE') );
+
+    #$c->res->body('<p>Multi User Blogs not implemented yet.</p>')
+}
+
+sub archived : Local {
+    my ( $self, $c, $year, $month, $day ) = @_;
+    my @articles =
+      $c->model('Typeface::Articles')->archived( $year, $month, $day );
+
+    $c->stash->{articles} = [@articles];
+	$c->stash->{template} = 'index.tt2';
+}
+
+sub default : Local {
+    my ( $self, $c ) = @_;
+	
+    my @articles = $c->model('Typeface::Articles')->get_latest_articles();
+
+    $c->stash->{articles} = [@articles];
+	$c->stash->{template} = 'index.tt2';
+}
+
+sub categories : Local {
+    my ( $self, $c ) = @_;
+
+    my @categories =
+      $c->model('Typeface::Categories')->all();
+    $c->stash->{categories} = [@categories];
+}
+
+sub links : Local {
+    my ( $self, $c ) = @_;
+    my @links =
+      $c->model('Typeface::Links')
+      ->search( undef, { order_by => 'id desc' } )->all();
+
+
+    $c->stash->{links} = [@links];
+}
+
+sub calendar : Local {
+    my ( $self, $c ) = @_;
+
+    
+	my $dt = DateTime->now();
+    my $cal = new HTML::CalendarMonthSimple(
+        'year'  => $dt->year,
+        'month' => $dt->month
+    );
+    $cal->border(0);
+    $cal->width(50);
+	$cal->headerclass('month_date');
+    $cal->showweekdayheaders(0);
+    
+    my @articles =
+      $c->model('Typeface::Articles')->from_month( $dt->month );
+      
+    foreach my $article (@articles) {
+        my $location = '/archived/' . $article->created_at->year() . '/' 
+                                    . $article->created_at->month() . '/' 
+                                    . $article->created_at->mday();
+        $cal->setdatehref( $article->created_at->mday() , $location );
+    }
+
+    $c->stash->{calendar} = $cal->as_HTML;
+}
+
+sub archives : Local {
+    my ( $self, $c ) = @_;
+
+    my @articles =
+      $c->model('Typeface::Articles')->all();
+
+    unless (@articles) {
+        $c->stash->{archives} = "<p>No Articles in Archive!</p>";
+        return;
+    }
+
+    my $months;
+    foreach my $article (@articles) {
+        my $month = $article->created_at()->month_name();
+        my $year  = $article->created_at()->year();
+        my $key   = "$year $month";
+        if ( (defined $months->{$key}->{count}) && ($months->{$key}->{count} > 0) ) {
+            $months->{$key}->{count} += 1;
+        }
+        else {
+            $months->{$key}->{count} = 1;
+            $months->{$key}->{year} = $year;
+            $months->{$key}->{month} = $article->created_at()->month();
+        }
+    }
+
+    my @out;
+    while ( my ( $key, $value ) = each(%{$months}) ) {
+        push @out,"<li><a href='/archived/$value->{year}/$value->{month}'>$key</a> <span class='special_text'>($value->{count})</span></li>";
+    }
+    $c->stash->{archives} = join(' ', at out);
+}
+
+
+sub test : Local Form {
+    my ( $self, $c ) = @_;
+    #$self->formbuilder->fields([qw/blah blah2/]);
+    $self->formbuilder->field(name => 'blah', label=>'eh', required=>1);
+    $c->stash->{sidebar} = 0;
+    # $c->stash->{template} = 'page.tt2';
+    $c->stash->{template} = 'index.tt2';
+    # $c->stash->{template} = 'page.tt2';
+}
+
+
+
+
+sub enable_sidebar : Local {
+    my ( $self, $c ) = @_;
+
+	$c->forward('/categories');
+	$c->forward('/archives');
+	$c->forward('/links');
+	$c->forward('/calendar');
+}
+
+sub auto : Private {
+    my ( $self, $c ) = @_;
+
+    $c->set_nifty_params(
+        [
+            [ 'ul#error_content h3', 'top' ]
+        ]
+    );
+
+
+    return 1;
+}
+
+sub end : Private {
+    my ( $self, $c ) = @_;
+    
+    return 1 if $c->req->method eq 'HEAD';
+    return 1 if length( $c->response->body );
+    return 1 if scalar @{ $c->error } && !$c->stash->{template};
+    return 1 if $c->response->status =~ /^(?:204|3\d\d)$/;
+
+	$c->forward('/enable_sidebar') if $c->stash->{sidebar};
+    $c->forward('TT');
+}
+
+1;

Added: trunk/examples/typeface/lib/Typeface/Controller/Search.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/Controller/Search.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/Controller/Search.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,42 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package Typeface::Controller::Search;
+
+use strict;
+use warnings;
+use base 'Catalyst::Controller';
+
+sub search : Global {
+    my ( $self, $c, $phrase ) = @_;
+
+	if(!defined $phrase)
+	{
+		$phrase = $c->req->params->{phrase};
+	}
+
+    my @finds = $c->model('Typeface::Articles')->search(
+		[
+			subject => { like => "%$phrase%" },
+		    body    => { like => "%$phrase%" },
+		]
+    )->all();
+
+    $c->stash->{articles} = [@finds];
+	$c->stash->{template} = 'index.tt2';
+}
+
+1;

Added: trunk/examples/typeface/lib/Typeface/Controller/Submit.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/Controller/Submit.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/Controller/Submit.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,155 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package Typeface::Controller::Submit;
+
+use strict;
+use warnings;
+use base 'Catalyst::Controller::FormBuilder::DBIC';
+
+sub captcha : Local {
+    my ( $self, $c ) = @_;
+    $c->create_captcha();
+}
+
+sub test : Local Form {
+    my ( $self, $c, $id ) = @_;
+    $id = 0 unless defined $id;
+    
+    if($self->formbuilder->validate && $self->formbuilder->submitted) {
+    }
+    else {
+        my $article = $c->model('Typeface::Articles')->find_or_new({id=>$id});
+        $self->create_form({
+            object  => $article,
+            action  => '/submit'
+        });
+    }
+    
+    $c->stash->{template} = 'test.tt2';
+}
+
+
+sub create_comment_form : Local Form {
+    my ( $self, $c, $form , $id ) = @_;
+
+    $form->field(
+        name     => 'name',
+        required => 1,
+        label    => 'Name',
+        size     => 25
+    );
+    $form->field( name => 'email', label => 'Email',   size => 25 );
+    $form->field( name => 'url',   label => 'Website', size => 25 );
+  
+  	$form->field(
+        name     => 'comment',
+        type     => 'textarea',
+        required => 1,
+        label    => 'Body',
+        cols     => 30,
+        rows     => 10
+    );
+
+    $form->field(
+        name     => 'verification',
+        label    => 'Verification',
+        size     => 25,
+        required => 1
+    );
+    # make sure no trailing slashes happen.
+    $id = '/' . $id;
+    $form->action( '/submit/comment' . $id );
+    $form->method('post');
+
+}
+
+sub view : Global Form {
+    my ( $self, $c, $id ) = @_;
+
+
+    my $article =
+      $c->model('Typeface::Articles')
+      ->search( { 'subject' => { like => $c->nifty_url_to_query($id) } } )
+      ->first();
+
+    $c->stash->{articles} = $article;
+    $c->stash->{title} = $article->subject();
+    $c->stash->{comments} = [ $article->comments->all() ];
+    
+    $c->forward('/submit/create_comment_form',[$self->formbuilder,$article->id]);
+
+    # re-using my index view, might as well
+    #to keep a consistent view through out the site.
+	$c->stash->{template} = 'index.tt2';
+}
+
+sub comment : Local Form {
+    my ( $self, $c, $from, $id ) = @_;
+
+    my $commit;
+    my $article = $c->model('Typeface::Articles')->find($from);
+    if (   $self->formbuilder->validate
+        && $c->validate_captcha( $c->req->param('verification') ) )
+    {
+        if ( defined $id ) {
+            $commit = $c->model('Typeface::Comments')->find($id);
+        }
+        else {
+            $commit = $c->model('Typeface::Comments')->new( {} );
+            $commit->article($article);
+        }
+        $commit->name( $c->req->params->{name} );
+        $commit->email( $c->req->params->{email} );
+		if ($c->req->params->{url} !~ /http/i)
+		{
+			$commit->url( 'http://' . $c->req->params->{url} );
+		} else {
+        	$commit->url( $c->req->params->{url} );
+		}
+        $commit->comment( $c->req->params->{comment} );
+        $commit->insert_or_update();
+
+        $self->cache_refresh( $c, $article );
+        $c->res->redirect(
+            '/view/' . $c->nifty_txt_to_url( $article->subject ) );
+    }
+    else {
+        $c->flash->{notice}='Incorrect verification'
+          if ( !$c->validate_captcha( $c->req->param('verification') ) && $c->user);
+          $c->res->redirect(
+            '/view/' . $c->nifty_txt_to_url( $article->subject ) );
+    }
+
+    $c->res->body('stub');
+}
+
+sub cache_refresh {
+    my ( $self, $c, $item ) = @_;
+
+    #$c->cache->remove('front_page_articles');
+    $c->clear_cached_page('/');
+    if ( ref($item) eq "Typeface::Model::Typeface::Articles" ) {
+        $c->clear_cached_page(
+            '/view/' . $c->nifty_txt_to_url( $item->subject ) );
+    }
+    if ( ref($item) eq "Typeface::Model::Typeface::Pages" ) {
+        $c->clear_cached_page(
+            '/page/' . $c->nifty_txt_to_url( $item->name ) );
+    }
+}
+
+1;

Added: trunk/examples/typeface/lib/Typeface/Model/Typeface.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/Model/Typeface.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/Model/Typeface.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,47 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package Typeface::Model::Typeface;
+
+use strict;
+use base 'Catalyst::Model::DBIC::Schema';
+
+
+# ./script/typeface_create.pl model DB::Typeface DBIC::Schema DB::Typeface::Schema create=static "dbi:Pg:dbname=typeface;host=xxxx;user=xxxx;password=xxxxx"
+
+=head1 NAME
+
+DB::Typeface - Catalyst DBIC Schema Model
+=head1 SYNOPSIS
+
+See L<Typeface>
+
+=head1 DESCRIPTION
+
+L<Catalyst::Model::DBIC::Schema> Model using schema L<DB::Typeface::Schema>
+
+=head1 AUTHOR
+
+Victor Igumnov
+
+=head1 LICENSE
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+1;

Added: trunk/examples/typeface/lib/Typeface/View/ADMIN.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/View/ADMIN.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/View/ADMIN.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,61 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package Typeface::View::ADMIN;
+
+use strict;
+use base 'Catalyst::View::TT';
+use Template::Stash::XS;
+use Path::Class qw(dir);
+
+__PACKAGE__->config({
+	COMPILE_DIR => dir( Typeface->config->{home}, 'tmp') ,
+    STASH => Template::Stash::XS->new,
+    CATALYST_VAR => 'c',
+    INCLUDE_PATH => [
+        Typeface->path_to( 'root', 'admin' ),
+        Typeface->path_to( 'root', 'lib' ),
+    ],
+    PRE_PROCESS  => 'config/main',
+    WRAPPER      => 'site/admin_wrapper',
+    TIMER        => 0
+});
+
+=head1 NAME
+
+Typeface::View::TT - Catalyst TTSite View
+
+=head1 SYNOPSIS
+
+See L<Typeface>
+
+=head1 DESCRIPTION
+
+Catalyst TTSite View.
+
+=head1 AUTHOR
+
+Victor Igumnov
+
+=head1 LICENSE
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+1;
+

Added: trunk/examples/typeface/lib/Typeface/View/JSON.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/View/JSON.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/View/JSON.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,29 @@
+package Typeface::View::JSON;
+
+use strict;
+use base 'Catalyst::View::JSON';
+
+=head1 NAME
+
+EBusinessSphere::View::JSON - Catalyst JSON View
+
+=head1 SYNOPSIS
+
+See L<EBusinessSphere>
+
+=head1 DESCRIPTION
+
+Catalyst JSON View.
+
+=head1 AUTHOR
+
+Victor Igumnov
+
+=head1 LICENSE
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+1;

Added: trunk/examples/typeface/lib/Typeface/View/REMOTE.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/View/REMOTE.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/View/REMOTE.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,58 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package Typeface::View::REMOTE;
+
+use strict;
+use base 'Catalyst::View::TT';
+
+__PACKAGE__->config({
+    CATALYST_VAR => 'c',
+    INCLUDE_PATH => [
+        Typeface->path_to( 'root', 'src' ),
+        Typeface->path_to( 'root', 'lib' )
+    ],
+    PRE_PROCESS  => 'config/main',
+    WRAPPER      => 'site/remote_wrapper',
+    ERROR        => 'error.tt2',
+    TIMER        => 0
+});
+
+=head1 NAME
+
+Typeface::View::TT - Catalyst TTSite View
+
+=head1 SYNOPSIS
+
+See L<Typeface>
+
+=head1 DESCRIPTION
+
+Catalyst TTSite View.
+
+=head1 AUTHOR
+
+Victor Igumnov
+
+=head1 LICENSE
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+1;
+

Added: trunk/examples/typeface/lib/Typeface/View/TT.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface/View/TT.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface/View/TT.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,63 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package Typeface::View::TT;
+
+use strict;
+use base 'Catalyst::View::TT';
+use Template::Stash::XS;
+use Path::Class qw(dir);
+
+__PACKAGE__->config({
+	COMPILE_DIR => dir( Typeface->config->{home}, 'tmp') ,
+    STASH => Template::Stash::XS->new,
+    CATALYST_VAR => 'c',
+    INCLUDE_PATH => [
+        Typeface->path_to( 'root', 'src' ),
+        Typeface->path_to( 'root', 'lib' ),
+		Typeface->path_to( 'root', 'templates' , Typeface->config->{site}->{template}),
+		Typeface->path_to( 'root', 'shared'),
+    ],
+    PRE_PROCESS  => 'config/main',
+    WRAPPER      => 'site/wrapper',
+    TIMER        => 0
+});
+
+=head1 NAME
+
+Typeface::View::TT - Catalyst TTSite View
+
+=head1 SYNOPSIS
+
+See L<Typeface>
+
+=head1 DESCRIPTION
+
+Catalyst TTSite View.
+
+=head1 AUTHOR
+
+Victor Igumnov
+
+=head1 LICENSE
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+1;
+

Added: trunk/examples/typeface/lib/Typeface.pm
===================================================================
--- trunk/examples/typeface/lib/Typeface.pm	                        (rev 0)
+++ trunk/examples/typeface/lib/Typeface.pm	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,59 @@
+# Copyright (C) 2006  name of Victor Igumnov
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+package Typeface;
+
+use strict;
+use warnings;
+use Cwd;
+
+use Catalyst::Runtime '5.70';
+
+use Catalyst qw/
+Static::Simple
+
+ConfigLoader
+Nifty
+Captcha
+
+Cache::FileCache
+PageCache
+
+Session 
+Session::Store::File 
+Session::State::Cookie 
+
+Server
+Server::XMLRPC
+ProxyReplyAs
+
+Authentication 
+Authentication::Store::DBIC 
+Authentication::Credential::Password
+
+/;
+
+use Switch;
+use DateTime;
+
+__PACKAGE__->config->{static}->{ignore_extensions} = [qw/tt2 tt/];
+
+our $VERSION = '0.71';
+
+# Start the application
+__PACKAGE__->setup;
+
+1;

Added: trunk/examples/typeface/lighttpd.conf
===================================================================
--- trunk/examples/typeface/lighttpd.conf	                        (rev 0)
+++ trunk/examples/typeface/lighttpd.conf	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,56 @@
+# Default configuration file for the lighttpd web server
+# Start using ./script/server lighttpd
+
+server.bind = "0.0.0.0"
+server.port = 3001
+
+server.modules           = ( "mod_alias","mod_setenv","mod_fastcgi", "mod_scgi","mod_proxy" )
+
+server.pid-file          = CWD + "/tmp/pids/lighttpd.pid"
+server.document-root     = CWD + "/root"
+
+server.errorlog          = CWD + "/log/lighttpd.error.log"
+accesslog.filename       = CWD + "/log/lighttpd.access.log"
+
+
+
+# Change *-procs to 2 if you need to use Upload Progress or other tasks that
+# *need* to execute a second request while the first is still pending.
+# $HTTP["url"] !~ "^/static/" {
+#     fastcgi.server = (
+#                 "" => ( "Typeface" => (
+#                     "socket" => "/tmp/fcgi.sock",
+#                      "check-local" => "disable"
+#                  ))
+#            )
+# }
+
+$HTTP["url"] !~ "^/static/" {
+    proxy.server = (
+                "" => ( "Typeface" => (
+                    "host" => "127.0.0.1",
+					"port" => 3000,
+                     "check-local" => "disable"
+                 ))
+           )
+}
+
+
+mimetype.assign = (  
+  ".css"        =>  "text/css",
+  ".gif"        =>  "image/gif",
+  ".htm"        =>  "text/html",
+  ".html"       =>  "text/html",
+  ".jpeg"       =>  "image/jpeg",
+  ".jpg"        =>  "image/jpeg",
+  ".js"         =>  "text/javascript",
+  ".png"        =>  "image/png",
+  ".swf"        =>  "application/x-shockwave-flash",
+  ".txt"        =>  "text/plain"
+)
+
+# Making sure file uploads above 64k always work when using IE or Safari
+# For more information, see http://trac.lighttpd.net/trac/ticket/360
+$HTTP["useragent"] =~ "^(.*MSIE.*)|(.*AppleWebKit.*)$" {
+  server.max-keep-alive-requests = 0
+}


Property changes on: trunk/examples/typeface/lighttpd.conf
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/loader.pl
===================================================================
--- trunk/examples/typeface/loader.pl	                        (rev 0)
+++ trunk/examples/typeface/loader.pl	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,16 @@
+use lib './lib';
+use DB::Typeface::Schema;
+
+my $db = DB::Typeface::Schema->connect('dbi:SQLite:./mydb.db');
+
+if(!defined $db) {
+  print "Can't connect to database!\n";
+  exit(0);
+}
+
+use lib './lib';
+use DBIC::Dumper::YAML;
+use Data::Dumper;
+
+my $dumper = DBIC::Dumper::YAML->new();
+$dumper->load($db,'fixtures');

Added: trunk/examples/typeface/root/admin/category.tt2
===================================================================
--- trunk/examples/typeface/root/admin/category.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/admin/category.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1 @@
+[% FormBuilder.render %]
\ No newline at end of file

Added: trunk/examples/typeface/root/admin/commit.tt2
===================================================================
--- trunk/examples/typeface/root/admin/commit.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/admin/commit.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,3 @@
+<br /><br />
+<div style="margin: auto; text-align: center;"><h1><a href="/">Thanks!</a></h1></div>
+<br /><br />
\ No newline at end of file

Added: trunk/examples/typeface/root/admin/entry.tt2
===================================================================
--- trunk/examples/typeface/root/admin/entry.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/admin/entry.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,52 @@
+<script type="text/javascript">
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.Editor2");
+</script>
+
+<div class="padding">
+		[% FormBuilder.start %]
+      	<div id="form">
+        [% FOREACH field IN FormBuilder.fields %]
+		[% IF field.name == "categories" %]
+			<p>
+			<a href="#" onclick="toggle_cats(); return false;">Display Categories</a> 
+			<div id="select_cats" style="display: none;">
+	            [% field.tag %]
+			</div>
+			</p>
+		[% ELSIF field.name == "body" %]
+			<p>
+			<strong>Editor Type: </strong>
+			<select name="type" onChange="switch_editor(this.value);">
+				<option value="textile">Textile / Plain</option>
+				<option value="wysiwyg">WYSIWYG Editor</option>	
+			</select>
+			</p>
+			<p id="pborder" style="width: 800px;">
+				<textarea id="body" name="body" style="width: 800px; height: 300px;">[% field.value %]</textarea>
+				</p>
+			</p>
+		[% ELSE %]
+        <div id="[%- field.name -%]">
+          <div class="label">
+			[% IF field.required %]
+				<span><strong>[% field.label %]</strong></span>
+			[% ELSE %]
+				<span>[% field.label %]</span>
+			[% END %]
+          </div>
+          <div class="field">
+            [% field.tag %]
+          </div>
+        </div>
+		[% END %]
+        [% END %]
+        <div id="submit">[% FormBuilder.submit %]</div>
+        <div id="reset">[% FormBuilder.reset %]</div>
+        <div id="state">
+          [% FormBuilder.statetags  %]
+          [% FormBuilder.keepextras %]
+          [% FormBuilder.end        %]
+        </div>			
+	</div>
+</div>
\ No newline at end of file

Added: trunk/examples/typeface/root/admin/fix.tt2
===================================================================
--- trunk/examples/typeface/root/admin/fix.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/admin/fix.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,109 @@
+
+<div style="float: left; overflow: hidden; height: 550px; width: 885px; margin-left: -40px;">
+<div dojoType="AccordionContainer" labelNodeClass="label" containerNodeClass="accBody" id="slide_tab">
+
+	
+	<div dojoType="ContentPane" label="Users &amp; Pages">
+		<div class="padding">
+			<h1>Users &amp; Pages &amp; Categories</h1>
+				<div style="float: left;">
+					<p>
+				<h3>Pages:</h3>
+				<br />
+				<a href="/admin/page">Create new page</a><br/>
+				<br />
+				[% FOREACH page = apages %]
+					<a href="/admin/page/[% page.id %]">[% page.name %]</a> 
+					<a href="/admin/destroy/Pages/[% page.id %]">Destroy</a> 
+					<br />
+				[% END %]
+			</p>
+			</div>
+			
+			<div style="float: left; padding-left: 30px;">
+				<p>
+					<h3>Users:</h3>
+					<br />
+					<a href="/admin/user">Create new user</a><br />
+					<br />
+					[% FOREACH user = users %]
+						<a href="/admin/user/[% user.id %]">[% user.name %]</a> 
+						<a href="/admin/destroy/Users/[% user.id %]">Destroy</a>
+						<br />
+					[% END %]
+				</p>
+			</div>
+			
+			<div style="float: right;">
+				<h1>Categories</h1>
+				<p>
+					[% IF categories %]
+						<h3>Categories:</h3>
+						<br />
+						<a href="/admin/category">Create new category</a><br />
+						<br />
+						[% FOREACH category = categories %]
+							<a href="/admin/category/[% category.id %]">[% category.name %]</a> 
+							<a href="/admin/destroy/Categories/[% category.id %]">Destroy</a>
+							<br />
+						[% END %]
+					[% END %]
+				</p>
+			</div>
+			
+		</div>
+	</div>
+	
+	
+	<div dojoType="ContentPane"label="Recent Posts">
+		<div class="padding">
+			<h1>Recent Posts</h1>
+			<p>
+				[% IF articles %]
+					<h3>Recent Posts</h3><br/><br/>
+					[% FOREACH article = articles %]
+						<a href="/admin/edit/[% article.id %]">Edit</a> 
+						<a href="/admin/destroy/Articles/[% article.id %]">Destroy</a> 
+						<a href="javascript:clear_cache([% article.id %]);">Clear Cache</a>
+						<h4><a href="/view/[% c.nifty_txt_to_url(article.subject,article.id) %]">[% article.subject %]</a></h4><br/>
+					[% END %]
+
+					<div id="jaxdate"></div>
+				[% END %]
+			</p>
+		</div>
+	</div>
+	
+	<div dojoType="ContentPane" open="true" label="New Post">
+		<div class="padding">
+			<h1>New Post</h1>
+			</div>
+			<p>
+				[% form.start %]
+				[% form.jshead %]
+				[% FOREACH field IN form.fields %]
+					[% IF field.name == 'body' %]
+					<p style="border: 1px solid;">
+					[% field.tag %]
+				</p>
+					
+					[% ELSE %]
+					<div class="padding">
+					<p>
+						[% IF field.required %]
+							<strong>[% field.label %]</strong>
+						[% ELSE %]
+						[% field.label %]
+						[% END %]
+					<br>
+					[% field.tag %]</p></div>
+					[% END %]
+				[% END %]
+				<div id="submit">[% form.submit %]</div>
+        <div id="reset">[% form.reset %]</div>
+				[% form.end %]
+			</p>
+	</div>
+	
+</div>
+</div>
\ No newline at end of file

Added: trunk/examples/typeface/root/admin/index.tt2
===================================================================
--- trunk/examples/typeface/root/admin/index.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/admin/index.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,261 @@
+&nbsp;
+<br class="clear" />
+<style type="text/css" media="screen">
+  @import "/static/dojo/dojo/resources/dojo.css";
+	@import "/static/dojo/dijit/themes/tundra/tundra.css";
+	
+	.dijitAlignTop {
+	  background-color: #F3F3F3;
+	}
+	
+	.dijitTabActive {
+	  background-color: #FFFFFF;
+	}
+	
+	.dijitTabInnerDiv {
+	  font-family: Arial, "MS Trebuchet", sans-serif;
+	  font-size: 16px;
+	  padding-left: 10px;
+	  padding-right: 10px;
+    margin-left: 10px !important;
+    margin-right: 10px !important;
+	}
+	
+</style>
+<script type="text/javascript" charset="utf-8">
+  dojo.require("dijit.layout.TabContainer");
+  dojo.require("dijit.layout.ContentPane");
+</script>
+
+[% FormBuilder.jshead %]
+
+<br class="clear" />
+
+<div id="mainTabContainer" dojoType="dijit.layout.TabContainer" style="width: 100%; height: 640px;">
+	<script>djConfig.searchIds.push("mainTabContainer");</script>
+	<div id="write_blog" dojoType="dijit.layout.ContentPane" label="Write Blog">
+		<script>djConfig.searchIds.push("write_blog");</script>
+		&nbsp;
+		<div class="padding">
+				[% FormBuilder.start %]
+		      	<div id="form">
+		        [% FOREACH field IN FormBuilder.fields %]
+				[% IF field.name == "categories" %]
+					<p>
+					<a href="#" onclick="toggle_cats(); return false;">Display Categories</a> 
+					<div id="select_cats" style="display: none;">
+			            [% field.tag %]
+					</div>
+					</p>
+				[% ELSIF field.name == "body" %]
+					<p>
+					<strong>Editor Type: </strong>
+					<select name="type" onChange="switch_editor(this.value);">
+						<option value="textile">Textile / Plain</option>
+						<option value="wysiwyg">WYSIWYG Editor</option>	
+					</select>
+					</p>
+					<p id="pborder" style="width: 800px;">
+						<textarea id="body" name="body" style="width: 800px; height: 300px;">[% field.value %]</textarea>
+						</p>
+					</p>
+				[% ELSE %]
+		        <div id="[%- field.name -%]">
+		          <div class="label">
+					[% IF field.required %]
+						<span><strong>[% field.label %]</strong></span>
+					[% ELSE %]
+						<span>[% field.label %]</span>
+					[% END %]
+		          </div>
+		          <div class="field">
+		            [% field.tag %]
+		          </div>
+		        </div>
+				[% END %]
+		        [% END %]
+		        <div id="submit">[% FormBuilder.submit %]</div>
+		        <div id="reset">[% FormBuilder.reset %]</div>
+		        <div id="state">
+		          [% FormBuilder.statetags  %]
+		          [% FormBuilder.keepextras %]
+		          [% FormBuilder.end        %]
+		        </div>			
+			</div>
+		</div>
+	</div>
+	
+	<div id="recent_blog" dojoType="dijit.layout.ContentPane" label="Recent Entries">
+		<script>djConfig.searchIds.push("recent_blog");</script>
+		&nbsp;
+		<div class="padding">
+			<p>
+				[% IF articles %]
+					<h3>Recent Posts</h3><br/><br/>
+					<div id="jaxdate"></div>
+					<table cellpadding="0" cellspacing="0">
+						<th>Id</th>
+						<th>Subject</th>
+						<th>Clear Cache</th>
+						<th>View</th>
+						<th>Edit</th>
+						<th>Delete</th>
+					[% FOREACH article = articles %]
+						[% IF loop.index % 2 %]
+							[% class="darken" %]
+						[% ELSE %]
+							[% class="" %]
+						[% END %]
+						<tr>
+							<td id="id" class="[% class %]">[% article.id %]</td>
+							<td class="[% class %]" id='subject'>[% article.subject %]</td>
+							<td id="cache" class="[% class %]"><a href="javascript:clear_cache([% article.id %]);">Clear Cache</a></td>
+							<td id="view" class="[% class %]"><a href="/view/[% c.nifty_txt_to_url(article.subject,article.id) %]">View</a></td>
+							<td id="edit" class="[% class %]"><a href="/admin/edit/[% article.id %]">Edit</a></td>
+							<td id="delete" class="[% class %]"><a href="/admin/destroy/Articles/[% article.id %]">Delete</a></td>
+						</tr>
+					[% END %]
+					</table>
+				[% END %]
+			</p>
+		</div>
+	</div>
+	
+	<div id="users" dojoType="dijit.layout.ContentPane" refreshOnShow="true" label="Users">
+		<script>djConfig.searchIds.push("users");</script>
+		&nbsp;
+		<div class="padding">
+			<p>
+				<br />
+				<a href="/admin/user">Create new user</a><br />
+				<br />
+				<table cellpadding="0" cellspacing="0">
+					<th>Id</th>
+					<th>Name</th>
+					<th>Email</th>
+					<th>Website</th>
+					<th>Edit</th>
+					<th>Delete</th>
+				[% FOREACH user = users %]
+				[% IF loop.index % 2 %]
+					[% class="darken" %]
+				[% ELSE %]
+					[% class="" %]
+				[% END %]
+					<tr>
+						<td class="[% class %]" id="id">[% user.id %]</td>
+						<td class="[% class %]" id="name">[% user.name %]</td>
+						<td class="[% class %]" id="email"><a href="mailto:[% user.email %]">[% user.email %]</a></td>
+						<td class="[% class %]" id="website"><a href="[% user.website %]">[% user.website %]</a></td>
+						<td class="[% class %]" id="edit"><a href="/admin/user/[% user.id %]">Edit</a></td>
+						<td class="[% class %]" id="delete"><a href="/admin/destroy/Users/[% user.id %]">Delete</a></td>
+					</tr>
+				[% END %]
+				</table>
+			</p>
+		</div>
+	</div>
+	
+	
+	<div id="categories" dojoType="dijit.layout.ContentPane" label="Categories">
+		<script>djConfig.searchIds.push("categories");</script>
+			&nbsp;
+			<div class="padding">
+				<p>
+			<br />
+			<a href="/admin/category">Create new category</a><br/>
+			<br />
+			<table cellpadding="0" cellspacing="0">
+				<th>Id</th>
+				<th>Category</th>
+				<th>Edit</th>
+				<th>Delete</th>
+			[% FOREACH category = categories %]
+				[% IF loop.index % 2 %]
+					[% class="darken" %]
+				[% ELSE %]
+					[% class="" %]
+				[% END %]
+				<tr>
+					<td class="[% class %]" id="id">[% category.id %]</td>
+					<td class="[% class %]" id="name">[% category.name %]</td>
+					<td class="[% class %]" id="edit"><a href="/admin/category/[% category.id %]">Edit</a></td>
+					<td class="[% class %]" id="delete"><a href="/admin/destroy/Categories/[% category.id %]">Destroy</a></td>
+				</tr>
+			[% END %]
+			</table>
+		</p>
+		</div>
+	</div>
+	
+	<div id="pages" dojoType="dijit.layout.ContentPane" label="Pages">
+		<script>djConfig.searchIds.push("pages");</script>
+			&nbsp;
+			<div class="padding">
+				<p>
+			<br />
+			<a href="/admin/page">Create new page</a><br/>
+			<br />
+			<table cellpadding="0" cellspacing="0">
+				<th>Id</th>
+				<th>Page Name</th>
+				<th>Clear Cache</th>
+				<th>View</th>
+				<th>Edit</th>
+				<th>Delete</th>
+			[% FOREACH page = apages %]
+				[% IF loop.index % 2 %]
+					[% class="darken" %]
+				[% ELSE %]
+					[% class="" %]
+				[% END %]
+				<tr>
+					<td class="[% class %]" id="id">[% page.id %]</td>
+					<td class="[% class %]" id="name">[% page.name %]</td>
+					<td class="[% class %]" id="cache"><a href="javascript:clear_cache_page([% page.id %]);">Clear Cache</a></td>
+					<td class="[% class %]" id="view"><a href="/view/[% c.nifty_txt_to_url(page.name,page.id) %]">View</a></td>
+					<td class="[% class %]" id="edit"><a href="/admin/page/[% page.id %]">Edit</a></td>
+					<td class="[% class %]" id="delete"><a href="/admin/destroy/Pages/[% page.id %]">Destroy</a> </td>
+				</tr>
+			[% END %]
+			</table>
+		</p>
+		</div>
+	</div>
+	
+	<div id="links" dojoType="dijit.layout.ContentPane" label="Links">
+		<script>djConfig.searchIds.push("links");</script>
+			&nbsp;
+				<div class="padding">
+					<p>
+					<br />
+					<a href="/admin/link">Create Link</a><br/>
+					<br />
+					<table cellpadding="0" cellspacing="0">
+						<th>Id</th>
+						<th>Name</th>
+						<th>Url</th>
+						<th>Description</th>
+						<th>Edit</th>
+						<th>Delete</th>
+					[% FOREACH link = alinks %]
+						[% IF loop.index % 2 %]
+							[% class="darken" %]
+						[% ELSE %]
+							[% class="" %]
+						[% END %]
+						<tr>
+							<td class="[% class %]" id="id">[% link.id %]</td>
+							<td class="[% class %]" id="name">[% link.name %]</td>
+							<td class="[% class %]" id="name"><a href="[% link.url %]">[% link.url %]</a></td>
+							<td class="[% class %]" id="name">[% link.description %]</td>
+							<td class="[% class %]" id="edit"><a href="/admin/link/[% link.id %]">Edit</a></td>
+							<td class="[% class %]" id="delete"><a href="/admin/destroy/Links/[% link.id %]">Destroy</a> </td>
+						</tr>
+					[% END %]
+					</table>
+					</p>
+			</div>
+	</div>
+
+</div>
\ No newline at end of file

Added: trunk/examples/typeface/root/admin/link.tt2
===================================================================
--- trunk/examples/typeface/root/admin/link.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/admin/link.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1 @@
+[% FormBuilder.render %]
\ No newline at end of file

Added: trunk/examples/typeface/root/admin/login_as.tt2
===================================================================
--- trunk/examples/typeface/root/admin/login_as.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/admin/login_as.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,22 @@
+&nbsp;
+<div id="login_box">
+<form action="/login/login_as" method="post">
+				<h1>Authentication:</h1>
+				<p>
+				<span>Login:</span> <br/>
+				<input type="text" name="login" id="login"/>
+				</p>
+				<p>
+				<span>Password:</span> <br/>
+				<input type="password" name="password" id="password"/>
+				</p>
+			<input type="submit" value="Login" />
+</form>
+</div>
+
+<script type="text/javascript" charset="utf-8">
+	function init () {
+		dojo.byId('login').focus();
+	}
+	dojo.addOnLoad(init);
+</script>
\ No newline at end of file

Added: trunk/examples/typeface/root/admin/login_pane.tt2
===================================================================
--- trunk/examples/typeface/root/admin/login_pane.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/admin/login_pane.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,8 @@
+<div id="login_pane">
+[% IF c.user %]
+	<p style="display: inline; font-size: 12px;">
+		<span class="special_text">Logged in as:</span> [% c.user.name %]<br />
+		<a href="/login/logout">Logout</a>
+	</p>
+[% END %]
+</div>
\ No newline at end of file

Added: trunk/examples/typeface/root/admin/message.tt2
===================================================================
--- trunk/examples/typeface/root/admin/message.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/admin/message.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,14 @@
+[% IF c.flash.notice %]
+        <br />
+				<br class="clear"/>
+				<br />
+        <ul id="error_content">
+                <li id="one">
+                        <h3>Notice</h3>
+                        <div>
+                                <p>[% c.flash.notice %]</p>
+                        </div>
+                </li>
+        </ul>
+        <br style="clear" />
+[% END %]
\ No newline at end of file

Added: trunk/examples/typeface/root/admin/page.tt2
===================================================================
--- trunk/examples/typeface/root/admin/page.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/admin/page.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1 @@
+[% FormBuilder.render %]
\ No newline at end of file

Added: trunk/examples/typeface/root/admin/user.tt2
===================================================================
--- trunk/examples/typeface/root/admin/user.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/admin/user.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1 @@
+[% FormBuilder.render %]
\ No newline at end of file

Added: trunk/examples/typeface/root/favicon.ico
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/favicon.ico
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/lib/config/main
===================================================================
--- trunk/examples/typeface/root/lib/config/main	                        (rev 0)
+++ trunk/examples/typeface/root/lib/config/main	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,89 @@
+[% # config/main
+   #
+   # This is the main configuration template which is processed before
+   # any other page, by virtue of it being defined as a PRE_PROCESS 
+   # template.  This is the place to define any extra template variables,
+   # macros, load plugins, and perform any other template setup.
+
+   IF Catalyst.debug;
+     # define a debug() macro directed to Catalyst's log
+     MACRO debug(message) CALL Catalyst.log.debug(message);
+   END;
+
+   # set defaults for variables, etc.
+   DEFAULT 
+     site = { 
+		     title     => c.config.site.name,
+		     copyright => '2006 Victor Igumnov',
+				layout => c.config.site.template _ '/layout.tt2',
+				stylesheets => 'templates/' _ c.config.site.template _ '/static/stylesheets',
+				javascripts => 'templates/' _ c.config.site.template _ '/static/javascripts'
+				images => 'templates/' _ c.config.site.template _ '/static/images'
+			};
+						
+			MACRO typeface_define_headers
+			BLOCK;
+			  dp_css_include_tag;
+				'<script src="/static/javascripts/application.js" type="text/javascript"></script>';
+				'<script src="/static/javascripts/nicetitles.js" type="text/javascript"></script>';
+				'<script src="/static/javascripts/niftycube.js" type="text/javascript"></script>';
+				'<script src="/static/javascripts/niftydates.js" type="text/javascript"></script>';
+				'<link href="/static/stylesheets/nicetitles.css" media="screen" rel="stylesheet" type="text/css" />';
+				'<link href="/static/stylesheets/default.css" media="screen" rel="stylesheet" type="text/css" />';
+				'<script src="/static/dojo/dojo/dojo.js" type="text/javascript"></script>';
+				'<script>';
+				'djConfig = { parseWidgets: false, searchIds: [] };';
+				'</script>';
+			END;
+			
+			MACRO stylesheet_link_tag ( stylesheet )
+			BLOCK;
+					'<link href="/' _ site.stylesheets _ '/' _ stylesheet _ '"' _ ' rel="stylesheet" type="text/css" media="all" />';
+			END;
+			
+			MACRO javascript_include_tag ( javascript )
+			BLOCK;
+				'<script src="/' _ site.javascripts _ '/' _ javascript _ '" type="text/javascript"></script>';
+			END;
+						
+			MACRO javascript_include_tag ( javascript )
+			BLOCK;
+				'<script src="/' _ site.javascripts _ '/' _ javascript _ '" type="text/javascript"></script>';
+			END;
+			
+			MACRO load_file ( file )
+			BLOCK;
+				 c.config.site.template _ '/' _ file;
+			END;
+			
+			MACRO dp_js_include_tag
+			BLOCK;
+			  '<script class="javascript" src="/static/Scripts/shCore.js"></script>';
+        '<script class="javascript" src="/static/Scripts/shBrushCSharp.js"></script>';
+        '<script class="javascript" src="/static/Scripts/shBrushPhp.js"></script>';
+        '<script class="javascript" src="/static/Scripts/shBrushJScript.js"></script>';
+        '<script class="javascript" src="/static/Scripts/shBrushJava.js"></script>';
+        '<script class="javascript" src="/static/Scripts/shBrushVb.js"></script>';
+        '<script class="javascript" src="/static/Scripts/shBrushSql.js"></script>';
+        '<script class="javascript" src="/static/Scripts/shBrushXml.js"></script>';
+        '<script class="javascript" src="/static/Scripts/shBrushDelphi.js"></script>';
+        '<script class="javascript" src="/static/Scripts/shBrushPython.js"></script>';
+        '<script class="javascript" src="/static/Scripts/shBrushPerl.js"></script>';
+        '<script class="javascript" src="/static/Scripts/shBrushRuby.js"></script>';
+        '<script class="javascript" src="/static/Scripts/shBrushCss.js"></script>';
+        '<script class="javascript" src="/static/Scripts/shBrushCpp.js"></script>';
+        '<script class="javascript">';
+        'dp.SyntaxHighlighter.HighlightAll("code");';
+        '</script>';
+			END;
+			
+			MACRO dp_css_include_tag
+			BLOCK;
+			'<link type="text/css" rel="stylesheet" href="/static/Styles/SyntaxHighlighter.css"></link>';
+			END;
+			
+			MACRO image_tag ( image )
+			BLOCK;
+				'<img src="/' _ site.images _ '/' _ image _ '" alt="" />'; 
+			END;
+-%]

Added: trunk/examples/typeface/root/lib/config/url
===================================================================
--- trunk/examples/typeface/root/lib/config/url	                        (rev 0)
+++ trunk/examples/typeface/root/lib/config/url	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,8 @@
+[% base = Catalyst.req.base;
+
+   site.url = {
+     base    = base
+     home    = "${base}welcome"
+     message = "${base}message"
+   }
+-%]

Added: trunk/examples/typeface/root/lib/site/admin
===================================================================
--- trunk/examples/typeface/root/lib/site/admin	                        (rev 0)
+++ trunk/examples/typeface/root/lib/site/admin	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,30 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+	"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" version="-//W3C//DTD XHTML 1.1//EN" xml:lang="en">
+<head>
+	<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
+
+	<title>Typeface - Admin</title>
+	<link rel="stylesheet" href="/static/stylesheets/admin.css" type="text/css" media="screen" charset="utf-8">
+	<script type="text/javascript" charset="utf-8">
+	 djConfig = { baseScriptUri: "/static/", parseWidgets: false, searchIds: [] };
+	</script>
+	<script src="/static/dojo/dojo/dojo.js" type="text/javascript"></script>
+	<script type="text/javascript" charset="utf-8" src="/static/javascripts/application.js"></script>
+</head>
+
+<body>
+<div id="main">
+	<div style="float: right; padding-right: 30px;">
+		[% PROCESS login_pane.tt2 %]
+	</div>
+	<h1 style="display: inline;">Typeface</h1>
+</div>
+&nbsp;
+[% PROCESS message.tt2 %]
+[% content %]
+</body>
+</html>
+
+

Added: trunk/examples/typeface/root/lib/site/admin_wrapper
===================================================================
--- trunk/examples/typeface/root/lib/site/admin_wrapper	                        (rev 0)
+++ trunk/examples/typeface/root/lib/site/admin_wrapper	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,8 @@
+[% IF template.name.match('\.(css|js|txt)');
+     debug("Passing page through as text: $template.name");
+     content;
+   ELSE;
+     debug("Applying HTML page layout wrappers to $template.name\n");
+     content WRAPPER site/admin;
+   END;
+-%]

Added: trunk/examples/typeface/root/lib/site/html
===================================================================
--- trunk/examples/typeface/root/lib/site/html	                        (rev 0)
+++ trunk/examples/typeface/root/lib/site/html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1 @@
+[% INCLUDE layout.tt2 %]
\ No newline at end of file

Added: trunk/examples/typeface/root/lib/site/remote
===================================================================
--- trunk/examples/typeface/root/lib/site/remote	                        (rev 0)
+++ trunk/examples/typeface/root/lib/site/remote	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1 @@
+[% content %]
\ No newline at end of file

Added: trunk/examples/typeface/root/lib/site/remote_wrapper
===================================================================
--- trunk/examples/typeface/root/lib/site/remote_wrapper	                        (rev 0)
+++ trunk/examples/typeface/root/lib/site/remote_wrapper	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,8 @@
+[% IF template.name.match('\.(css|js|txt)');
+     debug("Passing page through as text: $template.name");
+     content;
+   ELSE;
+     debug("Applying HTML page layout wrappers to $template.name\n");
+     content WRAPPER site/remote;
+   END;
+-%]

Added: trunk/examples/typeface/root/lib/site/wrapper
===================================================================
--- trunk/examples/typeface/root/lib/site/wrapper	                        (rev 0)
+++ trunk/examples/typeface/root/lib/site/wrapper	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,8 @@
+[% IF template.name.match('\.(css|js|txt)');
+     debug("Passing page through as text: $template.name");
+     content;
+   ELSE;
+     debug("Applying HTML page layout wrappers to $template.name\n");
+     content WRAPPER site/html;
+   END;
+-%]

Added: trunk/examples/typeface/root/shared/archives_list.tt2
===================================================================
--- trunk/examples/typeface/root/shared/archives_list.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/shared/archives_list.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+<h2>Archives</h2>
+<ul>
+[% archives %]
+</ul>
\ No newline at end of file

Added: trunk/examples/typeface/root/shared/calendar_list.tt2
===================================================================
--- trunk/examples/typeface/root/shared/calendar_list.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/shared/calendar_list.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,8 @@
+<h2>Calendar</h2>
+<ul>
+	<li>
+		<div id="calendar">
+				[% calendar %]
+		</div>
+	</li>
+</ul>
\ No newline at end of file

Added: trunk/examples/typeface/root/shared/categories_list.tt2
===================================================================
--- trunk/examples/typeface/root/shared/categories_list.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/shared/categories_list.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,12 @@
+<h2>Categories</h2>
+<p style="font-size: 11px; display: inline;"><span class="special_text">Sort</span> [ <a href="#" id="alpha">alpha</a> | <a href="#" id="freq" class="selected">freq</a> ]</p>
+<ul>
+<div id="cat_list">
+[% FOREACH category = categories %]
+	<li><a title="[% category.name %]" href="/category/[% c.nifty_txt_to_url(category.name) %]">[% category.name %]</a></li>
+[% END %]
+<script type="text/javascript" charset="utf-8">
+	toggle_cat_list();
+</script>
+</div>
+</ul>
\ No newline at end of file

Added: trunk/examples/typeface/root/shared/links_list.tt2
===================================================================
--- trunk/examples/typeface/root/shared/links_list.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/shared/links_list.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,6 @@
+<h2>Links</h2>
+<ul>
+[% FOREACH link = links %]
+	<li><a title="[% link.description %]" href="[% link.url %]">[% link.name %]</a></li> 
+[% END %]
+</ul>
\ No newline at end of file

Added: trunk/examples/typeface/root/shared/login_list.tt2
===================================================================
--- trunk/examples/typeface/root/shared/login_list.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/shared/login_list.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,10 @@
+<h2>Meta</h2>
+<ul>
+[% IF c.user %]
+<li><span>Logged in as: [% c.user.name %]</span></li>
+<li><a href="/admin">Site-Admin</a></li>
+<li><a href="/login/logout">Logout</a></li>
+[% ELSE %]
+<li><a href="/login">Login</a></li>
+[% END %]
+</ul>
\ No newline at end of file

Added: trunk/examples/typeface/root/shared/message.tt2
===================================================================
--- trunk/examples/typeface/root/shared/message.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/shared/message.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,14 @@
+[% IF c.flash.notice %]
+        <br />
+				<br class="clear"/>
+				<br />
+        <ul id="error_content">
+                <li id="one">
+                        <h3>Notice</h3>
+                        <div>
+                                <p>[% c.flash.notice %]</p>
+                        </div>
+                </li>
+        </ul>
+        <br style="clear" />
+[% END %]
\ No newline at end of file

Added: trunk/examples/typeface/root/shared/page.tt2
===================================================================
--- trunk/examples/typeface/root/shared/page.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/shared/page.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1 @@
+[% page.textilize('body') %]
\ No newline at end of file

Added: trunk/examples/typeface/root/shared/search_list.tt2
===================================================================
--- trunk/examples/typeface/root/shared/search_list.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/shared/search_list.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,13 @@
+<h2>Search</h2>
+<ul>
+	<li>
+<div id="search_pane">
+<form action="/search" method="post">
+<p>
+	<input type="text" name="phrase" size="20" onkeyup="check_articles(this);"/>
+	<div style="display: none;" id="search_board"></div>
+</p>
+</form>
+</div>
+	</li>
+</ul>
\ No newline at end of file

Added: trunk/examples/typeface/root/shared/syndicate_list.tt2
===================================================================
--- trunk/examples/typeface/root/shared/syndicate_list.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/shared/syndicate_list.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+<h2>Syndicate</h2>
+<ul>
+<li><a href="[% c.base_uri %]/feed/articles"><img src="/static/images/rss.png" alt="RSS" /> Articles</a></li>
+<li><a href="[% c.base_uri %]/feed/comments"><img src="/static/images/rss.png" alt="RSS" /> Comments</a></li>
+
+[% IF rss %]
+<li><a href="[% c.base_uri %]/feed/articles/[% c.nifty_txt_to_url(rss) %]"><img src="/static/images/rss.png" alt="RSS" /> [% rss %]</a></li>
+[% END %]
+</ul>
\ No newline at end of file

Added: trunk/examples/typeface/root/static/Scripts/shBrushCSharp.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shBrushCSharp.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shBrushCSharp.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,31 @@
+dp.sh.Brushes.CSharp = function()
+{
+	var keywords =	'abstract as base bool break byte case catch char checked class const ' +
+					'continue decimal default delegate do double else enum event explicit ' +
+					'extern false finally fixed float for foreach get goto if implicit in int ' +
+					'interface internal is lock long namespace new null object operator out ' +
+					'override params private protected public readonly ref return sbyte sealed set ' +
+					'short sizeof stackalloc static string struct switch this throw true try ' +
+					'typeof uint ulong unchecked unsafe ushort using virtual void while';
+
+	this.regexList = [
+		// There's a slight problem with matching single line comments and figuring out
+		// a difference between // and ///. Using lookahead and lookbehind solves the
+		// problem, unfortunately JavaScript doesn't support lookbehind. So I'm at a 
+		// loss how to translate that regular expression to JavaScript compatible one.
+//		{ regex: new RegExp('(?<!/)//(?!/).*$|(?<!/)////(?!/).*$|/\\*[^\\*]*(.)*?\\*/', 'gm'),	css: 'comment' },			// one line comments starting with anything BUT '///' and multiline comments
+//		{ regex: new RegExp('(?<!/)///(?!/).*$', 'gm'),											css: 'comments' },		// XML comments starting with ///
+
+		{ regex: dp.sh.RegexLib.SingleLineCComments,				css: 'comment' },			// one line comments
+		{ regex: dp.sh.RegexLib.MultiLineCComments,					css: 'comment' },			// multiline comments
+		{ regex: dp.sh.RegexLib.DoubleQuotedString,					css: 'string' },			// strings
+		{ regex: dp.sh.RegexLib.SingleQuotedString,					css: 'string' },			// strings
+		{ regex: new RegExp('^\\s*#.*', 'gm'),						css: 'preprocessor' },		// preprocessor tags like #region and #endregion
+		{ regex: new RegExp(this.GetKeywords(keywords), 'gm'),		css: 'keyword' }			// c# keyword
+		];
+
+	this.CssClass = 'dp-c';
+}
+
+dp.sh.Brushes.CSharp.prototype	= new dp.sh.Highlighter();
+dp.sh.Brushes.CSharp.Aliases	= ['c#', 'c-sharp', 'csharp'];


Property changes on: trunk/examples/typeface/root/static/Scripts/shBrushCSharp.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Scripts/shBrushCpp.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shBrushCpp.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shBrushCpp.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,72 @@
+/**
+ * Code Syntax Highlighter for C++(Windows Platform).
+ * Version 0.0.1
+ * Copyright (C) 2006 Shin, YoungJin.
+ * http://www.jiniya.net/lecture/techbox/test.html
+ * 
+ * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 
+ * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ */
+
+dp.sh.Brushes.Cpp = function()
+{
+	var datatypes = 
+	'ATOM BOOL BOOLEAN BYTE CHAR COLORREF DWORD DWORDLONG DWORD_PTR ' +
+	'DWORD32 DWORD64 FLOAT HACCEL HALF_PTR HANDLE HBITMAP HBRUSH ' + 
+	'HCOLORSPACE HCONV HCONVLIST HCURSOR HDC HDDEDATA HDESK HDROP HDWP ' +
+	'HENHMETAFILE HFILE HFONT HGDIOBJ HGLOBAL HHOOK HICON HINSTANCE HKEY ' +
+	'HKL HLOCAL HMENU HMETAFILE HMODULE HMONITOR HPALETTE HPEN HRESULT ' +
+	'HRGN HRSRC HSZ HWINSTA HWND INT INT_PTR INT32 INT64 LANGID LCID LCTYPE ' +
+	'LGRPID LONG LONGLONG LONG_PTR LONG32 LONG64 LPARAM LPBOOL LPBYTE LPCOLORREF ' +
+	'LPCSTR LPCTSTR LPCVOID LPCWSTR LPDWORD LPHANDLE LPINT LPLONG LPSTR LPTSTR ' +
+	'LPVOID LPWORD LPWSTR LRESULT PBOOL PBOOLEAN PBYTE PCHAR PCSTR PCTSTR PCWSTR ' +
+	'PDWORDLONG PDWORD_PTR PDWORD32 PDWORD64 PFLOAT PHALF_PTR PHANDLE PHKEY PINT ' +
+	'PINT_PTR PINT32 PINT64 PLCID PLONG PLONGLONG PLONG_PTR PLONG32 PLONG64 POINTER_32 ' +
+	'POINTER_64 PSHORT PSIZE_T PSSIZE_T PSTR PTBYTE PTCHAR PTSTR PUCHAR PUHALF_PTR ' +
+	'PUINT PUINT_PTR PUINT32 PUINT64 PULONG PULONGLONG PULONG_PTR PULONG32 PULONG64 ' +
+	'PUSHORT PVOID PWCHAR PWORD PWSTR SC_HANDLE SC_LOCK SERVICE_STATUS_HANDLE SHORT ' + 
+	'SIZE_T SSIZE_T TBYTE TCHAR UCHAR UHALF_PTR UINT UINT_PTR UINT32 UINT64 ULONG ' +
+	'ULONGLONG ULONG_PTR ULONG32 ULONG64 USHORT USN VOID WCHAR WORD WPARAM WPARAM WPARAM ' +
+	'char bool short int __int32 __int64 __int8 __int16 long float double __wchar_t ' +
+	'clock_t _complex _dev_t _diskfree_t div_t ldiv_t _exception _EXCEPTION_POINTERS ' +
+	'FILE _finddata_t _finddatai64_t _wfinddata_t _wfinddatai64_t __finddata64_t ' +
+	'__wfinddata64_t _FPIEEE_RECORD fpos_t _HEAPINFO _HFILE lconv intptr_t ' +
+	'jmp_buf mbstate_t _off_t _onexit_t _PNH ptrdiff_t _purecall_handler ' +
+	'sig_atomic_t size_t _stat __stat64 _stati64 terminate_function ' +
+	'time_t __time64_t _timeb __timeb64 tm uintptr_t _utimbuf ' +
+	'va_list wchar_t wctrans_t wctype_t wint_t signed';
+
+	var keywords = 
+	'break case catch class const __finally __exception __try ' +
+	'const_cast continue private public protected __declspec ' + 
+	'default delete deprecated dllexport dllimport do dynamic_cast ' + 
+	'else enum explicit extern if for friend goto inline ' + 
+	'mutable naked namespace new noinline noreturn nothrow ' + 
+	'register reinterpret_cast return selectany ' + 
+	'sizeof static static_cast struct switch template this ' + 
+	'thread throw true false try typedef typeid typename union ' + 
+	'using uuid virtual void volatile whcar_t while';
+
+	this.regexList = [
+		{ regex: dp.sh.RegexLib.SingleLineCComments,				css: 'comment' },			// one line comments
+		{ regex: dp.sh.RegexLib.MultiLineCComments,					css: 'comment' },			// multiline comments
+		{ regex: dp.sh.RegexLib.DoubleQuotedString,					css: 'string' },			// strings
+		{ regex: dp.sh.RegexLib.SingleQuotedString,					css: 'string' },			// strings
+		{ regex: new RegExp('^ *#.*', 'gm'),						css: 'preprocessor' },
+		{ regex: new RegExp(this.GetKeywords(datatypes), 'gm'),		css: 'datatypes' },
+		{ regex: new RegExp(this.GetKeywords(keywords), 'gm'),		css: 'keyword' }
+		];
+
+	this.CssClass = 'dp-cpp';
+}
+
+dp.sh.Brushes.Cpp.prototype	= new dp.sh.Highlighter();
+dp.sh.Brushes.Cpp.Aliases	= ['cpp', 'c', 'c++'];


Property changes on: trunk/examples/typeface/root/static/Scripts/shBrushCpp.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Scripts/shBrushCss.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shBrushCss.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shBrushCss.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,50 @@
+dp.sh.Brushes.CSS = function()
+{
+	var keywords =	'ascent azimuth background-attachment background-color background-image background-position ' +
+					'background-repeat background baseline bbox border-collapse border-color border-spacing border-style border-top ' +
+					'border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color ' +
+					'border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width ' +
+					'border-bottom-width border-left-width border-width border bottom cap-height caption-side centerline clear clip color ' +
+					'content counter-increment counter-reset cue-after cue-before cue cursor definition-src descent direction display ' +
+					'elevation empty-cells float font-size-adjust font-family font-size font-stretch font-style font-variant font-weight font ' +
+					'height letter-spacing line-height list-style-image list-style-position list-style-type list-style margin-top ' +
+					'margin-right margin-bottom margin-left margin marker-offset marks mathline max-height max-width min-height min-width orphans ' +
+					'outline-color outline-style outline-width outline overflow padding-top padding-right padding-bottom padding-left padding page ' +
+					'page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position ' +
+					'quotes richness right size slope src speak-header speak-numeral speak-punctuation speak speech-rate stemh stemv stress ' +
+					'table-layout text-align text-decoration text-indent text-shadow text-transform unicode-bidi unicode-range units-per-em ' +
+					'vertical-align visibility voice-family volume white-space widows width widths word-spacing x-height z-index';
+
+	var values =	'above absolute all always aqua armenian attr aural auto avoid baseline behind below bidi-override black blink block blue bold bolder '+
+					'both bottom braille capitalize caption center center-left center-right circle close-quote code collapse compact condensed '+
+					'continuous counter counters crop cross crosshair cursive dashed decimal decimal-leading-zero default digits disc dotted double '+
+					'embed embossed e-resize expanded extra-condensed extra-expanded fantasy far-left far-right fast faster fixed format fuchsia '+
+					'gray green groove handheld hebrew help hidden hide high higher icon inline-table inline inset inside invert italic '+
+					'justify landscape large larger left-side left leftwards level lighter lime line-through list-item local loud lower-alpha '+
+					'lowercase lower-greek lower-latin lower-roman lower low ltr marker maroon medium message-box middle mix move narrower '+
+					'navy ne-resize no-close-quote none no-open-quote no-repeat normal nowrap n-resize nw-resize oblique olive once open-quote outset '+
+					'outside overline pointer portrait pre print projection purple red relative repeat repeat-x repeat-y rgb ridge right right-side '+
+					'rightwards rtl run-in screen scroll semi-condensed semi-expanded separate se-resize show silent silver slower slow '+
+					'small small-caps small-caption smaller soft solid speech spell-out square s-resize static status-bar sub super sw-resize '+
+					'table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group teal '+
+					'text-bottom text-top thick thin top transparent tty tv ultra-condensed ultra-expanded underline upper-alpha uppercase upper-latin '+
+					'upper-roman url visible wait white wider w-resize x-fast x-high x-large x-loud x-low x-slow x-small x-soft xx-large xx-small yellow';
+	
+	var fonts =		'[mM]onospace [tT]ahoma [vV]erdana [aA]rial [hH]elvetica [sS]ans-serif [sS]erif';
+
+	this.regexList = [
+		{ regex: dp.sh.RegexLib.MultiLineCComments,					css: 'comment' },	// multiline comments
+		{ regex: dp.sh.RegexLib.DoubleQuotedString,					css: 'string' },	// double quoted strings
+		{ regex: dp.sh.RegexLib.SingleQuotedString,					css: 'string' },	// single quoted strings
+		{ regex: new RegExp('\\#[a-zA-Z0-9]{3,6}', 'g'),			css: 'colors' },	// html colors
+		{ regex: new RegExp('(\\d+)(px|pt|\:)', 'g'),				css: 'string' },	// size specifications
+		{ regex: new RegExp(this.GetKeywords(keywords), 'gm'),		css: 'keyword' },	// keywords
+		{ regex: new RegExp(this.GetKeywords(values), 'g'),			css: 'string' },	// values
+		{ regex: new RegExp(this.GetKeywords(fonts), 'g'),			css: 'string' }		// fonts
+		];
+
+	this.CssClass = 'dp-css';
+}
+
+dp.sh.Brushes.CSS.prototype	= new dp.sh.Highlighter();
+dp.sh.Brushes.CSS.Aliases	= ['css'];


Property changes on: trunk/examples/typeface/root/static/Scripts/shBrushCss.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Scripts/shBrushDelphi.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shBrushDelphi.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shBrushDelphi.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,31 @@
+/* Delphi brush is contributed by Eddie Shipman */
+dp.sh.Brushes.Delphi = function()
+{
+	var keywords =	'abs addr and ansichar ansistring array as asm begin boolean byte cardinal ' +
+					'case char class comp const constructor currency destructor div do double ' +
+					'downto else end except exports extended false file finalization finally ' +
+					'for function goto if implementation in inherited int64 initialization ' +
+					'integer interface is label library longint longword mod nil not object ' +
+					'of on or packed pansichar pansistring pchar pcurrency pdatetime pextended ' + 
+					'pint64 pointer private procedure program property pshortstring pstring ' + 
+					'pvariant pwidechar pwidestring protected public published raise real real48 ' +
+					'record repeat set shl shortint shortstring shr single smallint string then ' +
+					'threadvar to true try type unit until uses val var varirnt while widechar ' +
+					'widestring with word write writeln xor';
+
+	this.regexList = [
+		{ regex: new RegExp('\\(\\*[\\s\\S]*?\\*\\)', 'gm'),		css: 'comment' },  			// multiline comments (* *)
+		{ regex: new RegExp('{(?!\\$)[\\s\\S]*?}', 'gm'),			css: 'comment' },  			// multiline comments { }
+		{ regex: dp.sh.RegexLib.SingleLineCComments,				css: 'comment' },  			// one line
+		{ regex: dp.sh.RegexLib.SingleQuotedString,					css: 'string' },			// strings
+		{ regex: new RegExp('\\{\\$[a-zA-Z]+ .+\\}', 'g'),			css: 'directive' },			// Compiler Directives and Region tags
+		{ regex: new RegExp('\\b[\\d\\.]+\\b', 'g'),				css: 'number' },			// numbers 12345
+		{ regex: new RegExp('\\$[a-zA-Z0-9]+\\b', 'g'),				css: 'number' },			// numbers $F5D3
+		{ regex: new RegExp(this.GetKeywords(keywords), 'gm'),		css: 'keyword' }			// keyword
+		];
+
+	this.CssClass = 'dp-delphi';
+}
+
+dp.sh.Brushes.Delphi.prototype	= new dp.sh.Highlighter();
+dp.sh.Brushes.Delphi.Aliases	= ['delphi', 'pascal'];


Property changes on: trunk/examples/typeface/root/static/Scripts/shBrushDelphi.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Scripts/shBrushJScript.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shBrushJScript.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shBrushJScript.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,22 @@
+dp.sh.Brushes.JScript = function()
+{
+	var keywords =	'abstract boolean break byte case catch char class const continue debugger ' +
+					'default delete do double else enum export extends false final finally float ' +
+					'for function goto if implements import in instanceof int interface long native ' +
+					'new null package private protected public return short static super switch ' +
+					'synchronized this throw throws transient true try typeof var void volatile while with';
+
+	this.regexList = [
+		{ regex: dp.sh.RegexLib.SingleLineCComments,				css: 'comment' },			// one line comments
+		{ regex: dp.sh.RegexLib.MultiLineCComments,					css: 'comment' },			// multiline comments
+		{ regex: dp.sh.RegexLib.DoubleQuotedString,					css: 'string' },			// double quoted strings
+		{ regex: dp.sh.RegexLib.SingleQuotedString,					css: 'string' },			// single quoted strings
+		{ regex: new RegExp('^\\s*#.*', 'gm'),						css: 'preprocessor' },		// preprocessor tags like #region and #endregion
+		{ regex: new RegExp(this.GetKeywords(keywords), 'gm'),		css: 'keyword' }			// keywords
+		];
+
+	this.CssClass = 'dp-c';
+}
+
+dp.sh.Brushes.JScript.prototype	= new dp.sh.Highlighter();
+dp.sh.Brushes.JScript.Aliases	= ['js', 'jscript', 'javascript'];


Property changes on: trunk/examples/typeface/root/static/Scripts/shBrushJScript.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Scripts/shBrushJava.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shBrushJava.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shBrushJava.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,26 @@
+dp.sh.Brushes.Java = function()
+{
+	var keywords =	'abstract assert boolean break byte case catch char class const ' +
+			'continue default do double else enum extends ' +
+			'false final finally float for goto if implements import ' +
+			'instanceof int interface long native new null ' +
+			'package private protected public return ' +
+			'short static strictfp super switch synchronized this throw throws true ' +
+			'transient try void volatile while';
+
+	this.regexList = [
+		{ regex: dp.sh.RegexLib.SingleLineCComments,							css: 'comment' },		// one line comments
+		{ regex: dp.sh.RegexLib.MultiLineCComments,								css: 'comment' },		// multiline comments
+		{ regex: dp.sh.RegexLib.DoubleQuotedString,								css: 'string' },		// strings
+		{ regex: dp.sh.RegexLib.SingleQuotedString,								css: 'string' },		// strings
+		{ regex: new RegExp('\\b([\\d]+(\\.[\\d]+)?|0x[a-f0-9]+)\\b', 'gi'),	css: 'number' },		// numbers
+		{ regex: new RegExp('(?!\\@interface\\b)\\@[\\$\\w]+\\b', 'g'),			css: 'annotation' },	// annotation @anno
+		{ regex: new RegExp('\\@interface\\b', 'g'),							css: 'keyword' },		// @interface keyword
+		{ regex: new RegExp(this.GetKeywords(keywords), 'gm'),					css: 'keyword' }		// java keyword
+		];
+
+	this.CssClass = 'dp-j';
+}
+
+dp.sh.Brushes.Java.prototype	= new dp.sh.Highlighter();
+dp.sh.Brushes.Java.Aliases	= ['java'];


Property changes on: trunk/examples/typeface/root/static/Scripts/shBrushJava.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Scripts/shBrushPerl.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shBrushPerl.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shBrushPerl.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,27 @@
+dp.sh.Brushes.Perl = function()
+{
+	var funcs	=	'abs acos acosh addcslashes addslashes rmtree';
+
+	var keywords =	'and or xor __FILE__ __LINE__ array as break case @_ shift ' +
+					'sub continue break default die do else ' +
+					'elsif empty ' +
+					'extends for foreach use include if ' +
+					'new return switch package my ' +
+					'var while __FUNCTION__ __CLASS__ __PACKAGE__ ' +
+					'__METHOD__ abstract interface public implements extends private protected throw';
+//new RegExp('#.*$', 'gm'),
+	this.regexList = [
+		{ regex: dp.sh.RegexLib.SingleLinePerlComments,		        css: 'comment' },			// one line comments
+		{ regex: dp.sh.RegexLib.MultiLineCComments,					css: 'comment' },			// multiline comments
+		{ regex: dp.sh.RegexLib.DoubleQuotedString,					css: 'string' },			// double quoted strings
+		{ regex: dp.sh.RegexLib.SingleQuotedString,					css: 'string' },			// single quoted strings
+		{ regex: new RegExp('\\$\\w+', 'g'),						css: 'vars' },				// variables
+		{ regex: new RegExp(this.GetKeywords(funcs), 'gmi'),		css: 'func' },				// functions
+		{ regex: new RegExp(this.GetKeywords(keywords), 'gm'),		css: 'keyword' }			// keyword
+		];
+
+	this.CssClass = 'dp-c';
+}
+
+dp.sh.Brushes.Perl.prototype	= new dp.sh.Highlighter();
+dp.sh.Brushes.Perl.Aliases	= ['perl'];

Added: trunk/examples/typeface/root/static/Scripts/shBrushPhp.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shBrushPhp.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shBrushPhp.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,60 @@
+dp.sh.Brushes.Php = function()
+{
+	var funcs	=	'abs acos acosh addcslashes addslashes ' +
+					'array_change_key_case array_chunk array_combine array_count_values array_diff '+
+					'array_diff_assoc array_diff_key array_diff_uassoc array_diff_ukey array_fill '+
+					'array_filter array_flip array_intersect array_intersect_assoc array_intersect_key '+
+					'array_intersect_uassoc array_intersect_ukey array_key_exists array_keys array_map '+
+					'array_merge array_merge_recursive array_multisort array_pad array_pop array_product '+
+					'array_push array_rand array_reduce array_reverse array_search array_shift '+
+					'array_slice array_splice array_sum array_udiff array_udiff_assoc '+
+					'array_udiff_uassoc array_uintersect array_uintersect_assoc '+
+					'array_uintersect_uassoc array_unique array_unshift array_values array_walk '+
+					'array_walk_recursive atan atan2 atanh base64_decode base64_encode base_convert '+
+					'basename bcadd bccomp bcdiv bcmod bcmul bindec bindtextdomain bzclose bzcompress '+
+					'bzdecompress bzerrno bzerror bzerrstr bzflush bzopen bzread bzwrite ceil chdir '+
+					'checkdate checkdnsrr chgrp chmod chop chown chr chroot chunk_split class_exists '+
+					'closedir closelog copy cos cosh count count_chars date decbin dechex decoct '+
+					'deg2rad delete ebcdic2ascii echo empty end ereg ereg_replace eregi eregi_replace error_log '+
+					'error_reporting escapeshellarg escapeshellcmd eval exec exit exp explode extension_loaded '+
+					'feof fflush fgetc fgetcsv fgets fgetss file_exists file_get_contents file_put_contents '+
+					'fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype '+
+					'floatval flock floor flush fmod fnmatch fopen fpassthru fprintf fputcsv fputs fread fscanf '+
+					'fseek fsockopen fstat ftell ftok getallheaders getcwd getdate getenv gethostbyaddr gethostbyname '+
+					'gethostbynamel getimagesize getlastmod getmxrr getmygid getmyinode getmypid getmyuid getopt '+
+					'getprotobyname getprotobynumber getrandmax getrusage getservbyname getservbyport gettext '+
+					'gettimeofday gettype glob gmdate gmmktime ini_alter ini_get ini_get_all ini_restore ini_set '+
+					'interface_exists intval ip2long is_a is_array is_bool is_callable is_dir is_double '+
+					'is_executable is_file is_finite is_float is_infinite is_int is_integer is_link is_long '+
+					'is_nan is_null is_numeric is_object is_readable is_real is_resource is_scalar is_soap_fault '+
+					'is_string is_subclass_of is_uploaded_file is_writable is_writeable mkdir mktime nl2br '+
+					'parse_ini_file parse_str parse_url passthru pathinfo readlink realpath rewind rewinddir rmdir '+
+					'round str_ireplace str_pad str_repeat str_replace str_rot13 str_shuffle str_split '+
+					'str_word_count strcasecmp strchr strcmp strcoll strcspn strftime strip_tags stripcslashes '+
+					'stripos stripslashes stristr strlen strnatcasecmp strnatcmp strncasecmp strncmp strpbrk '+
+					'strpos strptime strrchr strrev strripos strrpos strspn strstr strtok strtolower strtotime '+
+					'strtoupper strtr strval substr substr_compare';
+
+	var keywords =	'and or xor __FILE__ __LINE__ array as break case ' +
+					'cfunction class const continue declare default die do else ' +
+					'elseif empty enddeclare endfor endforeach endif endswitch endwhile ' +
+					'extends for foreach function include include_once global if ' +
+					'new old_function return static switch use require require_once ' +
+					'var while __FUNCTION__ __CLASS__ ' +
+					'__METHOD__ abstract interface public implements extends private protected throw';
+
+	this.regexList = [
+		{ regex: dp.sh.RegexLib.SingleLineCComments,				css: 'comment' },			// one line comments
+		{ regex: dp.sh.RegexLib.MultiLineCComments,					css: 'comment' },			// multiline comments
+		{ regex: dp.sh.RegexLib.DoubleQuotedString,					css: 'string' },			// double quoted strings
+		{ regex: dp.sh.RegexLib.SingleQuotedString,					css: 'string' },			// single quoted strings
+		{ regex: new RegExp('\\$\\w+', 'g'),						css: 'vars' },				// variables
+		{ regex: new RegExp(this.GetKeywords(funcs), 'gmi'),		css: 'func' },				// functions
+		{ regex: new RegExp(this.GetKeywords(keywords), 'gm'),		css: 'keyword' }			// keyword
+		];
+
+	this.CssClass = 'dp-c';
+}
+
+dp.sh.Brushes.Php.prototype	= new dp.sh.Highlighter();
+dp.sh.Brushes.Php.Aliases	= ['php'];


Property changes on: trunk/examples/typeface/root/static/Scripts/shBrushPhp.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Scripts/shBrushPython.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shBrushPython.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shBrushPython.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,69 @@
+/* Python 2.3 syntax contributed by Gheorghe Milas */
+dp.sh.Brushes.Python = function()
+{
+	var keywords =		'and assert break class continue def del elif else except exec ' +
+						'finally for from global if import in is lambda not or object pass print ' +
+						'raise return try yield while';
+	
+	var builtins =		'self __builtin__ __dict__ __future__ __methods__ __members__ __author__ __email__ __version__' +
+						'__class__ __bases__ __import__ __main__ __name__ __doc__ __self__ __debug__ __slots__ ' +
+						'abs append apply basestring bool buffer callable chr classmethod clear close cmp coerce compile complex ' +
+						'conjugate copy count delattr dict dir divmod enumerate Ellipsis eval execfile extend False file fileno filter float flush ' +
+						'get getattr globals has_key hasarttr hash hex id index input insert int intern isatty isinstance isubclass ' +
+						'items iter keys len list locals long map max min mode oct open ord pop pow property range ' +
+						'raw_input read readline readlines reduce reload remove repr reverse round seek setattr slice sum ' +
+						'staticmethod str super tell True truncate tuple type unichr unicode update values write writelines xrange zip';
+	
+	var magicmethods =	'__abs__ __add__ __and__ __call__ __cmp__ __coerce__ __complex__ __concat__ __contains__ __del__ __delattr__ __delitem__ ' +
+						'__delslice__ __div__ __divmod__ __float__ __getattr__ __getitem__ __getslice__ __hash__ __hex__ __eq__ __le__ __lt__ __gt__ __ge__ ' +
+						'__iadd__ __isub__ __imod__ __idiv__ __ipow__ __iand__ __ior__ __ixor__ __ilshift__ __irshift__ ' +
+						'__invert__ __init__ __int__ __inv__ __iter__ __len__ __long__ __lshift__ __mod__ __mul__ __new__ __neg__ __nonzero__ __oct__ __or__ ' +
+						'__pos__ __pow__ __radd__ __rand__ __rcmp__ __rdiv__ __rdivmod__ __repeat__ __repr__ __rlshift__ __rmod__ __rmul__ ' +
+						'__ror__ __rpow__ __rrshift__ __rshift__ __rsub__ __rxor__ __setattr__ __setitem__ __setslice__ __str__ __sub__ __xor__';
+	
+	var exceptions =	'Exception StandardError ArithmeticError LookupError EnvironmentError AssertionError AttributeError EOFError ' +
+						'FutureWarning IndentationError OverflowWarning PendingDeprecationWarning ReferenceError RuntimeWarning ' +
+						'SyntaxWarning TabError UnicodeDecodeError UnicodeEncodeError UnicodeTranslateError UserWarning Warning ' +
+						'IOError ImportError IndexError KeyError KeyboardInterrupt MemoryError NameError NotImplementedError OSError ' +
+						'RuntimeError StopIteration SyntaxError SystemError SystemExit TypeError UnboundLocalError UnicodeError ValueError ' +
+						'FloatingPointError OverflowError WindowsError ZeroDivisionError';
+	
+	var types =			'NoneType TypeType IntType LongType FloatType ComplexType StringType UnicodeType BufferType TupleType ListType ' +
+						'DictType FunctionType LambdaType CodeType ClassType UnboundMethodType InstanceType MethodType BuiltinFunctionType BuiltinMethodType ' +
+						'ModuleType FileType XRangeType TracebackType FrameType SliceType EllipsisType';
+	
+	var commonlibs =	'anydbm array asynchat asyncore AST base64 binascii binhex bisect bsddb buildtools bz2 ' +
+						'BaseHTTPServer Bastion calendar cgi cmath cmd codecs codeop commands compiler copy copy_reg ' +
+						'cPickle crypt cStringIO csv curses Carbon CGIHTTPServer ConfigParser Cookie datetime dbhash ' +
+						'dbm difflib dircache distutils doctest DocXMLRPCServer email encodings errno exceptions fcntl ' +
+						'filecmp fileinput ftplib gc gdbm getopt getpass glob gopherlib gzip heapq htmlentitydefs ' +
+						'htmllib httplib HTMLParser imageop imaplib imgfile imghdr imp inspect itertools jpeg keyword ' +
+						'linecache locale logging mailbox mailcap marshal math md5 mhlib mimetools mimetypes mimify mmap ' +
+						'mpz multifile mutex MimeWriter netrc new nis nntplib nsremote operator optparse os parser pickle pipes ' +
+						'popen2 poplib posix posixfile pprint preferences profile pstats pwd pydoc pythonprefs quietconsole ' +
+						'quopri Queue random re readline resource rexec rfc822 rgbimg sched select sets sgmllib sha shelve shutil ' +
+						'signal site smtplib socket stat statcache string struct symbol sys syslog SimpleHTTPServer ' +
+						'SimpleXMLRPCServer SocketServer StringIO tabnanny tarfile telnetlib tempfile termios textwrap ' +
+						'thread threading time timeit token tokenize traceback tty types Tkinter unicodedata unittest ' +
+						'urllib urllib2 urlparse user UserDict UserList UserString warnings weakref webbrowser whichdb ' +
+						'xml xmllib xmlrpclib xreadlines zipfile zlib';
+
+	this.regexList = [
+		{ regex: new RegExp('#.*$', 'gm'),							css: 'comment' },			// comments
+		{ regex: new RegExp('"""(.|\n)*?"""', 'gm'),					css: 'string' },			// multi-line strings "
+		{ regex: new RegExp("'''(.|\n)*?'''", 'gm'),					css: 'string' },			// multi-line strings '
+//		{ regex: dp.sh.RegexLib.DoubleQuotedString,					css: 'string' },			// double quoted strings
+//		{ regex: dp.sh.RegexLib.SingleQuotedString,					css: 'string' },			// single quoted strings
+		{ regex: new RegExp(this.GetKeywords(keywords), 'gm'),		css: 'keyword' },			// keywords
+		{ regex: new RegExp(this.GetKeywords(builtins), 'gm'),		css: 'builtins' },			// builtin objects, functions, methods, magic attributes
+		{ regex: new RegExp(this.GetKeywords(magicmethods), 'gm'),	css: 'magicmethods' },		// special methods
+		{ regex: new RegExp(this.GetKeywords(exceptions), 'gm'),	css: 'exceptions' },		// standard exception classes
+		{ regex: new RegExp(this.GetKeywords(types), 'gm'),			css: 'types' },				// types from types.py
+		{ regex: new RegExp(this.GetKeywords(commonlibs), 'gm'),	css: 'commonlibs' }			// common standard library modules
+		];
+
+	this.CssClass = 'dp-py';
+}
+
+dp.sh.Brushes.Python.prototype	= new dp.sh.Highlighter();
+dp.sh.Brushes.Python.Aliases	= ['py', 'python'];


Property changes on: trunk/examples/typeface/root/static/Scripts/shBrushPython.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Scripts/shBrushRuby.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shBrushRuby.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shBrushRuby.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,26 @@
+/* Ruby 1.8.4 syntax contributed by Erik Peterson */
+dp.sh.Brushes.Ruby = function()
+{
+  var keywords =	'alias and BEGIN begin break case class def define_method defined do each else elsif ' +
+					'END end ensure false for if in module new next nil not or raise redo rescue retry return ' +
+					'self super then throw true undef unless until when while yield';
+
+  var builtins =	'Array Bignum Binding Class Continuation Dir Exception FalseClass File::Stat File Fixnum Fload ' +
+					'Hash Integer IO MatchData Method Module NilClass Numeric Object Proc Range Regexp String Struct::TMS Symbol ' +
+					'ThreadGroup Thread Time TrueClass'
+
+	this.regexList = [
+		{ regex: dp.sh.RegexLib.SingleLinePerlComments,			css: 'comment' },	// one line comments
+		{ regex: dp.sh.RegexLib.DoubleQuotedString,				css: 'string' },	// double quoted strings
+		{ regex: dp.sh.RegexLib.SingleQuotedString,				css: 'string' },	// single quoted strings
+		{ regex: new RegExp(':[a-z][A-Za-z0-9_]*', 'g'),		css: 'symbol' },	// symbols
+		{ regex: new RegExp('[\\$|@|@@]\\w+', 'g'),				css: 'variable' },	// $global, @instance, and @@class variables
+		{ regex: new RegExp(this.GetKeywords(keywords), 'gm'),	css: 'keyword' },	// keywords
+		{ regex: new RegExp(this.GetKeywords(builtins), 'gm'),	css: 'builtin' }	// builtins
+		];
+
+	this.CssClass = 'dp-rb';
+}
+
+dp.sh.Brushes.Ruby.prototype	= new dp.sh.Highlighter();
+dp.sh.Brushes.Ruby.Aliases	= ['ruby', 'rails'];


Property changes on: trunk/examples/typeface/root/static/Scripts/shBrushRuby.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Scripts/shBrushSql.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shBrushSql.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shBrushSql.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,40 @@
+dp.sh.Brushes.Sql = function()
+{
+	var funcs	=	'abs avg case cast coalesce convert count current_timestamp ' +
+					'current_user day isnull left lower month nullif replace right ' +
+					'session_user space substring sum system_user upper user year';
+
+	var keywords =	'absolute action add after alter as asc at authorization begin bigint ' +
+					'binary bit by cascade char character check checkpoint close collate ' +
+					'column commit committed connect connection constraint contains continue ' +
+					'create cube current current_date current_time cursor database date ' +
+					'deallocate dec decimal declare default delete desc distinct double drop ' +
+					'dynamic else end end-exec escape except exec execute false fetch first ' +
+					'float for force foreign forward free from full function global goto grant ' +
+					'group grouping having hour ignore index inner insensitive insert instead ' +
+					'int integer intersect into is isolation key last level load local max min ' +
+					'minute modify move name national nchar next no numeric of off on only ' +
+					'open option order out output partial password precision prepare primary ' +
+					'prior privileges procedure public read real references relative repeatable ' +
+					'restrict return returns revoke rollback rollup rows rule schema scroll ' +
+					'second section select sequence serializable set size smallint static ' +
+					'statistics table temp temporary then time timestamp to top transaction ' +
+					'translation trigger true truncate uncommitted union unique update values ' +
+					'varchar varying view when where with work';
+
+	var operators =	'all and any between cross in join like not null or outer some';
+
+	this.regexList = [
+		{ regex: new RegExp('--(.*)$', 'gm'),						css: 'comment' },			// one line and multiline comments
+		{ regex: dp.sh.RegexLib.DoubleQuotedString,					css: 'string' },			// double quoted strings
+		{ regex: dp.sh.RegexLib.SingleQuotedString,					css: 'string' },			// single quoted strings
+		{ regex: new RegExp(this.GetKeywords(funcs), 'gmi'),		css: 'func' },				// functions
+		{ regex: new RegExp(this.GetKeywords(operators), 'gmi'),	css: 'op' },				// operators and such
+		{ regex: new RegExp(this.GetKeywords(keywords), 'gmi'),		css: 'keyword' }			// keyword
+		];
+
+	this.CssClass = 'dp-sql';
+}
+
+dp.sh.Brushes.Sql.prototype	= new dp.sh.Highlighter();
+dp.sh.Brushes.Sql.Aliases	= ['sql'];


Property changes on: trunk/examples/typeface/root/static/Scripts/shBrushSql.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Scripts/shBrushVb.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shBrushVb.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shBrushVb.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,29 @@
+dp.sh.Brushes.Vb = function()
+{
+	var keywords =	'AddHandler AddressOf AndAlso Alias And Ansi As Assembly Auto ' +
+					'Boolean ByRef Byte ByVal Call Case Catch CBool CByte CChar CDate ' +
+					'CDec CDbl Char CInt Class CLng CObj Const CShort CSng CStr CType ' +
+					'Date Decimal Declare Default Delegate Dim DirectCast Do Double Each ' +
+					'Else ElseIf End Enum Erase Error Event Exit False Finally For Friend ' +
+					'Function Get GetType GoSub GoTo Handles If Implements Imports In ' +
+					'Inherits Integer Interface Is Let Lib Like Long Loop Me Mod Module ' +
+					'MustInherit MustOverride MyBase MyClass Namespace New Next Not Nothing ' +
+					'NotInheritable NotOverridable Object On Option Optional Or OrElse ' +
+					'Overloads Overridable Overrides ParamArray Preserve Private Property ' +
+					'Protected Public RaiseEvent ReadOnly ReDim REM RemoveHandler Resume ' +
+					'Return Select Set Shadows Shared Short Single Static Step Stop String ' +
+					'Structure Sub SyncLock Then Throw To True Try TypeOf Unicode Until ' +
+					'Variant When While With WithEvents WriteOnly Xor';
+
+	this.regexList = [
+		{ regex: new RegExp('\'.*$', 'gm'),							css: 'comment' },			// one line comments
+		{ regex: dp.sh.RegexLib.DoubleQuotedString,					css: 'string' },			// strings
+		{ regex: new RegExp('^\\s*#.*', 'gm'),						css: 'preprocessor' },		// preprocessor tags like #region and #endregion
+		{ regex: new RegExp(this.GetKeywords(keywords), 'gm'),		css: 'keyword' }			// c# keyword
+		];
+
+	this.CssClass = 'dp-vb';
+}
+
+dp.sh.Brushes.Vb.prototype	= new dp.sh.Highlighter();
+dp.sh.Brushes.Vb.Aliases	= ['vb', 'vb.net'];


Property changes on: trunk/examples/typeface/root/static/Scripts/shBrushVb.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Scripts/shBrushXml.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shBrushXml.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shBrushXml.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,61 @@
+dp.sh.Brushes.Xml = function()
+{
+	this.CssClass = 'dp-xml';
+}
+
+dp.sh.Brushes.Xml.prototype	= new dp.sh.Highlighter();
+dp.sh.Brushes.Xml.Aliases	= ['xml', 'xhtml', 'xslt', 'html', 'xhtml'];
+
+dp.sh.Brushes.Xml.prototype.ProcessRegexList = function()
+{
+	function push(array, value)
+	{
+		array[array.length] = value;
+	}
+	
+	/* If only there was a way to get index of a group within a match, the whole XML
+	   could be matched with the expression looking something like that:
+	
+	   (<!\[CDATA\[\s*.*\s*\]\]>)
+	   | (<!--\s*.*\s*?-->)
+	   | (<)*(\w+)*\s*(\w+)\s*=\s*(".*?"|'.*?'|\w+)(/*>)*
+	   | (</?)(.*?)(/?>)
+	*/
+	var index	= 0;
+	var match	= null;
+	var regex	= null;
+
+	// Match CDATA in the following format <![ ... [ ... ]]>
+	// <\!\[[\w\s]*?\[(.|\s)*?\]\]>
+	this.GetMatches(new RegExp('<\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\]>', 'gm'), 'cdata');
+	
+	// Match comments
+	// <!--\s*.*\s*?-->
+	this.GetMatches(new RegExp('<!--\\s*.*\\s*?-->', 'gm'), 'comments');
+
+	// Match attributes and their values
+	// (:|\w+)\s*=\s*(".*?"|\'.*?\'|\w+)*
+	regex = new RegExp('([:\\w-\.]+)\\s*=\\s*(".*?"|\'.*?\'|\\w+)*', 'gm'); // Thanks to Tomi Blinnikka of Yahoo! for fixing namespaces in attributes
+	while((match = regex.exec(this.code)) != null)
+	{
+		push(this.matches, new dp.sh.Match(match[1], match.index, 'attribute'));
+	
+		// if xml is invalid and attribute has no property value, ignore it	
+		if(match[2] != undefined)
+		{
+			push(this.matches, new dp.sh.Match(match[2], match.index + match[0].indexOf(match[2]), 'attribute-value'));
+		}
+	}
+
+	// Match opening and closing tag brackets
+	// </*\?*(?!\!)|/*\?*>
+	this.GetMatches(new RegExp('</*\\?*(?!\\!)|/*\\?*>', 'gm'), 'tag');
+
+	// Match tag names
+	// </*\?*\s*(\w+)
+	regex = new RegExp('</*\\?*\\s*([:\\w-\.]+)', 'gm');
+	while((match = regex.exec(this.code)) != null)
+	{
+		push(this.matches, new dp.sh.Match(match[1], match.index + match[0].indexOf(match[1]), 'tag-name'));
+	}
+}


Property changes on: trunk/examples/typeface/root/static/Scripts/shBrushXml.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Scripts/shCore.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shCore.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shCore.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1 @@
+var dp={sh:{Toolbar:{},Utils:{},RegexLib:{},Brushes:{},Strings:{},Version:"1.4.1"}};dp.sh.Strings={AboutDialog:"<html><head><title>About...</title></head><body class=\"dp-about\"><table cellspacing=\"0\"><tr><td class=\"copy\"><p class=\"title\">dp.SyntaxHighlighter</div><div class=\"para\">Version: {V}</p><p><a href=\"http://www.dreamprojections.com/syntaxhighlighter/?ref=about\" target=\"_blank\">http://www.dreamprojections.com/SyntaxHighlighter</a></p>&copy;2004-2005 Alex Gorbatchev. All right reserved.</td></tr><tr><td class=\"footer\"><input type=\"button\" class=\"close\" value=\"OK\" onClick=\"window.close()\"/></td></tr></table></body></html>"};dp.SyntaxHighlighter=dp.sh;dp.sh.Toolbar.Commands={ExpandSource:{label:"+ expand source",check:function(_1){return _1.collapse;},func:function(_2,_3){_2.parentNode.removeChild(_2);_3.div.className=_3.div.className.replace("collapsed","");}},ViewSource:{label:"view plain",func:function(_4,_5){var _6=_5.originalCode.replace(/</g,"&lt;");var _7=window.open("","_blank","width=750, height=400, location=0, resizable=1, menubar=0, scrollbars=1");_7.document.write("<textarea style=\"width:99%;height:99%\">"+_6+"</textarea>");_7.document.close();}},CopyToClipboard:{label:"copy to clipboard",check:function(){return window.clipboardData!=null;},func:function(_8,_9){window.clipboardData.setData("text",_9.originalCode);alert("The code is in your clipboard now");}},PrintSource:{label:"print",func:function(_a,_b){var _c=document.createElement("IFRAME");var _d=null;_c.style.cssText="position:absolute;width:0px;height:0px;left:-500px;top:-500px;";document.body.appendChild(_c);_d=_c.contentWindow.document;dp.sh.Utils.CopyStyles(_d,window.document);_d.write("<div class=\""+_b.div.className.replace("collapsed","")+" printing\">"+_b.div.innerHTML+"</div>");_d.close();_c.contentWindow.focus();_c.contentWindow.print();alert("Printing...");document.body.removeChild(_c);}},About:{label:"?",func:function(_e){var _f=window.open("","_blank","dialog,width=300,height=150,scrollbars=0");var doc=_f.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write(dp.sh.Strings.AboutDialog.replace("{V}",dp.sh.Version));doc.close();_f.focus();}}};dp.sh.Toolbar.Create=function(_11){var div=document.createElement("DIV");div.className="tools";for(var _13 in dp.sh.Toolbar.Commands){var cmd=dp.sh.Toolbar.Commands[_13];if(cmd.check!=null&&!cmd.check(_11)){continue;}div.innerHTML+="<a href=\"#\" onclick=\"dp.sh.Toolbar.Command('"+_13+"',this);return false;\">"+cmd.label+"</a>";}return div;};dp.sh.Toolbar.Command=function(_15,_16){var n=_16;while(n!=null&&n.className.indexOf("dp-highlighter")==-1){n=n.parentNode;}if(n!=null){dp.sh.Toolbar.Commands[_15].func(_16,n.highlighter);}};dp.sh.Utils.CopyStyles=function(_18,_19){var _1a=_19.getElementsByTagName("link");for(var i=0;i<_1a.length;i++){if(_1a[i].rel.toLowerCase()=="stylesheet"){_18.write("<link type=\"text/css\" rel=\"stylesheet\" href=\""+_1a[i].href+"\"></link>");}}};dp.sh.RegexLib={MultiLineCComments:new RegExp("/\\*[\\s\\S]*?\\*/","gm"),SingleLineCComments:new RegExp("//.*$","gm"),SingleLinePerlComments:new RegExp("#.*$","gm"),DoubleQuotedString:new RegExp("\"(?:\\.|(\\\\\\\")|[^\\\"\"])*\"","g"),SingleQuotedString:new RegExp("'(?:\\.|(\\\\\\')|[^\\''])*'","g")};dp.sh.Match=function(_1c,_1d,css){this.value=_1c;this.index=_1d;this.length=_1c.length;this.css=css;};dp.sh.Highlighter=function(){this.noGutter=false;this.addControls=true;this.collapse=false;this.tabsToSpaces=true;this.wrapColumn=80;this.showColumns=true;};dp.sh.Highlighter.SortCallback=function(m1,m2){if(m1.index<m2.index){return -1;}else{if(m1.index>m2.index){return 1;}else{if(m1.length<m2.length){return -1;}else{if(m1.length>m2.length){return 1;}}}}return 0;};dp.sh.Highlighter.prototype.CreateElement=function(_21){var _22=document.createElement(_21);_22.highlighter=this;return _22;};dp.sh.Highlighter.prototype.GetMatches=function(_23,css){var _25=0;var _26=null;while((_26=_23.exec(this.code))!=null){this.matches[this.matches.length]=new dp.sh.Match(_26[0],_26.index,css);}};dp.sh.Highlighter.prototype.AddBit=function(str,css){if(str==null||str.length==0){return;}var _29=this.CreateElement("SPAN");str=str.replace(/&/g,"&amp;");str=str.replace(/ /g,"&nbsp;");str=str.replace(/</g,"&lt;");str=str.replace(/\n/gm,"&nbsp;<br>");if(css!=null){var _2a=new RegExp("<br>","gi");if(_2a.test(str)){var _2b=str.split("&nbsp;<br>");str="";for(var i=0;i<_2b.length;i++){_29=this.CreateElement("SPAN");_29.className=css;_29.innerHTML=_2b[i];this.div.appendChild(_29);if(i+1<_2b.length){this.div.appendChild(this.CreateElement("BR"));}}}else{_29.className=css;_29.innerHTML=str;this.div.appendChild(_29);}}else{_29.innerHTML=str;this.div.appendChild(_29);}};dp.sh.Highlighter.prototype.IsInside=function(_2d){if(_2d==null||_2d.length==0){return false;}for(var i=0;i<this.matches.length;i++){var c=this.matches[i];if(c==null){continue;}if((_2d.index>c.index)&&(_2d.index<c.index+c.length)){return true;}}return false;};dp.sh.Highlighter.prototype.ProcessRegexList=function(){for(var i=0;i<this.regexList.length;i++){this.GetMatches(this.regexList[i].regex,this.regexList[i].css);}};dp.sh.Highlighter.prototype.ProcessSmartTabs=function(_31){var _32=_31.split("\n");var _33="";var _34=4;var tab="\t";function InsertSpaces(_36,pos,_38){var _39=_36.substr(0,pos);var _3a=_36.substr(pos+1,_36.length);var _3b="";for(var i=0;i<_38;i++){_3b+=" ";}return _39+_3b+_3a;}function ProcessLine(_3d,_3e){if(_3d.indexOf(tab)==-1){return _3d;}var pos=0;while((pos=_3d.indexOf(tab))!=-1){var _40=_3e-pos%_3e;_3d=InsertSpaces(_3d,pos,_40);}return _3d;}for(var i=0;i<_32.length;i++){_33+=ProcessLine(_32[i],_34)+"\n";}return _33;};dp.sh.Highlighter.prototype.SwitchToList=function(){var _42=this.div.innerHTML.replace(/<(br)\/?>/gi,"\n");var _43=_42.split("\n");if(this.addControls==true){this.bar.appendChild(dp.sh.Toolbar.Create(this));}if(this.showColumns){var div=this.CreateElement("div");var _45=this.CreateElement("div");var _46=10;var i=1;while(i<=150){if(i%_46==0){div.innerHTML+=i;i+=(i+"").length;}else{div.innerHTML+="&middot;";i++;}}_45.className="columns";_45.appendChild(div);this.bar.appendChild(_45);}for(var i=0,lineIndex=this.firstLine;i<_43.length-1;i++,lineIndex++){var li=this.CreateElement("LI");var _4a=this.CreateElement("SPAN");li.className=(i%2==0)?"alt":"";_4a.innerHTML=_43[i]+"&nbsp;";li.appendChild(_4a);this.ol.appendChild(li);}this.div.innerHTML="";};dp.sh.Highlighter.prototype.Highlight=function(_4b){function Trim(str){return str.replace(/^\s*(.*?)[\s\n]*$/g,"$1");}function Chop(str){return str.replace(/\n*$/,"").replace(/^\n*/,"");}function Unindent(str){var _4f=str.split("\n");var _50=new Array();var _51=new RegExp("^\\s*","g");var min=1000;for(var i=0;i<_4f.length&&min>0;i++){if(Trim(_4f[i]).length==0){continue;}var _54=_51.exec(_4f[i]);if(_54!=null&&_54.length>0){min=Math.min(_54[0].length,min);}}if(min>0){for(var i=0;i<_4f.length;i++){_4f[i]=_4f[i].substr(min);}}return _4f.join("\n");}function Copy(_56,_57,_58){return _56.substr(_57,_58-_57);}var pos=0;this.originalCode=_4b;this.code=Chop(Unindent(_4b));this.div=this.CreateElement("DIV");this.bar=this.CreateElement("DIV");this.ol=this.CreateElement("OL");this.matches=new Array();this.div.className="dp-highlighter";this.div.highlighter=this;this.bar.className="bar";this.ol.start=this.firstLine;if(this.CssClass!=null){this.ol.className=this.CssClass;}if(this.collapse){this.div.className+=" collapsed";}if(this.noGutter){this.div.className+=" nogutter";}if(this.tabsToSpaces==true){this.code=this.ProcessSmartTabs(this.code);}this.ProcessRegexList();if(this.matches.length==0){this.AddBit(this.code,null);this.SwitchToList();this.div.appendChild(this.ol);return;}this.matches=this.matches.sort(dp.sh.Highlighter.SortCallback);for(var i=0;i<this.matches.length;i++){if(this.IsInside(this.matches[i])){this.matches[i]=null;}}for(var i=0;i<this.matches.length;i++){var _5c=this.matches[i];if(_5c==null||_5c.length==0){continue;}this.AddBit(Copy(this.code,pos,_5c.index),null);this.AddBit(_5c.value,_5c.css);pos=_5c.index+_5c.length;}this.AddBit(this.code.substr(pos),null);this.SwitchToList();this.div.appendChild(this.bar);this.div.appendChild(this.ol);};dp.sh.Highlighter.prototype.GetKeywords=function(str){return "\\b"+str.replace(/ /g,"\\b|\\b")+"\\b";};dp.sh.HighlightAll=function(_5e,_5f,_60,_61,_62,_63){function FindValue(){var a=arguments;for(var i=0;i<a.length;i++){if(a[i]==null){continue;}if(typeof (a[i])=="string"&&a[i]!=""){return a[i]+"";}if(typeof (a[i])=="object"&&a[i].value!=""){return a[i].value+"";}}return null;}function IsOptionSet(_66,_67){for(var i=0;i<_67.length;i++){if(_67[i]==_66){return true;}}return false;}function GetOptionValue(_69,_6a,_6b){var _6c=new RegExp("^"+_69+"\\[(\\w+)\\]$","gi");var _6d=null;for(var i=0;i<_6a.length;i++){if((_6d=_6c.exec(_6a[i]))!=null){return _6d[1];}}return _6b;}var _6f=document.getElementsByName(_5e);var _70=null;var _71=new Object();var _72="value";if(_6f==null){return;}for(var _73 in dp.sh.Brushes){var _74=dp.sh.Brushes[_73].Aliases;if(_74==null){continue;}for(var i=0;i<_74.length;i++){_71[_74[i]]=_73;}}for(var i=0;i<_6f.length;i++){var _77=_6f[i];var _78=FindValue(_77.attributes["class"],_77.className,_77.attributes["language"],_77.language);var _79="";if(_78==null){continue;}_78=_78.split(":");_79=_78[0].toLowerCase();if(_71[_79]==null){continue;}_70=new dp.sh.Brushes[_71[_79]]();_77.style.display="none";_70.noGutter=(_5f==null)?IsOptionSet("nogutter",_78):!_5f;_70.addControls=(_60==null)?!IsOptionSet("nocontrols",_78):_60;_70.collapse=(_61==null)?IsOptionSet("collapse",_78):_61;_70.showColumns=(_63==null)?IsOptionSet("showcolumns",_78):_63;_70.firstLine=(_62==null)?parseInt(GetOptionValue("firstline",_78,1)):_62;_70.Highlight(_77[_72]);_77.parentNode.insertBefore(_70.div,_77);}};
\ No newline at end of file


Property changes on: trunk/examples/typeface/root/static/Scripts/shCore.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Scripts/shCore.uncompressed.js
===================================================================
--- trunk/examples/typeface/root/static/Scripts/shCore.uncompressed.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/Scripts/shCore.uncompressed.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,636 @@
+/**
+ * Code Syntax Highlighter.
+ * Version 1.3.0
+ * Copyright (C) 2004 Alex Gorbatchev.
+ * http://www.dreamprojections.com/syntaxhighlighter/
+ * 
+ * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 
+ * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ */
+
+//
+// create namespaces
+//
+var dp = {
+	sh :
+	{
+		Toolbar : {},
+		Utils	: {},
+		RegexLib: {},
+		Brushes	: {},
+		Strings : {},
+		Version : '1.4.1'
+	}
+};
+
+dp.sh.Strings = {
+	AboutDialog : '<html><head><title>About...</title></head><body class="dp-about"><table cellspacing="0"><tr><td class="copy"><p class="title">dp.SyntaxHighlighter</div><div class="para">Version: {V}</p><p><a href="http://www.dreamprojections.com/syntaxhighlighter/?ref=about" target="_blank">http://www.dreamprojections.com/SyntaxHighlighter</a></p>&copy;2004-2005 Alex Gorbatchev. All right reserved.</td></tr><tr><td class="footer"><input type="button" class="close" value="OK" onClick="window.close()"/></td></tr></table></body></html>'
+};
+
+dp.SyntaxHighlighter = dp.sh;
+
+//
+// Toolbar functions
+//
+
+dp.sh.Toolbar.Commands = {
+	ExpandSource: {
+		label: '+ expand source',
+		check: function(highlighter) { return highlighter.collapse; },
+		func: function(sender, highlighter)
+		{
+			sender.parentNode.removeChild(sender);
+			highlighter.div.className = highlighter.div.className.replace('collapsed', '');
+		}
+	},
+	
+	// opens a new windows and puts the original unformatted source code inside.
+	ViewSource: {
+		label: 'view plain',
+		func: function(sender, highlighter)
+		{
+			var code = highlighter.originalCode.replace(/</g, '&lt;');
+			var wnd = window.open('', '_blank', 'width=750, height=400, location=0, resizable=1, menubar=0, scrollbars=1');
+			wnd.document.write('<textarea style="width:99%;height:99%">' + code + '</textarea>');
+			wnd.document.close();
+		}
+	},
+	
+	// copies the original source code in to the clipboard (IE only)
+	CopyToClipboard: {
+		label: 'copy to clipboard',
+		check: function() { return window.clipboardData != null; },
+		func: function(sender, highlighter)
+		{
+			window.clipboardData.setData('text', highlighter.originalCode);
+			alert('The code is in your clipboard now');
+		}
+	},
+	
+	// creates an invisible iframe, puts the original source code inside and prints it
+	PrintSource: {
+		label: 'print',
+		func: function(sender, highlighter)
+		{
+			var iframe = document.createElement('IFRAME');
+			var doc = null;
+
+			// this hides the iframe
+			iframe.style.cssText = 'position:absolute;width:0px;height:0px;left:-500px;top:-500px;';
+			
+			document.body.appendChild(iframe);
+			doc = iframe.contentWindow.document;
+
+			dp.sh.Utils.CopyStyles(doc, window.document);
+			doc.write('<div class="' + highlighter.div.className.replace('collapsed', '') + ' printing">' + highlighter.div.innerHTML + '</div>');
+			doc.close();
+
+			iframe.contentWindow.focus();
+			iframe.contentWindow.print();
+			
+			alert('Printing...');
+			
+			document.body.removeChild(iframe);
+		}
+	},
+	
+	About: {
+		label: '?',
+		func: function(highlighter)
+		{
+			var wnd	= window.open('', '_blank', 'dialog,width=300,height=150,scrollbars=0');
+			var doc	= wnd.document;
+
+			dp.sh.Utils.CopyStyles(doc, window.document);
+			
+			doc.write(dp.sh.Strings.AboutDialog.replace('{V}', dp.sh.Version));
+			doc.close();
+			wnd.focus();
+		}
+	}
+};
+
+// creates a <div /> with all toolbar links
+dp.sh.Toolbar.Create = function(highlighter)
+{
+	var div = document.createElement('DIV');
+	
+	div.className = 'tools';
+	
+	for(var name in dp.sh.Toolbar.Commands)
+	{
+		var cmd = dp.sh.Toolbar.Commands[name];
+		
+		if(cmd.check != null && !cmd.check(highlighter))
+			continue;
+		
+		div.innerHTML += '<a href="#" onclick="dp.sh.Toolbar.Command(\'' + name + '\',this);return false;">' + cmd.label + '</a>';
+	}
+	
+	return div;
+}
+
+// executes toolbar command by name
+dp.sh.Toolbar.Command = function(name, sender)
+{
+	var n = sender;
+	
+	while(n != null && n.className.indexOf('dp-highlighter') == -1)
+		n = n.parentNode;
+	
+	if(n != null)
+		dp.sh.Toolbar.Commands[name].func(sender, n.highlighter);
+}
+
+// copies all <link rel="stylesheet" /> from 'target' window to 'dest'
+dp.sh.Utils.CopyStyles = function(destDoc, sourceDoc)
+{
+	var links = sourceDoc.getElementsByTagName('link');
+
+	for(var i = 0; i < links.length; i++)
+		if(links[i].rel.toLowerCase() == 'stylesheet')
+			destDoc.write('<link type="text/css" rel="stylesheet" href="' + links[i].href + '"></link>');
+}
+
+//
+// Common reusable regular expressions
+//
+dp.sh.RegexLib = {
+	MultiLineCComments : new RegExp('/\\*[\\s\\S]*?\\*/', 'gm'),
+	SingleLineCComments : new RegExp('//.*$', 'gm'),
+	SingleLinePerlComments : new RegExp('#.*$', 'gm'),
+	DoubleQuotedString : new RegExp('"(?:\\.|(\\\\\\")|[^\\""])*"','g'),
+	SingleQuotedString : new RegExp("'(?:\\.|(\\\\\\')|[^\\''])*'", 'g')
+};
+
+//
+// Match object
+//
+dp.sh.Match = function(value, index, css)
+{
+	this.value = value;
+	this.index = index;
+	this.length = value.length;
+	this.css = css;
+}
+
+//
+// Highlighter object
+//
+dp.sh.Highlighter = function()
+{
+	this.noGutter = false;
+	this.addControls = true;
+	this.collapse = false;
+	this.tabsToSpaces = true;
+	this.wrapColumn = 80;
+	this.showColumns = true;
+}
+
+// static callback for the match sorting
+dp.sh.Highlighter.SortCallback = function(m1, m2)
+{
+	// sort matches by index first
+	if(m1.index < m2.index)
+		return -1;
+	else if(m1.index > m2.index)
+		return 1;
+	else
+	{
+		// if index is the same, sort by length
+		if(m1.length < m2.length)
+			return -1;
+		else if(m1.length > m2.length)
+			return 1;
+	}
+	return 0;
+}
+
+dp.sh.Highlighter.prototype.CreateElement = function(name)
+{
+	var result = document.createElement(name);
+	result.highlighter = this;
+	return result;
+}
+
+// gets a list of all matches for a given regular expression
+dp.sh.Highlighter.prototype.GetMatches = function(regex, css)
+{
+	var index = 0;
+	var match = null;
+
+	while((match = regex.exec(this.code)) != null)
+		this.matches[this.matches.length] = new dp.sh.Match(match[0], match.index, css);
+}
+
+dp.sh.Highlighter.prototype.AddBit = function(str, css)
+{
+	if(str == null || str.length == 0)
+		return;
+
+	var span = this.CreateElement('SPAN');
+	
+	str = str.replace(/&/g, '&amp;');
+	str = str.replace(/ /g, '&nbsp;');
+	str = str.replace(/</g, '&lt;');
+	str = str.replace(/\n/gm, '&nbsp;<br>');
+
+	// when adding a piece of code, check to see if it has line breaks in it 
+	// and if it does, wrap individual line breaks with span tags
+	if(css != null)
+	{
+		var regex = new RegExp('<br>', 'gi');
+		
+		if(regex.test(str))
+		{
+			var lines = str.split('&nbsp;<br>');
+			
+			str = '';
+			
+			for(var i = 0; i < lines.length; i++)
+			{
+				span = this.CreateElement('SPAN');
+				span.className = css;
+				span.innerHTML = lines[i];
+				
+				this.div.appendChild(span);
+				
+				// don't add a <BR> for the last line
+				if(i + 1 < lines.length)
+					this.div.appendChild(this.CreateElement('BR'));
+			}
+		}
+		else
+		{
+			span.className = css;
+			span.innerHTML = str;
+			this.div.appendChild(span);
+		}
+	}
+	else
+	{
+		span.innerHTML = str;
+		this.div.appendChild(span);
+	}
+}
+
+// checks if one match is inside any other match
+dp.sh.Highlighter.prototype.IsInside = function(match)
+{
+	if(match == null || match.length == 0)
+		return false;
+	
+	for(var i = 0; i < this.matches.length; i++)
+	{
+		var c = this.matches[i];
+		
+		if(c == null)
+			continue;
+
+		if((match.index > c.index) && (match.index < c.index + c.length))
+			return true;
+	}
+	
+	return false;
+}
+
+dp.sh.Highlighter.prototype.ProcessRegexList = function()
+{
+	for(var i = 0; i < this.regexList.length; i++)
+		this.GetMatches(this.regexList[i].regex, this.regexList[i].css);
+}
+
+dp.sh.Highlighter.prototype.ProcessSmartTabs = function(code)
+{
+	var lines	= code.split('\n');
+	var result	= '';
+	var tabSize	= 4;
+	var tab		= '\t';
+
+	// This function inserts specified amount of spaces in the string
+	// where a tab is while removing that given tab. 
+	function InsertSpaces(line, pos, count)
+	{
+		var left	= line.substr(0, pos);
+		var right	= line.substr(pos + 1, line.length);	// pos + 1 will get rid of the tab
+		var spaces	= '';
+		
+		for(var i = 0; i < count; i++)
+			spaces += ' ';
+		
+		return left + spaces + right;
+	}
+
+	// This function process one line for 'smart tabs'
+	function ProcessLine(line, tabSize)
+	{
+		if(line.indexOf(tab) == -1)
+			return line;
+
+		var pos = 0;
+
+		while((pos = line.indexOf(tab)) != -1)
+		{
+			// This is pretty much all there is to the 'smart tabs' logic.
+			// Based on the position within the line and size of a tab, 
+			// calculate the amount of spaces we need to insert.
+			var spaces = tabSize - pos % tabSize;
+			
+			line = InsertSpaces(line, pos, spaces);
+		}
+		
+		return line;
+	}
+
+	// Go through all the lines and do the 'smart tabs' magic.
+	for(var i = 0; i < lines.length; i++)
+		result += ProcessLine(lines[i], tabSize) + '\n';
+	
+	return result;
+}
+
+dp.sh.Highlighter.prototype.SwitchToList = function()
+{
+	// thanks to Lachlan Donald from SitePoint.com for this <br/> tag fix.
+	var html = this.div.innerHTML.replace(/<(br)\/?>/gi, '\n');
+	var lines = html.split('\n');
+	
+	if(this.addControls == true)
+		this.bar.appendChild(dp.sh.Toolbar.Create(this));
+
+	// add columns ruler
+	if(this.showColumns)
+	{
+		var div = this.CreateElement('div');
+		var columns = this.CreateElement('div');
+		var showEvery = 10;
+		var i = 1;
+		
+		while(i <= 150)
+		{
+			if(i % showEvery == 0)
+			{
+				div.innerHTML += i;
+				i += (i + '').length;
+			}
+			else
+			{
+				div.innerHTML += '&middot;';
+				i++;
+			}
+		}
+		
+		columns.className = 'columns';
+		columns.appendChild(div);
+		this.bar.appendChild(columns);
+	}
+
+	for(var i = 0, lineIndex = this.firstLine; i < lines.length - 1; i++, lineIndex++)
+	{
+		var li = this.CreateElement('LI');
+		var span = this.CreateElement('SPAN');
+		
+		// uses .line1 and .line2 css styles for alternating lines
+		li.className = (i % 2 == 0) ? 'alt' : '';
+		span.innerHTML = lines[i] + '&nbsp;';
+
+		li.appendChild(span);
+		this.ol.appendChild(li);
+	}
+	
+	this.div.innerHTML	= '';
+}
+
+dp.sh.Highlighter.prototype.Highlight = function(code)
+{
+	function Trim(str)
+	{
+		return str.replace(/^\s*(.*?)[\s\n]*$/g, '$1');
+	}
+	
+	function Chop(str)
+	{
+		return str.replace(/\n*$/, '').replace(/^\n*/, '');
+	}
+
+	function Unindent(str)
+	{
+		var lines = str.split('\n');
+		var indents = new Array();
+		var regex = new RegExp('^\\s*', 'g');
+		var min = 1000;
+
+		// go through every line and check for common number of indents
+		for(var i = 0; i < lines.length && min > 0; i++)
+		{
+			if(Trim(lines[i]).length == 0)
+				continue;
+				
+			var matches = regex.exec(lines[i]);
+
+			if(matches != null && matches.length > 0)
+				min = Math.min(matches[0].length, min);
+		}
+
+		// trim minimum common number of white space from the begining of every line
+		if(min > 0)
+			for(var i = 0; i < lines.length; i++)
+				lines[i] = lines[i].substr(min);
+
+		return lines.join('\n');
+	}
+	
+	// This function returns a portions of the string from pos1 to pos2 inclusive
+	function Copy(string, pos1, pos2)
+	{
+		return string.substr(pos1, pos2 - pos1);
+	}
+
+	var pos	= 0;
+	
+	this.originalCode = code;
+	this.code = Chop(Unindent(code));
+	this.div = this.CreateElement('DIV');
+	this.bar = this.CreateElement('DIV');
+	this.ol = this.CreateElement('OL');
+	this.matches = new Array();
+
+	this.div.className = 'dp-highlighter';
+	this.div.highlighter = this;
+	
+	this.bar.className = 'bar';
+	
+	// set the first line
+	this.ol.start = this.firstLine;
+
+	if(this.CssClass != null)
+		this.ol.className = this.CssClass;
+
+	if(this.collapse)
+		this.div.className += ' collapsed';
+	
+	if(this.noGutter)
+		this.div.className += ' nogutter';
+
+	// replace tabs with spaces
+	if(this.tabsToSpaces == true)
+		this.code = this.ProcessSmartTabs(this.code);
+
+	this.ProcessRegexList();	
+
+	// if no matches found, add entire code as plain text
+	if(this.matches.length == 0)
+	{
+		this.AddBit(this.code, null);
+		this.SwitchToList();
+		this.div.appendChild(this.ol);
+		return;
+	}
+
+	// sort the matches
+	this.matches = this.matches.sort(dp.sh.Highlighter.SortCallback);
+
+	// The following loop checks to see if any of the matches are inside
+	// of other matches. This process would get rid of highligted strings
+	// inside comments, keywords inside strings and so on.
+	for(var i = 0; i < this.matches.length; i++)
+		if(this.IsInside(this.matches[i]))
+			this.matches[i] = null;
+
+	// Finally, go through the final list of matches and pull the all
+	// together adding everything in between that isn't a match.
+	for(var i = 0; i < this.matches.length; i++)
+	{
+		var match = this.matches[i];
+
+		if(match == null || match.length == 0)
+			continue;
+
+		this.AddBit(Copy(this.code, pos, match.index), null);
+		this.AddBit(match.value, match.css);
+
+		pos = match.index + match.length;
+	}
+	
+	this.AddBit(this.code.substr(pos), null);
+
+	this.SwitchToList();
+	this.div.appendChild(this.bar);
+	this.div.appendChild(this.ol);
+}
+
+dp.sh.Highlighter.prototype.GetKeywords = function(str) 
+{
+	return '\\b' + str.replace(/ /g, '\\b|\\b') + '\\b';
+}
+
+// highlightes all elements identified by name and gets source code from specified property
+dp.sh.HighlightAll = function(name, showGutter /* optional */, showControls /* optional */, collapseAll /* optional */, firstLine /* optional */, showColumns /* optional */)
+{
+	function FindValue()
+	{
+		var a = arguments;
+		
+		for(var i = 0; i < a.length; i++)
+		{
+			if(a[i] == null)
+				continue;
+				
+			if(typeof(a[i]) == 'string' && a[i] != '')
+				return a[i] + '';
+		
+			if(typeof(a[i]) == 'object' && a[i].value != '')
+				return a[i].value + '';
+		}
+		
+		return null;
+	}
+	
+	function IsOptionSet(value, list)
+	{
+		for(var i = 0; i < list.length; i++)
+			if(list[i] == value)
+				return true;
+		
+		return false;
+	}
+	
+	function GetOptionValue(name, list, defaultValue)
+	{
+		var regex = new RegExp('^' + name + '\\[(\\w+)\\]$', 'gi');
+		var matches = null;
+
+		for(var i = 0; i < list.length; i++)
+			if((matches = regex.exec(list[i])) != null)
+				return matches[1];
+		
+		return defaultValue;
+	}
+
+	var elements = document.getElementsByName(name);
+	var highlighter = null;
+	var registered = new Object();
+	var propertyName = 'value';
+	
+	// if no code blocks found, leave
+	if(elements == null)
+		return;
+
+	// register all brushes
+	for(var brush in dp.sh.Brushes)
+	{
+		var aliases = dp.sh.Brushes[brush].Aliases;
+
+		if(aliases == null)
+			continue;
+		
+		for(var i = 0; i < aliases.length; i++)
+			registered[aliases[i]] = brush;
+	}
+
+	for(var i = 0; i < elements.length; i++)
+	{
+		var element = elements[i];
+		var options = FindValue(
+				element.attributes['class'], element.className, 
+				element.attributes['language'], element.language
+				);
+		var language = '';
+		
+		if(options == null)
+			continue;
+		
+		options = options.split(':');
+		
+		language = options[0].toLowerCase();
+
+		if(registered[language] == null)
+			continue;
+		
+		// instantiate a brush
+		highlighter = new dp.sh.Brushes[registered[language]]();
+		
+		// hide the original element
+		element.style.display = 'none';
+
+		highlighter.noGutter = (showGutter == null) ? IsOptionSet('nogutter', options) : !showGutter;
+		highlighter.addControls = (showControls == null) ? !IsOptionSet('nocontrols', options) : showControls;
+		highlighter.collapse = (collapseAll == null) ? IsOptionSet('collapse', options) : collapseAll;
+		highlighter.showColumns = (showColumns == null) ? IsOptionSet('showcolumns', options) : showColumns;
+		
+		// first line idea comes from Andrew Collington, thanks!
+		highlighter.firstLine = (firstLine == null) ? parseInt(GetOptionValue('firstline', options, 1)) : firstLine;
+
+		highlighter.Highlight(element[propertyName]);
+
+		element.parentNode.insertBefore(highlighter.div, element);
+	}	
+}


Property changes on: trunk/examples/typeface/root/static/Scripts/shCore.uncompressed.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Styles/SyntaxHighlighter.css
===================================================================
--- trunk/examples/typeface/root/static/Styles/SyntaxHighlighter.css	                        (rev 0)
+++ trunk/examples/typeface/root/static/Styles/SyntaxHighlighter.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,216 @@
+/* Main style for the table */
+
+.dp-highlighter
+{
+	font-family: "Courier New" , Courier, mono;
+	font-size: 12px;
+	border: 1px solid #2B91AF;
+	background-color: #fff;
+	width: 99%;
+	overflow: auto;
+	margin: 18px 0px 18px 0px;
+}
+
+.dp-highlighter .bar
+{
+	padding-left: 45px;
+}
+
+.dp-highlighter.collapsed .bar, .dp-highlighter.nogutter .bar
+{
+	padding-left: 0px;
+}
+
+.dp-highlighter ol
+{
+	margin: 0px 0px 1px 45px; /* 1px bottom margin seems to fix occasional Firefox scrolling */
+	padding: 0px;
+	color: #2B91AF;
+}
+
+.dp-highlighter.nogutter ol
+{
+	list-style-type: none;
+	margin-left: 0px;
+}
+
+.dp-highlighter ol li, .dp-highlighter .columns div
+{
+	border-left: 3px solid #6CE26C;
+	background-color: #fff;
+	padding-left: 10px;
+	line-height: 14px;
+}
+
+.dp-highlighter.nogutter ol li, .dp-highlighter.nogutter .columns div
+{
+	border: 0;
+}
+
+.dp-highlighter .columns
+{
+	color: gray;
+	overflow: hidden;
+	width: 100%;
+}
+
+.dp-highlighter .columns div
+{
+	padding-bottom: 5px;
+}
+
+.dp-highlighter ol li.alt
+{
+	background-color: #f8f8f8;
+}
+
+.dp-highlighter ol li span
+{
+	color: Black;
+}
+
+/* Adjust some properties when collapsed */
+
+.dp-highlighter.collapsed ol
+{
+	margin: 0px;
+}
+
+.dp-highlighter.collapsed ol li
+{
+	display: none;
+}
+
+/* Additional modifications when in print-view */
+
+.dp-highlighter.printing 
+{
+	border: none;
+}
+
+.dp-highlighter.printing .tools
+{
+	display: none !important;
+}
+
+.dp-highlighter.printing li
+{
+	display: list-item !important;
+}
+
+/* Styles for the tools */
+
+.dp-highlighter .tools
+{
+	padding: 3px 8px 3px 10px;
+	border-bottom: 1px solid #2B91AF;
+	font: 9px Verdana, Geneva, Arial, Helvetica, sans-serif;
+	color: silver;
+}
+
+.dp-highlighter.collapsed .tools
+{
+	border-bottom: 0;
+}
+
+.dp-highlighter .tools a
+{
+	font-size: 9px;
+	color: gray;
+	text-decoration: none;
+	margin-right: 10px;
+}
+
+.dp-highlighter .tools a:hover
+{
+	color: red;
+	text-decoration: underline;
+}
+
+/* About dialog styles */
+
+.dp-about { background-color: #fff; margin: 0px; padding: 0px; }
+.dp-about table { width: 100%; height: 100%; font-size: 11px; font-family: Tahoma, Verdana, Arial, sans-serif !important; }
+.dp-about td { padding: 10px; vertical-align: top; }
+.dp-about .copy { border-bottom: 1px solid #ACA899; height: 95%; }
+.dp-about .title { color: red; font-weight: bold; }
+.dp-about .para { margin: 0 0 4px 0; }
+.dp-about .footer { background-color: #ECEADB; border-top: 1px solid #fff; text-align: right; }
+.dp-about .close { font-size: 11px; font-family: Tahoma, Verdana, Arial, sans-serif !important; background-color: #ECEADB; width: 60px; height: 22px; }
+
+/* Language specific styles */
+
+.dp-c {}
+.dp-c .comment { color: green; }
+.dp-c .string { color: blue; }
+.dp-c .preprocessor { color: gray; }
+.dp-c .keyword { color: blue; }
+.dp-c .vars { color: #d00; }
+
+.dp-vb {}
+.dp-vb .comment { color: green; }
+.dp-vb .string { color: blue; }
+.dp-vb .preprocessor { color: gray; }
+.dp-vb .keyword { color: blue; }
+
+.dp-sql {}
+.dp-sql .comment { color: green; }
+.dp-sql .string { color: red; }
+.dp-sql .keyword { color: blue; }
+.dp-sql .func { color: #ff1493; }
+.dp-sql .op { color: #808080; }
+
+.dp-xml {}
+.dp-xml .cdata { color: #ff1493; }
+.dp-xml .comments { color: green; }
+.dp-xml .tag { font-weight: bold; color: blue; }
+.dp-xml .tag-name { color: black; font-weight: bold; }
+.dp-xml .attribute { color: red; }
+.dp-xml .attribute-value { color: blue; }
+
+.dp-delphi {}
+.dp-delphi .comment { color: #008200; font-style: italic; }
+.dp-delphi .string { color: blue; }
+.dp-delphi .number { color: blue; }
+.dp-delphi .directive { color: #008284; }
+.dp-delphi .keyword { font-weight: bold; color: navy; }
+.dp-delphi .vars { color: #000; }
+
+.dp-py {}
+.dp-py .comment { color: green; }
+.dp-py .string { color: red; }
+.dp-py .docstring { color: green; }
+.dp-py .keyword { color: blue; font-weight: bold;}
+.dp-py .builtins { color: #ff1493; }
+.dp-py .magicmethods { color: #808080; }
+.dp-py .exceptions { color: brown; }
+.dp-py .types { color: brown; font-style: italic; }
+.dp-py .commonlibs { color: #8A2BE2; font-style: italic; }
+
+.dp-rb {}
+.dp-rb .comment { color: #c00; }
+.dp-rb .string  { color: #f0c; }
+.dp-rb .symbol  { color: #02b902; }
+.dp-rb .keyword { color: #069; }
+.dp-rb .variable { color: #6cf; }
+
+.dp-css {}
+.dp-css .comment { color: green; }
+.dp-css .string { color: red; }
+.dp-css .keyword { color: blue; }
+.dp-css .colors { color: darkred; }
+.dp-css .vars { color: #d00; }
+
+.dp-j {}
+.dp-j .comment { color: rgb(63,127,95); }
+.dp-j .string { color: rgb(42,0,255); }
+.dp-j .keyword { color: rgb(127,0,85); font-weight: bold }
+.dp-j .annotation { color: #646464; }
+.dp-j .number { color: #C00000; }
+
+.dp-cpp {}
+.dp-cpp .comment { color: #e00; }
+.dp-cpp .string { color: red; }
+.dp-cpp .preprocessor { color: #CD00CD; font-weight: bold; }
+.dp-cpp .keyword { color: #5697D9; font-weight: bold; }
+.dp-cpp .datatypes { color: #2E8B57; font-weight: bold; }


Property changes on: trunk/examples/typeface/root/static/Styles/SyntaxHighlighter.css
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/Styles/TestPages.css
===================================================================
--- trunk/examples/typeface/root/static/Styles/TestPages.css	                        (rev 0)
+++ trunk/examples/typeface/root/static/Styles/TestPages.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,61 @@
+body
+{
+	background-color: #fff;
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 12px;
+	padding: 20px;
+}
+
+h1, h2, h3 { font-weight: normal; margin: 0px 0px 10px 0px; }
+h1 { font-size: 200%; border-bottom: 5px solid #f0f0f0; padding-bottom: 5px; }
+h2 { font-size: 150%; margin-left: 20%; }
+h3 { font-size: 120%; }
+
+li a
+{
+	color: blue;
+	text-decoration: none;
+}
+
+li a:hover
+{
+	background-color: #FFFF00 !important;
+}
+
+li a:visited
+{
+	background-color: #ececec;
+}
+
+.layout
+{
+	position: relative;
+}
+
+.column1
+{
+	width: 15%;
+	border-right: 15px solid silver;
+	background-color: #f0f0f0;
+	padding-top: 10px;
+	padding-bottom: 10px;
+}
+
+.column1 h3
+{
+	margin-left: 10px;
+}
+
+.column2
+{
+	position: absolute;
+	left: 20%;
+	top: 0px;
+	width: 75%;
+}
+
+.footer
+{
+	margin-top: 20px;
+	width: 15%;
+}
\ No newline at end of file


Property changes on: trunk/examples/typeface/root/static/Styles/TestPages.css
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/dojo/dijit/ColorPalette.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/ColorPalette.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/ColorPalette.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,251 @@
+dojo.provide("dijit.ColorPalette");
+
+dojo.require("dijit.util.place");
+dojo.require("dijit.util.typematic");
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.TemplatedWidget");
+
+dojo.declare(
+		"dijit.ColorPalette",
+		[dijit.base.Widget, dijit.base.TemplatedWidget],null,
+{
+	// summary
+	//		Grid showing various colors, so the user can pick a certain color
+	
+	// defaultTimeout: Number
+	//      number of milliseconds before a held key or button becomes typematic
+	defaultTimeout: 500,
+
+	// timeoutChangeRate: Number
+	//      fraction of time used to change the typematic timer between events
+	//      1.0 means that each typematic event fires at defaultTimeout intervals
+	//      < 1.0 means that each typematic event fires at an increasing faster rate
+	timeoutChangeRate: 0.90,
+	// palette: String
+	//		Size of grid, either "7x10" or "3x4".
+	palette: "7x10",
+	
+	//_selectedColor: String
+	//		The value of the selected color.
+	selectedColor: null,
+	
+	//_currentFocus: Integer
+	//		Index of the currently focused color.
+	_currentFocus: 0,
+	
+	// _xDim: Integer
+	//		This is the number of colors horizontally across.
+	_xDim: null,
+	
+	// _yDim: Integer
+	///		This is the number of colors vertically down.
+	_yDim: null,
+	
+	// _palettes: Map
+	// 		This represents the value of the colors.
+	//		The first level is a hashmap of the different arrays available
+	//		The next two dimensions represent the columns and rows of colors.
+	_palettes: {
+		"7x10": [["fff", "fcc", "fc9", "ff9", "ffc", "9f9", "9ff", "cff", "ccf", "fcf"],
+			["ccc", "f66", "f96", "ff6", "ff3", "6f9", "3ff", "6ff", "99f", "f9f"],
+			["c0c0c0", "f00", "f90", "fc6", "ff0", "3f3", "6cc", "3cf", "66c", "c6c"],
+			["999", "c00", "f60", "fc3", "fc0", "3c0", "0cc", "36f", "63f", "c3c"],
+			["666", "900", "c60", "c93", "990", "090", "399", "33f", "60c", "939"],
+			["333", "600", "930", "963", "660", "060", "366", "009", "339", "636"],
+			["000", "300", "630", "633", "330", "030", "033", "006", "309", "303"]],
+
+		"3x4": [["ffffff"/*white*/, "00ff00"/*lime*/, "008000"/*green*/, "0000ff"/*blue*/],
+			["c0c0c0"/*silver*/, "ffff00"/*yellow*/, "ff00ff"/*fuchsia*/, "000080"/*navy*/],
+			["808080"/*gray*/, "ff0000"/*red*/, "800080"/*purple*/, "000000"/*black*/]]
+			//["00ffff"/*aqua*/, "808000"/*olive*/, "800000"/*maroon*/, "008080"/*teal*/]];
+	},
+	
+	// _imagePaths: Map
+	//		This is stores the path to the palette images
+	_imagePaths: {
+		"7x10": dojo.moduleUrl("dijit", "templates/colors7x10.png"),
+		"3x4": dojo.moduleUrl("dijit", "templates/colors3x4.png")
+	},
+	
+	// _paletteCoords: Map
+	//		This is a map that is used to calculate the coordinates of the 
+	//		images that make up the palette. 
+	_paletteCoords: {
+		"leftOffset": 3, "topOffset": 3,
+		"cWidth": 18, "cHeight": 16
+	},
+	
+	// templatePath: String
+	//		Path to the template of this widget.
+	templateString:"<fieldset class=\"dijitInlineBox\">\n\t<div style=\"overflow: hidden\" dojoAttachPoint=\"divNode\" >\n\t\t<img style=\"border-style: none;\" dojoAttachPoint=\"imageNode\" tabIndex=\"-1\" />\n\t</div>\t\n</fieldset>\n",
+		
+	
+	_paletteDims: {
+		"7x10": {"width": "185px", "height": "117px"},
+		"3x4": {"width": "82px", "height": "58px"}
+	},
+	
+		
+	postCreate: function() {
+		
+		// A name has to be given to the colorMap, this needs to be unique per Palette.	
+		this.divNode.style.width = this._paletteDims[this.palette]["width"];
+		this.divNode.style.height = this._paletteDims[this.palette]["height"];
+		this.imageNode.setAttribute("src",this._imagePaths[this.palette]);
+		var alts = this._palettes[this.palette];	
+		var imagePos = dojo.coords(this.imageNode);
+		this.domNode.style.position = "relative";
+		this._highlightNodes = [];	
+				 				 
+		for (var row=0; row<alts.length; row++) {
+			for (var col=0; col<alts[row].length; col++) {
+				var highlightNode = document.createElement("img");
+				highlightNode.src = dojo.moduleUrl("dijit", "templates/blank.gif")
+				dojo.addClass(highlightNode, "dijitPaletteImg");
+				highlightNode.color = alts[row][col];
+				highlightNode.alt = highlightNode.color;
+				highlightNode.style.color = "#"+highlightNode.color;
+				highlightNode.style.backgroundColor = "#"+highlightNode.color; 
+				this.connect(highlightNode,"onmouseover", "onMouseOver");
+				this.connect(highlightNode,"onmousedown", "onClick");
+				this.connect(highlightNode,"onblur","onBlur");
+				this.connect(highlightNode,"onfocus","onFocus");
+				this.connect(highlightNode,"onkeydown","onKeyDown");
+				this.divNode.appendChild(highlightNode);
+				highlightNode.style.top = this._paletteCoords["topOffset"] + (row * this._paletteCoords["cHeight"])+"px";
+				highlightNode.style.left = this._paletteCoords["leftOffset"] + (col * this._paletteCoords["cWidth"])+"px";
+				highlightNode.setAttribute("tabIndex","-1");
+				highlightNode.title = highlightNode.color;
+				highlightNode.index = this._highlightNodes.length;
+				this._highlightNodes.push(highlightNode);
+			}
+		}
+		this._highlightNodes[this._currentFocus].tabIndex = 0;
+		this._xDim = alts[0].length;
+		this._yDim = alts.length;
+				
+		// Now set all events
+		// The palette itself is navigated to with the tab key on the keyboard
+		// Keyboard navigation within the Palette is with the arrow keys
+		// Spacebar selects the color.
+		// For the up key the index is changed by negative the x dimension.		
+			
+		dijit.util.typematic.addKeyListener(this.domNode, 
+			{keyCode:dojo.keys.UP_ARROW,ctrlKey:false,altKey:false,shiftKey:false}, 
+			this, function(count,node,evt) { this._navigateByKey(-this._xDim,count); }, 
+			this.timeoutChangeRate, this.defaultTimeout);
+		// The down key the index is increase by the x dimension.	
+		dijit.util.typematic.addKeyListener(this.domNode, 
+			{keyCode:dojo.keys.DOWN_ARROW,ctrlKey:false,altKey:false,shiftKey:false}, 
+			this, function(count,node,evt) { this._navigateByKey(this._xDim,count); }, 
+			this.timeoutChangeRate, this.defaultTimeout);
+		// Right and left move the index by 1.
+		dijit.util.typematic.addKeyListener(this.domNode, 
+			{keyCode:dojo.keys.RIGHT_ARROW,ctrlKey:false,altKey:false,shiftKey:false}, 
+			this, function(count,node,evt) { this._navigateByKey(1,count); }, 
+			this.timeoutChangeRate, this.defaultTimeout);
+		dijit.util.typematic.addKeyListener(this.domNode, 
+			{keyCode:dojo.keys.LEFT_ARROW,ctrlKey:false,altKey:false,shiftKey:false}, 
+			this, function(count,node,evt) { this._navigateByKey(-1,count); }, 
+			this.timeoutChangeRate, this.defaultTimeout);
+	},
+			
+	onColorSelect: function(color){
+		// summary:
+		//		Callback when a color is selected.
+		// color: String
+		//		Hex value corresponding to color.
+		console.debug("Color selected is: "+color);
+	},
+
+	onClick: function(/*Event*/ evt) {
+		// summary:
+		//		Handler when a mouse click occurs. This causes the color that is clicked to be selected.
+		// evt:
+		//			The click event.
+		this._currentFocus = evt.currentTarget.index;
+		evt.currentTarget.focus();
+		this._selectColor(evt.currentTarget);	
+	},
+	
+	onMouseOver: function(evt) {
+		// summary:
+		//		Handler for onMouseOver. This changes the color being highlighted.
+		// evt:
+		//		The mouse event.	
+		evt.currentTarget.tabIndex = 0;
+		evt.currentTarget.focus();
+	},
+	
+	onBlur: function(evt) {
+		// summary:
+		//		Handler for the onBlur event. Causes the highlight Div 
+		//		to be destroyed.
+		// evt:
+		//		The blur event.
+		dojo.removeClass(evt.currentTarget, "dijitPaletteImgHighlight");
+	},
+	
+	onFocus: function(evt) {
+		// summary:
+		//		Handler for onFocus. This highlights the first color in the 
+		//		palette if it is the first time the palette is focused.
+		//		Otherwise the last color highlighted is focused. 
+		// evt:
+		//		The focus event.
+		if (this._currentFocus != evt.currentTarget.index)
+		{
+			this._highlightNodes[this._currentFocus].tabIndex = -1;
+		}
+		this._currentFocus = evt.currentTarget.index;
+		dojo.addClass(evt.currentTarget, "dijitPaletteImgHighlight");
+		
+	},
+	
+	onKeyDown: function(evt) {
+		// summary:
+		//		Handler for the onKeyDown event. 
+		//		It handles space and tab being pressed.
+		//		Space selects the color currently highlighted.
+		//		Tab blurs the area currently highlighted.
+		// evt:
+		//		The keydown event.
+		
+		if (evt.keyCode == dojo.keys.SPACE) 
+		{
+			if (this._currentFocus != null)
+			{
+				this._selectColor(this._highlightNodes[this._currentFocus]);
+			}
+		}
+	},
+	
+	_selectColor: function (selectNode) {	
+		// summary:
+		// 		This selects a color. It triggers the onColorSelect event
+		// area: 
+		//		The area node that covers the color being selected.
+		this.selectedColor = selectNode.color;
+		this.onColorSelect(selectNode.color);
+	},
+	
+	_navigateByKey: function(increment,typeCount) {
+		// summary:
+		// 	  	This is the callback for typematic.
+		// 		It changes the focus and the highlighed color.
+		// increment:
+		// 		How much the key is navigated.
+		//	typeCount:
+		//		How many times typematic has fired.
+		
+		// typecount == -1 means the key is released.
+		if (typeCount==-1) { return; }
+		
+		var newFocus = this._currentFocus+increment;
+		if (newFocus < this._highlightNodes.length && newFocus > -1) 
+		{
+			this._highlightNodes[newFocus].tabIndex = 0;
+			this._highlightNodes[newFocus].focus();
+		}
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/Declaration.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/Declaration.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/Declaration.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,44 @@
+dojo.provide("dijit.Declaration");
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.TemplatedWidget");
+
+dojo.declare(
+	"dijit.Declaration",
+	[ dijit.base.Widget ],
+	{
+		// summary:
+		//		The Declaration widget allows a user to declare new widget
+		//		classes directly from a snippet of markup.
+
+		widgetClass: "",
+		replaceVars: true,
+		defaults: null,
+		mixins: [],
+		buildRendering: function(){
+			var src = this.srcNodeRef.parentNode.removeChild(this.srcNodeRef);
+			var srcType = src.nodeName;
+
+			if(this.mixins.length){
+				this.mixins = dojo.map(this.mixins, dojo.getObject);
+			}else{
+				this.mixins = [ dijit.base.Widget, dijit.base.TemplatedWidget ];
+			}
+
+			var propList = this.defaults||{};
+			propList.widgetsInTemplate = true;
+			propList.templateString = "<"+srcType+">"+src.innerHTML+"</"+srcType+">";
+
+			// strip things so we don't create stuff under us in the initial setup phase
+			dojo.query("[dojoType]", src).forEach(function(node){
+				node.removeAttribute("dojoType");
+			});
+
+			// create the new widget class
+			dojo.declare(
+				this.widgetClass,
+				this.mixins,
+				propList
+			);
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/Menu.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/Menu.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/Menu.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,452 @@
+dojo.provide("dijit.Menu");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.Container");
+dojo.require("dijit.base.TemplatedWidget");
+dojo.require("dijit.util.PopupManager");
+dojo.require("dijit.util.scroll");
+dojo.require("dijit.util.window");
+
+dojo.declare(
+	"dijit.PopupMenu",
+	[dijit.base.Widget, dijit.base.TemplatedWidget, dijit.base.Container],
+{
+	templateString: 
+		'<div class="dijit dijitPopup dijitMenu">' +
+			'<table class="dijitReset dijitMenuTable" waiRole="menu">' +
+				'<tbody class="dijitReset" dojoAttachPoint="containerNode"></tbody>'+
+			'</table>' +
+		'</div>',
+
+	// targetNodeIds: String[]
+	//	Array of dom node ids of nodes to attach to.
+	//	Fill this with nodeIds upon widget creation and it becomes context menu for those nodes.
+	targetNodeIds: [],
+
+	// submenuOverlap: Integer
+	//	a submenu usually appears to the right, but slightly overlapping, it's parent menu;
+	//	this controls the number of pixels the two menus overlap.
+	submenuOverlap: 5,
+	
+	// contextMenuForWindow: Boolean
+	//	if true, right clicking anywhere on the window will cause this context menu to open;
+	//	if false, must specify targetNodeIds
+	contextMenuForWindow: false,
+
+	// parentMenu: Widget
+	// pointer to menu that displayed me
+	parentMenu: null,
+
+	// submenuDelay: Integer
+	//	number of milliseconds before hovering (without clicking) causes the submenu to automatically open
+	submenuDelay: 500,
+	
+	postCreate: function(){
+		if(this.contextMenuForWindow){
+			this.bindDomNode(dojo.body());
+		}else{
+			dojo.forEach(this.targetNodeIds, this.bindDomNode, this);
+		}
+
+		if(!this.isLeftToRight()){
+			this.containerNode.className += " dojoRTL";
+		}
+	},
+
+	_moveToParentMenu: function(/*Event*/ evt){
+		if(this.parentMenu){
+			//only process event in the focused menu
+			//and its immediate parentPopup to support
+			//MenuBar
+			if(evt._menuUpKeyProcessed){
+				return true; //do not pass to parent menu
+			}else{
+				if(this._focusedItem){
+					this._blurFocusedItem();
+				}
+				this.parentMenu.closeSubmenu();
+				evt._menuUpKeyProcessed = true;
+			}
+		}
+		return false;
+	},
+
+	_moveToChildMenu: function(/*Event*/ evt){
+		if(this._focusedItem && this._focusedItem.submenuId && !this._focusedItem.disabled){
+			return this._activateCurrentItem(evt);
+		}
+		return false;
+	},
+
+	_activateCurrentItem: function(/*Event*/ evt){
+		if(this._focusedItem){
+			this._focusedItem._onClick();
+			if(this.currentSubmenu){
+				this.currentSubmenu._focusFirstItem();
+			}
+			return true; //do not pass to parent menu
+		}
+		return false;
+	},
+
+	processKey: function(/*Event*/ evt){
+		// summary
+		//	Callback from PopupManager to process key strokes
+		//	return true to stop the event being processed by the
+		//	parent popupmenu
+		if(evt.ctrlKey || evt.altKey){ return false; }
+
+		var key = (evt.charCode == dojo.keys.SPACE ? dojo.keys.SPACE : evt.keyCode);
+		switch(key){
+ 			case dojo.keys.DOWN_ARROW:
+				this._focusNeighborItem(1);
+				return true; //do not pass to parent menu
+			case dojo.keys.UP_ARROW:
+				this._focusNeighborItem(-1);
+				return true; //do not pass to parent menu
+			case dojo.keys.RIGHT_ARROW:
+				this._moveToChildMenu(evt);
+				return true; //do not pass to parent menu
+			case dojo.keys.LEFT_ARROW:
+				return this._moveToParentMenu(evt);
+			case dojo.keys.ESCAPE:
+				if(this.parentMenu){
+					return this._moveToParentMenu(evt);
+				}else{
+					dijit.util.PopupManager.closeAll();
+				}
+				return true;
+			case dojo.keys.SPACE: //fall through
+			case dojo.keys.ENTER:
+				return this._activateCurrentItem(evt);
+			case dojo.keys.TAB:
+				dijit.util.PopupManager.closeAll();
+				return true; //do not pass to parent menu
+		}
+		// otherwise, pass to parent menu
+		return false;
+	},
+
+	_findValidItem: function(dir){
+		// summary: find the next/previous item to focus on (depending on dir setting).
+
+		var curItem = this._focusedItem;
+		if(curItem){
+			curItem = dir>0 ? curItem.getNextSibling() : curItem.getPreviousSibling();
+		}
+
+		var children = this.getChildren();
+		for(var i=0; i < children.length; ++i){
+			if(!curItem){
+				curItem = children[(dir>0) ? 0 : (children.length-1)];
+			}
+			//find next/previous visible menu item, not including separators
+			if(curItem._onHover && dojo.style(curItem.domNode, "display") != "none"){
+				return curItem;
+			}
+			curItem = dir>0 ? curItem.getNextSibling() : curItem.getPreviousSibling();
+		}
+	},
+
+	_focusNeighborItem: function(dir){
+		// summary: focus on the next / previous item (depending on dir setting)
+		var item = this._findValidItem(dir);
+		this._focusItem(item);
+	},
+
+	_focusFirstItem: function(){
+		// blur focused item to make findValidItem() find the first item in the menu
+		if(this._focusedItem){
+			this._blurFocusedItem();
+		}
+		var item = this._findValidItem(1);
+		this._focusItem(item);
+	},
+
+	_focusItem: function(/*MenuItem*/ item){
+		// summary: internal function to focus a given menu item
+
+		if(!item || item==this._focusedItem){
+			return;
+		}
+
+		if(this._focusedItem){
+			this._blurFocusedItem();
+		}
+		item._focus();
+		this._focusedItem = item;
+	},
+
+	onItemHover: function(/*MenuItem*/ item){
+		this._focusItem(item);
+
+		if(this._focusedItem.submenuId && !this._focusedItem.disabled && !this.hover_timer){
+			this.hover_timer = setTimeout(dojo.hitch(this, "_openSubmenu"), this.submenuDelay);
+		}
+	},
+
+	_blurFocusedItem: function(){
+		// summary: internal function to remove focus from the currently focused item
+		if(this._focusedItem){
+			// Close all submenus that are open and descendents of this menu
+			dijit.util.PopupManager.closeTo(this);
+			this._focusedItem._blur();
+			this._stopSubmenuTimer();
+			this._focusedItem = null;
+		}
+	},
+
+	onItemUnhover: function(/*MenuItem*/ item){
+		//this._blurFocusedItem();
+	},
+
+	_stopSubmenuTimer: function(){
+		if(this.hover_timer){
+			clearTimeout(this.hover_timer);
+			this.hover_timer = null;
+		}
+	},
+	
+	onItemClick: function(/*Widget*/ item){
+		// summary: user defined function to handle clicks on an item
+		// summary: internal function for clicks
+		if(item.disabled){ return false; }
+
+		if(item.submenuId){
+			if(!this.is_open){
+				this._openSubmenu();
+			}
+		}else{
+			dijit.util.PopupManager.closeAll();
+		}
+
+		// user defined handler for click
+		item.onClick();
+	},
+
+	closeSubmenu: function(force){
+		// summary: close the currently displayed submenu
+		if(!this.currentSubmenu){ return; }
+
+		dijit.util.PopupManager.closeTo(this);
+		this._focusedItem._focus();	// put focus back on my node
+
+		this.currentSubmenu = null;
+	},
+
+	// thanks burstlib!
+	_iframeContentWindow: function(/* HTMLIFrameElement */iframe_el) {
+		//	summary
+		//	returns the window reference of the passed iframe
+		var win = dijit.util.window.getDocumentWindow(dijit.Menu._iframeContentDocument(iframe_el)) ||
+			// Moz. TODO: is this available when defaultView isn't?
+			dijit.Menu._iframeContentDocument(iframe_el)['__parent__'] ||
+			(iframe_el.name && document.frames[iframe_el.name]) || null;
+		return win;	//	Window
+	},
+
+	_iframeContentDocument: function(/* HTMLIFrameElement */iframe_el){
+		//	summary
+		//	returns a reference to the document object inside iframe_el
+		var doc = iframe_el.contentDocument // W3
+			|| (iframe_el.contentWindow && iframe_el.contentWindow.document) // IE
+			|| (iframe_el.name && document.frames[iframe_el.name] && document.frames[iframe_el.name].document) 
+			|| null;
+		return doc;	//	HTMLDocument
+	},
+
+	bindDomNode: function(/*String|DomNode*/ node){
+		// summary: attach menu to given node
+		node = dojo.byId(node);
+
+		//TODO: this is to support context popups in Editor.  Maybe this shouldn't be in dijit.Menu
+		var win = dijit.util.window.getDocumentWindow(node.ownerDocument);
+		if(node.tagName.toLowerCase()=="iframe"){
+			win = this._iframeContentWindow(node);
+			node = dojo.withGlobal(win, dojo.body);
+		}
+
+		// to capture these events at the top level, 
+		// attach to document, not body
+		var cn = (node == dojo.body() ? dojo.doc : node);
+		node[this.id+'_connect'] = [
+			dojo.connect(cn, "oncontextmenu", this, "_openMyself"),
+			dojo.connect(cn, "onkeydown", this, "_contextKey")
+		];
+	},
+
+	unBindDomNode: function(/*String|DomNode*/ nodeName){
+		// summary: detach menu from given node
+		var node = dojo.byId(nodeName);
+		dojo.forEach(node[this.id+'_connect'], dojo.disconnect);
+	},
+
+	_contextKey: function(e){
+		if (e.keyCode == dojo.keys.F10) {
+			dojo.stopEvent(e);
+			if (e.shiftKey && e.type=="keydown") {
+				// FF: copying the wrong property from e will cause the system 
+				// context menu to appear in spite of stopEvent. Don't know 
+				// exactly which properties cause this effect.
+				var _e = { target: e.target, pageX: e.pageX, pageY: e.pageY };
+				_e.preventDefault = _e.stopPropagation = function(){};
+				// IE: without the delay, focus work in "open" causes the system 
+				// context menu to appear in spite of stopEvent.
+				window.setTimeout(dojo.hitch(this, function(){ this._openMyself(_e); }), 1);
+			}
+		}
+	},
+
+	_openMyself: function(/*Event*/ e){
+		// summary:
+		//		Internal function for opening myself when the user
+		//		does a right-click or something similar
+		dojo.stopEvent(e);
+		dijit.util.PopupManager.open(e, this);
+	},
+
+	onOpen: function(/*Event*/ e){
+		// summary
+		//		Open menu relative to the mouse
+		this._focusFirstItem();
+		this.isShowingNow = true;
+	},
+
+	onClose: function(){
+		// summary: close this menu and any open submenus
+		this._stopSubmenuTimer();
+		this.parentMenu = null;
+		this.isShowingNow = false;
+		this.currentSubmenu = null;
+	},
+
+	_openSubmenu: function(){
+		// summary: open the submenu to the side of the current menu item
+		this._stopSubmenuTimer();
+		var from_item = this._focusedItem;
+		var submenu = dijit.byId(from_item.submenuId);
+
+		if(submenu.isShowingNow){ return; }
+		submenu.parentMenu = this;
+		dijit.util.PopupManager.openAround(from_item.arrowCell, submenu, {'TR': 'TL', 'TL': 'TR'});
+
+		this.currentSubmenu = submenu;
+	}
+}
+);
+
+dojo.declare(
+	"dijit.MenuItem",
+	[dijit.base.Widget, dijit.base.TemplatedWidget, dijit.base.Contained],
+{
+	// summary
+	//	A line item in a Menu2
+
+	// Make 3 columns
+	//   icon, label, and arrow (BiDi-dependent) indicating sub-menu
+	templateString:
+		 '<tr class="dijitReset dijitMenuItem" dojoAttachEvent="onmouseover: _onHover; onmouseout: _onUnhover; onclick: _onClick;">'
+		+'<td class="dijitReset"><div class="dijitMenuItemIcon" style="${iconStyle}"></div></td>'
+		+'<td tabIndex="-1" class="dijitReset dijitMenuItemLabel" dojoAttachPoint="containerNode" waiRole="menuitem"></td>'
+		+'<td class="dijitReset" dojoAttachPoint="arrowCell"><div class="dijitRightArrowOuter"><div class="dijitRightArrowInner" style="display:none;" dojoAttachPoint="arrow"></div></div></td>'
+		+'</tr>',
+
+	// iconSrc: String
+	//	path to icon to display to the left of the menu text
+	iconSrc: '',
+
+	// caption: String
+	//	menu text
+	caption: '',
+
+	// submenuId: String
+	//	widget ID of Menu2 widget to open when this menu item is clicked
+	submenuId: '',
+	
+	// disabled: Boolean
+	//  if true, the menu item is disabled
+	//  if false, the menu item is enabled
+	disabled: false,
+	
+	postMixInProperties: function(){
+		this.iconStyle="";
+		if(this.iconSrc){
+			this.iconStyle = ((this.iconSrc.toLowerCase().substring(this.iconSrc.length-4) == ".png") &&
+				(dojo.isIE && dojo.isIE < 7)) ?
+				"filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+this.iconSrc+"', sizingMethod='image')" :
+				"background-image: url("+this.iconSrc+")";
+		}
+		dijit.MenuItem.superclass.postMixInProperties.apply(this, arguments);
+	},
+
+	postCreate: function(){
+		dijit._disableSelection(this.domNode);
+		if(this.submenuId){
+			dojo.style(this.arrow, "display", "");
+			dijit.util.wai.setAttr(this.containerNode, "waiState", "haspopup", "true");
+		}
+		this.setDisabled(this.disabled);
+		if(this.caption){
+			this.containerNode.innerHTML=this.caption;
+		}
+	},
+
+	_onHover: function(){
+		// summary: callback when mouse is moved onto menu item
+		this.getParent().onItemHover(this);
+	},
+
+	_onUnhover: function(){
+		// summary: callback when mouse is moved off of menu item
+		// if we are unhovering the currently selected item
+		// then unselect it
+		this.getParent().onItemUnhover(this);
+	},
+
+	_onClick: function(focus){
+		this.getParent().onItemClick(this);
+	},
+
+	onClick: function() {
+		// summary
+		//	User defined function to handle clicks
+	},
+
+	_focus: function(){
+		dojo.addClass(this.domNode, 'dijitMenuItemHover');
+		try{
+			this.containerNode.focus();
+		}catch(e){
+			// this throws on IE (at least) in some scenarios
+		}
+		dijit.util.scroll.scrollIntoView(this.domNode);
+	},
+
+	_blur: function(){
+		dojo.removeClass(this.domNode, 'dijitMenuItemHover');
+	},
+
+	setDisabled: function(/*Boolean*/ value){
+		// summary: enable or disable this menu item
+		this.disabled = value;
+		dojo[value ? "addClass" : "removeClass"](this.domNode, 'dijitMenuItemDisabled');
+		dijit.util.wai.setAttr(this.containerNode, 'waiState', 'disabled', value ? 'true' : 'false');
+	}
+});
+
+dojo.declare(
+	"dijit.MenuSeparator",
+	[dijit.base.Widget, dijit.base.TemplatedWidget, dijit.base.Contained],
+{
+	// summary
+	//	A line between two menu items
+
+	templateString: '<tr class="dijitMenuSeparator"><td colspan=3>'
+			+'<div class="dijitMenuSeparatorTop"></div>'
+			+'<div class="dijitMenuSeparatorBottom"></div>'
+			+'</td></tr>',
+
+	postCreate: function(){
+		dijit._disableSelection(this.domNode);
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/ProgressBar.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/ProgressBar.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/ProgressBar.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,176 @@
+dojo.provide("dijit.ProgressBar");
+
+dojo.require("dojo.fx");
+dojo.require("dojo.number");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.TemplatedWidget");
+dojo.require("dijit.util.sniff");
+
+dojo.declare(
+	"dijit.ProgressBar",
+	[dijit.base.Widget, dijit.base.TemplatedWidget],
+	null,
+	{
+		// summary:
+		// a progress widget, with some calculation and server polling capabilities
+		//
+		// description: 
+		// (implementation) four overlapped divs:
+		// (1) lower z-index
+		// (4) higher z-index
+		// empty and full percent label have the same content: when the vertical line (*)
+		// partially hides the emptyLabel, the fullLabel becomes visible
+		// 
+		//  ___________________________(1)_domNode____________________________________
+		// |__(3)_internalProgress____________                                        |
+		// |                                  | <--- (*)                              |
+		// |            (4) fullLabel        | (2) emptyLabel                         |
+		// |__________________________________|                                       |
+		// |__________________________________________________________________________| 
+		//
+		// usage:
+		// <div dojoType="ProgressBar"
+		//   duration="..."
+		//   places="0"
+		//   orientation="vertical" 
+		//   progress="..." maximum="..."></div>
+	
+		// progress: String (Percentage or Number)
+		// initial progress value. 
+		// with "%": percentual value, 0% <= progress <= 100%
+		// or without "%": absolute value, 0 <= progress <= maximum
+		progress: "0",
+
+		// maximum: Float
+		// max sample number
+		maximum: 100,
+
+		// orientation: String
+		// whether bar grows along the x-axis (default) or y- axis (vertical)
+		orientation: "",
+
+		// places: Number
+		// number of places to show in values; 0 by default
+		places: 0,
+
+		// duration: Integer
+		// duration of the animation
+		duration: 1000,
+
+		templateString:"<div class=\"dijitProgressBar dijitProgressBarEmpty\"\n\t><div dojoAttachPoint=\"emptyLabel\" class=\"dijitProgressBarEmptyLabel\"\n\t></div\n\t><div waiRole=\"progressbar\" tabindex=\"0\" dojoAttachPoint=\"internalProgress\" class=\"dijitProgressBarFull\"\n\t\t><div class=\"dijitProgressBarTile\"\n\t\t></div\n\t\t><div dojoAttachPoint=\"fullLabel\" class=\"dijitProgressBarFullLabel\"\n\t\t></div\n\t></div\n></div>\n",		
+
+		// public functions
+		postCreate: function(){
+			dijit.ProgressBar.superclass.postCreate.apply(this, arguments);
+			if(this.orientation == "vertical"){
+//TODO: if !this.domNode.className?
+				this.domNode.className += " "+"dijitProgressBarVertical";
+				this._dimension = "height";
+			}else{
+				this._dimension = "width";
+			}
+			//TODO: can this be accomplished in the template layout?
+			// MOW: don't think so because it needs to be set to the absolute size
+			//		of the dom node, not the size of the containing element (the full part)
+			this.fullLabel.style.width = dojo.getComputedStyle(this.domNode).width; 
+			this.update();
+		},
+
+		update: function(/*Object?*/attributes){
+			// summary: update progress information
+			//
+			// attributes: may provide progress and/or maximum properties on this parameter,
+			//	see attribute specs for details.
+			dojo.mixin(this, attributes||{});
+			var percent;
+			if(String(this.progress).indexOf("%") != -1){
+				percent = Math.min(parseFloat(this.progress)/100, 1);
+				this.progress = percent * this.maximum;
+			}else{
+				this.progress = Math.min(this.progress, this.maximum);
+				percent = this.progress / this.maximum;
+			}
+
+			if(!this._animationStopped){return;}
+
+			var text = this.report(percent);
+			this._setWaiValueNow(text);
+			this.internalProgress.style[this._dimension] = (percent * 100) + "%";
+
+			dojo.forEach(["full", "empty"], function(name){
+				var labelNode = this[name+"Label"];
+				if(labelNode.firstChild){
+					labelNode.firstChild.nodeValue = text;
+				}else{
+					labelNode.appendChild(dojo.doc.createTextNode(text));
+				}
+
+// move this out of update, or perhaps replace with css or template layout?
+				var dim = dojo.contentBox(labelNode);
+				var labelBottom = (parseInt(dojo.getComputedStyle(this.domNode).height) - dim.h)/2;
+				labelNode.style.bottom = labelBottom + 'px';
+			}, this);
+
+			this.onChange();
+		},
+
+		report: function(/*float*/percent){
+			// Generates message to show; may be overridden by user
+			return dojo.number.format(percent, {type: "percent", places: this.places, locale: this.lang});
+		},
+
+		_animationStopped: true,
+
+		_setupAnimation: function(){
+			var self = this;
+			this._animation = dojo.fx.slideTo({node: this.internalProgress,
+				top: 0,
+				left: parseInt(dojo.getComputedStyle(this.domNode).width)-parseInt(dojo.getComputedStyle(this.internalProgress).width),
+				duration: this.duration});
+			dojo.connect(this._animation, "onEnd", null, function(){
+				var backAnim = dojo.fx.slideTo({node: self.internalProgress, top: 0, left: 0, duration: self.duration});
+				dojo.connect(backAnim, "onEnd", null, function(){
+					if(!self._animationStopped){
+						self._animation.play();
+					}
+				});
+				if(!self._animationStopped){
+					backAnim.play();
+				}
+				backAnim = null; // to avoid memory leaks in IE
+			});
+		},
+
+		startAnimation: function(){
+			// summary: starts the left-right animation, useful when
+			// the user doesn't know how much time the operation will last
+			if(this._animationStopped){
+				this._backup = {progress: this.progress};
+				this.update({progress: "10%"});
+				this._setWaiValueNow("unknown");
+				this._animationStopped = false;
+				this._setupAnimation();
+				this.internalProgress.style.height="105%";
+				this._animation.play();
+			}
+		},
+		stopAnimation: function(){
+			// summary: stops the left-right animation
+			if(this._animation){
+				this._animationStopped = true;
+				this._animation.stop();
+				this.internalProgress.style.height="100%";
+				this.internalProgress.style.left = "0px";
+				dojo.mixin(this, this._backup);
+				this.update();
+			}
+		},
+
+		_setWaiValueNow: function(value){
+			dijit.util.wai.setAttr(this.internalProgress, "waiState", "valuenow", value);
+		},
+
+		onChange: function(){}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/TitlePane.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/TitlePane.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/TitlePane.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,82 @@
+dojo.provide("dijit.TitlePane");
+
+dojo.require("dojo.fx");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.TemplatedWidget");
+
+dojo.declare(
+	"dijit.TitlePane",
+	[dijit.base.Widget, dijit.base.TemplatedWidget],
+{
+	// summary
+	//		A pane with a title on top, that can be opened or collapsed.
+	
+	// label: String
+	//		Title of the pane
+	label: "",
+	
+	// open: Boolean
+	//		Whether pane is opened or closed.
+	open: true,
+
+	// duration: Integer
+	//		milliseconds to fade in/fade out
+	duration: 250,
+
+	contentClass : "dijitTitlePaneContent",
+
+	templateString:"<div id=\"${id}\">\n\t<div dojoAttachEvent=\"onclick: onLabelClick; onkeypress: onLabelKey\" tabindex=\"0\" \n\t\t\twaiRole=\"button\" class=\"dijitTitlePaneLabel\" dojoAttachPoint=\"focusNode\">\n\t\t<span class=\"dijitOpenCloseArrowOuter\" style=\"float: left;\"><span class=\"dijitOpenCloseArrowInner\"></span></span>\n\t\t<span dojoAttachPoint=\"labelNode\" class=\"dijitInlineBox dijitLabelNode\"></span>\n\t</div>\n\t<div dojoAttachPoint=\"containerNode\" waiRole=\"region\" tabindex=\"-1\" class=\"${contentClass}\"></div>\n</div>\n",
+
+	postCreate: function(){
+		this.setLabel(this.label);
+		if(!this.open){
+			dojo.style(this.containerNode, "display", "none");
+		}
+		this._setCss();
+		dijit.TitlePane.superclass.postCreate.apply(this, arguments);
+		dijit.util.wai.setAttr(this.containerNode, "waiState", "labelledby", this.labelNode.id);
+		dijit.util.wai.setAttr(this.focusNode, "waiState", "haspopup", "true");
+		
+		// setup open/close animations
+		this._slideIn = dojo.fx.slideIn({node: this.containerNode, duration: this.duration});
+		this._slideOut = dojo.fx.slideOut({node: this.containerNode, duration: this.duration});
+	},
+
+	onLabelClick: function(){
+		// summary: callback when label is clicked
+		dojo.forEach([this._slideIn, this._slideOut], function(animation){
+			if(animation.status() == "playing"){
+				animation.stop();
+			}
+		});
+		this[this.open ? "_slideOut" : "_slideIn"].play();
+		this.open=!this.open;
+		this._setCss();
+	},
+
+	_setCss: function(){
+		var classes = ["dijitClosed", "dijitOpen"];
+		var boolIndex = this.open;
+		dojo.removeClass(this.domNode, classes[!boolIndex+0]);
+		this.domNode.className += " " + classes[boolIndex+0];
+	},
+
+	onLabelKey: function(/*Event*/ e){
+		// summary: callback when user hits a key
+		if(e.keyCode == dojo.keys.ENTER || e.charCode == dojo.keys.SPACE){
+			this.onLabelClick();
+		}
+		else if (e.keyCode == dojo.keys.DOWN_ARROW){
+			if(this.open){
+				this.containerNode.focus();
+				e.preventDefault();
+			}
+	 	}
+	},
+
+	setLabel: function(/*String*/ label){
+		// summary: sets the text of the label
+		this.labelNode.innerHTML=label;
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/Tooltip.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/Tooltip.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/Tooltip.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,200 @@
+dojo.provide("dijit.Tooltip");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.TemplatedWidget");
+dojo.require("dijit.util.place");
+dojo.require("dijit.util.BackgroundIframe");
+dojo.require("dijit.util.sniff");
+
+dojo.declare(
+	"dijit._MasterTooltip",
+	[dijit.base.Widget, dijit.base.TemplatedWidget],
+	{
+		// summary
+		//		Internal widget that holds the actual tooltip markup,
+		//		which occurs once per page.
+		//		Called by Tooltip widgets which are just containers to hold
+		//		the markup
+
+		// duration: Integer
+		//		Milliseconds to fade in/fade out
+		duration: 200,
+
+		templateString:"<div class=\"dijitTooltip\" id=\"dojoTooltip\">\n\t<div class=\"dijitTooltipContainer dijitTooltipContents\" dojoAttachPoint=\"containerNode\" waiRole='alert'></div>\n\t<div class=\"dijitTooltipConnector\"></div>\n</div>\n",
+
+		postCreate: function(){
+			dojo.body().appendChild(this.domNode);
+
+			this.bgIframe = new dijit.util.BackgroundIframe();
+			this.bgIframe.setZIndex(dojo.style(this.domNode, "zIndex")-1);
+
+			// Setup fade-in and fade-out functions.  An IE bug prevents the arrow from showing up
+			// unless opacity==1, because it's displayed via overflow: visible on the main div. 
+			var opacity = dojo.isIE ? 1 : dojo.style(this.domNode, "opacity");
+			this.fadeIn = dojo._fade({node: this.domNode, duration: this.duration, end: opacity});
+			dojo.connect(this.fadeIn, "onEnd", this, "_onShow");
+			this.fadeOut = dojo._fade({node: this.domNode, duration: this.duration, end: 0});
+			dojo.connect(this.fadeOut, "onEnd", this, "_onHide");
+
+		},
+
+		show: function(/*String*/ innerHTML, /*DomNode*/ aroundNode){
+			// summary: display tooltip w/specified contents underneath specified node
+
+			if(this.fadeOut.status() == "playing"){
+				// previous tooltip is being hidden; wait until the hide completes then show new one
+				this._onDeck=arguments;
+				return;
+			}
+			this.containerNode.innerHTML=innerHTML;
+			dijit.util.placeOnScreenAroundElement(this.domNode, aroundNode, [0,0],
+				{'BL': 'TL', 'TL': 'BL'});
+			dojo.style(this.domNode, "opacity", 0);
+			this.fadeIn.play();
+			this.isShowingNow = true;
+		},
+
+		_onShow: function(){
+			this.bgIframe.size(this.domNode);
+			this.bgIframe.show();
+			if(dojo.isIE){
+				// the arrow won't show up on a node w/an opacity filter
+				this.domNode.style.filter="";
+			}
+		},
+
+		hide: function(){
+			// summary: hide the tooltip
+			if(this._onDeck){
+				// this hide request is for a show() that hasn't even started yet;
+				// just cancel the pending show()
+				this._onDeck=null;
+				return;
+			}
+			this.fadeIn.stop();
+			this.isShowingNow = false;
+			this.fadeOut.play();
+		},
+
+		_onHide: function(){
+			this.domNode.style.cssText="";	// to position offscreen again
+			this.bgIframe.hide();
+			if(this._onDeck){
+				// a show request has been queue up; do it now
+				this.show.apply(this, this._onDeck);
+				this._onDeck=null;
+			}
+		}
+
+	}
+);
+
+// Make a single tooltip markup on the page that is reused as appropriate
+dojo.addOnLoad(function(){
+	dijit.MasterTooltip = new dijit._MasterTooltip();
+});
+
+dojo.declare(
+	"dijit.Tooltip",
+	dijit.base.Widget,
+	{
+		// summary
+		//		Pops up a tooltip (a help message) when you hover over a node.
+
+		// caption: String
+		//		Text to display in the tooltip.
+		//		Can also be specified as innerHTML (when creating the widget from markup).
+		caption: "",
+		
+		// showDelay: Integer
+		//		Number of milliseconds to wait after hovering over/focusing on the object, before
+		//		the tooltip is displayed.
+		showDelay: 400,
+		
+		// connectId: String
+		//		Id of domNode to attach the tooltip to.
+		//		(When user hovers over specified dom node, the tooltip will appear.)
+		connectId: "",
+
+		postCreate: function(){
+			this._connectNode = dojo.byId(this.connectId);
+
+			dojo.forEach(["onMouseOver", "onHover", "onMouseOut", "onUnHover"], function(event){
+				this.connect(this._connectNode, event.toLowerCase(), "_"+event);
+			}, this);
+		},
+
+		//PORT #2804
+		_isDescendantOf: function(/*Node*/node, /*Node*/ancestor){
+			//	summary
+			//	Returns boolean if node is a descendant of ancestor
+
+			while(node){
+				if(node === ancestor){ 
+					return true; // boolean
+				}
+				try{
+					node = node.parentNode;
+				}catch(e){
+					return false;
+				}
+			}
+			return false; // boolean
+		},
+
+		_onMouseOver: function(/*Event*/ e){
+			this._onHover(e);
+		},
+
+		_onMouseOut: function(/*Event*/ e){
+			if(this._isDescendantOf(e.relatedTarget, this._connectNode)){
+				// false event; just moved from target to target child; ignore.
+				return;
+			}
+			this._onUnHover(e);
+		},
+
+		_onHover: function(/*Event*/ e){
+			if(this._hover){ return; }
+			this._hover=true;
+			// If tooltip not showing yet then set a timer to show it shortly
+			if(!this.isShowingNow && !this._showTimer){
+				this._showTimer = setTimeout(dojo.hitch(this, "open"), this.showDelay);
+			}
+		},
+
+		_onUnHover: function(/*Event*/ e){
+			if(!this._hover){ return; }
+			this._hover=false;
+
+			if(this._showTimer){
+				clearTimeout(this._showTimer);
+				delete this._showTimer;
+			}else{
+				this.close();
+			}
+		},
+
+		open: function(){
+			// summary: display the tooltip; usually not called directly.
+			if(this.isShowingNow){ return; }
+			if(this._showTimer){
+				clearTimeout(this._showTimer);
+				delete this._showTimer;
+			}
+			dijit.MasterTooltip.show(this.caption || this.domNode.innerHTML, this._connectNode);
+			this.isShowingNow = true;
+		},
+
+		close: function(){
+			// summary: hide the tooltip; usually not called directly.
+			if(!this.isShowingNow){ return; }
+			dijit.MasterTooltip.hide();
+			this.isShowingNow = false;
+		},
+
+		uninitialize: function(){
+			this.close();
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/Tree.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/Tree.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/Tree.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,407 @@
+dojo.provide("dijit.Tree");
+
+dojo.require("dojo.fx");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.TemplatedWidget");
+dojo.require("dijit.base.Container");
+dojo.require("dijit._tree.Controller");
+
+dojo.declare(
+	"dijit._TreeBase",
+	[dijit.base.Widget, dijit.base.TemplatedWidget, dijit.base.Container, dijit.base.Contained],
+{
+	// summary:
+	//	Base class for Tree and _TreeNode
+
+	// state: String
+	//		dynamic loading-related stuff. 
+	//		When an empty folder node appears, it is "UNCHECKED" first,
+	//		then after dojo.data query it becomes "LOADING" and, finally "LOADED"	
+	state: "UNCHECKED",
+	locked: false,
+
+	lock: function(){
+		// summary: lock this node (and it's descendants) while a delete is taking place?
+		this.locked=true;
+	},
+	unlock: function(){
+		if(!this.locked){
+			//dojo.debug((new Error()).stack);
+			throw new Error(this.declaredClass+" unlock: not locked");
+		}
+		this.locked=false;
+	},
+		
+	isLocked: function(){
+		// summary: can this node be modified?
+		// returns: false if this node or any of it's ancestors are locked
+		var node = this;
+		while(true){
+			if(node.lockLevel){
+				return true;
+			}
+			if(!node.getParent() || node.isTree){
+				break;
+			}	
+			node = node.getParent();	
+		}
+		return false;
+	},
+
+	setChildren: function(/* Object[] */ childrenArray){
+		// summary:
+		//		Sets the children of this node.
+		//		Sets this.isFolder based on whether or not there are children
+		// 		Takes array of objects like: {label: ..., type: ... }
+		//		See parameters of _TreeNode for details.
+
+		this.destroyDescendants();
+
+		this.state = "LOADED";
+
+		if(childrenArray && childrenArray.length > 0){
+			this.isFolder = true;
+			if(!this.containerNode){ // maybe this node was unfolderized and still has container
+				this.containerNode = this.tree.containerNodeTemplate.cloneNode(true);
+				this.domNode.appendChild(this.containerNode);
+			}
+	
+			// Create _TreeNode widget for each specified tree node
+			dojo.forEach(childrenArray, function(childParams){
+				var child = new dijit._TreeNode(dojo.mixin({tree: this.tree}, childParams));
+				this.addChild(child);
+			}, this);
+	
+			// note that updateLayout() needs to be called on each child after
+			// _all_ the children exist
+			dojo.forEach(this.getChildren(), function(child, idx){
+				child._updateLayout();
+	
+				var message = {
+					child: child,
+					index: idx,
+					parent: this
+				};
+			});
+		}else{
+			this.isFolder=false;
+		}
+	}
+});
+
+dojo.declare(
+	"dijit.Tree",
+	dijit._TreeBase,
+{
+	// summary
+	//	Tree view does all the drawing, visual node management etc.
+	//	Throws events about clicks on it, so someone may catch them and process
+	//	Events:
+	//		afterTreeCreate,
+	//		beforeTreeDestroy,
+	//		execute				: for clicking the label, or hitting the enter key when focused on the label,
+	//		toggleOpen			: for clicking the expando key (toggles hide/collapse),
+	//		previous			: go to previous visible node,
+	//		next				: go to next visible node,
+	//		zoomIn				: go to child nodes,
+	//		zoomOut				: go to parent node
+
+	// store: String||dojo.data.Store
+	//	The store to get data to display in the tree
+	store: null,
+
+	// query: String
+	//	query to get top level node(s) of tree (ex: {type:'continent'})
+	query: null,
+
+	// labelAttr: String
+	//		name of attribute that holds label (title) for each tree node
+	labelAttr: "label",
+
+	// typeAttr: String
+	//		name of attribute that holds type for each tree node
+	typeAttr: "type",
+
+	// childrenAttr: String
+	//		name of attribute that holds children of a tree node
+	childrenAttr: "children",
+
+	templateString:"<div class=\"TreeContainer\" style=\"\" waiRole=\"tree\" tabindex=\"0\"\n\tdojoAttachEvent=\"onclick:_onClick;onkeypress:_onKeyPress\"\n></div>\n",		
+
+	isExpanded: true, // consider this "root node" to be always expanded
+
+	isTree: true,
+
+	_publish: function(/*String*/ topicName, /*Object*/ message){
+		// summary:
+		//		Publish a message for this widget/topic
+		dojo.publish(this.id, [dojo.mixin({tree: this, event: topicName}, message||{})]);
+	},
+
+	postMixInProperties: function(){
+		this.tree = this;
+
+		// setup table mapping keys to events
+		var keyTopicMap = {};
+		keyTopicMap[dojo.keys.ENTER]="execute";
+		keyTopicMap[dojo.keys.LEFT_ARROW]="zoomOut";
+		keyTopicMap[dojo.keys.RIGHT_ARROW]="zoomIn";
+		keyTopicMap[dojo.keys.UP_ARROW]="previous";
+		keyTopicMap[dojo.keys.DOWN_ARROW]="next";
+		keyTopicMap[dojo.keys.HOME]="first";
+		keyTopicMap[dojo.keys.END]="last";
+		this._keyTopicMap = keyTopicMap;
+	},
+	
+	postCreate: function(){
+		this.containerNode = this.domNode;
+
+		// make template for container node (we will clone this and insert it into
+		// any nodes that have children)
+		var div = document.createElement('div');
+		div.style.display = 'none';
+		div.className="TreeContainer";	
+		dijit.util.wai.setAttr(div, "waiRole", "role", "presentation");
+		this.containerNodeTemplate = div;
+
+
+		// start the controller, passing in the store
+		this._controller = new dijit._tree.DataController(
+			{	
+				store: this.store, 
+				treeId: this.id,
+				query: this.query, 
+				labelAttr: this.labelAttr, 
+				typeAttr: this.typeAttr, 
+				childrenAttr: this.childrenAttr
+			}
+		);
+
+		this._publish("afterTreeCreate");
+	},
+	
+	destroy: function(){
+		// publish destruction event so that any listeners should stop listening
+		this._publish("beforeTreeDestroy");
+
+		return dijit.base.Widget.prototype.destroy.apply(this, arguments);
+	},
+	
+	toString: function(){
+		return "["+this.declaredClass+" ID:"+this.id	+"]"
+	},
+
+	_domElement2TreeNode: function(/*DomNode*/ domElement){
+		var ret;
+		do{
+			ret=dijit.util.manager.byNode(domElement);
+		}while(!ret && (domElement=domElement.parentNode));
+		return ret;
+	},
+
+	_onClick: function(/*Event*/ e){
+		// summary: translates click events into commands for the controller to process
+		var domElement = e.target;
+
+		// find node
+        var nodeWidget = this._domElement2TreeNode(domElement);	
+		if(!nodeWidget || !nodeWidget.isTreeNode){
+			return;
+		}
+
+		this._publish(
+			(domElement == nodeWidget.expandoNode || 
+			 domElement == nodeWidget.expandoNodeText) ? "toggleOpen" : "execute",
+			 { node: nodeWidget} );	
+
+		dojo.stopEvent(e);
+	},
+	
+	_onKeyPress: function(/*Event*/ e){
+		// summary: translates key events into commands for the controller to process
+		if(!e.keyCode || e.altKey){ return; }
+		var nodeWidget = this._domElement2TreeNode(e.target);
+		if(!nodeWidget){ return; }
+
+		if(this._keyTopicMap[e.keyCode]){
+			this._publish(this._keyTopicMap[e.keyCode], { node: nodeWidget} );	
+			dojo.stopEvent(e);
+		}
+	},
+	
+	blurNode: function(){
+		// summary
+		//	Removes focus from the currently focused node (which must be visible).
+		//	Usually not called directly (just call focusNode() on another node instead)
+		var node = this.lastFocused;
+		if(!node){ return; }
+		var labelNode = node.labelNode;
+		dojo.removeClass(labelNode, "TreeLabelFocused");
+		labelNode.setAttribute("tabIndex", "-1");
+		this.lastFocused = null;
+	},
+	
+	// TODO:
+	//	make sure that if a node is deleted tabIndex goes to another node, and also that
+	//	if you programatically create a tree with no data, when the first row is added
+	//	tabIndex will go to that node
+	
+	focusNode: function(/* _tree.Node */ node){
+		// summary
+		//	Focus on the specified node (which must be visible)
+
+		this.blurNode();
+
+		// set tabIndex so that the tab key can find this node
+		var labelNode = node.labelNode;
+		labelNode.setAttribute("tabIndex", "0");
+		this.lastFocused = node;
+	
+		dojo.addClass(labelNode, "TreeLabelFocused");
+
+		// set focus so that the label wil be voiced using screen readers
+		labelNode.focus();
+	}
+});
+
+dojo.declare(
+	"dijit._TreeNode",
+	dijit._TreeBase,
+{
+	// summary
+	//		Single node within a tree
+
+	templateString:"<div class=\"TreeNode TreeExpandLeaf TreeChildrenNo\" waiRole=\"presentation\"\n\t><span dojoAttachPoint=\"expandoNode\" class=\"TreeExpando\" waiRole=\"presentation\"\n\t></span\n\t><span dojoAttachPoint=\"expandoNodeText\" class=\"dijitExpandoText\" waiRole=\"presentation\"\n\t></span\n\t><div dojoAttachPoint=\"iconNode\" class=\"TreeIcon\" waiRole=\"presentation\"\n\t ><div dojoAttachPoint=\"contentNode\" class=\"TreeContent\" waiRole=\"presentation\"\n\t  ><span dojoAttachPoint=labelNode class=\"TreeLabel\" wairole=\"treeitem\" expanded=\"true\" tabindex=\"-1\"\n\t  ></span\n\t ></div\n\t></div\n></div>\n",		
+
+	// type: String
+	//		User defined identifier to differentiate nodes, and to control icon used
+	//		Example: folder, garbage, inbox, draftsFolder
+	//		TODO: set CSS string base on this type
+	nodeType: "",
+	
+	// item: dojo.data.Item
+	//		the dojo.data entry this tree represents
+	item: null,	
+			
+	isTreeNode: true,
+
+	// label: String
+	//		HTML for the text of this tree node
+	label: "",
+
+	isFolder: null, // set by widget depending on children/args
+
+	isExpanded: false,
+	
+	postCreate: function(){
+		this.labelNode.innerHTML = this.label;	
+		var children = this.getChildren();			
+		// set expand icon for leaf 	
+		this._setExpando();
+	},
+	
+	markProcessing: function(){
+		// summary: visually denote that tree is loading data, etc.
+		this.state = "LOADING";
+		this._setExpando(true);	
+	},
+
+	unmarkProcessing: function(){
+		// summary: clear markup from markProcessing() call
+		this._setExpando(false);	
+	},
+
+	_updateLayout: function(){
+		// summary: set appropriate CSS classes for this.domNode
+
+		dojo.removeClass(this.domNode, "TreeIsRoot");
+		if(this.getParent()["isTree"]){
+			dojo.addClass(this.domNode, 'TreeIsRoot');
+		}
+
+		dojo.removeClass(this.domNode, "TreeIsLast");
+		if(!this.getNextSibling()){
+			dojo.addClass(this.domNode, 'TreeIsLast');	
+		}
+	},
+		
+	_setExpando: function(/*Boolean*/ processing) {
+		// summary: set the right image for the expando node
+
+		// apply the appropriate class to the expando node
+		var styles = ["TreeExpandoLoading", "TreeExpandoOpened", 
+			"TreeExpandoClosed", "TreeExpandoLeaf"];
+		var idx = processing ? 0 : (this.isFolder ?	(this.isExpanded ? 1 : 2) : 3);
+		dojo.forEach(styles,
+			function(s){
+				dojo.removeClass(this.expandoNode, s);
+			}, this
+		);
+		dojo.addClass(this.expandoNode, styles[idx]);
+		
+		// provide a non-image based indicator for images-off mode
+		this.expandoNodeText.innerHTML = 
+			processing ? "*" :
+				(this.isFolder ?
+					(this.isExpanded ? "&#9660;" : "&#9658;") : "-");
+	},	
+
+	setChildren: function(items){
+		dijit.Tree.superclass.setChildren.apply(this, arguments);
+		
+		// create animations for showing/hiding the children
+		this._slideIn = dojo.fx.slideIn({node: this.containerNode, duration: 250});
+		dojo.connect(this.slideIn, "onEnd", dojo.hitch(this, "_afterExpand"));
+		this._slideOut = dojo.fx.slideOut({node: this.containerNode, duration: 250});
+		dojo.connect(this.slideOut, "onEnd", dojo.hitch(this, "_afterCollapse"));
+	},
+
+	expand: function(){
+        // summary: show my children
+		if(this.isExpanded){ return; }
+
+		// cancel in progress collapse operation
+		if(this._slideOut.status() == "playing"){
+			this._slideOut.stop();
+		}
+
+		this.isExpanded = true;
+		dijit.util.wai.setAttr(this.labelNode, "waiState", "expanded", "true");
+		dijit.util.wai.setAttr(this.containerNode, "waiRole", "role", "group");
+		
+		this._setExpando();
+
+		// TODO: use animation that's constant speed of movement, not constant time regardless of height
+		this._slideIn.play();
+	},
+
+	_afterExpand: function(){
+        this.onShow();
+ 		this._publish("afterExpand", {node: this});		
+	},
+
+	collapse: function(){					
+		if(!this.isExpanded){ return; }
+		
+		// cancel in progress expand operation
+		if(this._slideIn.status() == "playing"){
+			this._slideIn.stop();
+		}
+
+		this.isExpanded = false;
+		dijit.util.wai.setAttr(this.labelNode, "waiState", "expanded", "false");
+		this._setExpando();
+		
+		this._slideOut.play();
+	},
+    
+	_afterCollapse: function(){
+		this.onHide();
+		this._publish("afterCollapse", {node: this});
+	},
+
+	toString: function(){
+		return '['+this.declaredClass+', '+this.label+']';
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/_Calendar.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/_Calendar.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/_Calendar.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,229 @@
+dojo.provide("dijit._Calendar");
+
+dojo.require("dojo.cldr.supplemental");
+dojo.require("dojo.date");
+dojo.require("dojo.date.locale");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.TemplatedWidget");
+dojo.require("dijit.base.FormElement");
+
+dojo.declare(
+	"dijit._Calendar",
+	[dijit.base.Widget, dijit.base.TemplatedWidget],
+	{
+		/*
+		summary: 
+			A simple GUI for choosing a date in the context of a monthly calendar.
+
+		description:
+			This widget is used internally by other widgets and is not accessible
+			as a standalone widget.
+			This widget can't be used in a form because it doesn't serialize the date to an
+			<input> field.  For a form element, use DateTextbox instead.
+
+			Note that the parser takes all dates attributes passed in the `RFC 3339` format:
+			http://www.faqs.org/rfcs/rfc3339.html (2005-06-30T08:05:00-07:00)
+			so that they are serializable and locale-independent.
+		
+		usage: 
+			var calendar = new dijit._Calendar({}, dojo.byId("calendarNode")); 
+		 	-or-
+			<div dojoType="dijit._Calendar"></div> 
+		*/
+		templateString:"<table cellspacing=\"0\" cellpadding=\"0\" class=\"calendarContainer\">\n\t<thead>\n\t\t<tr class=\"dijitReset calendarMonthContainer\" valign=\"top\">\n\t\t\t<th class='dijitReset'>\n\t\t\t\t<img dojoAttachPoint=\"monthDecrease\" dojoAttachEvent=\"onclick: _onDecrementMonth;\" class=\"dijitDownArrow calendarMonthDecrement calendarIncrementControl calendarDecrease\" alt=\"-\">\n\t\t\t</th>\n\t\t\t<th class='dijitReset' colspan=\"5\">\n\t\t\t\t<div dojoAttachPoint=\"monthLabelSpacer\" class=\"calendarMonthLabelSpacer\"></div>\n\t\t\t\t<div dojoAttachPoint=\"monthLabelNode\" class=\"calendarMonth\"></div>\n\t\t\t</th>\n\t\t\t<th class='dijitReset'>\n\t\t\t\t<img dojoAttachPoint=\"monthIncrease\" dojoAttachEvent=\"onclick: _onIncrementMonth;\" class=\"dijitUpArrow calendarMonthIncrement calendarIncrementControl calendarIncrease\" alt=\"+\">\n\t\t\t</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<th class=\"dijitReset calendarDayLabelTemplate\"><span class=\"calendarDayLabel\"></span></th>\n\t\t</tr>\n\t</thead>\n\t<tbody dojoAttachEvent=\"onclick: _onDayClick;\" class=\"dijitReset calendarBodyContainer\">\n\t\t<tr class=\"dijitReset calendarWeekTemplate\">\n\t\t\t<td class=\"dijitReset calendarDateTemplate\"><span class=\"calendarDateLabel\"></span></td>\n\t\t</tr>\n\t</tbody>\n\t<tfoot class=\"dijitReset calendarYearContainer\">\n\t\t<tr>\n\t\t\t<td class='dijitReset' valign=\"top\" colspan=\"7\">\n\t\t\t\t<h3 class=\"calendarYearLabel\">\n\t\t\t\t\t<span dojoAttachPoint=\"previousYearLabelNode\"\n\t\t\t\t\t\tdojoAttachEvent=\"onclick: _onDecrementYear;\" class=\"calendarPreviousYear\"></span>\n\t\t\t\t\t<span dojoAttachPoint=\"currentYearLabelNode\" class=\"calendarSelectedYear\"></span>\n\t\t\t\t\t<span dojoAttachPoint=\"nextYearLabelNode\" \n\t\t\t\t\t\tdojoAttachEvent=\"onclick: _onIncrementYear;\" class=\"calendarNextYear\"></span>\n\t\t\t\t</h3>\n\t\t\t</td>\n\t\t</tr>\n\t</tfoot>\n</table>\t\n",
+
+		// value: Date
+		// the currently selected Date
+		value: new Date(),
+
+		// dayWidth: String
+		// How to represent the days of the week in the calendar header. See dojo.date.locale
+		dayWidth: "narrow",
+
+		setValue: function(/*Date*/ value){
+			//summary: set the current date and update the UI
+			if(!this.value || dojo.date.compare(value, this.value)){
+				value = new Date(value);
+				if(this.isDisabledDate(value, this.lang)){return;}
+				this.value = value;
+				this.value.setHours(0,0,0,0);
+				this.displayMonth = new Date(this.value);
+				this._populateGrid();
+				this.onValueChanged(this.value);
+			}
+		},
+
+		_populateGrid: function(){
+			var month = this.displayMonth;
+			month.setDate(1);
+			var firstDay = month.getDay();
+			var daysInMonth = dojo.date.getDaysInMonth(month);
+			var daysInPreviousMonth = dojo.date.getDaysInMonth(dojo.date.add(month, "month", -1));
+			var today = new Date();
+			var selected = this.value;
+
+			var dayOffset = dojo.cldr.supplemental.getFirstDayOfWeek(this.lang);
+			if(dayOffset > firstDay){ dayOffset -= 7; }
+
+			// Iterate through dates in the calendar and fill in date numbers and style info
+			dojo.query(".calendarDateTemplate", this.domNode).forEach(function(template, i){
+				i += dayOffset;
+				var date = new Date(month);
+				var number, clazz, adj = 0;
+
+				if(i < firstDay){
+					number = daysInPreviousMonth - firstDay + i + 1;
+					adj = -1;
+					clazz = "calendarPrevious";
+				}else if(i >= (firstDay + daysInMonth)){
+					number = i - firstDay - daysInMonth + 1;
+					adj = 1;
+					clazz = "calendarNext";
+				}else{
+					number = i - firstDay + 1;
+					clazz = "calendarCurrent";
+				}
+
+				if(adj){
+					date = dojo.date.add(date, "month", adj);
+				}
+				date.setDate(number);
+
+				if(!dojo.date.compare(date, today, "date")){
+					clazz = "calendarCurrentDate " + clazz;
+				}
+
+				if(!dojo.date.compare(date, selected, "date")){
+					clazz = "calendarSelectedDate " + clazz;
+				}
+
+				if(this.isDisabledDate(date, this.lang)){
+					clazz = "calendarDisabledDate " + clazz;
+				}
+
+				template.className =  clazz + "Month calendarDateTemplate";
+				template.dijitDateValue = date.valueOf();
+				var label = dojo.query(".calendarDateLabel", template)[0];
+				label.innerHTML = date.getDate();
+			}, this);
+
+			// Fill in localized month name
+			var monthNames = dojo.date.locale.getNames('months', 'wide', 'standAlone', this.lang);
+			this.monthLabelNode.innerHTML = monthNames[month.getMonth()];
+
+			// Fill in localized prev/current/next years
+			var y = month.getFullYear() - 1;
+			dojo.forEach(["previous", "current", "next"], function(name){
+				this[name+"YearLabelNode"].innerHTML =
+					dojo.date.locale.format(new Date(y++, 0), {selector:'year', locale:this.lang});
+			}, this);
+		},
+
+		postCreate: function(){
+			dijit._Calendar.superclass.postCreate.apply(this);
+
+			var cloneClass = dojo.hitch(this, function(clazz, n){
+				var template = dojo.query(clazz, this.domNode)[0];
+	 			for(var i=0; i<n; i++){
+					template.parentNode.appendChild(template.cloneNode(true));
+				}
+			});
+
+			// clone the day label and calendar day templates 6 times to make 7 columns
+			cloneClass(".calendarDayLabelTemplate", 6);
+			cloneClass(".calendarDateTemplate", 6);
+
+			// now make 6 week rows
+			cloneClass(".calendarWeekTemplate", 5);
+
+			// insert localized day names in the header
+			var dayNames = dojo.date.locale.getNames('days', this.dayWidth, 'standAlone', this.lang);
+			var dayOffset = dojo.cldr.supplemental.getFirstDayOfWeek(this.lang);
+			dojo.query(".calendarDayLabel", this.domNode).forEach(function(label, i){
+				label.innerHTML = dayNames[(i + dayOffset) % 7];
+			});
+
+			// Fill in spacer element with all the month names (invisible) so that the maximum width will affect layout
+			var monthNames = dojo.date.locale.getNames('months', 'wide', 'standAlone', this.lang);
+			dojo.forEach(monthNames, function(name){
+				var monthSpacer = dojo.doc.createElement("div");
+				monthSpacer.innerHTML = name;
+				this.monthLabelSpacer.appendChild(monthSpacer);
+			}, this);
+
+			this.value = null;
+			this.setValue(new Date());
+
+			this._convertImages();
+		},
+
+		_convertImages : function() {
+			// convert the arrow images from using style.background-image to the .src property (a11y)
+			dijit.util.wai.imageBgToSrc([this.monthDecrease, this.monthIncrease]);
+
+			// Trick to get image path reference from CSS as background image, then copy it into the img src attribute
+/*			dojo.forEach(["monthDecrease", "monthIncrease"], function(item){
+				var bi = dojo.getComputedStyle(this[item]).backgroundImage;
+				var href = bi.charAt(4)=='"' ? bi.slice(5,-2) : bi.slice(4,-1);	// url(foo) --> foo, url("foo") --> foo
+				this[item].src=href;
+			}, this);
+*/		
+		},
+
+		_adjustDate: function(/*String*/part, /*int*/amount){
+			this.displayMonth = dojo.date.add(this.displayMonth, part, amount);
+			this._populateGrid();
+		},
+
+		_onIncrementMonth: function(/*Event*/evt){
+			// summary: handler for increment month event
+			evt.stopPropagation();
+			this._adjustDate("month", 1);
+		},
+	
+		_onDecrementMonth: function(/*Event*/evt){
+			// summary: handler for increment month event
+			evt.stopPropagation();
+			this._adjustDate("month", -1);
+		},
+
+		_onIncrementYear: function(/*Event*/evt){
+			// summary: handler for increment year event
+			evt.stopPropagation();
+			this._adjustDate("year", 1);
+		},
+	
+		_onDecrementYear: function(/*Event*/evt){
+			// summary: handler for increment year event
+			evt.stopPropagation();
+			this._adjustDate("year", -1);
+		},
+
+		_onDayClick: function(/*Event*/evt){
+			var node = evt.target;
+			dojo.stopEvent(evt);
+			while(!node.dijitDateValue){
+				node = node.parentNode;
+			}
+			if(!dojo.hasClass(node, "calendarDisabledDate")){
+				this.setValue(node.dijitDateValue);
+				this.onValueSelected(this.value);
+			}
+		},
+
+		onValueSelected: function(/*Date*/date){
+			//summary: a date cell was selected.  It may be the same as the previous value.
+		},
+
+		onValueChanged: function(/*Date*/date){
+			//summary: called only when the selected date has changed
+		},
+
+		isDisabledDate: function(/*Date*/dateObject, /*String?*/locale){
+			// summary:
+			//	May be overridden to disable certain dates in the calendar e.g. isDisabledDate=dojo.date.locale.isWeekend
+			return false; // Boolean
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/_editor/RichText.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/_editor/RichText.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/_editor/RichText.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,1989 @@
+dojo.provide("dijit._editor.RichText");
+dojo.require("dijit.base.Widget");
+dojo.require("dijit._editor.selection");
+
+// dojo.require("dojo.html.layout");
+// dojo.require("dojo.html.range");
+// dojo.require("dojo.string.extras");
+
+// used to save content
+// but do not try doing document.write if we are using xd loading.
+// document.write will only work if RichText.js is included in the dojo.js
+// file. If it is included in dojo.js and you want to allow rich text saving
+// for back/forward actions, then set djConfig.allowXdRichTextSave = true.
+if(!djConfig["useXDomain"] || djConfig["allowXdRichTextSave"]){
+	if(dojo._post_load){
+		(function(){
+			var savetextarea = dojo.doc.createElement('textarea');
+			savetextarea.id = "dijit._editor.RichText.savedContent";
+			var s = savetextarea.style;
+			s.display='none';
+			s.position='absolute';
+			s.top="-100px";
+			s.left="-100px"
+			s.height="3px";
+			s.width="3px";
+			dojo.body().appendChild(savetextarea);
+		})();
+	}else{
+		//dojo.body() is not available before onLoad is fired
+		try {
+			dojo.doc.write('<textarea id="dijit._editor.RichText.savedContent" ' +
+				'style="display:none;position:absolute;top:-100px;left:-100px;height:3px;width:3px;overflow:hidden;"></textarea>');
+		}catch(e){ }
+	}
+}
+dojo.declare(
+	"dijit._editor.RichText",
+	[ dijit.base.Widget ], null,
+	{
+		preamble: function(){
+			// summary:
+			//		dijit._editor.RichText is the core of the WYSIWYG editor in dojo, which
+			//		provides the basic editing features. It also encapsulates the differences
+			//		of different js engines for various browsers
+
+			// contentPreFilters: Array
+			//		pre content filter function register array.
+			//		these filters will be executed before the actual
+			//		editing area get the html content
+			this.contentPreFilters = [];
+
+			// contentPostFilters: Array
+			//		post content filter function register array.
+			//		these will be used on the resulting html
+			//		from contentDomPostFilters. The resuling
+			//		content is the final html (returned by getValue())
+			this.contentPostFilters = [];
+
+			// contentDomPreFilters: Array
+			//		pre content dom filter function register array.
+			//		these filters are applied after the result from
+			//		contentPreFilters are set to the editing area
+			this.contentDomPreFilters = [];
+
+			// contentDomPostFilters: Array
+			//		post content dom filter function register array.
+			//		these filters are executed on the editing area dom
+			//		the result from these will be passed to contentPostFilters
+			this.contentDomPostFilters = [];
+
+			// editingAreaStyleSheets: Array
+			//		array to store all the stylesheets applied to the editing area
+			this.editingAreaStyleSheets=[];
+
+			this._keyHandlers = {};
+			this.contentPreFilters.push(dojo.hitch(this, "_preFixUrlAttributes"));
+			if(dojo.isMoz){
+				this.contentPreFilters.push(this._fixContentForMoz);
+			}
+			//this.contentDomPostFilters.push(this._postDomFixUrlAttributes);
+
+
+			this.onLoadDeferred = new dojo.Deferred();
+			if(this.blockNodeForEnter=='BR'){
+				if(dojo.isIE){
+					this.contentDomPreFilters.push(dojo.hitch(this, "regularPsToSingleLinePs"));
+					this.contentDomPostFilters.push(dojo.hitch(this, "singleLinePsToRegularPs"));
+				}
+			}else if(this.blockNodeForEnter){
+				//add enter key handler
+				// FIXME: need to port to the new event code!!
+				this.addKeyHandler(13, 0, this.handleEnterKey); //enter
+				this.addKeyHandler(13, 2, this.handleEnterKey); //shift+enter
+			}
+		},
+
+		// inheritWidth: Boolean
+		//		whether to inherit the parent's width or simply use 100%
+		inheritWidth: false,
+
+		// focusOnLoad: Boolean
+		//		whether focusing into this instance of richtext when page onload
+		focusOnLoad: false,
+
+		// saveName: String
+		//		If a save name is specified the content is saved and restored when the user
+		//		leave this page can come back, or if the editor is not properly closed after
+		//		editing has started.
+		saveName: "",
+
+		// styleSheets: String
+		//		semicolon (";") separated list of css files for the editing area
+		styleSheets: "",
+
+		// _content: String
+		//		temporary content storage
+		_content: "",
+
+		// height: String
+		//		set height to fix the editor at a specific height, with scrolling
+		height: "",
+
+		// minHeight: String
+		//		The minimum height that the editor should have
+		minHeight: "1em",
+
+		// isClosed: Boolean
+		isClosed: true,
+
+		// isLoaded: Boolean
+		isLoaded: false,
+
+		// _SEPARATOR: String
+		//		used to concat contents from multiple textareas into a single string
+		_SEPARATOR: "@@**%%__RICHTEXTBOUNDRY__%%**@@",
+
+		// onLoadDeferred: dojo.Deferred
+		//		deferred that can be used to connect to the onLoad function. This
+		//		will only be set if dojo.Deferred is required
+		onLoadDeferred: null,
+
+		// Init
+		postCreate: function(){
+			dojo.publish("dijit._editor.RichText::init", [this]);
+			this.open();
+			this.setupDefaultShortcuts();
+		},
+
+		setupDefaultShortcuts: function(){
+			// summary: add some default key handlers
+			// description: 
+			// 		Overwrite this to setup your own handlers. The default
+			// 		implementation does not use Editor2 commands, but directly
+			//		executes the builtin commands within the underlying browser
+			//		support.
+			var ctrl = this.KEY_CTRL;
+			var exec = function(cmd, arg){
+				return arguments.length == 1 ? function(){ this.execCommand(cmd); } :
+					function(){ this.execCommand(cmd, arg); }
+			}
+			this.addKeyHandler("b", ctrl, exec("bold"));
+			this.addKeyHandler("i", ctrl, exec("italic"));
+			this.addKeyHandler("u", ctrl, exec("underline"));
+			this.addKeyHandler("a", ctrl, exec("selectall"));
+			this.addKeyHandler("s", ctrl, function () { this.save(true); });
+
+			this.addKeyHandler("1", ctrl, exec("formatblock", "h1"));
+			this.addKeyHandler("2", ctrl, exec("formatblock", "h2"));
+			this.addKeyHandler("3", ctrl, exec("formatblock", "h3"));
+			this.addKeyHandler("4", ctrl, exec("formatblock", "h4"));
+
+			this.addKeyHandler("\\", ctrl, exec("insertunorderedlist"));
+			if(!dojo.isIE){
+				this.addKeyHandler("Z", ctrl, exec("redo"));
+			}
+		},
+
+		// events: Array
+		//		 events which should be connected to the underlying editing area
+		events: ["onBlur", "onFocus", "onKeyPress", "onKeyDown", "onKeyUp", "onClick"],
+
+		// events: Array
+		//		 events which should be connected to the underlying editing
+		//		 area, events in this array will be addListener with
+		//		 capture=true
+		captureEvents: [],
+
+		_safariIsLeopard: function(){
+			var gt420 = false;
+			if(dojo.isSafari){
+				var tmp = navigator.userAgent.split("AppleWebKit/")[1];
+				var ver = parseFloat(tmp.split(" ")[0]);
+				if(ver >= 420){ gt420 = true; }
+			}
+			return gt420;
+		},
+
+		_editorCommandsLocalized: false,
+		_localizeEditorCommands: function(){
+			if(this._editorCommandsLocalized){
+				return;
+			}
+			this._editorCommandsLocalized = true;
+			//do not use _cacheLocalBlockFormatNames here, as it will
+			//trigger security warning in IE7
+
+			//in the array below, ul can not come directly after ol,
+			//otherwise the queryCommandValue returns Normal for it
+			var formats = ['p', 'pre', 'address', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'div', 'ul'];
+			var localhtml = "", format, i=0;
+			while(format=formats[i++]){
+				if(format.charAt(1) != 'l'){
+					localhtml += "<"+format+"><span>content</span></"+format+">";
+				}else{
+					localhtml += "<"+format+"><li>content</li></"+format+">";
+				}
+			}
+			//queryCommandValue returns empty if we hide editNode, so move it out of screen temporary
+			with(this.iframe.style){
+				position = "absolute";
+				left = "-2000px";
+				top = "-2000px";
+			}
+			this.editNode.innerHTML = localhtml;
+			var node = this.editNode.firstChild;
+			while(node){
+				dojo.withGlobal(this.window, "selectElement", dijit._editor.selection, [node.firstChild]);
+				var nativename = node.tagName.toLowerCase();
+				this._local2NativeFormatNames[nativename] = this.queryCommandValue("formatblock");
+				this._native2LocalFormatNames[this._local2NativeFormatNames[nativename]] = nativename;
+				node = node.nextSibling;
+			}
+			with(this.iframe.style){
+				position = "";
+				left = "";
+				top = "";
+			}
+		},
+
+		open: function(/*DomNode, optional*/element){
+			// summary:
+			//		Transforms the node referenced in this.domNode into a rich text editing
+			//		node. This will result in the creation and replacement with an <iframe> 
+			//		if designMode(FF)/contentEditable(IE) is used.
+
+			if((!this.onLoadDeferred)||(this.onLoadDeferred.fired >= 0)){
+				this.onLoadDeferred = new dojo.Deferred();
+			}
+
+			if(!this.isClosed){ this.close(); }
+			dojo.publish("dijit._editor.RichText::open", [ this ]);
+
+			this._content = "";
+			if((arguments.length == 1)&&(element["nodeName"])){ this.domNode = element; } // else unchanged
+
+			if(	(this.domNode["nodeName"])&&
+				(this.domNode.nodeName.toLowerCase() == "textarea")){
+				// if we were created from a textarea, then we need to create a
+				// new editing harness node.
+				this.textarea = this.domNode;
+				var html = this._preFilterContent(this.textarea.value);
+				this.domNode = dojo.doc.createElement("div");
+				this.domNode.cssText = this.textarea.cssText;
+				this.domNode.className += " "+this.textarea.className;
+
+				if(!dojo.isSafari){
+					// FIXME: VERY STRANGE safari 2.0.4 behavior here caused by
+					// moving the textarea. Often crashed the browser!!! Seems
+					// fixed on webkit nightlies.
+					dojo.place(this.domeNode, this.textarea, "before");
+				}
+				var tmpFunc = dojo.hitch(this, function(){
+					//some browsers refuse to submit display=none textarea, so
+					//move the textarea out of screen instead
+					with(this.textarea.style){
+						display = "block";
+						position = "absolute";
+						left = top = "-1000px";
+
+						if(dojo.isIE){ //nasty IE bug: abnormal formatting if overflow is not hidden
+							this.__overflow = overflow;
+							overflow = "hidden";
+						}
+					}
+				});
+				if(dojo.isIE){
+					setTimeout(tmpFunc, 10);
+				}else{
+					tmpFunc();
+				}
+
+				// this.domNode.innerHTML = html;
+
+				if(this.textarea.form){
+					// FIXME: port: this used to be before advice!!!
+					dojo.connect(this.textarea.form, "onsubmit", this, function(){
+						// FIXME: should we be calling close() here instead?
+						this.textarea.value = this.getValue();
+					});
+				}
+
+				// dojo plucks our original domNode from the document so we need
+				// to go back and put ourselves back in
+				//	var editor = this;
+				//	dojo.connect(this, "postCreate", function (){
+				//		dojo.place(editor.textarea, editor.domNode, "after");
+				//	});
+			}else{
+				var html = this._preFilterContent(this.getNodeChildrenHtml(this.domNode));
+				this.domNode.innerHTML = '';
+			}
+			if(html == ""){ html = "&nbsp;"; }
+
+			// dojo.body().appendChild(this.domNode);
+			dojo.place(this.domNode, this.srcNodeRef, "before");
+			var content = dojo.contentBox(this.domNode);
+			// var content = dojo.contentBox(this.srcNodeRef);
+			this._oldHeight = content.h;
+			this._oldWidth = content.w;
+
+			// FIXME: port to new style APIs instead?
+			this._firstChildContributingMargin = this.height ? 0 : this._getContributingMargin(this.domNode, "top");
+			this._lastChildContributingMargin = this.height ? 0 : this._getContributingMargin(this.domNode, "bottom");
+
+			this.savedContent = html;
+
+			// If we're a list item we have to put in a blank line to force the
+			// bullet to nicely align at the top of text
+			if(	(this.domNode["nodeName"]) &&
+				(this.domNode.nodeName == "LI") ){
+				this.domNode.innerHTML = " <br>";
+			}
+
+			this.editingArea = dojo.doc.createElement("div");
+			this.domNode.appendChild(this.editingArea);
+
+			if(this.saveName != "" && (!djConfig["useXDomain"] || djConfig["allowXdRichTextSave"])){
+				var saveTextarea = dojo.byId("dijit._editor.RichText.savedContent");
+				if(saveTextarea.value != ""){
+					var datas = saveTextarea.value.split(this._SEPARATOR), i=0, dat;
+					while(dat=datas[i++]){
+						var data = dat.split(":");
+						if(data[0] == this.saveName){
+							html = data[1];
+							datas.splice(i, 1);
+							break;
+						}
+					}
+				}
+				// FIXME: need to do something different for Opera/Safari
+				dojo.connect(window, "onbeforeunload", this, "_saveContent");
+				// dojo.connect(window, "onunload", this, "_saveContent");
+			}
+
+			this.isClosed = false;
+			// Safari's selections go all out of whack if we do it inline,
+			// so for now IE is our only hero
+			//if (typeof document.body.contentEditable != "undefined") {
+			if(dojo.isIE || this._safariIsLeopard() || dojo.isOpera){ // contentEditable, easy
+				var ifr = this.iframe = dojo.doc.createElement('iframe');
+				ifr.src = 'javascript:void(0)';
+				this.editorObject = ifr;
+				ifr.style.border = "none";
+				ifr.style.width = "100%";
+				ifr.frameBorder = 0;
+				this.editingArea.appendChild(ifr)
+				this.window = ifr.contentWindow;
+				this.document = this.window.document;
+				this.document.open();
+				this.document.write(this._getIframeDocTxt());
+				this.document.close();
+				if(this.height){
+					this.editNode = this.document.body;
+				}else{
+					this.document.body.appendChild(this.document.createElement("div"));
+					this.editNode = this.document.body.firstChild;
+				}
+				this.editNode.contentEditable = true;
+				if(dojo.isIE >= 7){
+					if(this.height){
+						ifr.style.height = this.height;
+					}
+					if(this.minHeight){
+						ifr.style.minHeight = this.minHeight;
+					}
+				}else{
+					ifr.style.height = this.height ? this.height : this.minHeight;
+				}
+
+				// FIXME: setting contentEditable on switches this element to
+				// IE's hasLayout mode, triggering weird margin collapsing
+				// behavior. It's particularly bad if the element you're editing
+				// contains childnodes that don't have margin: defined in local
+				// css rules. It would be nice if it was possible to hack around
+				// this. Sadly _firstChildContributingMargin and
+				// _lastChildContributingMargin don't work on IE unless all
+				// elements have margins set in CSS :-(
+
+				//in IE, names for blockformat is locale dependent, so we cache the values here
+
+				//if the normal way fails, we try the hard way to get the list
+
+				this._localizeEditorCommands();
+
+				this.editNode.innerHTML = html;
+				this._preDomFilterContent(this.editNode);
+				//	if(this.height){ this.document.body.style.overflowY="scroll"; }
+				var events=this.events.concat(this.captureEvents);
+				dojo.forEach(events, function(e){
+					dojo.connect(this.editNode, e.toLowerCase(), this, e);
+				}, this);
+
+				this.onLoad();
+			}else{ // designMode in iframe
+				this._drawIframe(html);
+				this.editorObject = this.iframe;
+			}
+
+			// TODO: this is a guess at the default line-height, kinda works
+			if(this.domNode.nodeName == "LI"){ this.domNode.lastChild.style.marginTop = "-1.2em"; }
+			this.domNode.className += " RichTextEditable";
+		},
+
+		//static cache variables shared among all instance of this class
+		_local2NativeFormatNames: {},
+		_native2LocalFormatNames: {},
+
+		_hasCollapseableMargin: function(/*DomNode*/element, /*String*/side){
+			// summary:
+			//		check if an element has padding or borders on the given side
+			//		which would prevent it from collapsing margins
+			/*
+			if(dojo.html.getPixelValue(element, 'border-'+side+'-width', false)){
+				return false;
+			}else if(dojo.html.getPixelValue(element, 'padding-'+side, false)){
+				return false;
+			}else{
+				return true;
+			}
+			*/
+		},
+
+		// FIXME: need to port this to 0.9 methods
+		_getContributingMargin:	function(/*DomNode*/element, /*String*/topOrBottom){
+			// summary:
+			//		calculate how much margin this element and its first or last
+			//		child are contributing to the total margin between this element
+			//		and the adjacent node. CSS border collapsing makes this
+			//		necessary.
+			
+			return 0; // FIXME: port
+
+			// FIXME: OMG. This has to be horribly inefficient.
+			if(topOrBottom == "top"){
+				var siblingAttr = "previousSibling";
+				var childSiblingAttr = "nextSibling";
+				var childAttr = "firstChild";
+				var marginProp = "margin-top";
+				var siblingMarginProp = "margin-bottom";
+			}else{
+				var siblingAttr = "nextSibling";
+				var childSiblingAttr = "previousSibling";
+				var childAttr = "lastChild";
+				var marginProp = "margin-bottom";
+				var siblingMarginProp = "margin-top";
+			}
+
+			var elementMargin = dojo.html.getPixelValue(element, marginProp, false);
+
+			// FIXME: redef'd on every call!!
+			function isSignificantNode(element){
+				// see if an node is significant in the current context
+				// for calulating margins
+				return !(element.nodeType==3 && dojo.string.isBlank(element.data))
+					&& dojo.html.getStyle(element, "display") != "none"
+					&& !dojo.html.isPositionAbsolute(element);
+			}
+
+			// walk throuh first/last children to find total collapsed margin size
+			var childMargin = 0;
+			var child = element[childAttr];
+			while(child){
+				// skip over insignificant elements (whitespace, etc)
+				while((!isSignificantNode(child)) && child[childSiblingAttr]){
+					child = child[childSiblingAttr];
+				}
+
+				childMargin = Math.max(childMargin, dojo.html.getPixelValue(child, marginProp, false));
+				// stop if we hit a bordered/padded element
+				if (!this._hasCollapseableMargin(child, topOrBottom)) break;
+				child = child[childAttr];
+			}
+
+			// if this element has a border, return full child margin immediately
+			// as there won't be any margin collapsing
+			if (!this._hasCollapseableMargin(element, topOrBottom)){ return parseInt(childMargin); }
+
+			// find margin supplied by nearest sibling
+			var contextMargin = 0;
+			var sibling = element[siblingAttr];
+			while(sibling){
+				if(isSignificantNode(sibling)){
+					contextMargin = dojo.html.getPixelValue(sibling,
+															 siblingMarginProp,
+															 false);
+					break;
+				}
+				sibling = sibling[siblingAttr];
+			}
+			if(!sibling){ // no sibling, look at parent's margin instead
+				contextMargin = dojo.html.getPixelValue(element.parentNode, marginProp, false);
+			}
+
+			if(childMargin > elementMargin){
+				return parseInt(Math.max((childMargin-elementMargin)-contextMargin, 0));
+			}else{
+				return 0;
+			}
+		},
+
+		_getIframeDocTxt: function(){
+			var _cs = dojo.getComputedStyle(this.domNode);
+
+			var font = [ _cs.fontWeight, _cs.fontSize, _cs.fontFamily ].join(" ");
+
+			// line height is tricky - applying a units value will mess things up.
+			// if we can't get a non-units value, bail out.
+			var lineHeight = _cs.lineHeight;
+			if(lineHeight.indexOf("px") >= 0){
+				lineHeight = parseFloat(lineHeight)/parseFloat(_cs.fontSize);
+				// console.debug(lineHeight);
+			}else if(lineHeight.indexOf("em")>=0){
+				lineHeight = parseFloat(lineHeight);
+			}else{
+				lineHeight = "1.0";
+			}
+			return [
+				"<html><head><style>",
+				"body,html {",
+				"	background:transparent;",
+				"	padding: 0;",
+				"	margin: 0;",
+				"}",
+				// TODO: left positioning will case contents to disappear out of view
+				//       if it gets too wide for the visible area
+				"body{",
+				"	top:0px; left:0px; right:0px;",
+					((this.height||dojo.isOpera) ? "" : "position: fixed;"),
+				"	font:", font, ";",
+				// FIXME: IE 6 won't understand min-height?
+				"	min-height:", this.minHeight, ";",
+				"	line-height:", lineHeight,
+				"}",
+				"p{ margin: 1em 0 !important; }",
+				(this.height ? 
+					"" :
+					"body > *:first-child{ padding-top:0 !important;margin-top:" + this._firstChildContributingMargin + "px !important;}" + // FIXME: test firstChild nodeType
+					"body > *:last-child {"+
+					"	padding-bottom:0 !important;"+
+					"	margin-bottom:" + this._lastChildContributingMargin + "px !important;"+
+					"}"
+				),
+				"li > ul:-moz-first-node, li > ol:-moz-first-node{ padding-top: 1.2em; } ",
+				"li{ min-height:1.2em; }",
+				"</style>", 
+				this._applyEditingAreaStyleSheets(),
+				"</head><body></body></html>"
+			].join("");
+		},
+
+		_drawIframe: function(/*String*/html){
+			// summary:
+			//		Draws an iFrame using the existing one if one exists.
+			//		Used by Mozilla, Safari, and Opera
+
+			// detect firefox < 1.5, which has some iframe loading issues
+			var oldMoz = Boolean(dojo.isMoz && (typeof window.XML == 'undefined'));
+
+			if(!this.iframe){
+				var ifr = this.iframe = dojo.doc.createElement("iframe");
+				// this.iframe.src = "about:blank";
+				// document.body.appendChild(this.iframe);
+				// console.debug(this.iframe.contentDocument.open());
+				// dojo.body().appendChild(this.iframe);
+				var ifrs = ifr.style;
+				// ifrs.border = "1px solid black";
+				ifrs.border = "none";
+				ifrs.lineHeight = "0"; // squash line height
+				ifrs.verticalAlign = "bottom";
+				ifrscrolling = this.height ? "auto" : "vertical";
+			}
+			// opera likes this to be outside the with block
+			//	this.iframe.src = "javascript:void(0)";//dojo.uri.dojoUri("src/widget/templates/richtextframe.html") + ((dojo.doc.domain != currentDomain) ? ("#"+dojo.doc.domain) : "");
+			this.iframe.style.width = this.inheritWidth ? this._oldWidth : "100%";
+
+			if(this.height){
+				this.iframe.style.height = this.height;
+			}else{
+				var height = this._oldHeight;
+				if(this._hasCollapseableMargin(this.domNode, 'top')){
+					height += this._firstChildContributingMargin;
+				}
+				if(this._hasCollapseableMargin(this.domNode, 'bottom')){
+					height += this._lastChildContributingMargin;
+				}
+				this.iframe.height = height;
+			}
+
+			var tmpContent = this.srcNodeRef;
+			// var tmpContent = dojo.doc.createElement('div');
+			//	tmpContent.style.display="none";
+			// tmpContent.innerHTML = html;
+			//append tmpContent to under the current domNode so that the margin
+			//calculation below is correct
+			// this.editingArea.appendChild(tmpContent);
+
+			dojo.place(this.iframe, this.srcNodeRef, "before");
+
+			if(!this.height){
+				// fix margins on tmpContent
+				var c = dojo.query(">", tmpContent);
+				var firstChild = c[0];
+				var lastChild = c.pop();
+				if(firstChild){
+					firstChild.style.marginTop = this._firstChildContributingMargin+"px";
+				}
+				if(lastChild){
+					lastChild.style.marginBottom = this._lastChildContributingMargin+"px";
+				}
+			}
+			//do we want to show the content before the editing area finish loading here?
+			//if external style sheets are used for the editing area, the appearance now
+			//and after loading of the editing area won't be the same (and padding/margin
+			//calculation above may not be accurate)
+			//	tmpContent.style.display = "none";
+			//	this.editingArea.appendChild(this.iframe);
+
+			var _iframeInitialized = false;
+			// console.debug(this.iframe);
+			// var contentDoc = this.iframe.contentWindow.document;
+
+
+			// note that on Safari lower than 420+, we have to get the iframe
+			// by ID in order to get something w/ a contentDocument property
+
+			var contentDoc = this.iframe.contentDocument;
+			contentDoc.open();
+			contentDoc.write(this._getIframeDocTxt());
+			contentDoc.close();
+
+			// now we wait for onload. Janky hack!
+			var ifrFunc = dojo.hitch(this, function(){
+				if(!_iframeInitialized){
+					_iframeInitialized = true;
+				}else{ return; }
+				if(!this.editNode){
+					if(this.iframe.contentWindow){
+						this.window = this.iframe.contentWindow;
+						this.document = this.iframe.contentWindow.document
+					}else if(this.iframe.contentDocument){
+						// for opera
+						this.window = this.iframe.contentDocument.window;
+						this.document = this.iframe.contentDocument;
+					}
+
+					// FIXME: what's the 0.9 eqivalent for this?
+					// dojo.html.removeNode(tmpContent);
+					tmpContent.parentNode.removeChild(tmpContent);
+					this.document.body.innerHTML = html;
+					this.document.designMode = "on";
+					//	try{
+					//	this.document.designMode = "on";
+					// }catch(e){
+					//	this._tryDesignModeOnClick=true;
+					// }
+					try{
+						var currentDomain = (new dojo._Url(dojo.doc.location)).host;
+						if(dojo.doc.domain!=currentDomain){
+							this.document.domain = dojo.doc.domain;
+						}
+					}catch(e){}
+
+					this.onLoad();
+				}else{
+					// FIXME: what's the 0.9 eqivalent for this?
+					// dojo.html.removeNode(tmpContent);
+					tmpContent.parentNode.removeChild(tmpContent);
+					this.editNode.innerHTML = html;
+					this.onDisplayChanged();
+				}
+				this._preDomFilterContent(this.editNode);
+			});
+
+			if(this.editNode){
+				ifrFunc(); // iframe already exists, just set content
+			}else if(dojo.isMoz){
+//				// FIXME: if we put this on a delay, we get a height of 20px.
+//				// Otherwise we get the correctly specified minHeight value.
+				setTimeout(ifrFunc, 250);
+			}else{ // new mozillas, opera, safari
+				ifrFunc();
+			}
+		},
+
+		_applyEditingAreaStyleSheets: function(){
+			// summary:
+			//		apply the specified css files in styleSheets
+			var files = [];
+			if(this.styleSheets){
+				files = this.styleSheets.split(';');
+				this.styleSheets = '';
+			}
+
+			//empty this.editingAreaStyleSheets here, as it will be filled in addStyleSheet
+			files = files.concat(this.editingAreaStyleSheets);
+			this.editingAreaStyleSheets = [];
+
+			var text='', i=0, url;
+			while(url=files[i++]){
+				var abstring = (new dojo._Url(dojo.global.location, url)).toString();
+				this.editingAreaStyleSheets.push(abstring);
+				text += '<link rel="stylesheet" type="text/css" href="'+abstring+'"/>' 
+ 			}
+			return text;
+		},
+
+		addStyleSheet: function(/*dojo._Url*/uri){
+			// summary:
+			//		add an external stylesheet for the editing area
+			// uri:	a dojo.uri.Uri pointing to the url of the external css file
+			var url=uri.toString();
+			if(dojo.indexOf(this.editingAreaStyleSheets, url) > -1){
+				console.debug("dijit._editor.RichText.addStyleSheet: Style sheet "+url+" is already applied to the editing area!");
+				return;
+			}
+
+			//if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe
+			if(url.charAt(0) == '.' || (url.charAt(0) != '/' && !uri.host)){
+				url = (new dojo._Url(dojo.global.location, url)).toString();
+			}
+
+			this.editingAreaStyleSheets.push(url);
+			if(this.document.createStyleSheet){ //IE
+				this.document.createStyleSheet(url);
+			}else{ //other browser
+				var head = this.document.getElementsByTagName("head")[0];
+				var stylesheet = this.document.createElement("link");
+				with(stylesheet){
+					rel="stylesheet";
+					type="text/css";
+					href=url;
+				}
+				head.appendChild(stylesheet);
+			}
+		},
+
+		removeStyleSheet: function(/*dojo._Url*/uri){
+			// summary:
+			//		remove an external stylesheet for the editing area
+			var url=uri.toString();
+			//if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe
+			if(url.charAt(0) == '.' || (url.charAt(0) != '/' && !uri.host)){
+				url = (new dojo._Url(dojo.global.location, url)).toString();
+			}
+			var index = dojo.indexOf(this.editingAreaStyleSheets, url);
+			if(index == -1){
+				console.debug("dijit._editor.RichText.removeStyleSheet: Style sheet "+url+" is not applied to the editing area so it can not be removed!");
+				return;
+			}
+			delete this.editingAreaStyleSheets[index];
+
+			var link, i=0, links = this.document.getElementsByTagName("link");
+			while(link=links[i++]){
+				if(link.href == url){
+					if(dojo.isIE){//we need to empty the href first, to get IE to remove the rendered styles
+						link.href="";
+					}
+					// FIXME
+					dojo.html.removeNode(link);
+					break;
+				}
+			}
+		},
+
+		enabled: true,
+		enable: function(){
+			if(dojo.isIE || this._safariIsLeopard() || dojo.isOpera){
+				this.editNode.contentEditable=true;
+			}else{ //moz
+				this.document.execCommand('contentReadOnly', false, false);
+//				this.document.designMode='on';
+			}
+			this.enabled=true;
+		},
+		disable: function(){
+			if(dojo.isIE || this._safariIsLeopard() || dojo.isOpera){
+				this.editNode.contentEditable=false;
+			}else{ //moz
+				this.document.execCommand('contentReadOnly', false, true);
+//				this.blur(); //to remove the blinking caret
+//				this.document.designMode='off';
+			}
+			this.enabled=false;
+		},
+	/* Event handlers
+	 *****************/
+
+		_isResized: function(){ return false; },
+
+		onLoad: function(e){
+			// summary: handler after the content of the document finishes loading
+			this.isLoaded = true;
+			if (this.iframe && !dojo.isIE){
+				this.editNode = this.document.body;
+				if(!this.height){
+					this.connect(this, "onDisplayChanged", "_updateHeight");
+				}
+
+				try { // sanity check for Mozilla
+//					this.document.execCommand("useCSS", false, true); // old moz call
+					this.document.execCommand("styleWithCSS", false, false); // new moz call
+					//this.document.execCommand("insertBrOnReturn", false, false); // new moz call
+				}catch(e2){ }
+
+				if(dojo.isSafari){
+					/*
+					this.iframe.style.visiblity = "visible";
+					this.iframe.style.border = "1px solid black";
+					this.editNode.style.visiblity = "visible";
+					this.editNode.style.border = "1px solid black";
+					*/
+					// this.onDisplayChanged();
+					this.connect(this.editNode, "onblur", "onBlur");
+					this.connect(this.editNode, "onfocus", "onFocus");
+					this.connect(this.editNode, "onclick", "onFocus");
+
+					this.interval = setInterval(dojo.hitch(this, "onDisplayChanged"), 750);
+					// dojo.raise("onload");
+				}else if(dojo.isMoz|| dojo.isOpera){
+					var doc = this.document;
+					var self = this;
+					var events=this.events.concat(this.captureEvents);
+					dojo.forEach(events, function(e){
+						var l = dojo.connect(this.document, e.toLowerCase(), dojo.hitch(this, e));
+						if(e=="onBlur"){
+							// We need to unhook the blur event listener on close as we
+							// can encounter a garunteed crash in FF if another event is
+							// also fired
+							// FIXME:
+							/*
+							var unBlur = { unBlur: function(e){
+									// FIXME
+									dojo.event.browser.removeListener(doc, "blur", l);
+							} };
+							// FIXME: need a to attach before!
+							// dojo.connect("before", this, "close", unBlur, "unBlur");
+							*/
+						}
+					}, this);
+				}
+				// FIXME: when scrollbars appear/disappear this needs to be fired
+			}else if(dojo.isIE){
+				// IE contentEditable
+				if(!this.height){
+					this.connect(this, "onDisplayChanged", "_updateHeight");
+				}
+				// give the node Layout on IE
+				this.editNode.style.zoom = 1.0;
+			}
+
+			if(this.focusOnLoad){
+				this.focus();
+			}
+			this.onDisplayChanged(e);
+			if(this.onLoadDeferred){
+				this.onLoadDeferred.callback(true);
+			}
+			if(this.blockNodeForEnter=='BR'){
+				if(dojo.isIE){
+					this._fixNewLineBehaviorForIE();
+				}else{
+					try{
+						this.document.execCommand("insertBrOnReturn", false, true);
+					}catch(e){}
+				}
+			}
+		},
+
+		onKeyDown: function(e){
+			// summary: Fired on keydown
+
+			// console.debug("onkeydown:", e.keyCode);
+
+			// we need this event at the moment to get the events from control keys
+			// such as the backspace. It might be possible to add this to Dojo, so that
+			// keyPress events can be emulated by the keyDown and keyUp detection.
+			if((dojo.isIE)&&(e.keyCode == dojo.keys.TAB)){
+				e.preventDefault();
+				e.stopPropagation();
+				// FIXME: this is a poor-man's indent/outdent. It would be
+				// better if it added 4 "&nbsp;" chars in an undoable way.
+				// Unfortuantly pasteHTML does not prove to be undoable
+				this.execCommand((e.shiftKey ? "outdent" : "indent"));
+			}else if(dojo.isIE){
+				// FIXME: get this from connect() instead!
+				if((65 <= e.keyCode&&e.keyCode <= 90) ||
+				  (e.keyCode>=37&&e.keyCode<=40)){ //arrow keys
+					e.charCode = e.keyCode;
+					this.onKeyPress(e);
+				}
+			}
+		},
+
+		onKeyUp: function(e){
+			// summary: Fired on keyup
+			return;
+		},
+
+		KEY_CTRL: 1,
+		KEY_SHIFT: 2,
+
+		onKeyPress: function(e){
+			// summary: Fired on keypress
+
+			// console.debug("onkeypress:", e.keyCode);
+
+			// handle the various key events
+			var modifiers = e.ctrlKey ? this.KEY_CTRL : 0 | e.shiftKey?this.KEY_SHIFT : 0;
+
+			// var key = e.key||e.keyCode;
+			var key = e.keyChar;
+			if(this._keyHandlers[key]){
+				// dojo.debug("char:", e.key);
+				var handlers = this._keyHandlers[key], i = 0, h;
+				while(h = handlers[i++]){
+					if(modifiers == h.modifiers){
+						if(!h.handler.apply(this,arguments)){
+							e.preventDefault();
+						}
+						break;
+					}
+				}
+			}
+
+			// function call after the character has been inserted
+			setTimeout(dojo.hitch(this, function(){
+				this.onKeyPressed(e);
+			}), 1);
+		},
+
+		addKeyHandler: function (/*String*/key, /*Int*/modifiers, /*Function*/handler) {
+			// summary: add a handler for a keyboard shortcut
+			if(!dojo.isArray(this._keyHandlers[key])){ this._keyHandlers[key] = []; }
+			this._keyHandlers[key].push({
+				modifiers: modifiers || 0,
+				handler: handler
+			});
+		},
+
+		onKeyPressed: function(e){
+			if(this._checkListLater){
+				// FIXME:
+				if(dojo.withGlobal(this.window, 'isCollapsed', dijit._editor.selection)){
+					// FIXME:
+					if(!dojo.withGlobal(this.window, 'hasAncestorElement', dijit._editor.selection, ['LI'])){
+						//circulate the undo detection code by calling RichText::execCommand directly
+						// FIXME:
+						dijit._editor.RichText.prototype.execCommand.apply(this, ['formatblock',this.blockNodeForEnter]);
+						//set the innerHTML of the new block node
+						var block = dojo.withGlobal(this.window, 'getAncestorElement', dijit._editor.selection, [this.blockNodeForEnter])
+						if(block){
+							block.innerHTML=this.bogusHtmlContent;
+							if(dojo.isIE){
+								//the following won't work, it will move the caret to the last list item in the previous list
+	//							var newrange = dojo.html.range.create();
+	//							newrange.setStart(block.firstChild,0);
+	//							var selection = dojo.html.range.getSelection(this.editor.window)
+	//							selection.removeAllRanges();
+	//							selection.addRange(newrange);
+								//move to the start by move backward one char
+								var r = this.document.selection.createRange();
+								r.move('character',-1);
+								r.select();
+							}
+						}else{
+							alert('onKeyPressed: Can not find the new block node');
+						}
+					}
+				}
+				this._checkListLater = false;
+			}else if(this._pressedEnterInBlock){
+				//the new created is the original current P, so we have previousSibling below
+				this.removeTrailingBr(this._pressedEnterInBlock.previousSibling);
+				delete this._pressedEnterInBlock;
+			}
+			this.onDisplayChanged(/*e*/); // can't pass in e
+		},
+
+		// blockNodeForEnter: String
+		//		this property decides the behavior of Enter key. It can be either P, 
+		//		DIV, BR, or empty (which means disable this feature). Anything else
+		//		will trigger errors.
+		blockNodeForEnter: 'BR',
+		bogusHtmlContent: '&nbsp;',
+		handleEnterKey: function(e){
+			// summary: manually handle enter key event to make the behavior consistant across
+			//	all supported browsers. See property blockNodeForEnter for available options
+			if(!this.blockNodeForEnter){ return true; } //let browser handle this 
+			if(e.shiftKey  //shift+enter always generates <br>
+			    || this.blockNodeForEnter=='BR'){
+				// FIXME
+				var parent = dojo.withGlobal(this.window, "getParentElement", dijit._editor.selection);
+				// FIXME
+				var header = dojo.html.range.getAncestor(parent,/^(?:H1|H2|H3|H4|H5|H6|LI)$/);
+				if(header){
+					if(header.tagName=='LI'){
+						return true; //let brower handle
+					}
+					// FIXME
+					var selection = dojo.html.range.getSelection(this.window);
+					var range = selection.getRangeAt(0);
+					if(!range.collapsed){
+						range.deleteContents();
+					}
+					// FIXME
+					if(dojo.html.range.atBeginningOfContainer(header, range.startContainer, range.startOffset)){
+						dojo.place(this.document.createElement('br'), header, "before");
+					}else if(dojo.html.range.atEndOfContainer(header, range.startContainer, range.startOffset)){
+						dojo.place(this.document.createElement('br'), header, "after");
+						// FIXME
+						var newrange = dojo.html.range.create();
+						newrange.setStartAfter(header);
+
+						selection.removeAllRanges();
+						selection.addRange(newrange);
+					}else{
+						return true; //let brower handle
+					}
+				}else{
+					//don't change this: do not call this.execCommand, as that may have other logic in subclass
+					// FIXME
+					dijit._editor.RichText.prototype.execCommand.call(this, 'inserthtml', '<br>');
+				}
+				return false;
+			}
+			var _letBrowserHandle = true;
+			//blockNodeForEnter is either P or DIV
+			//first remove selection
+			// FIXME
+			var selection = dojo.html.range.getSelection(this.window);
+			var range = selection.getRangeAt(0);
+			if(!range.collapsed){
+				range.deleteContents();
+			}
+	
+			// FIXME
+			var block = dojo.html.range.getBlockAncestor(range.endContainer, null, this.editNode);
+	
+			if(block.blockNode && block.blockNode.tagName == 'LI'){
+				this._checkListLater = true;
+				return true;
+			}else{
+				this._checkListLater = false;
+			}
+
+			//text node directly under body, let's wrap them in a node
+			if(!block.blockNode){
+				this.document.execCommand('formatblock',false, this.blockNodeForEnter);
+				//get the newly created block node
+				// FIXME
+				block = {blockNode:dojo.withGlobal(this.window, "getAncestorElement", dijit._editor.selection, [this.blockNodeForEnter]),
+						blockContainer: this.editNode};
+				if(block.blockNode){
+					if(dojo.html.textContent(block.blockNode).replace(/^\s+|\s+$/g, "").length==0){
+						this.removeTrailingBr(block.blockNode);
+						return false;
+					}
+				}else{
+					block.blockNode = this.editNode;
+				}
+				selection = dojo.html.range.getSelection(this.window);
+				range = selection.getRangeAt(0);
+			}
+			var newblock = this.document.createElement(this.blockNodeForEnter);
+			newblock.innerHTML=this.bogusHtmlContent;
+			this.removeTrailingBr(block.blockNode);
+			if(dojo.html.range.atEndOfContainer(block.blockNode, range.endContainer, range.endOffset)){
+				if(block.blockNode === block.blockContainer){
+					block.blockNode.appendChild(newblock);
+				}else{
+					dojo.html.insertAfter(newblock,block.blockNode);
+				}
+				_letBrowserHandle = false;
+				//lets move caret to the newly created block
+				var newrange = dojo.html.range.create();
+				newrange.setStart(newblock,0);
+				selection.removeAllRanges();
+				selection.addRange(newrange);
+				if(this.height){
+					newblock.scrollIntoView(false);
+				}
+			}else if(dojo.html.range.atBeginningOfContainer(block.blockNode, 
+					range.startContainer, range.startOffset)){
+				if(block.blockNode === block.blockContainer){
+					dojo.html.prependChild(newblock,block.blockNode);
+				}else{
+					dojo.html.insertBefore(newblock,block.blockNode);
+				}
+				if(this.height){
+					//browser does not scroll the caret position into view, do it manually
+					newblock.scrollIntoView(false);
+				}
+				_letBrowserHandle = false;
+			}else{ //press enter in the middle of P
+				if(dojo.isMoz){
+					//press enter in middle of P may leave a trailing <br/>, let's remove it later
+					this._pressedEnterInBlock = block.blockNode;
+				}
+			}
+			return _letBrowserHandle;
+		},
+		removeTrailingBr: function(container){
+			if(/P|DIV|LI/i .test(container.tagName)){
+				var para = container;
+			}else{
+				var para = dijit._editor.selection.getParentOfType(container,['P','DIV','LI']);
+			}
+
+			if(!para){ return; }
+			if(para.lastChild){
+				if(para.childNodes.length>1 && para.lastChild.nodeType==3 && /^[\s\xAD]*$/ .test(para.lastChild.nodeValue)){
+					dojo.html.destroyNode(para.lastChild);
+				}
+				if(para.lastChild && para.lastChild.tagName=='BR'){
+					dojo.html.destroyNode(para.lastChild);
+				}
+			}
+			if(para.childNodes.length==0){
+				para.innerHTML=this.bogusHtmlContent;
+			}
+		},
+		onClick: function(e){ 
+//			dojo.debug('onClick',this._tryDesignModeOnClick);
+//			if(this._tryDesignModeOnClick){
+//				try{
+//					this.document.designMode='on';
+//					this._tryDesignModeOnClick=false;
+//				}catch(e){}
+//			}
+			this.onDisplayChanged(e); },
+		onBlur: function(e){ },
+		_initialFocus: true,
+		onFocus: function(e){
+			// summary: Fired on focus
+			if( (dojo.isMoz)&&(this._initialFocus) ){
+				this._initialFocus = false;
+				if(this.editNode.innerHTML.replace(/^\s+|\s+$/g, "") == "&nbsp;"){
+					this.placeCursorAtStart();
+//					this.execCommand("selectall");
+//					this.window.getSelection().collapseToStart();
+				}
+			}
+		},
+
+		blur: function(){
+			// summary: remove focus from this instance
+			if(this.iframe){
+				this.window.blur();
+			}else if(this.editNode){ 
+				this.editNode.blur();
+			}
+		},
+
+		focus: function(){
+			// summary: move focus to this instance
+			if(this.iframe && !dojo.isIE){ 
+				this.window.focus();
+			}else if(this.editNode && this.editNode.focus){ 
+				// editNode may be hidden in display:none div, lets just punt in this case
+				this.editNode.focus();
+			}else{
+				console.debug("Have no idea how to focus into the editor!");
+			}
+		},
+
+		onDisplayChanged: function(e){
+			// summary:
+			//		this event will be fired everytime the display context
+			//		changes and the result needs to be reflected in the UI
+		},
+
+		_normalizeCommand: function (/*String*/cmd){
+			// summary:
+			//		Used as the advice function by dojo.connect to map our
+			//		normalized set of commands to those supported by the target
+			//		browser
+
+			var command = cmd.toLowerCase();
+			if(command == "formatblock"){
+				if(dojo.isSafari){ command = "heading"; }
+			}else if(command == "hilitecolor" && !dojo.isMoz){
+				command = "backcolor";
+			}
+
+			return command;
+		},
+
+		queryCommandAvailable: function (/*String*/command) {
+			// summary:
+			//		Tests whether a command is supported by the host. Clients SHOULD check
+			//		whether a command is supported before attempting to use it, behaviour
+			//		for unsupported commands is undefined.
+			// command: The command to test for
+			var ie = 1;
+			var mozilla = 1 << 1;
+			var safari = 1 << 2;
+			var opera = 1 << 3;
+			var safari420 = 1 << 4;
+
+			var gt420 = this._safariIsLeopard();
+
+			function isSupportedBy (browsers) {
+				return {
+					ie: Boolean(browsers & ie),
+					mozilla: Boolean(browsers & mozilla),
+					safari: Boolean(browsers & safari),
+					safari420: Boolean(browsers & safari420),
+					opera: Boolean(browsers & opera)
+				}
+			}
+
+			var supportedBy = null;
+
+			switch (command.toLowerCase()) {
+				case "bold": case "italic": case "underline":
+				case "subscript": case "superscript":
+				case "fontname": case "fontsize":
+				case "forecolor": case "hilitecolor":
+				case "justifycenter": case "justifyfull": case "justifyleft":
+				case "justifyright": case "delete": case "selectall":
+					supportedBy = isSupportedBy(mozilla | ie | safari | opera);
+					break;
+
+				case "createlink": case "unlink": case "removeformat":
+				case "inserthorizontalrule": case "insertimage":
+				case "insertorderedlist": case "insertunorderedlist":
+				case "indent": case "outdent": case "formatblock":
+				case "inserthtml": case "undo": case "redo": case "strikethrough":
+					supportedBy = isSupportedBy(mozilla | ie | opera | safari420);
+					break;
+
+				case "blockdirltr": case "blockdirrtl":
+				case "dirltr": case "dirrtl":
+				case "inlinedirltr": case "inlinedirrtl":
+					supportedBy = isSupportedBy(ie);
+					break;
+				case "cut": case "copy": case "paste":
+					supportedBy = isSupportedBy( ie | mozilla | safari420);
+					break;
+
+				case "inserttable":
+					supportedBy = isSupportedBy(mozilla | ie);
+					break;
+
+				case "insertcell": case "insertcol": case "insertrow":
+				case "deletecells": case "deletecols": case "deleterows":
+				case "mergecells": case "splitcell":
+					supportedBy = isSupportedBy(ie | mozilla);
+					break;
+
+				default: return false;
+			}
+
+			return (dojo.isIE && supportedBy.ie) ||
+				(dojo.isMoz && supportedBy.mozilla) ||
+				(dojo.isSafari && supportedBy.safari) ||
+				(gt420 && supportedBy.safari420) ||
+				(dojo.isOpera && supportedBy.opera);  // Boolean return true if the command is supported, false otherwise
+		},
+
+		execCommand: function (/*String*/command, argument){
+			// summary: Executes a command in the Rich Text area
+			// command: The command to execute
+			// argument: An optional argument to the command
+			var returnValue;
+
+			//focus() is required for IE to work
+			//In addition, focus() makes sure after the execution of
+			//the command, the editor receives the focus as expected
+			this.focus();
+
+			command = this._normalizeCommand(command);
+			if(argument != undefined){
+				if(command == "heading"){ 
+					throw new Error("unimplemented");
+				}else if((command == "formatblock") && dojo.isIE){
+					argument = '<'+argument+'>';
+				}
+			}
+			if(command == "inserthtml"){
+				//TODO: we shall probably call _preDomFilterContent here as well
+				argument=this._preFilterContent(argument);
+				if(dojo.isIE){
+					var insertRange = this.document.selection.createRange();
+					insertRange.pasteHTML(argument);
+					insertRange.select();
+					//insertRange.collapse(true);
+					return true;
+				}else if(dojo.isMoz && argument.length==0){
+					//mozilla can not inserthtml an empty html to delete current selection
+					//so we delete the selection instead in this case
+					dojo.withGlobal(this.window,'remove',dijit._editor.selection); // FIXME
+					return true;
+				}else{
+					return this.document.execCommand(command, false, argument);
+				}
+			}else if(
+				(command == "unlink")&&
+				(this.queryCommandEnabled("unlink"))&&
+				(dojo.isMoz)
+			){
+				// fix up unlink in Mozilla to unlink the link and not just the selection
+
+				// grab selection
+				// Mozilla gets upset if we just store the range so we have to
+				// get the basic properties and recreate to save the selection
+				var selection = this.window.getSelection();
+				//	var selectionRange = selection.getRangeAt(0);
+				//	var selectionStartContainer = selectionRange.startContainer;
+				//	var selectionStartOffset = selectionRange.startOffset;
+				//	var selectionEndContainer = selectionRange.endContainer;
+				//	var selectionEndOffset = selectionRange.endOffset;
+
+				// select our link and unlink
+				var a = dojo.withGlobal(this.window, "getAncestorElement",dijit._editor.selection, ['a']);
+				dojo.withGlobal(this.window, "selectElement", dijit._editor.selection, [a]);
+
+				return this.document.execCommand("unlink");
+			}else if((command == "hilitecolor")&&(dojo.isMoz)){
+//				// mozilla doesn't support hilitecolor properly when useCSS is
+//				// set to false (bugzilla #279330)
+
+//				this.document.execCommand("useCSS", false, false);
+				returnValue = this.document.execCommand(command, false, argument);
+//				this.document.execCommand("useCSS", false, true);
+
+			}else if((dojo.isIE)&&( (command == "backcolor")||(command == "forecolor") )){
+				// Tested under IE 6 XP2, no problem here, comment out
+				// IE weirdly collapses ranges when we exec these commands, so prevent it
+//				var tr = this.document.selection.createRange();
+				argument = arguments.length > 1 ? argument : null;
+				returnValue = this.document.execCommand(command, false, argument);
+
+				// timeout is workaround for weird IE behavior were the text
+				// selection gets correctly re-created, but subsequent input
+				// apparently isn't bound to it
+//				setTimeout(function(){tr.select();}, 1);
+			}else{
+				argument = arguments.length > 1 ? argument : null;
+//				if(dojo.isMoz){
+//					this.document = this.iframe.contentWindow.document
+//				}
+
+				if(argument || command!="createlink") {
+					returnValue = this.document.execCommand(command, false, argument);
+				}
+			}
+
+			this.onDisplayChanged();
+			return returnValue;
+		},
+
+		queryCommandEnabled: function(/*String*/command){
+			// summary: check whether a command is enabled or not
+			command = this._normalizeCommand(command);
+			if(dojo.isMoz){
+				if(command == "unlink"){ // mozilla returns true always
+					return dojo.withGlobal(this.window, "hasAncestorElement",dijit._editor.selection, ['a']);
+				} else if (command == "inserttable") {
+					return true;
+				}
+			}
+
+			// return this.document.queryCommandEnabled(command);
+			var elem = (dojo.isIE) ? this.document.selection.createRange() : this.document;
+			return elem.queryCommandEnabled(command);
+		},
+
+		queryCommandState: function(command){
+			// summary: check the state of a given command
+			command = this._normalizeCommand(command);
+			return this.document.queryCommandState(command);
+		},
+
+		queryCommandValue: function (command) {
+			// summary: check the value of a given command
+			command = this._normalizeCommand(command);
+			if(dojo.isIE && command == "formatblock"){
+				return this._local2NativeFormatNames[this.document.queryCommandValue(command)] || this.document.queryCommandValue(command);
+			}
+			return this.document.queryCommandValue(command);
+		},
+
+		// Misc.
+
+		placeCursorAtStart: function(){
+			// summary:
+			//		place the cursor at the start of the editing area
+			this.focus();
+
+			//see comments in placeCursorAtEnd
+			var isvalid=false;
+			if(dojo.isMoz){
+				var first=this.editNode.firstChild;
+				while(first){
+					if(first.nodeType == 3){
+						if(first.nodeValue.replace(/^\s+|\s+$/g, "").length>0){
+							isvalid=true;
+							dojo.withGlobal(this.window, "selectElement", dijit._editor.selection, [first]);
+							break;
+						}
+					}else if(first.nodeType == 1){
+						isvalid=true;
+						dojo.withGlobal(this.window, "selectElementChildren",dijit._editor.selection, [first]);
+						break;
+					}
+					first = first.nextSibling;
+				}
+			}else{
+				isvalid=true;
+				dojo.withGlobal(this.window, "selectElementChildren",dijit._editor.selection, [this.editNode]);
+			}
+			if(isvalid){
+				dojo.withGlobal(this.window, "collapse", dijit._editor.selection, [true]);
+			}
+		},
+
+		placeCursorAtEnd: function(){
+			// summary:
+			//		place the cursor at the end of the editing area
+			this.focus();
+
+			//In mozilla, if last child is not a text node, we have to use selectElementChildren on this.editNode.lastChild
+			//otherwise the cursor would be placed at the end of the closing tag of this.editNode.lastChild
+			var isvalid=false;
+			if(dojo.isMoz){
+				var last=this.editNode.lastChild;
+				while(last){
+					if(last.nodeType == 3){
+						if(last.nodeValue.replace(/^\s+|\s+$/g, "").length>0){
+							isvalid=true;
+							dojo.withGlobal(this.window, "selectElement",dijit._editor.selection, [last]);
+							break;
+						}
+					}else if(last.nodeType == 1){
+						isvalid=true;
+						if(last.lastChild){
+							dojo.withGlobal(this.window, "selectElement",dijit._editor.selection, [last.lastChild]);
+						}else{
+							dojo.withGlobal(this.window, "selectElement",dijit._editor.selection, [last]);
+						}
+						break;
+					}
+					last = last.previousSibling;
+				}
+			}else{
+				dojo.withGlobal(this.window, "selectElementChildren",dijit._editor.selection, [this.editNode]);
+			}
+			if(isvalid){
+				dojo.withGlobal(this.window, "collapse", dijit._editor.selection, [false]);
+			}
+		},
+
+		getValue: function(/*Boolean?*/nonDestructive){
+			// summary:
+			//		return the current content of the editing area (post filters are applied)
+			if(this.isClosed && this.textarea){
+				return this.textarea.value;
+			}else{
+				return this._postFilterContent(null, nonDestructive);
+			}
+		},
+
+		setValue: function(/*String*/html){
+			// summary:
+			//		this function set the content. No undo history is preserved
+			if(this.isClosed && this.textarea){
+				this.textarea.value=html;
+			}else{
+				html = this._preFilterContent(html);
+				if(this.isClosed){
+					this.domNode.innerHTML = html;
+					this._preDomFilterContent(this.domNode);
+				}else{
+					this.editNode.innerHTML = html;
+					this._preDomFilterContent(this.editNode);
+				}
+			}
+		},
+
+		replaceValue: function(/*String*/html){
+			// summary:
+			//		this function set the content while trying to maintain the undo stack
+			//		(now only works fine with Moz, this is identical to setValue in all 
+			//		other browsers)
+			if(this.isClosed){
+				this.setValue(html);
+			}else if(this.window && this.window.getSelection && !dojo.isMoz){ // Safari
+				// look ma! it's a totally f'd browser!
+				this.setValue(html);
+			}else if(this.window && this.window.getSelection){ // Moz
+				html = this._preFilterContent(html);
+				this.execCommand("selectall");
+				if(dojo.isMoz && !html){ html = "&nbsp;" }
+				this.execCommand("inserthtml", html);
+				this._preDomFilterContent(this.editNode);
+			}else if(this.document && this.document.selection){//IE
+				//In IE, when the first element is not a text node, say
+				//an <a> tag, when replacing the content of the editing 
+				//area, the <a> tag will be around all the content
+				//so for now, use setValue for IE too
+				this.setValue(html);
+			}
+		},
+
+		_preFilterContent: function(/*String*/html){
+			// summary:
+			//		filter the input before setting the content of the editing area
+			var ec = html;
+			dojo.forEach(this.contentPreFilters, function(ef){ if(ef){ ec = ef(ec); } });
+			return ec;
+		},
+		_preDomFilterContent: function(/*DomNode*/dom){
+			// summary:
+			//		filter the input 
+			dom = dom || this.editNode;
+			dojo.forEach(this.contentDomPreFilters, function(ef){ 
+				if(ef && dojo.isFunction(ef)){ 
+					ef(dom); 
+				} 
+			}, this);
+		},
+
+		_postFilterContent: function(/*DomNode|DomNode[]?*/dom,/*Boolean?*/nonDestructive){
+			// summary:
+			//		filter the output after getting the content of the editing area
+			dom = dom || this.editNode;
+			if(this.contentDomPostFilters.length){
+				if(nonDestructive && dom['cloneNode']){
+					dom = dom.cloneNode(true);
+				}
+				dojo.forEach(this.contentDomPostFilters, function(ef){
+					dom = ef(dom);
+				});
+			}
+			var ec = this.getNodeChildrenHtml(dom);
+			if(ec.replace(/^\s+|\s+$/g, "") == "&nbsp;"){ ec = ""; }
+
+			//	if(dojo.isIE){
+			//		//removing appended <P>&nbsp;</P> for IE
+			//		ec = ec.replace(/(?:<p>&nbsp;</p>[\n\r]*)+$/i,"");
+			//	}
+			dojo.forEach(this.contentPostFilters, function(ef){
+				ec = ef(ec);
+			});
+
+			return ec;
+		},
+
+		//Int: stored last time height
+		_lastHeight: 0,
+
+		_updateHeight: function(){
+			// summary:
+			//		Updates the height of the editor area to fit the contents.
+			if(!this.isLoaded){ return; }
+			if(this.height){ return; }
+
+			if(dojo.isSafari && (!this._safariIsLeopard())){
+				// old safari (2.0.4) is super-janky
+				if(!this.editorObject){ return; }
+				try{
+					this.editorObject.style.height = (this.editNode.offsetHeight + 10) + "px";
+					// console.debug("_updateHeight"); 
+				}catch(e){
+					try{
+						this.editorObject.style.height = "500px";
+					}catch(e2){}
+				}
+				// this.editorObject.style.height = (this.editNode.offsetHeight + 10) + "px";
+				return;
+			}
+
+			// var height = dojo.marginBox(this.editNode).h;
+			var height = dojo.marginBox(this.editNode).h;
+
+			// console.debug(this.editNode);
+			// alert(this.editNode);
+
+			//height maybe zero in some cases even though the content is not empty,
+			//we try the height of body instead
+			if(!height){
+				height = dojo.marginBox(this.document.body).h;
+			}
+			if(height == 0){
+				console.debug("Can not figure out the height of the editing area!");
+				return; //prevent setting height to 0
+			}
+			this._lastHeight = height;
+			// this.editorObject.style.height = this._lastHeight + "px";
+			dojo.marginBox(this.editorObject, { h: this._lastHeight });
+			// this.window.scrollTo(0, 0);
+		},
+
+		_saveContent: function(e){
+			// summary:
+			//		Saves the content in an onunload event if the editor has not been closed
+			var saveTextarea = dojo.byId("dijit._editor.RichText.savedContent");
+			saveTextarea.value += this._SEPARATOR + this.saveName + ":" + this.getValue();
+		},
+
+
+		escapeXml: function(/*string*/str, /*boolean*/noSingleQuotes){
+			//summary:
+			//		Adds escape sequences for special characters in XML: &<>"'
+			//		Optionally skips escapes for single quotes
+			str = str.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;");
+			if(!noSingleQuotes){ 
+				str = str.replace(/'/gm, "&#39;");
+			}
+			return str; // string
+		},
+
+		getNodeHtml: function(node){
+			switch(node.nodeType){
+				case 1: //element node
+					var output = '<'+node.tagName.toLowerCase();
+					if(dojo.isMoz){
+						if(node.getAttribute('type')=='_moz'){
+							node.removeAttribute('type');
+						}
+						if(node.getAttribute('_moz_dirty') != undefined){
+							node.removeAttribute('_moz_dirty');
+						}
+					}
+					//store the list of attributes and sort it to have the
+					//attributes appear in the dictionary order
+					var attrarray = [];
+					if(dojo.isIE){
+						var s = node.outerHTML;
+						s = s.substr(0,s.indexOf('>'));
+						s = s.replace(/(?:['"])[^"']*\1/g, '');//to make the following regexp safe
+						var reg = /([^\s=]+)=/g;
+						var m, key;
+						while((m = reg.exec(s)) != undefined){
+							key=m[1];
+							if(key.substr(0,3) != '_dj'){
+								if(key == 'src' || key == 'href'){
+									if(node.getAttribute('_djrealurl')){
+										attrarray.push([key,node.getAttribute('_djrealurl')]);
+										continue;
+									}
+								}
+								if(key == 'class'){
+									attrarray.push([key,node.className]);
+								}else{
+									attrarray.push([key,node.getAttribute(key)]);
+								}
+							}
+						}
+					}else{
+						var attr, i=0, attrs = node.attributes;
+						while(attr=attrs[i++]) {
+							//ignore all attributes starting with _dj which are 
+							//internal temporary attributes used by the editor
+							if(attr.name.substr(0,3) != '_dj' /*&& 
+								(attr.specified == undefined || attr.specified)*/){
+								var v = attr.value;
+								if(attr.name == 'src' || attr.name == 'href'){
+									if(node.getAttribute('_djrealurl')){
+										v = node.getAttribute('_djrealurl');
+									}
+								}
+								attrarray.push([attr.name,v]);
+							}
+						}
+					}
+					attrarray.sort(function(a,b){
+						return a[0]<b[0]?-1:(a[0]==b[0]?0:1);
+					});
+					i=0;
+					while(attr=attrarray[i++]){
+						output += ' '+attr[0]+'="'+attr[1]+'"';
+					}
+					if(node.childNodes.length>0){
+						output += '>' + this.getNodeChildrenHtml(node)+'</'+node.tagName.toLowerCase()+'>';
+					}else{
+						output += ' />';
+					}
+					break;
+				case 3: //text
+					// FIXME:
+					var output = this.escapeXml(node.nodeValue,true);
+					break;
+				case 8: //comment
+					// FIXME:
+					var output = '<!--'+this.escapeXml(node.nodeValue,true)+'-->';
+					break;
+				default:
+					var output = "Element not recognized - Type: " + node.nodeType + " Name: " + node.nodeName;
+			}
+			return output;
+		},
+
+		getNodeChildrenHtml: function(dom){
+			var out = "";
+			if(!dom){ return out; }
+			var nodes = dom["childNodes"]||dom;
+			var i=0;
+			var node;
+			while(node=nodes[i++]){
+				out += this.getNodeHtml(node);
+			}
+			return out;
+		},
+
+		close: function(/*Boolean*/save, /*Boolean*/force){
+			// summary:
+			//		Kills the editor and optionally writes back the modified contents to the
+			//		element from which it originated.
+			// save:
+			//		Whether or not to save the changes. If false, the changes are discarded.
+			// force:
+			if(this.isClosed){return false; }
+
+			if (arguments.length == 0) { save = true; }
+			this._content = this.getValue();
+			var changed = (this.savedContent != this._content);
+
+			// line height is squashed for iframes
+			// FIXME: why was this here? if (this.iframe){ this.domNode.style.lineHeight = null; }
+
+			if(this.interval){ clearInterval(this.interval); }
+
+			/*
+			if(dojo.isIE){
+				dojo.event.browser.clean(this.editNode);
+			}
+
+			if(this.iframe){
+				// FIXME: should keep iframe around for later re-use
+				dojo.html.destroyNode(this.iframe);
+				delete this.iframe;
+			}
+			*/
+
+			if(this.textarea){
+				with(this.textarea.style){
+					position = "";
+					left = top = "";
+					if(dojo.isIE){
+						overflow = this.__overflow;
+						this.__overflow = null;
+					}
+				}
+				if(save){
+					this.textarea.value = this._content;
+				}else{
+					this.textarea.value = this.savedContent;
+				}
+				// dojo.html.removeNode(this.domNode);
+				if(this.domNode.parentNode){ // FIXME
+					this.domNode.parentNode.removeNode(this.domNode);
+				}
+				this.domNode = this.textarea;
+			}else{
+				if(save){
+					if(dojo.isMoz){
+						var nc = dojo.doc.createElement("span");
+						this.domNode.appendChild(nc);
+						nc.innerHTML = this.editNode.innerHTML;
+					}else{
+						this.domNode.innerHTML = this._content;
+					}
+				}else{
+					this.domNode.innerHTML = this.savedContent;
+				}
+			}
+
+			dojo.removeClass(this.domNode, "RichTextEditable");
+			this.isClosed = true;
+			this.isLoaded = false;
+			// FIXME: is this always the right thing to do?
+			delete this.editNode;
+
+			if(this.window && this.window._frameElement){
+				this.window._frameElement = null;
+			}
+
+			this.window = null;
+			this.document = null;
+			this.editingArea = null;
+			this.editorObject = null;
+
+			return changed; // Boolean: whether the content has been modified
+		},
+
+		destroyRendering: function(){}, // stub!
+
+		destroy: function(){
+			this.destroyRendering();
+			if(!this.isClosed){ this.close(false); }
+
+			dijit._editor.RichText.superclass.destroy.call(this);
+		},
+
+		_fixContentForMoz: function(html){
+			// summary:
+			//		Moz can not handle strong/em tags correctly, convert them to b/i
+			html = html.replace(/<(\/)?strong([ \>])/gi, '<$1b$2' );
+			html = html.replace(/<(\/)?em([ \>])/gi, '<$1i$2' );
+			return html;
+		},
+		_srcInImgRegex	: /(?:(<img(?=\s).*?\ssrc=)("|')(.*?)\2)|(?:(<img\s.*?src=)([^"'][^ >]+))/gi ,
+		_hrefInARegex	: /(?:(<a(?=\s).*?\shref=)("|')(.*?)\2)|(?:(<a\s.*?href=)([^"'][^ >]+))/gi ,
+		_preFixUrlAttributes: function(html){
+			html = html.replace(this._hrefInARegex, '$1$4$2$3$5$2 _djrealurl=$2$3$5$2') ;
+			html = html.replace(this._srcInImgRegex, '$1$4$2$3$5$2 _djrealurl=$2$3$5$2') ;
+			return html;
+		},
+		regularPsToSingleLinePs: function(element, noWhiteSpaceInEmptyP){
+			function wrapLinesInPs(el){
+			  // move "lines" of top-level text nodes into ps
+				function wrapNodes(nodes){
+					// nodes are assumed to all be siblings
+					var newP = nodes[0].ownerDocument.createElement('p'); // FIXME: not very idiomatic
+					nodes[0].parentNode.insertBefore(newP, nodes[0]);
+					for(var i=0; i<nodes.length; i++){
+					    newP.appendChild(nodes[i]);
+					}
+				}
+			    
+				var currentNodeIndex = 0;
+				var nodesInLine = [];
+				var currentNode;
+				while(currentNodeIndex < el.childNodes.length){
+					currentNode = el.childNodes[currentNodeIndex];
+					if( (currentNode.nodeName!='BR') && 
+						(dojo.style(currentNode, "display")!="block")
+					){
+						nodesInLine.push(currentNode);
+					}else{
+						// hit line delimiter; process nodesInLine if there are any
+						var nextCurrentNode = currentNode.nextSibling;
+						if(nodesInLine.length){
+							wrapNodes(nodesInLine);
+							currentNodeIndex = (currentNodeIndex+1)-nodesInLine.length;
+							if(currentNode.nodeName=="BR"){
+								currentNode.parentNode.removeChild(currentNode);
+							}
+						}
+						nodesInLine = [];
+					}
+					currentNodeIndex++;
+				}
+				if(nodesInLine.length){ wrapNodes(nodesInLine); }
+			}
+		
+			function splitP(el){
+			    // split a paragraph into seperate paragraphs at BRs
+			    var currentNode = null;
+			    var trailingNodes = [];
+			    var lastNodeIndex = el.childNodes.length-1;
+			    for(var i=lastNodeIndex; i>=0; i--){
+					currentNode = el.childNodes[i];
+					if(currentNode.nodeName=="BR"){
+						var newP = currentNode.ownerDocument.createElement('p');
+						dojo.place(newP, el, "after");
+						if (trailingNodes.length==0 && i != lastNodeIndex) {
+							newP.innerHTML = "&nbsp;"
+						}
+						dojo.forEach(trailingNodes, function(node){
+							newP.appendChild(node);
+						});
+						currentNode.parentNode.removeChild(currentNode);
+						trailingNodes = []
+					}else{
+						trailingNodes.unshift(currentNode);
+					}
+			    }
+			}
+		
+			var pList = [];
+			var ps = element.getElementsByTagName('p');
+			dojo.forEach(ps, function(p){ pList.push(p); });
+			dojo.forEach(pList, function(p){
+				if(	(p.previousSibling) &&
+					(p.previousSibling.nodeName == 'P' || dojo.style(p.previousSibling, 'display') != 'block')
+				){
+					var newP = p.parentNode.insertBefore(this.document.createElement('p'), p);
+					// this is essential to prevent IE from losing the P.
+					// if it's going to be innerHTML'd later we need
+					// to add the &nbsp; to _really_ force the issue
+					newP.innerHTML = noWhiteSpaceInEmptyP ? "" : "&nbsp;";
+				}
+				splitP(p);
+		  },this);
+			wrapLinesInPs(element);
+			return element;
+		},
+		
+		singleLinePsToRegularPs: function(element){
+			function getParagraphParents(node){
+				var ps = node.getElementsByTagName('p');
+				var parents = [];
+				for(var i=0; i<ps.length; i++){
+					var p = ps[i];
+					var knownParent = false;
+					for(var k=0; k < parents.length; k++){
+						if(parents[k] === p.parentNode){
+							knownParent = true;
+							break;
+						}
+					}
+					if(!knownParent){
+						parents.push(p.parentNode);
+					}
+				}
+				return parents;
+			}
+		
+			function isParagraphDelimiter(node){
+				if(node.nodeType != 1 || node.tagName != 'P'){
+					return (dojo.style(node, 'display') == 'block');
+				}else{
+				if(!node.childNodes.length || node.innerHTML=="&nbsp;"){ return true }
+				//return node.innerHTML.match(/^(<br\ ?\/?>| |\&nbsp\;)$/i);
+				}
+			}
+		
+			var paragraphContainers = getParagraphParents(element);
+			for(var i=0; i<paragraphContainers.length; i++){
+				var container = paragraphContainers[i];
+				var firstPInBlock = null;
+				var node = container.firstChild;
+				var deleteNode = null;
+				while(node){
+					if(node.nodeType != "1" || node.tagName != 'P'){
+						firstPInBlock = null;
+					}else if (isParagraphDelimiter(node)){
+						deleteNode = node;
+						firstPInBlock = null;
+					}else{
+						if(firstPInBlock == null){
+							firstPInBlock = node;
+						}else{
+							if( (!firstPInBlock.lastChild || firstPInBlock.lastChild.nodeName != 'BR') && 
+								(node.firstChild) && 
+								(node.firstChild.nodeName != 'BR')
+							){
+								firstPInBlock.appendChild(this.document.createElement('br'));
+							}
+							while(node.firstChild){
+								firstPInBlock.appendChild(node.firstChild);
+							}
+							deleteNode = node;
+						}
+					}
+					node = node.nextSibling;
+					if(deleteNode){
+						deleteNode.parentNode.removeChild(deleteNode);
+						deleteNode = null;
+					}
+				}
+			}
+			return element;
+		},
+		
+		_fixNewLineBehaviorForIE: function(){
+			if(typeof this.document.__INSERTED_EDITIOR_NEWLINE_CSS == "undefined"){
+				var lineFixingStyles = "p{margin:0;}";
+				// FIXME:
+				// dojo.html.insertCssText(lineFixingStyles, this.document);
+				this.document.__INSERTED_EDITIOR_NEWLINE_CSS = true;
+//				this.regularPsToSingleLinePs(this.editNode);
+			}
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/_editor/selection.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/_editor/selection.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/_editor/selection.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,192 @@
+dojo.provide("dijit._editor.selection");
+
+// FIXME: 
+//		all of these methods branch internally for IE. This is probably
+//		sub-optimal in terms of runtime performance. We should investigate the
+//		size difference for differentiating at definition time.
+
+dojo.mixin(dijit._editor.selection, {
+	isCollapsed: function(){
+		// summary: return whether the current selection is empty
+		var _window = dojo.global;
+		var _document = dojo.doc;
+		if(_document["selection"]){ // IE
+			return _document.selection.createRange().text == "";
+		}else if(_window["getSelection"]){
+			var selection = _window.getSelection();
+			if(dojo.isString(selection)){ // Safari
+				return selection == "";
+			}else{ // Mozilla/W3
+				return selection.isCollapsed || selection.toString() == "";
+			}
+		}
+	},
+
+	getType: function(){
+		// summary: Get the selection type (like document.select.type in IE).
+		if(dojo.doc["selection"]){ //IE
+			return dojo.doc.selection.type.toLowerCase();
+		}else{
+			var stype = "text";
+	
+			// Check if the actual selection is a CONTROL (IMG, TABLE, HR, etc...).
+			var oSel;
+			try{
+				oSel = dojo.global.getSelection();
+			}catch(e){ /*squelch*/ }
+			
+			if(oSel && oSel.rangeCount==1){
+				var oRange = oSel.getRangeAt(0);
+				if(	(oRange.startContainer == oRange.endContainer) && 
+					((oRange.endOffset - oRange.startOffset) == 1) && 
+					(oRange.startContainer.nodeType != 3 /* text node*/)
+				){
+					stype = "control";
+				}
+			}
+			return stype;
+		}
+	},
+
+	getSelectedElement: function(){
+		// summary: 
+		//		Retrieves the selected element (if any), just in the case that
+		//		a single element (object like and image or a table) is
+		//		selected.
+		if(this.getType() == "control"){
+			if(dojo.doc["selection"]){ //IE
+				var range = dojo.doc.selection.createRange();
+				if(range && range.item){
+					return dojo.doc.selection.createRange().item(0);
+				}
+			}else{
+				var selection = dojo.global.getSelection();
+				return selection.anchorNode.childNodes[ selection.anchorOffset ];
+			}
+		}
+	},
+
+	getParentElement: function(){
+		// summary: 
+		//		Get the parent element of the current selection
+		if(this.getType() == "control"){
+			var p = this.getSelectedElement();
+			if(p){ return p.parentNode; }
+		}else{
+			if(dojo.doc["selection"]){ //IE
+				return dojo.doc.selection.createRange().parentElement();
+			}else{
+				var selection = dojo.global.getSelection();
+				if(selection){
+					var node = selection.anchorNode;
+		
+					while(node && (node.nodeType != 1)){ // not an element
+						node = node.parentNode;
+					}
+		
+					return node;
+				}
+			}
+		}
+	},
+
+	hasAncestorElement: function(/*String*/tagName /* ... */){
+		// summary: 
+		// 		Check whether current selection has a  parent element which is
+		// 		of type tagName (or one of the other specified tagName)
+		return (this.getAncestorElement.apply(this, arguments) != null);
+	},
+
+	getAncestorElement: function(/*String*/tagName /* ... */){
+		// summary:
+		//		Return the parent element of the current selection which is of
+		//		type tagName (or one of the other specified tagName)
+
+		var node = this.getSelectedElement() || this.getParentElement();
+		return this.getParentOfType(node, arguments);
+	},
+
+	isTag: function(/*DomNode*/node, /*Array*/tags){
+		if(node && node.tagName){
+			var _nlc = node.tagName.toLowerCase();
+			for(var i=0; i<tags.length; i++){
+				var _tlc = String(tags[i]).toLowerCase();
+				if(_nlc == _tlc){
+					return _tlc;
+				}
+			}
+		}
+		return "";
+	},
+
+	getParentOfType: function(/*DomNode*/node, /*Array*/tags){
+		while(node){
+			if(this.isTag(node, tags).length){
+				return node;
+			}
+			node = node.parentNode;
+		}
+		return null;
+	},
+
+	remove: function(){
+		// summary: delete current selection
+		var _s = dojo.doc.selection;
+		if(_s){ //IE
+			if(_s.type.toLowerCase() != "none"){
+				_s.clear();
+			}
+			return _s;
+		}else{
+			_s = dojo.global.getSelection();
+			_s.deleteFromDocument();
+			return _s;
+		}
+	},
+
+	selectElementChildren: function(/*DomNode*/element){
+		// summary: 
+		//		clear previous selection and select the content of the node
+		//		(excluding the node itself)
+		var _window = dojo.global;
+		var _document = dojo.doc;
+		element = dojo.byId(element);
+		if(_document.selection && dojo.body().createTextRange){ // IE
+			var range = element.ownerDocument.body.createTextRange();
+			range.moveToElementText(element);
+			range.select();
+		}else if(_window["getSelection"]){
+			var selection = _window.getSelection();
+			if(selection["setBaseAndExtent"]){ // Safari
+				selection.setBaseAndExtent(element, 0, element, element.innerText.length - 1);
+			}else if(selection["selectAllChildren"]){ // Mozilla
+				selection.selectAllChildren(element);
+			}
+		}
+	},
+
+	selectElement: function(/*DomNode*/element){
+		// summary: 
+		//		clear previous selection and select element (including all its children)
+		var _document = dojo.doc;
+		element = dojo.byId(element);
+		if(_document.selection && dojo.body().createTextRange){ // IE
+			try{
+				var range = dojo.body().createControlRange();
+				range.addElement(element);
+				range.select();
+			}catch(e){
+				this.selectElementChildren(element);
+			}
+		}else if(dojo.global["getSelection"]){
+			var selection = dojo.global.getSelection();
+			// FIXME: does this work on Safari?
+			if(selection["removeAllRanges"]){ // Mozilla
+				var range = _document.createRange() ;
+				range.selectNode(element) ;
+				selection.removeAllRanges() ;
+				selection.addRange(range) ;
+			}
+		}
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/_tree/Controller.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/_tree/Controller.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/_tree/Controller.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,319 @@
+dojo.provide("dijit._tree.Controller");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.Tree");
+
+dojo.declare(
+	"dijit._tree.Controller",
+	[dijit.base.Widget],
+{
+	// Summary: _tree.Controller performs all basic operations on Tree
+	// Description:
+	//	Controller is the component to operate on model.
+	//	Tree/_tree.Node know how to modify themselves and show to user,
+	//  but operating on the tree often involves higher-level extensible logic,
+	//  like: database synchronization, node loading, reacting on clicks etc.
+	//  That's why it is handled by separate controller.
+	//  Controller processes expand/collapse and should be used if you 
+	//  modify a tree.
+
+	// treeId: String
+	//		id of Tree widget that I'm controlling
+	treeId: "",
+
+	postMixInProperties: function(){
+		// setup to handle events from tree
+		dojo.subscribe(this.treeId, this, "_listener");	
+	},
+
+	_listener: function(/*Object*/ message){
+		// summary: dispatcher to handle events from tree
+		var event = message.event;
+		var eventHandler =  "on" + event.charAt(0).toUpperCase() + event.substr(1);
+		if(this[eventHandler]){
+			this[eventHandler](message);
+		}
+	},
+
+	onBeforeTreeDestroy: function(message) {
+		dojo.unsubscribe(message.tree.id);
+	},
+
+	onExecute: function(/*Object*/ message) {
+		// summary: an execute event has occured
+		
+		// does the user override this handler?
+		console.log("execute message for " + message.node);
+	},
+	
+	onNext: function(/*Object*/ message) {
+		// summary: down arrow pressed; move to next visible node
+
+		var returnWidget;
+
+		// if this is an expanded folder, get the first child
+		var nodeWidget = message.node;
+		if (nodeWidget.isFolder && nodeWidget.isExpanded && nodeWidget.hasChildren()) {
+			returnWidget = nodeWidget.getChildren()[0];			
+		} else {
+			// find a parent node with a sibling
+			while (nodeWidget.isTreeNode) {
+				returnWidget = nodeWidget.getNextSibling();
+				if(returnWidget){
+					break;
+				}
+				nodeWidget = nodeWidget.getParent();
+			}	
+		}
+				
+		if (returnWidget && returnWidget.isTreeNode) {
+			returnWidget.tree.focusNode(returnWidget);
+			return returnWidget;
+		}	
+	},
+	
+	onPrevious: function(/*Object*/ message) {
+		// summary: up arrow pressed; move to previous visible node
+
+		var nodeWidget = message.node;
+		var returnWidget = nodeWidget;
+		
+		// if younger siblings		
+		var previousSibling = nodeWidget.getPreviousSibling();
+		if (previousSibling) {
+			nodeWidget = previousSibling;
+			// if the previous nodeWidget is expanded, dive in deep
+			while (nodeWidget.isFolder && nodeWidget.isExpanded && nodeWidget.hasChildren()) {
+				returnWidget = nodeWidget;
+				// move to the last child
+				var children = nodeWidget.getChildren();
+				nodeWidget = children[children.length-1];
+			}
+		} else {
+			// if this is the first child, return the parent
+			nodeWidget = nodeWidget.getParent();
+		}
+		
+		if (nodeWidget && nodeWidget.isTreeNode) {
+			returnWidget = nodeWidget;
+		}
+		
+		if (returnWidget && returnWidget.isTreeNode) {
+			returnWidget.tree.focusNode(returnWidget);
+			return returnWidget;
+		}
+	},
+	
+	onZoomIn: function(/*Object*/ message) {
+		// summary: right arrow pressed; go to child node
+		var nodeWidget = message.node;
+		var returnWidget = nodeWidget;
+		
+		// if not expanded, expand, else move to 1st child
+		if (nodeWidget.isFolder && !nodeWidget.isExpanded) {
+			this._expand(nodeWidget);
+		}else if (nodeWidget.hasChildren()) {
+			nodeWidget = nodeWidget.getChildren()[0];
+		}
+		
+		if (nodeWidget && nodeWidget.isTreeNode) {
+			returnWidget = nodeWidget;
+		}
+		
+		if (returnWidget && returnWidget.isTreeNode) {
+			returnWidget.tree.focusNode(returnWidget);
+			return returnWidget;
+		}
+	},
+	
+	onZoomOut: function(/*Object*/ message) {
+		// summary: left arrow pressed; go to parent
+		
+		var node = message.node;
+		var returnWidget = node;
+
+		// if not collapsed, collapse, else move to parent
+		if (node.isFolder && node.isExpanded) {
+			this._collapse(node);
+		} else {
+			node = node.getParent();
+		}
+		if (node && node.isTreeNode) {
+			returnWidget = node;
+		}
+		
+		if (returnWidget && returnWidget.isTreeNode) {
+			returnWidget.tree.focusNode(returnWidget);
+			return returnWidget;
+		}
+	},
+
+	onFirst: function(/*Object*/ message) {
+		// summary: home pressed; go to first visible node
+
+		var returnWidget = message.node;
+
+		// the first node is always the root; isn't it?
+		while (!returnWidget.isTree){
+			returnWidget = returnWidget.getParent();
+		}
+		
+		if (returnWidget){
+			returnWidget = returnWidget.getChildren()[0];
+			if (returnWidget && returnWidget.isTreeNode){
+				returnWidget.tree.focusNode(returnWidget);
+				return returnWidget;
+			}
+		}
+	},
+
+	onLast: function(/*Object*/ message) {
+		// summary: end pressed; go to last visible node
+
+		var returnWidget = message.node;
+		
+		// find the tree root
+		while (!returnWidget.isTree){
+			returnWidget = returnWidget.getParent();
+		}
+		
+		var lastChild = returnWidget;
+		while(lastChild.isExpanded){
+			var c = lastChild.getChildren();
+			lastChild = c[c.length - 1];
+			if (lastChild.isTreeNode){
+				returnWidget = lastChild;
+			}
+		}
+
+		if (returnWidget && returnWidget.isTreeNode){
+			returnWidget.tree.focusNode(returnWidget);
+			return returnWidget;
+		}
+	},
+
+	onToggleOpen: function(/*Object*/ message){
+		// summary: user clicked the +/- icon; expand or collapse my children.
+		var node = message.node;
+		if (node.isExpanded){
+			this._collapse(node);
+		} else {
+			this._expand(node);
+		}
+	},
+	
+	_expand: function(node) {
+		if (node.isFolder) {
+			node.expand(); // skip trees or non-folders
+		}
+	},
+
+	_collapse: function(node) {
+		if (node.isFolder) {
+			node.collapse();
+		}
+	}
+});
+
+
+
+dojo.declare(
+	"dijit._tree.DataController",
+	dijit._tree.Controller,
+{
+	// summary
+	//		Controller for tree that hooks up to dojo.data
+
+	onAfterTreeCreate: function(message) {
+		// when a tree is created, we query against the store to get the top level nodes
+		// in the tree
+		var tree = message.tree;
+
+		var _this = this;
+		function onComplete(/*dojo.data.Item[]*/ items){
+			var childParams=dojo.map(items,
+				function(item){
+					return {
+						item: item,
+						label: _this.store.getValue(item, _this.labelAttr),
+						type: _this.store.getValue(item, _this.typeAttr),
+						isFolder: _this.store.hasAttribute(item, _this.childrenAttr)
+						};
+				});
+			tree.setChildren(childParams);
+		}
+		this.store.fetch({ query: this.query, onComplete: onComplete });
+	},
+
+	_expand: function(/*_TreeNode*/ node){
+		var store = this.store;
+		var getValue = this.store.getValue;
+
+		switch(node.state){
+			case "LOADING":
+				// ignore clicks while we are in the process of loading data
+				return;
+
+			case "UNCHECKED":
+				// need to load all the children, and then expand
+				var parentItem = node.item;
+				var childItems = store.getValues(parentItem, this.childrenAttr);
+	
+				// count how many items need to be loaded
+				var _waitCount = 0;
+				dojo.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } });
+	
+		       	if(_waitCount == 0){
+		       		// all items are already loaded.  proceed..
+		       		this._onLoadAllItems(node, childItems);
+		       	}else{
+		       		// still waiting for some or all of the items to load
+		       		node.markProcessing();
+	
+					var _this = this;
+					function onItem(item){
+		   				if(--_waitCount == 0){
+							// all nodes have been loaded, send them to the tree
+							node.unmarkProcessing();
+							_this._onLoadAllItems(node, childItems);
+						}
+					}
+					dojo.forEach(childItems, function(item){
+						if(!store.isItemLoaded(item)){
+			       			store.loadItem({item: item, onItem: onItem});
+			       		}
+			       	});
+		       	}
+		       	break;
+		       	
+			default:
+				// data is already loaded; just proceed
+				dijit._tree.Controller.prototype._expand.apply(this, arguments);
+				break;
+		}
+	},
+
+	_onLoadAllItems: function(/*_TreeNode*/ node, /*dojo.data.Item[]*/ items){
+		// sumary: callback when all the children of a given node have been loaded
+		// TODO: should this be used when the top level nodes are loaded too?
+		var childParams=dojo.map(items, function(item){
+			return {
+				item: item,
+				label: this.store.getValue(item, this.labelAttr),
+				type: this.store.getValue(item, this.typeAttr),
+				isFolder: this.store.hasAttribute(item, this.childrenAttr)
+			};
+		}, this);
+		node.setChildren(childParams);
+		dijit._tree.Controller.prototype._expand.apply(this, arguments);
+	},
+
+	_collapse: function(/*_TreeNode*/ node){
+		if(node.state == "LOADING"){
+			// ignore clicks while we are in the process of loading data
+			return;
+		}
+		dijit._tree.Controller.prototype._collapse.apply(this, arguments);
+	}
+
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/_tree/Node.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/_tree/Node.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/_tree/Node.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,12 @@
+<div class="TreeNode TreeExpandLeaf TreeChildrenNo" waiRole="presentation"
+	><span dojoAttachPoint="expandoNode" class="TreeExpando" waiRole="presentation"
+	></span
+	><span dojoAttachPoint="expandoNodeText" class="dijitExpandoText" waiRole="presentation"
+	></span
+	><div dojoAttachPoint="iconNode" class="TreeIcon" waiRole="presentation"
+	 ><div dojoAttachPoint="contentNode" class="TreeContent" waiRole="presentation"
+	  ><span dojoAttachPoint=labelNode class="TreeLabel" wairole="treeitem" expanded="true" tabindex="-1"
+	  ></span
+	 ></div
+	></div
+></div>

Added: trunk/examples/typeface/root/static/dojo/dijit/_tree/Tree.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/_tree/Tree.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/_tree/Tree.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,3 @@
+<div class="TreeContainer" style="" waiRole="tree" tabindex="0"
+	dojoAttachEvent="onclick:_onClick;onkeypress:_onKeyPress"
+></div>
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dijit/base/Container.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/base/Container.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/base/Container.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,119 @@
+dojo.provide("dijit.base.Container");
+
+dojo.require("dijit.util.manager");
+
+dojo.declare("dijit.base.Contained",
+	null,
+	{
+		// summary
+		//		Mixin for widgets that are children of a container widget
+
+		getParent: function(){
+			// summary:
+			//		returns parent widget
+			for(var p=this.domNode.parentNode; p; p=p.parentNode){
+				var widgetId = p.widgetId;
+				if(widgetId){
+					return dijit.byId(widgetId);
+				}
+			}
+			return null;
+		},
+
+		_getSibling: function(which){
+			var node = this.domNode;
+			do{
+				node = node[which+"Sibling"];
+			}while(node && node.nodeType != 1);
+			if(!node){ return null; } // null
+			var id = node.widgetId;
+			return dijit.byId(id);
+		},
+
+		getPreviousSibling: function(){
+			// summary:
+			//		returns null if this is the first child of the parent,
+			//		otherwise returns the next element sibling to the "left".
+
+			return this._getSibling("previous");
+		},
+	 
+		getNextSibling: function(){
+			// summary:
+			//		returns null if this is the last child of the parent,
+			//		otherwise returns the next element sibling to the "right".
+	 
+			return this._getSibling("next");
+		}
+	}
+);
+
+dojo.declare("dijit.base.Container", 
+	null,
+	{
+		// summary
+		//		Mixin for widgets that contain a list of children like SplitContainer
+
+		isContainer: true,
+
+		addChild: function(/*Widget*/ widget, /*int?*/ insertIndex){
+			// summary:
+			//		Process the given child widget, inserting it's dom node as
+			//		a child of our dom node
+
+			var containerNode = this.containerNode || this.domNode;
+			if(typeof insertIndex == "undefined"){
+				dojo.place(widget.domNode, containerNode, "last");
+			}else{
+				dojo.place(widget.domNode, containerNode, insertIndex);
+			}
+		},
+
+		removeChild: function(/*Widget*/ widget){
+			// summary: 
+			//		removes the passed widget instance from this widget but does
+			//		not destroy it
+			var node = widget.domNode;
+			node.parentNode.removeChild(node); //PORT leak #2931 -- call widget.destroy() instead?
+		},
+		
+		_nextElement: function(node){
+			do{
+				node = node.nextSibling;
+			}while(node && node.nodeType != 1);
+			return node;
+		},
+
+		_firstElement: function(node){
+			node = node.firstChild;
+			if(node && node.nodeType != 1){
+				node = this._nextElement(node);
+			}
+			return node;
+		},
+
+		getChildren: function(){
+			// summary:
+			//		returns array of children widgets
+
+			var res = [];
+			var cn = this.containerNode || this.domNode;
+			var childNode = this._firstElement(cn);
+			while(childNode){
+				var tmp = dijit.byId(childNode.widgetId);
+				if(tmp){
+					res.push(tmp);
+				}
+				childNode = this._nextElement(childNode);
+			}
+			return res;
+		},
+
+		hasChildren: function(){
+			// summary:
+			//		returns true if widget has children
+			var cn = this.containerNode || this.domNode;
+			return !!this._firstElement(cn);
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/base/FormElement.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/base/FormElement.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/base/FormElement.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,168 @@
+dojo.provide("dijit.base.FormElement");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.util.sniff");
+dojo.require("dijit.util.wai");
+
+dojo.declare("dijit.base.FormElement", dijit.base.Widget,
+{
+	/*
+	Summary:
+		FormElement widgets correspond to native HTML elements such as <input> or <button> or <select>.
+		Each FormElement represents a single input value, and has a (possibly hidden) <input> element,
+		to which it serializes its input value, so that form submission (either normal submission or via FormBind?)
+		works as expected.
+		
+		All these widgets should have these attributes just like native HTML input elements.
+		You can set them during widget construction, but after that they are read only.
+		
+		They also share some common methods.
+		
+	TODO:
+		should this be a mixin or a base class?
+		automatically add CSS tags for hover and focus like *class*Hover and *class*Focus (or maybe in FormElement)
+	*/
+	// baseClass: String
+	//		Used to add CSS classes like FormElementDisabled
+	baseClass: "",
+
+	// value: String
+	//		Corresponds to the native HTML <input> element's attribute.
+	value: "", 
+
+	// name: String
+	//		Name used when submitting form; same as "name" attribute or plain HTML elements
+	name: "",
+
+	// id: String
+	//		Corresponds to the native HTML <input> element's attribute.
+	//		Also becomes the id for the widget.
+	id: "",
+
+	// alt: String
+	//		Corresponds to the native HTML <input> element's attribute.
+	alt: "",
+
+	// type: String
+	//		Corresponds to the native HTML <input> element's attribute.
+	type: "text",
+
+	// tabIndex: Integer
+	//		Order fields are traversed when user hits the tab key
+	tabIndex: "0",
+
+	// disabled: Boolean
+	//		Should this widget respond to user input?
+	//		In markup, this is specified as "disabled='disabled'", or just "disabled".
+	disabled: false,
+
+	enable: function(){
+		// summary:
+		//		enables the widget, usually involving unmasking inputs and
+		//		turning on event handlers. Not implemented here.
+		this._setDisabled(false);
+	},
+
+	disable: function(){
+		// summary:
+		//		disables the widget, usually involves masking inputs and
+		//		unsetting event handlers. Not implemented here.
+		this._setDisabled(true);
+	},
+	
+	_setDisabled: function(/*Boolean*/ disabled){
+		// summary:
+		//		Set disabled state of widget.
+		// TODO:
+		//		not sure which parts of disabling a widget should be here;
+		//		not sure which code is common to many widgets and which is specific to a particular widget.
+		this.domNode.disabled = this.disabled = disabled;
+		if(this.focusNode){
+			this.focusNode.disabled = disabled;
+		}
+		dijit.util.wai.setAttr(this.focusNode || this.domNode, "waiState", "disabled", disabled);
+		this.setStateClass(null, this.domNode);
+	},
+	
+
+	setStateClass : function(event, mouseNode, baseClass) {
+		// summary:
+		//	Update the visual state of the widget by changing the css class according to the mouse state.
+		//	State will be one of:
+		//		<baseClass> + "Enabled"|"Disabled"|"Active"|"Hover"
+		if (mouseNode == null) mouseNode = this.domNode;
+		if (event) dojo.stopEvent(event);
+		var base = mouseNode.getAttribute("baseClass") || this.baseClass || (this.baseClass = "dijit"+this.declaredClass.replace(/.*\./g,""));
+		
+		if (this.disabled) {
+			dojo.removeClass(this.domNode, base+"Enabled");
+			dojo.removeClass(this.domNode, base+"Hover");
+			dojo.removeClass(this.domNode, base+"Active");
+			dojo.addClass(this.domNode, base+"Disabled");
+		} else {
+			if (event) {
+				switch (event.type) {
+					case "mouseover" :
+						mouseNode._hovering = true;
+						break;
+						
+					case "mouseout" :	
+						mouseNode._hovering = false;	
+						break;
+						
+					case "mousedown" :
+						mouseNode._active = true;
+						// set a global event to handle mouseup, so it fires properly
+						//	even if the cursor leaves the button
+						var self = this;
+						var method = function(event) {
+							self.setStateClass(event, mouseNode);
+						}
+						mouseNode._mouseUpConnector = dojo.connect(dojo.global, "onmouseup", this, method);
+						break;
+	
+					case "mouseup" :
+						mouseNode._active = false;
+						// clear the global mouseup event, if set
+						if (this._mouseUpConnector) {
+							dojo.disconnect(mouseNode._mouseUpConnector);
+							mouseNode._mouseUpConnector = false;
+						}
+						break;
+						
+					case "click" :
+						this.onClick(event);
+						break;				
+				}
+			}
+//console.info(this.disabled, this._hovering, this._active);
+			dojo.removeClass(this.domNode, base+"Disabled");
+			dojo.toggleClass(this.domNode, base+"Active", mouseNode._active == true);
+			dojo.toggleClass(this.domNode, base+"Hover", mouseNode._hovering == true && mouseNode._active != true);
+			dojo.addClass(this.domNode, base+"Enabled");
+		}
+	},
+
+	onValueChanged: function(newValue){
+		// summary: callback when value is changed
+	},
+	
+	postCreate: function(){
+		this._setDisabled(this.disabled == true);
+	},
+
+	_lastValueReported: null,
+	setValue: function(newValue){
+		// summary: set the value of the widget.
+		if(newValue != this._lastValueReported){
+			this._lastValueReported = newValue;
+			dijit.util.wai.setAttr(this.focusNode || this.domNode, "waiState", "valuenow", newValue);
+			this.onValueChanged(newValue);
+		}
+	},
+
+	getValue: function(){
+		// summary: get the value of the widget.
+		return this._lastValueReported;
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/base/Layout.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/base/Layout.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/base/Layout.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,242 @@
+dojo.provide("dijit.base.Layout");
+
+dojo.require("dijit.base.Container");
+
+dojo.declare("dijit.base.Sizable", 
+	null,
+	{
+		// summary
+		//		Helper mixin for widgets that can have their size adjusted,
+		//		and that need to do some processing when their size changes (like SplitContainer)
+
+		resize: function(mb){
+			// summary:
+			//		Explicitly set this widget's size (in pixels), 
+			//		and then call layout() to resize contents (and maybe adjust child widgets)
+			//	
+			// mb: Object?
+			//		{w: int, h: int, l: int, t: int}
+
+			var node = this.domNode;
+
+			// set margin box size, unless it wasn't specified, in which case use current size
+			if(mb){
+				dojo.marginBox(node, mb);
+
+				// set offset of the node
+				if(mb.t){ node.style.top = mb.t + "px"; }
+				if(mb.l){ node.style.left = mb.l + "px"; }
+			}
+			mb = dojo.marginBox(node);
+
+			// Save the size of my content box.
+			this._contentBox = dijit.base.Layout.marginBox2contentBox(node, mb);
+			
+			// Callback for widget to adjust size of it's children
+			this.layout();
+		},
+	
+		layout: function(){
+			//	summary
+			//		Widgets override this method to size & position their contents/children.
+			//		When this is called this._contentBox is guaranteed to be set (see resize()).
+			//
+			//		This is called after startup(), and also when the widget's size has been
+			//		changed.
+		}
+	}
+);
+
+dojo.declare("dijit.base.Layout", 
+	[dijit.base.Sizable, dijit.base.Container, dijit.base.Contained, dijit.base.Showable],
+	{
+		// summary
+		//		Mixin for widgets that contain a list of children like SplitContainer.
+		//		Widgets which mixin this code must define layout() to lay out the children
+
+		isLayoutContainer: true,
+
+		startup: function(){
+			// summary:
+			//		Called after all the widgets have been instantiated and their
+			//		dom nodes have been inserted somewhere under document.body.
+			//
+			//		Widgets should override this method to do any initialization
+			//		dependent on other widgets existing, and then call
+			//		this superclass method to finish things off.
+			//
+			//		startup() in subclasses shouldn't do anything
+			//		size related because the size of the widget hasn't been set yet.
+
+			if(this._started){
+				return;
+			}
+			this._started=true;
+
+			if(this.getChildren){
+				dojo.forEach(this.getChildren(), function(child){ child.startup(); });
+			}
+
+			// If I am a top level widget
+			if(!this.getParent || !this.getParent()){
+				// Do recursive sizing and layout of all my descendants
+				this.resize();
+
+				// since my parent isn't a layout container, and my style is width=height=100% (or something similar),
+				// then I need to watch when the window resizes, and size myself accordingly
+				this.connect(window, 'onresize', "resize");
+			}
+		}
+	}
+);
+
+dijit.base.Layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
+	// summary:
+	//		Given the margin-box size of a node, return it's content box size.
+	//		Functions like dojo.contentBox() but is more reliable since it doesn't have
+	//		to wait for the browser to compute sizes.
+	var cs = dojo.getComputedStyle(node);
+	var me=dojo._getMarginExtents(node, cs);
+	var pb=dojo._getPadBorderExtents(node, cs);
+	return {
+		l: dojo._toPixelValue(this.containerNode, cs.paddingLeft),
+		t: dojo._toPixelValue(this.containerNode, cs.paddingTop),
+		w: mb.w - (me.w + pb.w),
+		h: mb.h - (me.h + pb.h)
+	};
+};
+
+dijit.base.Layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Object[]*/ children, /*String*/ layoutPriority){
+	/**
+	 * summary
+	 *		Layout a bunch of child dom nodes within a parent dom node
+	 *		Returns true if successful, returns false if any of the children would 
+	 * 		have been calculated to be hidden (typically if browser hasn't flowed the nodes)
+	 *		In the latter case, a best-effort of the layout is done and the caller can
+	 *		reschedule a layout at a later time - when the browser has more accurate metrics
+	 * container:
+	 *		parent node
+	 * dim:
+	 *		{l, t, w, h} object specifying dimensions of container into which to place children
+	 * layoutPriority:
+	 *		"top-bottom" or "left-right"
+	 * children:
+	 *		an array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ]
+	 */
+
+	dojo.addClass(container, "dijitLayoutContainer");
+
+	// Copy children array and remove elements w/out layout.
+	// Also record each child's position in the input array, for sorting purposes.
+	children = dojo.filter(children, function(child, idx){
+		child.idx = idx;
+		return dojo.indexOf(["top","bottom","left","right","client","flood"], child.layoutAlign) > -1;
+	});
+
+	// Order the children according to layoutPriority.
+	// Multiple children w/the same layoutPriority will be sorted by their position in the input array.
+	if(layoutPriority && layoutPriority!="none"){
+		var rank = function(child){
+			switch(child.layoutAlign){
+				case "flood":
+					return 1;
+				case "left":
+				case "right":
+					return (layoutPriority=="left-right") ? 2 : 3;
+				case "top":
+				case "bottom":
+					return (layoutPriority=="left-right") ? 3 : 2;
+				default:
+					return 4;
+			}
+		};
+		children.sort(function(a,b){
+			return (rank(a)-rank(b)) || (a.idx - b.idx);
+		});
+	}
+
+	// set positions/sizes
+	var ret=true;
+	dojo.forEach(children, function(child){
+		var elm=child.domNode;
+		var pos=child.layoutAlign;
+		// set elem to upper left corner of unused space; may move it later
+		var elmStyle = elm.style;
+		elmStyle.left = dim.l+"px";
+		elmStyle.top = dim.t+"px";
+		elmStyle.bottom = elmStyle.right = "auto";
+
+		var capitalize = function(word){
+			return word.substring(0,1).toUpperCase() + word.substring(1);
+		};
+		
+		dojo.addClass(elm, "dijitAlign" + capitalize(pos));
+
+		// set size && adjust record of remaining space.
+		// note that setting the width of a <div> may affect it's height.
+		if (pos=="top" || pos=="bottom"){
+			if(child.resize){
+				child.resize({w: dim.w});
+			}else{
+				dojo.marginBox(elm, { w: dim.w });
+			}
+			var h = dojo.marginBox(elm).h;
+			dim.h -= h;
+			dojo.mixin(child, {w: dim.w, h: h});	// return child size
+			if(pos=="top"){
+				dim.t += h;
+			}else{
+				elmStyle.top = dim.t + dim.h + "px";
+			}
+		}else if(pos=="left" || pos=="right"){
+			var w = dojo.marginBox(elm).w;
+
+			// TODO: this zero stuff shouldn't be necessary anymore
+			var hasZero = dijit.base.Layout._sizeChild(child, elm, w, dim.h);
+			if(hasZero){
+				ret = false;
+			}
+			dim.w -= w;
+			if(pos=="left"){
+				dim.l += w;
+			}else{
+				elmStyle.left = dim.l + dim.w + "px";
+			}
+		} else if(pos=="flood" || pos=="client"){
+			// #1635 - filter for zero dimensions (see below)
+			var hasZero = dijit.base.Layout._sizeChild(child, elm, dim.w, dim.h);
+			if(hasZero){
+				ret = false;
+			}
+		}
+	});
+	return ret;
+};
+
+dijit.base.Layout._sizeChild = function (child, elm, w, h){
+	// Note: zero dimensions can occur if we are called before the browser
+	// don't allow such values for width and height, let the browser adjust the
+	// layout itself when it reflows and report if any dimension is zero
+	var box = {};
+	
+	var hasZero = (w == 0 || h == 0);
+	if(!hasZero){
+	// TODO: Bill: this makes no sense.  If !hasZero then w!=0 and h!=0.
+	// The following two if statements are meaningless.
+		if(w != 0){
+			box.w = w;
+		}
+		if(h != 0){
+			box.h = h;
+		}
+		if(child.resize){
+			child.resize(box);
+		}else{
+			dojo.marginBox(elm, box);
+		}
+	}
+	dojo.mixin(child, box);	// return child size
+	return hasZero;
+}
+
+

Added: trunk/examples/typeface/root/static/dojo/dijit/base/Showable.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/base/Showable.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/base/Showable.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,51 @@
+dojo.provide("dijit.base.Showable");
+
+//TODO: do we need this class at all?
+dojo.declare("dijit.base.Showable", null,
+{
+	// Summary
+	//		Mixin for widgets that show/hide themselves in a fancy way
+
+	isShowing: function(){
+		// summary
+		//	Tests whether widget is set to show-mode or hide-mode (see show() and 
+		//	hide() methods)
+		//
+		//	This function is poorly named.  Even if widget is in show-mode,
+		//	if it's inside a container that's hidden
+		//	(either a container widget, or just a domnode with display:none),
+		//	then it won't be displayed
+		return dojo.style(this.domNode, "display") != 'none';	// Boolean
+	},
+
+	toggleShowing: function(){
+		// summary: show or hide the widget, to switch it's state
+		if(this.isShowing()){
+			this.hide();
+		}else{
+			this.show();
+		}
+	},
+
+	show: function(){
+		// summary: show the widget
+		if(this.isShowing()){ return; }
+		this.domNode.style.display = "";
+		this.onShow();
+	},
+
+	onShow: function(){
+		// summary: callback for when widget is shown
+	},
+
+	hide: function(){
+		// summary: hide the widget (ending up with display:none)
+		if(!this.isShowing()){ return; }
+		this.domNode.style.display = "none";
+		this.onHide();
+	},
+	
+	onHide: function(){
+		// summary: callback for when widget is hidden
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/base/TemplatedWidget.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/base/TemplatedWidget.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/base/TemplatedWidget.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,316 @@
+dojo.provide("dijit.base.TemplatedWidget");
+
+dojo.require("dojo.string");
+dojo.require("dijit.util.wai");
+dojo.require("dijit.util.parser");
+
+dojo.declare("dijit.base.TemplatedWidget", 
+	null,
+	{
+		// summary:
+		//		mixin for widgets that are instantiated from a template
+			 
+		// templateNode: DomNode
+		//		a node that represents the widget template. Pre-empts both templateString and templatePath.
+		templateNode: null,
+
+		// templateString String:
+		//		a string that represents the widget template. Pre-empts the
+		//		templatePath. In builds that have their strings "interned", the
+		//		templatePath is converted to an inline templateString, thereby
+		//		preventing a synchronous network call.
+		templateString: null,
+
+		// templatePath: String
+		//	Path to template (HTML file) for this widget
+		templatePath: null,
+
+		// widgetsInTemplate Boolean:
+		//		should we parse the template to find widgets that might be
+		//		declared in markup inside it? false by default.
+		// TODO: unsupported; need to copy over code from trunk
+		widgetsInTemplate: false,
+		
+		// containerNode DomNode:
+		//		holds child elements. "containerNode" is generally set via a
+		//		dojoAttachPoint assignment and it designates where children of
+		//		the src dom node will be placed
+		containerNode: null,
+
+		// method over-ride
+		buildRendering: function(){
+			// summary:
+			//		Construct the UI for this widget from a template.
+			// description:
+			// Lookup cached version of template, and download to cache if it
+			// isn't there already.  Returns either a DomNode or a string, depending on
+			// whether or not the template contains ${foo} replacement parameters.
+
+			var cached = dijit.base.getCachedTemplate(this.templatePath, this.templateString);
+
+			var node;
+			if(dojo.isString(cached)){
+				// Cache contains a string because we need to do property replacement
+				// do the property replacement
+				var tstr = dojo.string.substitute(cached, this, function(value){
+					// Safer substitution, see heading "Attribute values" in  
+					// http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
+					return value.toString().replace(/"/g,"&quot;"); //TODO: support a more complete set of escapes?
+				}, this);
+
+				node = dijit.base._createNodesFromText(tstr)[0];
+			}else{
+				// if it's a node, all we have to do is clone it
+				node = cached.cloneNode(true);
+			}
+
+			// recurse through the node, looking for, and attaching to, our
+			// attachment points which should be defined on the template node.
+			this._attachTemplateNodes(node);
+			if(this.srcNodeRef){
+				dojo.style(node, "cssText", this.srcNodeRef.style.cssText);
+				if(this.srcNodeRef.className){
+					node.className += " " + this.srcNodeRef.className;
+				}
+			}
+
+			this.domNode = node;
+			if(this.srcNodeRef && this.srcNodeRef.parentNode){
+				this.srcNodeRef.parentNode.replaceChild(this.domNode, this.srcNodeRef);
+			}
+			if(this.widgetsInTemplate){
+				var childWidgets = dijit.util.parser.parse(this.domNode);
+				this._attachTemplateNodes(childWidgets, function(n,p){
+					return n[p];
+				});
+			}
+
+			// relocate source contents to templated container node
+			// this.containerNode must be able to receive children, or exceptions will be thrown
+			if(this.srcNodeRef && this.srcNodeRef.hasChildNodes()){
+				var dest = this.containerNode||this.domNode;
+				while(this.srcNodeRef.hasChildNodes()){
+					dest.appendChild(this.srcNodeRef.firstChild);
+				}
+			}
+		},
+
+		_attachTemplateNodes: function(rootNode, getAttrFunc){
+			// summary:
+			//		map widget properties and functions to the handlers specified in
+			//		the dom node and it's descendants. This function iterates over all
+			//		nodes and looks for these properties:
+			//			* dojoAttachPoint
+			//			* dojoAttachEvent	
+			//			* waiRole
+			//			* waiState
+			// rootNode: DomNode|Array[Widgets]
+			//		the node to search for properties. All children will be searched.
+			// getAttrFunc: function?
+			//		a function which will be used to obtain property for a given 
+			//		DomNode/Widget
+		
+			var trim = function(str){
+				return str.replace(/^\s+|\s+$/g, "");
+			};
+
+			getAttrFunc = getAttrFunc || function(n,p){ return n.getAttribute(p); } 
+
+			var nodes = dojo.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*")); 
+			var x=dojo.isArray(rootNode)?0:-1; 
+			for(; x<nodes.length; x++){
+				var baseNode = (x == -1) ? rootNode : nodes[x];
+				if(this.widgetsInTemplate && getAttrFunc(baseNode,'dojoType')){
+					return;
+				}
+				// Process dojoAttachPoint
+				var tmpAttachPoint = getAttrFunc(baseNode, "dojoAttachPoint");
+				if(tmpAttachPoint){
+					var attachPoint = tmpAttachPoint.split(";");
+					var z = 0, ap;
+					while((ap=attachPoint[z++])){
+						if(dojo.isArray(this[ap])){
+							this[ap].push(baseNode);
+						}else{
+							this[ap]=baseNode;
+						}
+					}
+				}
+
+				// dojoAttachEvent
+				var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent");
+				if(attachEvent){
+					// NOTE: we want to support attributes that have the form
+					// "domEvent: nativeEvent; ..."
+					var evts = attachEvent.split(";");
+					var y = 0, evt;
+					while((evt=evts[y++])){
+						if(!evt || !evt.length){ continue; }
+						var thisFunc = null;
+						var tevt = trim(evt);
+						if(evt.indexOf(":") != -1){
+							// oh, if only JS had tuple assignment
+							var funcNameArr = tevt.split(":");
+							tevt = trim(funcNameArr[0]);
+							thisFunc = trim(funcNameArr[1]);
+						}
+						if(!thisFunc){
+							thisFunc = tevt;
+						}
+						this.connect(baseNode, tevt, thisFunc); 
+					}
+				}
+		
+				// waiRole, waiState
+				dojo.forEach(["waiRole", "waiState"], function(name){
+					var wai = dijit.util.wai[name];
+					var val = getAttrFunc(baseNode, wai.name);
+					if(val){
+						var role = "role";
+						if(val.indexOf('-') != -1){ 
+							// this is a state-value pair
+							var statePair = val.split('-');
+							role = statePair[0];
+							val = statePair[1];
+						}
+						dijit.util.wai.setAttr(baseNode, wai.name, role, val);
+					}
+				}, this);
+			}
+		}
+	}
+);
+
+// key is either templatePath or templateString; object is either string or DOM tree
+dijit.base._templateCache = {};
+
+dijit.base.getCachedTemplate = function(templatePath, templateString){
+	// summary:
+	//		static method to get a template based on the templatePath or
+	//		templateString key
+	// templatePath: String
+	//		the URL to get the template from. dojo.uri.Uri is often passed as well.
+	// templateString: String?
+	//		a string to use in lieu of fetching the template from a URL
+	// Returns:
+	//	Either string (if there are ${} variables that need to be replaced) or just
+	//	a DOM tree (if the node can be cloned directly)
+
+	// is it already cached?
+	var tmplts = dijit.base._templateCache;
+	var key = templateString || templatePath;
+	var cached = tmplts[key];
+	if(cached){
+		return cached;
+	}
+
+	// If necessary, load template string from template path
+	if(!templateString){
+		templateString = dijit.base._sanitizeTemplateString(dojo._getText(templatePath));
+	}
+
+	templateString = templateString.replace(/^\s+|\s+$/g, "");
+
+	if(templateString.match(/\$\{([^\}]+)\}/g)){
+		// there are variables in the template so all we can do is cache the string
+		return (tmplts[key] = templateString); //String
+	}else{
+		// there are no variables in the template so we can cache the DOM tree
+		return (tmplts[key] = dijit.base._createNodesFromText(templateString)[0]); //Node
+	}
+};
+
+dijit.base._sanitizeTemplateString = function(/*String*/tString){
+	//summary: Strips <?xml ...?> declarations so that external SVG and XML
+	//documents can be added to a document without worry. Also, if the string
+	//is an HTML document, only the part inside the body tag is returned.
+	if(tString){
+		tString = tString.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
+		var matches = tString.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+		if(matches){
+			tString = matches[1];
+		}
+	}else{
+		tString = "";
+	}
+	return tString; //String
+};
+
+
+if(dojo.isIE){
+	dojo.addOnUnload(function(){
+		var cache = dijit.base._templateCache;
+		for(var key in cache){
+			var value = cache[key];
+			if(!isNaN(value.nodeType)){ // isNode equivalent
+// PORT.  Fix leak			dojo.dom.destroyNode(value);
+			}
+			cache[key] = null;
+		}
+	});
+}
+
+(function(){
+	var tagMap = {
+		cell: {re: /^<t[dh][\s\r\n>]/i, pre: "<table><tbody><tr>", post: "</tr></tbody></table>"},
+		row: {re: /^<tr[\s\r\n>]/i, pre: "<table><tbody>", post: "</tbody></table>"},
+		section: {re: /^<(thead|tbody|tfoot)[\s\r\n>]/i, pre: "<table>", post: "</table>"}
+	};
+
+	var tn;
+	var _parent;
+
+	dijit.base._createNodesFromText = function(/*String*/text){
+		//	summary
+		//	Attempts to create a set of nodes based on the structure of the passed text.
+
+		if(!tn){
+			_parent = tn = dojo.doc.createElement("div");
+			tn.style.visibility="hidden";
+		}
+		var tableType = "none";
+		var rtext = text.replace(/^\s+/);
+		for(var type in tagMap){
+			var map = tagMap[type];
+			if(map.re.test(rtext)){ //FIXME: replace with one arg?  is this a no-op?
+				tableType = type;
+				text = map.pre + text + map.post;
+				break;
+			}
+		}
+
+		tn.innerHTML = text;
+		dojo.body().appendChild(tn);
+		if(tn.normalize){
+			tn.normalize();
+		}
+
+		var tag = { cell: "tr", row: "tbody", section: "table" }[tableType];
+		if(typeof tag != "undefined"){
+			_parent = tn.getElementsByTagName(tag)[0];
+		}
+
+		var nodes = [];
+		/*
+		for(var x=0; x<_parent.childNodes.length; x++){
+			nodes.push(_parent.childNodes[x].cloneNode(true));
+		}
+		*/
+		while(_parent.firstChild){
+			nodes.push(_parent.removeChild(_parent.firstChild));
+		}
+		//PORT	dojo.html.destroyNode(tn); FIXME: need code to prevent leaks and such
+		_parent = dojo.body().removeChild(tn);
+		return nodes;	//	Array
+	}
+})();
+
+// These arguments can be specified for widgets which are used in templates.
+// Since any widget can be specified as sub widgets in template, mix it
+// into the base widget class.  (This is a hack, but it's effective.)
+dojo.extend(dijit.base.Widget,{
+	dojoAttachEvent: "",
+	dojoAttachPoint: "",
+	waiRole: "",
+	waiState:""
+})

Added: trunk/examples/typeface/root/static/dojo/dijit/base/Widget.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/base/Widget.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/base/Widget.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,254 @@
+dojo.provide("dijit.base.Widget");
+
+dojo.require("dijit.util.manager");
+
+dojo.declare("dijit.base.Widget", null,
+function(params, srcNodeRef){
+	// summary:
+	//		To understand the process by which widgets are instantiated, it
+	//		is critical to understand what other methods the constructor calls and
+	//		which of them you'll want to over-ride. Of course, adventurous
+	//		developers could over-ride the constructor entirely, but this should
+	//		only be done as a last resort.
+	//
+	//		Below is a list of the methods that are called, in the order
+	//		they are fired, along with notes about what they do and if/when
+	//		you should over-ride them in your widget:
+	//			
+	//			postMixInProperties:
+	//				a stub function that you can over-ride to modify
+	//				variables that may have been naively assigned by
+	//				mixInProperties
+	//			# widget is added to manager object here
+	//			buildRendering
+	//				Subclasses use this method to handle all UI initialization
+	//				Sets this.domNode.  Templated widgets do this automatically
+	//				and otherwise it just uses the source dom node. 
+	//			postCreate
+	//				a stub function that you can over-ride to modify take
+	//				actions once the widget has been placed in the UI
+
+	// store pointer to original dom tree
+	this.srcNodeRef = dojo.byId(srcNodeRef);
+
+	// for garbage collection
+	this._connects=[];
+
+	//mixin our passed parameters
+	if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
+	if(params){
+		dojo.mixin(this,params);
+	}
+
+	this.postMixInProperties();
+	dijit.util.manager.add(this);
+	this.buildRendering();
+	if(this.domNode){
+		this.domNode.widgetId = this.id;
+		if(this.srcNodeRef && this.srcNodeRef.dir){ 
+			this.domNode.dir = this.srcNodeRef.dir; 
+		}
+	}
+	this.postCreate();
+
+	// If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC.
+	if(this.srcNodeRef && !this.srcNodeRef.parentNode){
+		delete this.srcNodeRef;
+	}
+},
+{
+	// id: String
+	//		a unique, opaque ID string that can be assigned by users or by the
+	//		system. If the developer passes an ID which is known not to be
+	//		unique, the specified ID is ignored and the system-generated ID is
+	//		used instead.
+	id: "",
+
+	// lang: String
+	//	Language to display this widget in (like en-us).
+	//	Defaults to brower's specified preferred language (typically the language of the OS)
+	lang: "",
+
+	// dir: String
+	//  Bi-directional support, as defined by the HTML DIR attribute. Either left-to-right "ltr" or right-to-left "rtl".
+	dir: "",
+
+	// srcNodeRef: DomNode
+	//		pointer to original dom node
+	srcNodeRef: null,
+
+	// domNode DomNode:
+	//		this is our visible representation of the widget! Other DOM
+	//		Nodes may by assigned to other properties, usually through the
+	//		template system's dojoAttachPonit syntax, but the domNode
+	//		property is the canonical "top level" node in widget UI.
+	domNode: null, 
+
+	//////////// INITIALIZATION METHODS ///////////////////////////////////////
+
+	postMixInProperties: function(){
+		// summary
+		//	Called after the parameters to the widget have been read-in,
+		//	but before the widget template is instantiated.
+		//	Especially useful to set properties that are referenced in the widget template.
+
+//		this.lang = this.lang || null;
+	},
+
+	buildRendering: function(){
+		// summary:
+		//		Construct the UI for this widget, setting this.domNode.
+		//		Most widgets will mixin TemplatedWidget, which overrides this method.
+		this.domNode = this.srcNodeRef;
+	},
+
+	postCreate: function(){
+		// summary:
+		//		Called after a widget's dom has been setup
+	},
+
+	startup: function(){
+		// summary:
+		//		Called after a widget's children, and other widgets on the page, have been created.
+		//		Provides an opportunity to manipulate any children before they are displayed
+		//		This is useful for composite widgets that need to control or layout sub-widgets
+		//		Many layout widgets can use this as a wiring phase
+		
+	},
+
+	//////////// DESTROY FUNCTIONS ////////////////////////////////
+
+	destroyRecursive: function(/*Boolean*/ finalize){
+		// summary:
+		// 		Destroy this widget and it's descendants. This is the generic
+		// 		"destructor" function that all widget users should call to
+		// 		cleanly discard with a widget. Once a widget is destroyed, it's
+		// 		removed from the manager object.
+		// finalize: Boolean
+		//		is this function being called part of global environment
+		//		tear-down?
+
+		this.destroyDescendants();
+		this.destroy();
+	},
+	
+	destroy: function(/*Boolean*/ finalize){
+		// summary:
+		// 		Destroy this widget, but not its descendents
+		// finalize: Boolean
+		//		is this function being called part of global environment
+		//		tear-down?
+		this.uninitialize();
+		dojo.forEach(this._connects, dojo.disconnect);
+		this.destroyRendering(finalize);
+		dijit.util.manager.remove(this.id);
+	},
+
+	destroyRendering: function(/*Boolean*/ finalize){
+		// summary:
+		//		Destroys the DOM nodes associated with this widget
+		// finalize: Boolean
+		//		is this function being called part of global environment
+		//		tear-down?
+
+		if(this.bgIframe){
+			this.bgIframe.remove();
+			delete this.bgIframe;
+		}
+
+		if(this.domNode){
+			//			dojo.dom.destroyNode(this.domNode);
+			//PORT #2931
+			if(this.domNode.parentNode){
+				this.domNode.parentNode.removeChild(this.domNode);
+			}
+			delete this.domNode;
+		}
+
+		if(this.srcNodeRef && this.srcNodeRef.parentNode){
+//			dojo.dom.destroyNode(this.srcNodeRef);
+//PORT #2931
+			this.srcNodeRef.parentNode.removeChild(this.srcNodeRef);
+			delete this.srcNodeRef;
+		}
+	},
+
+	destroyDescendants: function(){
+		// summary:
+		//		Recursively destroy the children of this widget and their
+		//		descendents.
+		dojo.forEach(this.getDescendants(), function(widget){
+			widget.destroy();
+		});
+	},
+
+	uninitialize: function(){
+		// summary: 
+		//		stub function. Over-ride to implement custom widget tear-down
+		//		behavior.
+		return false;
+	},
+
+	////////////////// MISCELLANEOUS METHODS ///////////////////
+	
+	toString: function(){
+		// summary:
+		//		returns a string that represents the widget. When a widget is
+		//		cast to a string, this method will be used to generate the
+		//		output. Currently, it does not implement any sort of reversable
+		//		serialization.
+		return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String
+	},
+
+	getDescendants: function(){
+		// summary:
+		//	return all the descendent widgets
+		var allNodes = this.domNode.all || this.domNode.getElementsByTagName("*");
+		var i=0, node;
+		var nodes = [];
+		while((node = allNodes[i++])){
+			var id = node.widgetId;
+			if(id){
+				nodes.push(dijit.byId(id));
+			}
+		}
+		return nodes;
+	},
+
+	connect: function(
+			/*Object|null*/ obj, 
+			/*String*/ event, 
+			/*String|Function*/ method){
+
+		// summary:
+		//		Connects specified obj/event to specified method of this object
+		//		and registers for disconnect() on widget destroy.
+		//		Similar to dojo.connect() but takes three arguments rather than four.
+		this._connects.push(dojo.connect(obj, event, this, method));
+	},
+
+	isLeftToRight: function(){
+		// summary:
+		//		Checks the DOM to for the text direction for bi-directional support
+		//		See HTML spec, DIR attribute for more information.
+
+		if(typeof this._ltr == "undefined"){
+			this._ltr = (this.dir || dojo.getComputedStyle(this.domNode).direction) != "rtl";
+		}
+		return this._ltr; //Boolean
+	}
+});
+
+//PORT - where does this go?  dijit.util?  dojo.html?
+dijit._disableSelection = function(/*DomNode*/element){
+	// summary: disable selection on a node
+
+	if(dojo.isMozilla){
+		element.style.MozUserSelect = "none";
+	}else if(dojo.isKhtml){
+		element.style.KhtmlUserSelect = "none"; 
+	}else if(dojo.isIE){
+		element.unselectable = "on";
+	}
+	//FIXME: else?  Opera?
+};

Added: trunk/examples/typeface/root/static/dojo/dijit/bench/create_widgets.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/bench/create_widgets.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/bench/create_widgets.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>PROGRAMMATIC - Dojo Widget Creation Test</title>
+		<script type="text/javascript" src="../../dojo/dojo.js"></script>
+		<script type="text/javascript" src="../dijit.js"></script>
+		<script type="text/javascript">
+			var queryCount = location.search.match(/count=(\d*)/);
+			var count = (queryCount ? parseInt(queryCount[1]) : 100);
+			var queryClass = location.search.match(/class=([a-zA-z.]*)/);
+			var className = (queryClass ? queryClass[1] : "form.Button");
+
+			dojo.require("dijit." + className);
+			dojo.require("dijit.util.parser");
+			logMessage = window.alert;
+		</script>
+		<style type="text/css">
+			@import "../themes/tundra/tundra.css";
+			/* group multiple buttons in a row */
+			.box {
+				display: block;
+				text-align: center;
+			}
+			.box .dojoButton {
+				width: 80px;
+				margin-right: 10px;
+			}
+			.dojoButtonContents {
+				font-size: 1.6em;
+			}
+
+			#buttonContainer {
+				border: 1px solid black;
+				width: 100%;
+			}
+
+			#results {
+				color: darkred;
+			}
+		</style>
+	</head>
+	<body class=tundra>
+		<script language='javascript'>
+			document.write("<h2>Currently Creating "+count+" "+className+" instances</h2>");
+		</script>
+		Pass <code>?count=<i><b>100</b></i></code> in the query string to change the number of widgets.<br>
+		Pass <code>?class=<i><b>form.Button</b></i></code> in the query string to change the widget class.
+		<h3 id="results"></h3>
+
+		<div id="buttonContainer" class='box'></div>
+		<br>
+		<script type="text/javascript">
+			// See if we can make a widget in script and attach it to the DOM ourselves.
+			var constructor = dojo.getObject("dijit."+className);
+			function makeEm(){
+				var container = dojo.byId("buttonContainer");
+				var t0 = new Date().getTime();
+				for (var i = 1; i <= count; i++) {
+					var it = 
+						new constructor(
+								{caption:"Button "+i, onclick:'logMessage("clicked simple")'}
+							);
+					container.appendChild(it.domNode);
+					it.domNode.style.display = '';
+				}
+				var t1 = new Date().getTime();
+				dojo.byId("results").innerHTML = "It took " + (t1 - t0) + " msec to create " + count + " "+className+" instances programmatically.";
+			}
+			dojo.addOnLoad(makeEm);
+		</script>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/bench/parse_widgets.php
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/bench/parse_widgets.php	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/bench/parse_widgets.php	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+
+<html>
+	<head>
+		<title>PARSE - Dojo Widget Instantiation Test</title>
+		<script type="text/javascript" src="../../dojo/dojo.js"></script>
+		<script type="text/javascript" src="../dijit.js"></script>
+		<script type="text/javascript">
+			<?
+				$count  		= (array_key_exists('count', $_GET)   ? $_GET['count'] : 100);
+				$className  	= (array_key_exists('class', $_GET)   ? $_GET['class'] : 'form.Button');
+				
+				echo 	"dojo.require('dijit.$className');";
+				echo	"var count = $count;";
+				echo	"var className = '$className';";
+			?>
+
+			// start the timer right before the parser is loaded
+			dojo._loaders.unshift(function(){
+				// start the timer
+				t0 = new Date().getTime();
+			});
+			dojo.require("dijit.util.parser");
+			// this should end the timer right AFTER the parser finishes
+			dojo.addOnLoad(
+				function(){
+					var t1 = new Date().getTime();
+					dojo.byId("results").innerHTML = "It took " + (t1 - t0) + " msec to parse (and create) " + count + " " + className + " instances.";
+				}
+			);
+			logMessage = window.alert;
+		</script>
+
+		<style type="text/css">
+			
+			@import "../themes/tundra/tundra.css";
+
+			#widgetContainer {
+				border:1px solid black;
+				width:100%;
+			}
+
+			#results {
+				color:darkred;
+			}
+
+		</style>
+	</head>
+	<body class=tundra>
+	<?
+		echo	"<h2>Currently Parsing $count $className instances</h2>";
+		echo 	"Pass <code>?count=<i><b>100</b></i></code> in the query string to change the number of widgets.<br>";
+		echo 	"Pass <code>?class=<i><b>form.Button</b></i></code> in the query string to change the widget class.";
+	?>
+	<h3 id="results"></h3>
+	<div id="widgetContainer" class='box'>
+	<?
+		for($i=1; $i <= $count; $i++){
+			echo "<div dojoType='dijit.$className'>$className $i </div>";
+		}
+	?>
+	</div><br>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/bench/test_Button-parse.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/bench/test_Button-parse.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/bench/test_Button-parse.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,181 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+        <head>
+		<title>PARSE - Dojo Button Instantiate 100 Test</title>
+	<script type="text/javascript" src="../../dojo/dojo.js" XdjConfig='isDebug: true, debugAtAllCosts: true'></script>
+	<script type="text/javascript">
+		dojo.registerModulePath("dijit", "../dijit");
+		dojo.require("dijit.form.Button");
+		// start the timer right before the parser is loaded
+		dojo.addOnLoad(
+			function(){
+				// figure out how many thing's we're dealing with here...
+				var list = dojo.query("button");
+				window.count = list.length;
+				
+				// start the timer
+				window.t0 = new Date().getTime();
+			}
+		);
+		dojo.require("dijit.util.parser");
+		// this should end the timer right AFTER the parser finishes
+		dojo.addOnLoad(
+			function(){
+				window.t1 = new Date().getTime();
+				dojo.byId("results").innerHTML = "It took " + (t1 - t0) + " msec to parse (and create) 100 Buttons programmatically.";
+			}
+		);
+		logMessage = window.alert;
+	</script>
+
+<style>
+	
+	@import "../themes/tundra/tundra.css";
+
+	/* group multiple buttons in a row */
+	.box {
+		display: block;
+		text-align: center;
+	}
+	.box .dojoButton {
+		width:80px;
+		margin-right: 10px;
+	}
+	.dojoButtonContents {
+		font-size: 1.6em;
+	}
+	
+	#buttonContainer {
+		border:1px solid black;
+		width:100%;
+	}
+
+	#results {
+		color:darkred;
+	}
+
+</style>
+        </head>
+<body class=tundra>
+<h2>Parsing simple dijit.form.Buttons:</h2>
+<h3 id="results"></h3>
+
+<div id="buttonContainer" class='box'>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 1</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 2</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 3</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 4</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 5</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 6</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 7</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 8</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 9</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 10</button>
+
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 11</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 12</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 13</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 14</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 15</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 16</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 17</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 18</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 19</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 20</button>
+
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 21</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 22</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 23</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 24</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 25</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 26</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 27</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 28</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 29</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 30</button>
+
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 31</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 32</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 33</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 34</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 35</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 36</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 37</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 38</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 39</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 40</button>
+
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 41</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 42</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 43</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 44</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 45</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 46</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 47</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 48</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 49</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 50</button>
+
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 51</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 52</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 53</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 54</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 54</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 55</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 57</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 58</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 59</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 60</button>
+
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 61</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 62</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 63</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 64</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 64</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 66</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 67</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 68</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 69</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 70</button>
+
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 71</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 72</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 73</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 74</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 75</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 76</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 77</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 78</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 79</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 80</button>
+
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 81</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 82</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 83</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 84</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 85</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 86</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 87</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 88</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 89</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 90</button>
+
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 91</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 92</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 93</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 94</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 95</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 96</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 97</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 98</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 99</button>
+	<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>Button 100</button>
+
+</div>
+
+<br>
+Load the file "test_Button-parse.php?count=<b><i>n</i></b>" to change the number of buttons.
+
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/bench/test_Button-parse.php
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/bench/test_Button-parse.php	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/bench/test_Button-parse.php	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+
+<html>
+        <head>
+		<title>PARSE - Dojo Button Instantiation Test</title>
+	<script type="text/javascript" src="../../dojo/dojo.js" XdjConfig='isDebug: true, debugAtAllCosts: true'></script>
+	<script type="text/javascript">
+		dojo.registerModulePath("dijit", "../dijit");
+		dojo.require("dijit.form.Button");
+		// start the timer right before the parser is loaded
+		dojo.addOnLoad(
+			function(){
+				// figure out how many thing's we're dealing with here...
+				var list = dojo.query("button");
+				window.count = list.length;
+				
+				// start the timer
+				window.t0 = new Date().getTime();
+			}
+		);
+		dojo.require("dijit.util.parser");
+		// this should end the timer right AFTER the parser finishes
+		dojo.addOnLoad(
+			function(){
+				window.t1 = new Date().getTime();
+				dojo.byId("results").innerHTML = "It took " + (t1 - t0) + " msec to parse (and create) " + count + " Buttons programmatically.";
+			}
+		);
+		logMessage = window.alert;
+	</script>
+
+<style>
+	
+	@import "../themes/tundra/tundra.css";
+
+	/* group multiple buttons in a row */
+	.box {
+		display: block;
+		text-align: center;
+	}
+	.box .dojoButton {
+		width:80px;
+		margin-right: 10px;
+	}
+	.dojoButtonContents {
+		font-size: 1.6em;
+	}
+	
+	#buttonContainer {
+		border:1px solid black;
+		width:100%;
+	}
+
+	#results {
+		color:darkred;
+	}
+
+</style>
+        </head>
+<body class=tundra>
+<h2>Parsing simple dijit.form.Buttons!</h2>
+<h3 id="results"></h3>
+
+<div id="buttonContainer" class='box'>
+
+
+<script language="php">
+	$count  = (array_key_exists('count', $_GET)    ? $_GET['count'] : 100);
+	for($i=1; $i <= $count; $i++){
+		echo "<button dojoType='dijit.form.Button' onClick='alert(1)'>Button $i </button>";
+	}
+</script>
+</div>
+
+<br>
+Pass "?count=<i><b>n</b></i>" in the query string to change the number of buttons.
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/bench/test_Button-programmatic.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/bench/test_Button-programmatic.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/bench/test_Button-programmatic.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+        <head>
+		<title>PROGRAMMATIC - Dojo Button 100 Test</title>
+	<script type="text/javascript" src="../../dojo/dojo.js" XdjConfig='isDebug: true, debugAtAllCosts: true'></script>
+	<script type="text/javascript">
+		dojo.registerModulePath("dijit", "../dijit");
+		dojo.require("dijit.form.Button");
+		dojo.require("dijit.util.parser");
+		logMessage = window.alert;
+	</script>
+
+<style>
+	
+	@import "../themes/tundra/tundra.css";
+
+	/* group multiple buttons in a row */
+	.box {
+		display: block;
+		text-align: center;
+	}
+	.box .dojoButton {
+		width:80px;
+		margin-right: 10px;
+	}
+	.dojoButtonContents {
+		font-size: 1.6em;
+	}
+
+	#buttonContainer {
+		border:1px solid black;
+		width:100%;
+	}
+
+	#results {
+		color:darkred;
+	}
+
+</style>
+        </head>
+<body class=tundra>
+<h2>Creating dojot.form.buttons programmatically</h2>
+<h3 id="results"></h3>
+
+<div id="buttonContainer" class='box'></div>
+
+<br>
+Pass "?count=<i><b>n</b></i>" in the query string to change the number of buttons.
+
+<script type="text/javascript">
+// See if we can make a widget in script and attach it to the DOM ourselves.
+
+function makeEm() {
+	var queryCount = location.search.match(/count=(\d*)/);
+	var count = (queryCount ? parseInt(queryCount[1]) : 100);
+	var container = dojo.byId("buttonContainer");
+	var t0 = new Date().getTime();
+	for (var i = 1; i <= count; i++) {
+		var it = 
+			new dijit.form.Button(
+					{caption:"Button "+i, onclick:'logMessage("clicked simple")'}
+				);
+		container.appendChild(it.domNode);
+		it.domNode.style.display = '';
+	}
+	var t1 = new Date().getTime();
+	dojo.byId("results").innerHTML = "It took " + (t1 - t0) + " msec to create " + count + " Buttons programmatically.";
+}
+dojo.addOnLoad(makeEm);
+
+
+</script>
+
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/bench/test_button-results.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/bench/test_button-results.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/bench/test_button-results.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,68 @@
+<html>
+<style>
+	th	{	vertical-align:bottom;	}
+	td {
+		padding:10px;
+		text-align:right;
+	}
+	.computer	{	vertical-align:top;	}
+</style>
+<body>
+<h3>Widget instantiation timing test results</h3>
+
+<table>
+
+<tr><th rowspan=2>Computer/OS</th><th rowspan=2>Browser</th><th colspan=3>Parsing</th><th colspan=3>Programmatic</th></tr>
+<tr>														<th>100</th><th>500</th><th>1000</th><th>100</th><th>500</th><th>1000</th></tr>
+<tr><td class='computer' rowspan=3>MacBook Pro 2.16<br> OS 10.4 2GB RAM</td>
+	<td>FF (2.0.0.3)</td>
+	<td>303</td><td>1724</td><td>3505</td>
+	<td>195</td><td>1006</td><td>2266</td>
+</tr>
+<tr><td>Safari (2.04)</td>
+	<td>192</td><td>1460</td><td>4463</td>
+	<td>142</td><td>895</td><td>2403</td>
+</tr>
+<tr><td>WebKit Nightly (21223)</td>
+	<td>110</td><td>540</td><td>1096</td>
+	<td>85</td><td>458</td><td>940</td>
+</tr>
+
+
+<tr><td class='computer' rowspan=2>Dell Precision 2.13 PPro<br> XP SP 2 - 2GB RAM</td>
+	<td>FF (2.0.0.3)</td>
+	<td>282</td><td>1266</td><td>2484</td>
+	<td>250</td><td>890</td><td>1766</td>
+</tr>
+
+<tr>
+	<td>IE7 (7.0.5730.11)</td>
+	<td>303</td><td>2079</td><td>5172</td>
+	<td>203</td><td>1140</td><td>2422</td>
+</tr>
+
+<tr><td><!--browser--></td>
+	<td><!--100 parse--></td><td><!--500 parse--></td><td><!--1000 parse--></td>
+	<td><!--100 code--></td><td><!--500 code--></td><td><!--1000 code--></td>
+</tr>
+</table>
+
+
+<H3>If you want to play:</H3>
+<p>
+<ol>
+	<li> Run the following tests:
+		<ul>
+			<li><a href='http://dojotoolkit.org/~owen/bench/dojo/dijit/bench/test_Button-parse.php?count=100'>http://dojotoolkit.org/~owen/bench/dojo/dijit/bench/test_Button-parse.php?count=100</a></li>
+			<li><a href='http://dojotoolkit.org/~owen/bench/dojo/dijit/bench/test_Button-programmatic.html?count=100'>http://dojotoolkit.org/~owen/bench/dojo/dijit/bench/test_Button-programmatic.html?count=100</a></li>
+		</ul>
+		<br>
+		Change the "count=" to 100, 500, 1000 for each.
+		<br><br>
+		Restart the browser between each test/count.  Run each test 3 times and record the smallest number.
+	</li>
+	<li>Record your tests in the copy of this file in SVN:  <code>dijit/bench/test_Button-results.html</code>  and check it in.  Reference ticket #2968.
+</ol>
+</p>
+
+</body>

Added: trunk/examples/typeface/root/static/dojo/dijit/bench/widget_construction_test.php
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/bench/widget_construction_test.php	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/bench/widget_construction_test.php	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,186 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+
+<html>
+	<head>
+		<title>test of various synchronous page searching methods</title>
+		<style type="text/css">
+			@import "../../dojo/resources/dojo.css";
+			@import "../themes/tundra/tundra.css";
+		</style>
+		<script type="text/javascript" src="../../dojo/dojo.js"
+			djConfig="isDebug: true, debugAtAllCosts: true"></script>
+		<script type="text/javascript">
+			dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+			dojo.require("dijit.base.Widget");
+			dojo.require("dijit.base.TemplatedWidget");
+
+			/* dummy widget for benchmarking purposes */
+			dojo.declare(
+				"dijit.Button",
+				[ dijit.base.Widget, dijit.base.TemplatedWidget ],
+				function(){  },
+				{
+					caption: "",
+			
+					templateString: "<button dojoAttachEvent='onclick:onClick'>${caption}</button>",
+			
+					onClick: function(){
+						this.domNode.style.backgroundColor="green";
+					},
+					postCreate: function(){
+					}
+				}
+			);
+		</script>
+	</head>
+	<body>
+		<h1 style="font-size: 40px; line-height: 50px;">This page contains a huge number of nodes, most of which are "chaff".</h1>
+		<h3>Here's the relative timings for this page</h3>
+		<div id="profileOutputTable"></div>
+		<!--
+		<h3>And some comparison data</h3>
+		<table border=1>
+		<thead>
+			<tr>
+				<th>IE
+				<th>Safari
+				<th>Gecko (on PC)
+				<th>Gecko (on intel mac)
+			</tr>
+		</thead>
+		<tbody>
+			<tr>
+				<td>4890
+				<td>3242
+				<td>3094
+				<td>3782
+			</tr>
+		</tbody>
+		</table>
+		-->
+
+
+<?
+	$containerDepth = 30;
+	$leadingChaff = 100;
+	$trailingChaff = 100;
+	$items = 100;
+?>
+<? 
+	function generateChaff($iters){
+		for($i=0;$i<$iters;$i++){ ?>
+			<pre class="highlighted"><code><span class="hl-reserved">var </span><span class="hl-identifier">dlg</span><span class="hl-default"> = </span><span class="hl-reserved">new </span><span class="hl-identifier">blah</span><span class="hl-default">.</span><span class="hl-identifier">ext</span><span class="hl-default">.</span><span class="hl-identifier">LayoutDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">config</span><span class="hl-code">.</span><span class="hl-identifier">id</span><span class="hl-code"> || </span><span class="hl-identifier">blah</span><span class="hl-code">.</span><span class="hl-identifier">util</span><span class="hl-code">.</span><span class="hl-identifier">Dom</span><span class="hl-code">.</span><span class="hl-identifier">generateId</span><span class="hl-brackets">()</span><span class="hl-code">, </span><span class="hl-brackets">{
+				</span><span title="autoCreate" class="hl-identifier">autoCreate</span><span class="hl-code"> : </span><span class="hl-reserved">true</span><span class="hl-code">,
+				</span><span title="minWidth" class="hl-identifier">minWidth</span><span class="hl-code">:</span><span class="hl-number">400</span><span class="hl-code">,
+				</span><span title="minHeight" class="hl-identifier">minHeight</span><span class="hl-code">:</span><span class="hl-number">300</span><span class="hl-code">,
+				</span>
+				<span title="syncHeightBeforeShow" class="hl-identifier">syncHeightBeforeShow</span><span class="hl-code">: </span><span class="hl-reserved">true</span><span class="hl-code">,
+				</span><span title="shadow" class="hl-identifier">shadow</span><span class="hl-code">:</span><span class="hl-reserved">true</span><span class="hl-code">,
+				</span><span title="fixedcenter" class="hl-identifier">fixedcenter</span><span class="hl-code">: </span><span class="hl-reserved">true</span><span class="hl-code">,
+				</span><span title="center" class="hl-identifier">center</span><span class="hl-code">:</span><span class="hl-brackets">{</span><span class="hl-identifier">autoScroll</span><span class="hl-code">:</span><span class="hl-reserved">false</span><span class="hl-brackets">}</span><span class="hl-code">,
+				</span><span title="east"  class="hl-identifier">east</span><span class="hl-code">:</span><span class="hl-brackets">{</span><span class="hl-identifier">split</span><span class="hl-code">:</span><span class="hl-reserved">true</span><span class="hl-code">,</span><span class="hl-identifier">initialSize</span><span class="hl-code">:</span><span class="hl-number">150</span><span class="hl-code">,</span><span class="hl-identifier">minSize</span><span class="hl-code">:</span><span class="hl-number">150</span><span class="hl-code">,</span><span class="hl-identifier">maxSize</span><span class="hl-code">:</span><span class="hl-number">250</span><span class="hl-brackets">}
+			})</span><span class="hl-default">;
+			</span><span class="hl-identifier">dlg</span><span class="hl-default">.</span><span class="hl-identifier">setTitle</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">Choose an Image</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-default">;
+			</span><span class="hl-identifier">dlg</span><span class="hl-default">.</span><span class="hl-identifier">getEl</span><span class="hl-brackets">()</span><span class="hl-default">.</span><span class="hl-identifier">addClass</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">ychooser-dlg</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-default">;</span></code></pre><br />
+			<pre class="highlighted"><code><span class="hl-reserved">var </span><span class="hl-identifier">animated</span><span class="hl-default"> = </span><span class="hl-reserved">new </span><span class="hl-identifier">blah</span><span class="hl-default">.</span><span class="hl-identifier">ext</span><span class="hl-default">.</span><span class="hl-identifier">Resizable</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">animated</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-brackets">{
+			    </span><span title="east" class="hl-identifier">width</span><span class="hl-code">: </span><span class="hl-number">200</span><span class="hl-code">,
+			    </span><span title="east" class="hl-identifier">height</span><span class="hl-code">: </span><span class="hl-number">100</span><span class="hl-code">,
+			    </span><span title="east" class="hl-identifier">minWidth</span><span class="hl-code">:</span><span class="hl-number">100</span><span class="hl-code">,
+			    </span><span class="hl-identifier">minHeight</span><span class="hl-code">:</span><span class="hl-number">50</span><span class="hl-code">,
+			    </span><span class="hl-identifier">animate</span><span class="hl-code">:</span><span class="hl-reserved">true</span><span class="hl-code">,
+			    </span><span class="hl-identifier">easing</span><span class="hl-code">: </span><span class="hl-identifier">YAHOO</span><span class="hl-code">.</span><span class="hl-identifier">util</span><span class="hl-code">.</span><span class="hl-identifier">Easing</span><span class="hl-code">.</span><span class="hl-identifier">backIn</span><span class="hl-code">,
+			    </span><span class="hl-identifier">duration</span><span class="hl-code">:</span><span class="hl-number">.6
+			</span><span class="hl-brackets">})</span><span class="hl-default">;</span></code></pre>
+			<h4>The standard Lorem Ipsum passage, used since the 1500s</h4>
+			<p>
+			"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
+			eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
+			ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
+			aliquip ex ea commodo consequat. Duis aute irure dolor in
+			reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
+			pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
+			culpa qui officia deserunt mollit anim id est laborum."
+			</p>
+
+			<h4>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</h4>
+
+			<p>
+			"Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+			accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
+			quae ab illo inventore veritatis et quasi architecto beatae vitae
+			dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
+			aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
+			eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam
+			est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
+			velit, sed quia non numquam eius modi tempora incidunt ut labore et
+			dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,
+			quis nostrum exercitationem ullam corporis suscipit laboriosam,
+			nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure
+			reprehenderit qui in ea voluptate velit esse quam nihil molestiae
+			consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
+			pariatur?"
+			</p>
+
+			<h4>1914 translation by H. Rackham</h4>
+
+			<p>
+			"But I must explain to you how all this mistaken idea of denouncing
+			pleasure and praising pain was born and I will give you a complete
+			account of the system, and expound the actual teachings of the
+			great explorer of the truth, the master-builder of human happiness.
+			No one rejects, dislikes, or avoids pleasure itself, because it is
+			pleasure, but because those who do not know how to pursue pleasure
+			rationally encounter consequences that are extremely painful. Nor
+			again is there anyone who loves or pursues or desires to obtain
+			pain of itself, because it is pain, but because occasionally
+			circumstances occur in which toil and pain can procure him some
+			great pleasure. To take a trivial example, which of us ever
+			undertakes laborious physical exercise, except to obtain some
+			advantage from it? But who has any right to find fault with a man
+			who chooses to enjoy a pleasure that has no annoying consequences,
+			or one who avoids a pain that produces no resultant pleasure?" 
+			</p>
+		<? } 
+	} // end generateChaff
+	$widgetName = "dijit.Button";
+?>
+<? generateChaff($leadingChaff); ?>
+<hr>
+<? for($i=0;$i<$containerDepth;$i++){ ?>
+	<table border="1" cellpadding="0" cellspacing="0" width="100%">
+	<!--
+	<table>
+	-->
+		<tr>
+			<td>
+			<br>
+			chaff!
+			<br>
+<? } ?>
+<? for($i=0;$i<$items;$i++){ ?>
+			<div dojoType="<?= $widgetName ?>" caption="item2 <?= $i ?>">item2 <?= $i ?></div>
+<? } ?>
+<? for($i=0;$i<$containerDepth;$i++){ ?>
+			</td>
+		</tr>
+	</table>
+<? } ?>
+<? generateChaff($trailingChaff);  ?>
+<? for($i=0;$i<$items;$i++){ ?>
+	<div dojoType="<?= $widgetName ?>" caption="item2 <?= $i ?>"><span>item <?= $i ?></span></div>
+<? } ?>
+
+<script type="text/javascript">
+
+		oldTime = new Date();
+		dojo.addOnLoad(function(){
+			var time = new Date().getTime() - oldTime;
+			var p = document.createElement("p");
+			alert("Widgets loaded in " + time + "ms");
+		});
+
+</script>
+
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/changes.txt
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/changes.txt	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/changes.txt	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,87 @@
+Changes from Dojo 0.4 dojo.widgets to new dijit project
+=======================================================
+
+The widgets and widget infrastructure have been separated into separate project,
+vastly streamlined and with a new directory structure.   There are many other changes.
+
+Markup
+------
+
+dojoType="button" replaced by dojoType="dijit.Button"  Must use fully qualified class name,
+and it's case-sensitive.
+
+Need to manually dojo.require("dijit.util.parser") to get parsing
+
+Widget namespaces and widget auto-loading are desupported.
+
+onClick="foo" now overrides (ie, replaces) the default onClick() function rather than attaching to it,
+so widget designers should make empty onClick() functions (when appropriate).
+
+Programmatic creation
+---------------------
+Create widgets via
+
+	new dijit.Button(params, srcNodeRef)
+
+createWidget() call removed since multiple renderers are no longer supported (see next section).
+
+At least for the dijit widgets, all widgets are guaranteed to work programatically, which in
+effect means that all widgets must have templates, unless the default <div> works.
+
+Renderers
+---------
+Removed support for multiple renderers (svg & vml & a11y) for a single widget.
+If a widget wants to render differently on different platforms, there must be
+branching code inside the widget, or it needs to call a library that branches
+based on the browser type (like dojo.gfx or dojo.charting).
+
+
+Templates
+---------
+"this." is no longer used within ${} substitution notation.  See ticket #2905.
+dojoRoot,buildScriptBase,dojoModuleUrl are no longer supported, but
+any JavaScript properties on the widget's 'this' may be referenced with dotted notation.
+The attributes dojoOn* are desupported (including dojoOnBuild);
+also can't use id attribute to affect a dojoAttachPoint.
+
+dojoAttachEvent is case sensitive, so capitalization matters.   You will probably have
+to change
+
+dojoAttachEvent="onClick"
+
+to
+
+dojoAttachEvent="onclick: onClick"
+
+(given that the event name is lowercase, and assuming that the method name is camel case)
+
+Parent/Child relationships
+--------------------------
+By default widgets exist as islands, not knowing about their parent widget or children widgets.
+The exception is the destroy() function which will also delete all descendant widgets.
+Some widgets like Tree and SplitContainer will know about their children, but those widgets
+will use the special mixins in Container.js / Layout.js. 
+
+Widget.js base class
+--------------------
+
+ - Widget.js, Domwidget.js, HtmlWidget.js combined into dijit.base.Widget, with TemplatedWidget mixin
+for widgets with templates
+
+ - on widget creation, postMixInProperties(), buildRendering() and postCreate() is called.
+ fillInTemplate() is no longer called.  In addition, those functions call signatures have changed.
+ No arguments are passed.  To get the source dom Node, just reference this.srcDomNode.
+When postCreate() is called the widget children don't yet exist.
+
+ - The TemplatedWidget mixin defines buildRendering().  widgetsInTemplate not ported yet.
+
+ - onResized() removed
+
+ - the whole parent/child relationship thing is gone
+
+ - extraArgs[] is gone
+
+ - postCreate() called but child widgets don't exist yet
+
+ - templateCssPath ignored.   User must manually include tundra.css file
+ 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dijit/dijit.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/dijit.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/dijit.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,1369 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+/*
+	This is a compiled version of Dojo, built for deployment and not for
+	development. To get an editable version, please visit:
+
+		http://dojotoolkit.org
+
+	for documentation and information on getting the source.
+*/
+
+dojo.provide("dijit.util.manager");
+dijit.util.manager=new function(){
+var _1={};
+var _2={};
+this.getUniqueId=function(_3){
+var _4;
+do{
+_4=_3+"_"+(_2[_3]!==undefined?++_2[_3]:_2[_3]=0);
+}while(_1[_4]);
+return _4;
+};
+this.add=function(_5){
+if(!_5.id){
+_5.id=this.getUniqueId(_5.declaredClass.replace(".","_"));
+}
+_1[_5.id]=_5;
+};
+this.remove=function(id){
+delete _1.id;
+};
+this.destroyAll=function(){
+for(var id in _1){
+_1[id].destroy();
+}
+};
+this.getWidgets=function(){
+return _1;
+};
+this.byNode=function(_8){
+return _1[_8.widgetId];
+};
+};
+dojo.addOnUnload(function(){
+dijit.util.manager.destroyAll();
+});
+dijit.byId=function(id){
+return dijit.util.manager.getWidgets()[id];
+};
+dojo.provide("dijit.base.Widget");
+dojo.declare("dijit.base.Widget",null,function(_a,_b){
+this.srcNodeRef=dojo.byId(_b);
+this._connects=[];
+if(this.srcNodeRef&&(typeof this.srcNodeRef.id=="string")){
+this.id=this.srcNodeRef.id;
+}
+if(_a){
+dojo.mixin(this,_a);
+}
+this.postMixInProperties();
+dijit.util.manager.add(this);
+this.buildRendering();
+if(this.domNode){
+this.domNode.widgetId=this.id;
+if(this.srcNodeRef&&this.srcNodeRef.dir){
+this.domNode.dir=this.srcNodeRef.dir;
+}
+}
+this.postCreate();
+if(this.srcNodeRef&&!this.srcNodeRef.parentNode){
+delete this.srcNodeRef;
+}
+},{id:"",lang:"",dir:"",srcNodeRef:null,domNode:null,postMixInProperties:function(){
+},buildRendering:function(){
+this.domNode=this.srcNodeRef;
+},postCreate:function(){
+},startup:function(){
+},destroyRecursive:function(_c){
+this.destroyDescendants();
+this.destroy();
+},destroy:function(_d){
+this.uninitialize();
+dojo.forEach(this._connects,dojo.disconnect);
+this.destroyRendering(_d);
+dijit.util.manager.remove(this.id);
+},destroyRendering:function(_e){
+if(this.bgIframe){
+this.bgIframe.remove();
+delete this.bgIframe;
+}
+if(this.domNode){
+if(this.domNode.parentNode){
+this.domNode.parentNode.removeChild(this.domNode);
+}
+delete this.domNode;
+}
+if(this.srcNodeRef&&this.srcNodeRef.parentNode){
+this.srcNodeRef.parentNode.removeChild(this.srcNodeRef);
+delete this.srcNodeRef;
+}
+},destroyDescendants:function(){
+dojo.forEach(this.getDescendants(),function(_f){
+_f.destroy();
+});
+},uninitialize:function(){
+return false;
+},toString:function(){
+return "[Widget "+this.declaredClass+", "+(this.id||"NO ID")+"]";
+},getDescendants:function(){
+var _10=this.domNode.all||this.domNode.getElementsByTagName("*");
+var i=0,_12;
+var _13=[];
+while((_12=_10[i++])){
+var id=_12.widgetId;
+if(id){
+_13.push(dijit.byId(id));
+}
+}
+return _13;
+},connect:function(obj,_16,_17){
+this._connects.push(dojo.connect(obj,_16,this,_17));
+},isLeftToRight:function(){
+if(typeof this._ltr=="undefined"){
+this._ltr=(this.dir||dojo.getComputedStyle(this.domNode).direction)!="rtl";
+}
+return this._ltr;
+}});
+dijit._disableSelection=function(_18){
+if(dojo.isMozilla){
+_18.style.MozUserSelect="none";
+}else{
+if(dojo.isKhtml){
+_18.style.KhtmlUserSelect="none";
+}else{
+if(dojo.isIE){
+_18.unselectable="on";
+}
+}
+}
+};
+dojo.provide("dijit.base.Container");
+dojo.declare("dijit.base.Contained",null,{getParent:function(){
+for(var p=this.domNode.parentNode;p;p=p.parentNode){
+var _1a=p.widgetId;
+if(_1a){
+return dijit.byId(_1a);
+}
+}
+return null;
+},_getSibling:function(_1b){
+var _1c=this.domNode;
+do{
+_1c=_1c[_1b+"Sibling"];
+}while(_1c&&_1c.nodeType!=1);
+if(!_1c){
+return null;
+}
+var id=_1c.widgetId;
+return dijit.byId(id);
+},getPreviousSibling:function(){
+return this._getSibling("previous");
+},getNextSibling:function(){
+return this._getSibling("next");
+}});
+dojo.declare("dijit.base.Container",null,{isContainer:true,addChild:function(_1e,_1f){
+var _20=this.containerNode||this.domNode;
+if(typeof _1f=="undefined"){
+dojo.place(_1e.domNode,_20,"last");
+}else{
+dojo.place(_1e.domNode,_20,_1f);
+}
+},removeChild:function(_21){
+var _22=_21.domNode;
+_22.parentNode.removeChild(_22);
+},_nextElement:function(_23){
+do{
+_23=_23.nextSibling;
+}while(_23&&_23.nodeType!=1);
+return _23;
+},_firstElement:function(_24){
+_24=_24.firstChild;
+if(_24&&_24.nodeType!=1){
+_24=this._nextElement(_24);
+}
+return _24;
+},getChildren:function(){
+var res=[];
+var cn=this.containerNode||this.domNode;
+var _27=this._firstElement(cn);
+while(_27){
+var tmp=dijit.byId(_27.widgetId);
+if(tmp){
+res.push(tmp);
+}
+_27=this._nextElement(_27);
+}
+return res;
+},hasChildren:function(){
+var cn=this.containerNode||this.domNode;
+return !!this._firstElement(cn);
+}});
+dojo.provide("dijit.base.Layout");
+dojo.declare("dijit.base.Sizable",null,{resize:function(mb){
+var _2b=this.domNode;
+if(mb){
+dojo.marginBox(_2b,mb);
+if(mb.t){
+_2b.style.top=mb.t+"px";
+}
+if(mb.l){
+_2b.style.left=mb.l+"px";
+}
+}
+mb=dojo.marginBox(_2b);
+this._contentBox=dijit.base.Layout.marginBox2contentBox(_2b,mb);
+this.layout();
+},layout:function(){
+}});
+dojo.declare("dijit.base.Layout",[dijit.base.Sizable,dijit.base.Container,dijit.base.Contained,dijit.base.Showable],{isLayoutContainer:true,startup:function(){
+if(this._started){
+return;
+}
+this._started=true;
+if(this.getChildren){
+dojo.forEach(this.getChildren(),function(_2c){
+_2c.startup();
+});
+}
+if(!this.getParent||!this.getParent()){
+this.resize();
+this.connect(window,"onresize","resize");
+}
+}});
+dijit.base.Layout.marginBox2contentBox=function(_2d,mb){
+var cs=dojo.getComputedStyle(_2d);
+var me=dojo._getMarginExtents(_2d,cs);
+var pb=dojo._getPadBorderExtents(_2d,cs);
+return {l:dojo._toPixelValue(this.containerNode,cs.paddingLeft),t:dojo._toPixelValue(this.containerNode,cs.paddingTop),w:mb.w-(me.w+pb.w),h:mb.h-(me.h+pb.h)};
+};
+dijit.base.Layout.layoutChildren=function(_32,dim,_34,_35){
+dojo.addClass(_32,"dijitLayoutContainer");
+_34=dojo.filter(_34,function(_36,idx){
+_36.idx=idx;
+return dojo.indexOf(["top","bottom","left","right","client","flood"],_36.layoutAlign)>-1;
+});
+if(_35&&_35!="none"){
+var _38=function(_39){
+switch(_39.layoutAlign){
+case "flood":
+return 1;
+case "left":
+case "right":
+return (_35=="left-right")?2:3;
+case "top":
+case "bottom":
+return (_35=="left-right")?3:2;
+default:
+return 4;
+}
+};
+_34.sort(function(a,b){
+return (_38(a)-_38(b))||(a.idx-b.idx);
+});
+}
+var ret=true;
+dojo.forEach(_34,function(_3d){
+var elm=_3d.domNode;
+var pos=_3d.layoutAlign;
+var _40=elm.style;
+_40.left=dim.l+"px";
+_40.top=dim.t+"px";
+_40.bottom=_40.right="auto";
+var _41=function(_42){
+return _42.substring(0,1).toUpperCase()+_42.substring(1);
+};
+dojo.addClass(elm,"dijitAlign"+_41(pos));
+if(pos=="top"||pos=="bottom"){
+if(_3d.resize){
+_3d.resize({w:dim.w});
+}else{
+dojo.marginBox(elm,{w:dim.w});
+}
+var h=dojo.marginBox(elm).h;
+dim.h-=h;
+dojo.mixin(_3d,{w:dim.w,h:h});
+if(pos=="top"){
+dim.t+=h;
+}else{
+_40.top=dim.t+dim.h+"px";
+}
+}else{
+if(pos=="left"||pos=="right"){
+var w=dojo.marginBox(elm).w;
+var _45=dijit.base.Layout._sizeChild(_3d,elm,w,dim.h);
+if(_45){
+ret=false;
+}
+dim.w-=w;
+if(pos=="left"){
+dim.l+=w;
+}else{
+_40.left=dim.l+dim.w+"px";
+}
+}else{
+if(pos=="flood"||pos=="client"){
+var _45=dijit.base.Layout._sizeChild(_3d,elm,dim.w,dim.h);
+if(_45){
+ret=false;
+}
+}
+}
+}
+});
+return ret;
+};
+dijit.base.Layout._sizeChild=function(_46,elm,w,h){
+var box={};
+var _4b=(w==0||h==0);
+if(!_4b){
+if(w!=0){
+box.w=w;
+}
+if(h!=0){
+box.h=h;
+}
+if(_46.resize){
+_46.resize(box);
+}else{
+dojo.marginBox(elm,box);
+}
+}
+dojo.mixin(_46,box);
+return _4b;
+};
+dojo.provide("dijit.base.Showable");
+dojo.declare("dijit.base.Showable",null,{isShowing:function(){
+return dojo.style(this.domNode,"display")!="none";
+},toggleShowing:function(){
+if(this.isShowing()){
+this.hide();
+}else{
+this.show();
+}
+},show:function(){
+if(this.isShowing()){
+return;
+}
+this.domNode.style.display="";
+this.onShow();
+},onShow:function(){
+},hide:function(){
+if(!this.isShowing()){
+return;
+}
+this.domNode.style.display="none";
+this.onHide();
+},onHide:function(){
+}});
+dojo.provide("dijit.util.sniff");
+(function(){
+var d=dojo;
+var ie=d.isIE;
+var _4e=d.isOpera;
+var maj=Math.floor;
+var _50={dj_ie:ie,dj_ie6:maj(ie)==6,dj_ie7:maj(ie)==7,dj_iequirks:ie&&d.isQuirks,dj_opera:_4e,dj_opera8:maj(_4e)==8,dj_opera9:maj(_4e)==9,dj_khtml:d.isKhtml,dj_safari:d.isSafari,dj_gecko:d.isMozilla};
+for(var p in _50){
+if(_50[p]){
+var _52=dojo.doc.documentElement;
+if(_52.className){
+_52.className+=" "+p;
+}else{
+_52.className=p;
+}
+}
+}
+})();
+dojo.provide("dijit.util.wai");
+dijit.util.waiNames=["waiRole","waiState"];
+dijit.util.wai={waiRole:{name:"waiRole","namespace":"http://www.w3.org/TR/xhtml2",alias:"x2",prefix:"wairole:"},waiState:{name:"waiState","namespace":"http://www.w3.org/2005/07/aaa",alias:"aaa",prefix:""},setAttr:function(_53,ns,_55,_56){
+if(dojo.isIE){
+_53.setAttribute(this[ns].alias+":"+_55,this[ns].prefix+_56);
+}else{
+_53.setAttributeNS(this[ns]["namespace"],_55,this[ns].prefix+_56);
+}
+},getAttr:function(_57,ns,_59){
+if(dojo.isIE){
+return _57.getAttribute(this[ns].alias+":"+_59);
+}else{
+return _57.getAttributeNS(this[ns]["namespace"],_59);
+}
+},removeAttr:function(_5a,ns,_5c){
+var _5d=true;
+if(dojo.isIE){
+_5d=_5a.removeAttribute(this[ns].alias+":"+_5c);
+}else{
+_5a.removeAttributeNS(this[ns]["namespace"],_5c);
+}
+return _5d;
+},imageBgToSrc:function(_5e){
+if(!dojo.isArrayLike(_5e)){
+_5e=[_5e];
+}
+dojo.forEach(_5e,function(_5f){
+var _60=_5f&&dojo.getComputedStyle(_5f);
+if(!_60){
+return;
+}
+var _61=_60.backgroundImage.match(/url\(['"]?(.*?)['"]?\)/);
+if(!_61){
+return;
+}
+_5f.src=_61[1];
+_5f.style.backgroundImage="none";
+});
+}};
+dojo._loaders.unshift(function(){
+var div=document.createElement("div");
+div.id="a11yTestNode";
+dojo.body().appendChild(div);
+function check(){
+var cs=dojo.getComputedStyle(div);
+var _64=cs.backgroundImage;
+var _65=(cs.borderTopColor==cs.borderRightColor)||(_64!=null&&(_64=="none"||_64=="url(invalid-url:)"));
+dojo[_65?"addClass":"removeClass"](dojo.body(),"dijit_a11y");
+};
+if(dojo.isIE||dojo.isMoz){
+check();
+if(dojo.isIE){
+setInterval(check,4000);
+}
+}
+});
+dojo.provide("dijit.base.FormElement");
+dojo.declare("dijit.base.FormElement",dijit.base.Widget,{baseClass:"",value:"",name:"",id:"",alt:"",type:"text",tabIndex:"0",disabled:false,enable:function(){
+this._setDisabled(false);
+},disable:function(){
+this._setDisabled(true);
+},_setDisabled:function(_66){
+this.domNode.disabled=this.disabled=_66;
+if(this.focusNode){
+this.focusNode.disabled=_66;
+}
+dijit.util.wai.setAttr(this.focusNode||this.domNode,"waiState","disabled",_66);
+this.setStateClass(null,this.domNode);
+},setStateClass:function(_67,_68,_69){
+if(_68==null){
+_68=this.domNode;
+}
+if(_67){
+dojo.stopEvent(_67);
+}
+var _6a=_68.getAttribute("baseClass")||this.baseClass||(this.baseClass="dijit"+this.declaredClass.replace(/.*\./g,""));
+if(this.disabled){
+dojo.removeClass(this.domNode,_6a+"Enabled");
+dojo.removeClass(this.domNode,_6a+"Hover");
+dojo.removeClass(this.domNode,_6a+"Active");
+dojo.addClass(this.domNode,_6a+"Disabled");
+}else{
+if(_67){
+switch(_67.type){
+case "mouseover":
+_68._hovering=true;
+break;
+case "mouseout":
+_68._hovering=false;
+break;
+case "mousedown":
+_68._active=true;
+var _6b=this;
+var _6c=function(_6d){
+_6b.setStateClass(_6d,_68);
+};
+_68._mouseUpConnector=dojo.connect(dojo.global,"onmouseup",this,_6c);
+break;
+case "mouseup":
+_68._active=false;
+if(this._mouseUpConnector){
+dojo.disconnect(_68._mouseUpConnector);
+_68._mouseUpConnector=false;
+}
+break;
+case "click":
+this.onClick(_67);
+break;
+}
+}
+dojo.removeClass(this.domNode,_6a+"Disabled");
+dojo.toggleClass(this.domNode,_6a+"Active",_68._active==true);
+dojo.toggleClass(this.domNode,_6a+"Hover",_68._hovering==true&&_68._active!=true);
+dojo.addClass(this.domNode,_6a+"Enabled");
+}
+},onValueChanged:function(_6e){
+},postCreate:function(){
+this._setDisabled(this.disabled==true);
+},_lastValueReported:null,setValue:function(_6f){
+if(_6f!=this._lastValueReported){
+this._lastValueReported=_6f;
+dijit.util.wai.setAttr(this.focusNode||this.domNode,"waiState","valuenow",_6f);
+this.onValueChanged(_6f);
+}
+},getValue:function(){
+return this._lastValueReported;
+}});
+dojo.provide("dojo.string");
+dojo.string.pad=function(_70,_71,ch,end){
+var out=String(_70);
+if(!ch){
+ch="0";
+}
+while(out.length<_71){
+if(end){
+out+=ch;
+}else{
+out=ch+out;
+}
+}
+return out;
+};
+dojo.string.substitute=function(_75,map,_77,_78){
+return _75.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,function(_79,key,_7b){
+var _7c=dojo.getObject(key,false,map);
+if(_7b){
+_7c=dojo.getObject(_7b,false,_78)(_7c);
+}
+if(_77){
+_7c=_77(_7c);
+}
+return _7c.toString();
+});
+};
+dojo.provide("dojo.date.stamp");
+dojo.date.stamp.setIso8601=function(_7d,_7e){
+var _7f=(_7e.indexOf("T")==-1)?_7e.split(" "):_7e.split("T");
+_7d=dojo.date.stamp.setIso8601Date(_7d,_7f[0]);
+if(_7f.length==2){
+_7d=dojo.date.stamp.setIso8601Time(_7d,_7f[1]);
+}
+return _7d;
+};
+dojo.date.stamp.fromIso8601=function(_80){
+return dojo.date.stamp.setIso8601(new Date(0,0),_80);
+};
+dojo.date.stamp.setIso8601Date=function(_81,_82){
+var _83="^([0-9]{4})((-?([0-9]{2})(-?([0-9]{2}))?)|"+"(-?([0-9]{3}))|(-?W([0-9]{2})(-?([1-7]))?))?$";
+var d=_82.match(new RegExp(_83));
+if(!d){
+console.debug("invalid date string: "+_82);
+return null;
+}
+var _85=d[1];
+var _86=d[4];
+var _87=d[6];
+var _88=d[8];
+var _89=d[10];
+var _8a=d[12]||1;
+_81.setFullYear(_85);
+if(_88){
+_81.setMonth(0);
+_81.setDate(Number(_88));
+}else{
+if(_89){
+_81.setMonth(0);
+_81.setDate(1);
+var day=_81.getDay()||7;
+var _8c=Number(_8a)+(7*Number(_89));
+if(day<=4){
+_81.setDate(_8c+1-day);
+}else{
+_81.setDate(_8c+8-day);
+}
+}else{
+if(_86){
+_81.setDate(1);
+_81.setMonth(_86-1);
+}
+if(_87){
+_81.setDate(_87);
+}
+}
+}
+return _81;
+};
+dojo.date.stamp.fromIso8601Date=function(_8d){
+return dojo.date.stamp.setIso8601Date(new Date(0,0),_8d);
+};
+dojo.date.stamp.setIso8601Time=function(_8e,_8f){
+var _90="Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$";
+var d=_8f.match(new RegExp(_90));
+var _92=0;
+if(d){
+if(d[0]!="Z"){
+_92=(Number(d[3])*60)+Number(d[5]||0);
+if(d[2]!="-"){
+_92*=-1;
+}
+}
+_92-=_8e.getTimezoneOffset();
+_8f=_8f.substr(0,_8f.length-d[0].length);
+}
+var _93="^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(.([0-9]+))?)?)?$";
+d=_8f.match(new RegExp(_93));
+if(!d){
+console.debug("invalid time string: "+_8f);
+return null;
+}
+var _94=d[1];
+var _95=Number(d[3]||0);
+var _96=d[5]||0;
+var ms=d[7]?(Number("0."+d[7])*1000):0;
+_8e.setHours(_94);
+_8e.setMinutes(_95);
+_8e.setSeconds(_96);
+_8e.setMilliseconds(ms);
+if(_92!==0){
+_8e.setTime(_8e.getTime()+_92*60000);
+}
+return _8e;
+};
+dojo.date.stamp.fromIso8601Time=function(_98){
+return dojo.date.stamp.setIso8601Time(new Date(0,0),_98);
+};
+dojo.date.stamp.toRfc3339=function(_99,_9a){
+_99=_99||new Date();
+var _=dojo.string.pad;
+var _9c=[];
+if(_9a!="time"){
+var _9d=[_(_99.getFullYear(),4),_(_99.getMonth()+1,2),_(_99.getDate(),2)].join("-");
+_9c.push(_9d);
+}
+if(_9a!="date"){
+var _9e=[_(_99.getHours(),2),_(_99.getMinutes(),2),_(_99.getSeconds(),2)].join(":");
+var _9f=_99.getTimezoneOffset();
+_9e+=(_9f>0?"-":"+")+_(Math.floor(Math.abs(_9f)/60),2)+":"+_(Math.abs(_9f)%60,2);
+_9c.push(_9e);
+}
+return _9c.join("T");
+};
+dojo.date.stamp.fromRfc3339=function(_a0){
+_a0=_a0.replace("Tany","");
+return dojo.date.stamp.setIso8601(new Date(),_a0);
+};
+dojo.provide("dijit.util.parser");
+dijit.util.parser=new function(){
+function val2type(_a1){
+if(dojo.isString(_a1)){
+return "string";
+}
+if(typeof _a1=="number"){
+return "number";
+}
+if(typeof _a1=="boolean"){
+return "boolean";
+}
+if(dojo.isFunction(_a1)){
+return "function";
+}
+if(dojo.isArray(_a1)){
+return "array";
+}
+if(_a1 instanceof Date){
+return "date";
+}
+if(_a1 instanceof dojo._Url){
+return "url";
+}
+return "object";
+};
+function str2obj(_a2,_a3){
+switch(_a3){
+case "string":
+return _a2;
+case "number":
+return _a2.length?Number(_a2):null;
+case "boolean":
+return typeof _a2=="boolean"?_a2:!(_a2.toLowerCase()=="false");
+case "function":
+if(dojo.isFunction(_a2)){
+return _a2;
+}
+try{
+if(_a2.search(/[^\w\.]+/i)!=-1){
+_a2=dijit.util.parser._nameAnonFunc(new Function(_a2),this);
+}
+return dojo.getObject(_a2,false);
+}
+catch(e){
+return new Function();
+}
+case "array":
+return _a2.split(";");
+case "date":
+return dojo.date.stamp.fromRfc3339(_a2);
+case "url":
+return dojo.baseUrl+_a2;
+default:
+try{
+eval("var tmp = "+_a2);
+return tmp;
+}
+catch(e){
+return _a2;
+}
+}
+};
+var _a4={};
+function getWidgetClassInfo(_a5){
+if(!_a4[_a5]){
+var cls=dojo.getObject(_a5);
+if(!dojo.isFunction(cls)){
+throw new Error("Could not load widget '"+_a5+"'. Did you spell the name correctly and use a full path, like 'dijit.form.Button'?");
+}
+var _a7=cls.prototype;
+var _a8={};
+for(var _a9 in _a7){
+if(_a9.charAt(0)=="_"){
+continue;
+}
+var _aa=_a7[_a9];
+_a8[_a9]=val2type(_aa);
+}
+_a4[_a5]={cls:cls,params:_a8};
+}
+return _a4[_a5];
+};
+this.instantiate=function(_ab){
+var _ac=[];
+dojo.forEach(_ab,function(_ad){
+if(!_ad){
+return;
+}
+var _ae=_ad.getAttribute("dojoType");
+if((!_ae)||(!_ae.length)){
+return;
+}
+var _af=getWidgetClassInfo(_ae);
+var _b0={};
+for(var _b1 in _af.params){
+var _b2=_ad.getAttribute(_b1);
+if(_b2!=null){
+var _b3=_af.params[_b1];
+_b0[_b1]=str2obj(_b2,_b3);
+}
+}
+_ac.push(new _af.cls(_b0,_ad));
+var _b4=_ad.getAttribute("jsId");
+if(_b4){
+dojo.setObject(_b4,_ac[_ac.length-1]);
+}
+});
+dojo.forEach(_ac,function(_b5){
+if(_b5&&_b5.startup&&(!_b5.getParent||_b5.getParent()==null)){
+_b5.startup();
+}
+});
+return _ac;
+};
+this.parse=function(_b6){
+var _b7=dojo.query("[dojoType]",_b6);
+return this.instantiate(_b7);
+};
+}();
+dojo.addOnLoad(function(){
+dijit.util.parser.parse();
+});
+dijit.util.parser._anonCtr=0;
+dijit.util.parser._anon={};
+dijit.util.parser._nameAnonFunc=function(_b8,_b9,_ba){
+var jpn="$joinpoint";
+var nso=(_b9||dijit.util.parser._anon);
+if(dojo.isIE){
+var cn=_b8["__dojoNameCache"];
+if(cn&&nso[cn]===_b8){
+return _b8["__dojoNameCache"];
+}else{
+if(cn){
+var _be=cn.indexOf(jpn);
+if(_be!=-1){
+return cn.substring(0,_be);
+}
+}
+}
+}
+var ret="__"+dijit.util.parser._anonCtr++;
+while(typeof nso[ret]!="undefined"){
+ret="__"+dijit.util.parser._anonCtr++;
+}
+nso[ret]=_b8;
+return ret;
+};
+dojo.provide("dijit.base.TemplatedWidget");
+dojo.declare("dijit.base.TemplatedWidget",null,{templateNode:null,templateString:null,templatePath:null,widgetsInTemplate:false,containerNode:null,buildRendering:function(){
+var _c0=dijit.base.getCachedTemplate(this.templatePath,this.templateString);
+var _c1;
+if(dojo.isString(_c0)){
+var _c2=dojo.string.substitute(_c0,this,function(_c3){
+return _c3.toString().replace(/"/g,"&quot;");
+},this);
+_c1=dijit.base._createNodesFromText(_c2)[0];
+}else{
+_c1=_c0.cloneNode(true);
+}
+this._attachTemplateNodes(_c1);
+if(this.srcNodeRef){
+dojo.style(_c1,"cssText",this.srcNodeRef.style.cssText);
+if(this.srcNodeRef.className){
+_c1.className+=" "+this.srcNodeRef.className;
+}
+}
+this.domNode=_c1;
+if(this.srcNodeRef&&this.srcNodeRef.parentNode){
+this.srcNodeRef.parentNode.replaceChild(this.domNode,this.srcNodeRef);
+}
+if(this.widgetsInTemplate){
+var _c4=dijit.util.parser.parse(this.domNode);
+this._attachTemplateNodes(_c4,function(n,p){
+return n[p];
+});
+}
+if(this.srcNodeRef&&this.srcNodeRef.hasChildNodes()){
+var _c7=this.containerNode||this.domNode;
+while(this.srcNodeRef.hasChildNodes()){
+_c7.appendChild(this.srcNodeRef.firstChild);
+}
+}
+},_attachTemplateNodes:function(_c8,_c9){
+var _ca=function(str){
+return str.replace(/^\s+|\s+$/g,"");
+};
+_c9=_c9||function(n,p){
+return n.getAttribute(p);
+};
+var _ce=dojo.isArray(_c8)?_c8:(_c8.all||_c8.getElementsByTagName("*"));
+var x=dojo.isArray(_c8)?0:-1;
+for(;x<_ce.length;x++){
+var _d0=(x==-1)?_c8:_ce[x];
+if(this.widgetsInTemplate&&_c9(_d0,"dojoType")){
+return;
+}
+var _d1=_c9(_d0,"dojoAttachPoint");
+if(_d1){
+var _d2=_d1.split(";");
+var z=0,ap;
+while((ap=_d2[z++])){
+if(dojo.isArray(this[ap])){
+this[ap].push(_d0);
+}else{
+this[ap]=_d0;
+}
+}
+}
+var _d5=_c9(_d0,"dojoAttachEvent");
+if(_d5){
+var _d6=_d5.split(";");
+var y=0,evt;
+while((evt=_d6[y++])){
+if(!evt||!evt.length){
+continue;
+}
+var _d9=null;
+var _da=_ca(evt);
+if(evt.indexOf(":")!=-1){
+var _db=_da.split(":");
+_da=_ca(_db[0]);
+_d9=_ca(_db[1]);
+}
+if(!_d9){
+_d9=_da;
+}
+this.connect(_d0,_da,_d9);
+}
+}
+dojo.forEach(["waiRole","waiState"],function(_dc){
+var wai=dijit.util.wai[_dc];
+var val=_c9(_d0,wai.name);
+if(val){
+var _df="role";
+if(val.indexOf("-")!=-1){
+var _e0=val.split("-");
+_df=_e0[0];
+val=_e0[1];
+}
+dijit.util.wai.setAttr(_d0,wai.name,_df,val);
+}
+},this);
+}
+}});
+dijit.base._templateCache={};
+dijit.base.getCachedTemplate=function(_e1,_e2){
+var _e3=dijit.base._templateCache;
+var key=_e2||_e1;
+var _e5=_e3[key];
+if(_e5){
+return _e5;
+}
+if(!_e2){
+_e2=dijit.base._sanitizeTemplateString(dojo._getText(_e1));
+}
+_e2=_e2.replace(/^\s+|\s+$/g,"");
+if(_e2.match(/\$\{([^\}]+)\}/g)){
+return (_e3[key]=_e2);
+}else{
+return (_e3[key]=dijit.base._createNodesFromText(_e2)[0]);
+}
+};
+dijit.base._sanitizeTemplateString=function(_e6){
+if(_e6){
+_e6=_e6.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,"");
+var _e7=_e6.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+if(_e7){
+_e6=_e7[1];
+}
+}else{
+_e6="";
+}
+return _e6;
+};
+if(dojo.isIE){
+dojo.addOnUnload(function(){
+var _e8=dijit.base._templateCache;
+for(var key in _e8){
+var _ea=_e8[key];
+if(!isNaN(_ea.nodeType)){
+}
+_e8[key]=null;
+}
+});
+}
+(function(){
+var _eb={cell:{re:/^<t[dh][\s\r\n>]/i,pre:"<table><tbody><tr>",post:"</tr></tbody></table>"},row:{re:/^<tr[\s\r\n>]/i,pre:"<table><tbody>",post:"</tbody></table>"},section:{re:/^<(thead|tbody|tfoot)[\s\r\n>]/i,pre:"<table>",post:"</table>"}};
+var tn;
+var _ed;
+dijit.base._createNodesFromText=function(_ee){
+if(!tn){
+_ed=tn=dojo.doc.createElement("div");
+tn.style.visibility="hidden";
+}
+var _ef="none";
+var _f0=_ee.replace(/^\s+/);
+for(var _f1 in _eb){
+var map=_eb[_f1];
+if(map.re.test(_f0)){
+_ef=_f1;
+_ee=map.pre+_ee+map.post;
+break;
+}
+}
+tn.innerHTML=_ee;
+dojo.body().appendChild(tn);
+if(tn.normalize){
+tn.normalize();
+}
+var tag={cell:"tr",row:"tbody",section:"table"}[_ef];
+if(typeof tag!="undefined"){
+_ed=tn.getElementsByTagName(tag)[0];
+}
+var _f4=[];
+while(_ed.firstChild){
+_f4.push(_ed.removeChild(_ed.firstChild));
+}
+_ed=dojo.body().removeChild(tn);
+return _f4;
+};
+})();
+dojo.extend(dijit.base.Widget,{dojoAttachEvent:"",dojoAttachPoint:"",waiRole:"",waiState:""});
+dojo.provide("dijit.util.FocusManager");
+dijit.util.FocusManager=new function(){
+var _f5,_f6;
+function onFocus(_f7){
+if(_f7&&_f7.tagName=="body"){
+_f7=null;
+}
+if(_f7!==_f5){
+_f6=_f5;
+_f5=_f7;
+console.debug("focused on ",_f7?(_f7.id?_f7.id:_f7.tagName):"nothing");
+}
+};
+dojo.addOnLoad(function(){
+if(dojo.isIE){
+window.setInterval(function(){
+onFocus(document.activeElement);
+},100);
+}else{
+dojo.body().addEventListener("focus",function(evt){
+onFocus(evt.target);
+},true);
+}
+});
+var _f9=null;
+var _fa=false;
+var _fb;
+var _fc;
+var _fd;
+var _fe=function(){
+var _ff=dojo.global;
+var _100=dojo.doc;
+if(_100.selection){
+return _100.selection.createRange().text=="";
+}else{
+if(_ff.getSelection){
+var _101=_ff.getSelection();
+if(dojo.isString(_101)){
+return _101=="";
+}else{
+return _101.isCollapsed||_101.toString()=="";
+}
+}
+}
+};
+var _102=function(){
+var _103;
+var _104=dojo.doc;
+if(_104.selection){
+var _105=_104.selection.createRange();
+if(_104.selection.type.toUpperCase()=="CONTROL"){
+if(_105.length){
+_103=[];
+var i=0;
+while(i<_105.length){
+_103.push(_105.item(i++));
+}
+}else{
+_103=null;
+}
+}else{
+_103=_105.getBookmark();
+}
+}else{
+var _107;
+try{
+_107=dojo.global.getSelection();
+}
+catch(e){
+}
+if(_107){
+var _105=_107.getRangeAt(0);
+_103=_105.cloneRange();
+}else{
+console.debug("No idea how to store the current selection for this browser!");
+}
+}
+return _103;
+};
+var _108=function(_109){
+var _10a=dojo.doc;
+if(_10a.selection){
+if(dojo.isArray(_109)){
+var _10b=_10a.body.createControlRange();
+var i=0;
+while(i<_109.length){
+_10b.addElement(_109[i++]);
+}
+_10b.select();
+}else{
+var _10b=_10a.selection.createRange();
+_10b.moveToBookmark(_109);
+_10b.select();
+}
+}else{
+var _10d;
+try{
+_10d=dojo.global.getSelection();
+}
+catch(e){
+}
+if(_10d&&_10d.removeAllRanges){
+_10d.removeAllRanges();
+_10d.addRange(_109);
+}else{
+console.debug("No idea how to restore selection for this browser!");
+}
+}
+};
+this.save=function(menu,_10f){
+if(menu==_f9){
+return;
+}
+if(_f9){
+_f9.close();
+}
+_f9=menu;
+_fb=_10f;
+var _110=function(node,_112){
+while(node){
+if(node===_112){
+return true;
+}
+node=node.parentNode;
+}
+return false;
+};
+_fc=_110(_f5,menu.domNode)?_f6:_f5;
+console.debug("will restore focus to "+(_fc?(_fc.id||_fc.tagName):"nothing"));
+console.debug("prev focus is "+_f6);
+if(!dojo.withGlobal(_fb||dojo.global,_fe)){
+_fd=dojo.withGlobal(_fb||dojo.global,_102);
+}else{
+_fd=null;
+}
+};
+this.restore=function(menu){
+if(_f9==menu){
+if(_fc){
+_fc.focus();
+}
+if(_fd&&dojo.withGlobal(_fb||dojo.global,_fe)){
+if(_fb){
+_fb.focus();
+}
+try{
+dojo.withGlobal(_fb||dojo.global,_108,null,[_fd]);
+}
+catch(e){
+}
+}
+_fd=null;
+_fa=false;
+_f9=null;
+}
+};
+}();
+dojo.provide("dijit.util.BackgroundIframe");
+dijit.util.BackgroundIframe=function(node){
+if(dojo.isIE&&dojo.isIE<7){
+var html="<iframe src='javascript:false'"+" style='position: absolute; left: 0px; top: 0px; width: 100%; height: 100%;"+"z-index: -1; filter:Alpha(Opacity=\"0\");'>";
+this.iframe=dojo.doc.createElement(html);
+this.iframe.tabIndex=-1;
+if(node){
+node.appendChild(this.iframe);
+this.domNode=node;
+}else{
+dojo.body().appendChild(this.iframe);
+this.iframe.style.display="none";
+}
+}
+};
+dojo.extend(dijit.util.BackgroundIframe,{iframe:null,onResized:function(){
+if(this.iframe&&this.domNode&&this.domNode.parentNode){
+var _116=dojo.marginBox(this.domNode);
+if(!_116.w||!_116.h){
+setTimeout(this,this.onResized,100);
+return;
+}
+this.iframe.style.width=_116.w+"px";
+this.iframe.style.height=_116.h+"px";
+}
+},size:function(node){
+if(!this.iframe){
+return;
+}
+var _118=dojo.coords(node,true);
+var s=this.iframe.style;
+s.width=_118.w+"px";
+s.height=_118.h+"px";
+s.left=_118.x+"px";
+s.top=_118.y+"px";
+},setZIndex:function(node){
+if(!this.iframe){
+return;
+}
+this.iframe.style.zIndex=!isNaN(node)?node:(node.style.zIndex-1);
+},show:function(){
+if(this.iframe){
+this.iframe.style.display="block";
+}
+},hide:function(){
+if(this.iframe){
+this.iframe.style.display="none";
+}
+},remove:function(){
+if(this.iframe){
+this.iframe.parentNode.removeChild(this.iframe);
+delete this.iframe;
+this.iframe=null;
+}
+}});
+dojo.provide("dijit.util.place");
+dijit.util.getViewport=function(){
+var _11b=dojo.global;
+var _11c=dojo.doc;
+var w=0;
+var h=0;
+if(dojo.isMozilla){
+w=_11c.documentElement.clientWidth;
+h=_11b.innerHeight;
+}else{
+if(!dojo.isOpera&&_11b.innerWidth){
+w=_11b.innerWidth;
+h=_11b.innerHeight;
+}else{
+if(dojo.isIE&&_11c.documentElement&&_11c.documentElement.clientHeight){
+w=_11c.documentElement.clientWidth;
+h=_11c.documentElement.clientHeight;
+}else{
+if(dojo.body().clientWidth){
+w=dojo.body().clientWidth;
+h=dojo.body().clientHeight;
+}
+}
+}
+}
+return {w:w,h:h};
+};
+dijit.util.getScroll=function(){
+var _11f=dojo.global;
+var _120=dojo.doc;
+var top=_11f.pageYOffset||_120.documentElement.scrollTop||dojo.body().scrollTop||0;
+var left=_11f.pageXOffset||_120.documentElement.scrollLeft||dojo.body().scrollLeft||0;
+return {top:top,left:left,offset:{x:left,y:top}};
+};
+dijit.util.placeOnScreen=function(node,_124,_125,_126,_127,_128,_129){
+if(dojo.isArray(_124)){
+_129=_128;
+_128=_127;
+_127=_126;
+_126=_125;
+_125=_124[1];
+_124=_124[0];
+}
+if(dojo.isString(_128)){
+_128=_128.split(",");
+}
+if(!isNaN(_126)){
+_126=[Number(_126),Number(_126)];
+}else{
+if(!dojo.isArray(_126)){
+_126=[0,0];
+}
+}
+var _12a=dijit.util.getScroll().offset;
+var view=dijit.util.getViewport();
+node=dojo.byId(node);
+var _12c=node.style.display;
+var _12d=node.style.visibility;
+node.style.visibility="hidden";
+node.style.display="";
+var bb=dojo.marginBox(node);
+var w=bb.w;
+var h=bb.h;
+node.style.display=_12c;
+node.style.visibility=_12d;
+var _131,_132,_133,_134="";
+if(!dojo.isArray(_128)){
+_128=["TL"];
+}
+var _135,_136,_137=Infinity,_138;
+for(var _139=0;_139<_128.length;++_139){
+var _131,_132="";
+var _13a=_128[_139];
+var _13b=true;
+var tryX=_124-(_13a.charAt(1)=="L"?0:w)+_126[0]*(_13a.charAt(1)=="L"?1:-1);
+var tryY=_125-(_13a.charAt(0)=="T"?0:h)+_126[1]*(_13a.charAt(0)=="T"?1:-1);
+if(_127){
+tryX-=_12a.x;
+tryY-=_12a.y;
+}
+var x=tryX+w;
+if(x>view.w){
+_13b=false;
+}
+x=Math.max(_126[0],tryX)+_12a.x;
+if(_13a.charAt(1)=="L"){
+if(w>view.w-tryX){
+_131=view.w-tryX;
+_13b=false;
+}else{
+_131=w;
+}
+}else{
+if(tryX<0){
+_131=w+tryX;
+_13b=false;
+}else{
+_131=w;
+}
+}
+var y=tryY+h;
+if(y>view.h){
+_13b=false;
+}
+y=Math.max(_126[1],tryY)+_12a.y;
+if(_13a.charAt(0)=="T"){
+if(h>view.h-tryY){
+_132=view.h-tryY;
+_13b=false;
+}else{
+_132=h;
+}
+}else{
+if(tryY<0){
+_132=h+tryY;
+_13b=false;
+}else{
+_132=h;
+}
+}
+if(_13b){
+_135=x;
+_136=y;
+_137=0;
+_133=_131;
+_134=_132;
+_138=_13a;
+break;
+}else{
+var dist=Math.pow(x-tryX-_12a.x,2)+Math.pow(y-tryY-_12a.y,2);
+if(dist==0){
+dist=Math.pow(h-_132,2);
+}
+if(_137>dist){
+_137=dist;
+_135=x;
+_136=y;
+_133=_131;
+_134=_132;
+_138=_13a;
+}
+}
+}
+if(!_129){
+node.style.left=_135+"px";
+node.style.top=_136+"px";
+}
+return {left:_135,top:_136,x:_135,y:_136,dist:_137,corner:_138,h:_134,w:_133};
+};
+dijit.util.placeOnScreenAroundElement=function(node,_142,_143,_144,_145){
+if(!node.parentNode||String(node.parentNode.tagName).toLowerCase()!="body"){
+dojo.body().appendChild(node);
+}
+var best,_147=Infinity;
+_142=dojo.byId(_142);
+var _148=_142.style.display;
+_142.style.display="";
+var _149=_142.offsetWidth;
+var _14a=_142.offsetHeight;
+var _14b=dojo.coords(_142,true);
+_142.style.display=_148;
+for(var _14c in _144){
+var pos,_14e,_14f;
+var _150=_144[_14c];
+_14e=_14b.x+(_14c.charAt(1)=="L"?0:_149);
+_14f=_14b.y+(_14c.charAt(0)=="T"?0:_14a);
+pos=dijit.util.placeOnScreen(node,_14e,_14f,_143,true,_150,true);
+if(pos.dist==0){
+best=pos;
+break;
+}else{
+if(_147>pos.dist){
+_147=pos.dist;
+best=pos;
+}
+}
+}
+if(!_145){
+node.style.left=best.left+"px";
+node.style.top=best.top+"px";
+}
+return best;
+};
+console.warn("dijit.dijit may dissapear in the 0.9 timeframe in lieu of a different rollup file!");
+dojo.provide("dijit.dijit");

Added: trunk/examples/typeface/root/static/dojo/dijit/dijit.js.uncompressed.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/dijit.js.uncompressed.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/dijit.js.uncompressed.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,2420 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+/*
+	This is a compiled version of Dojo, built for deployment and not for
+	development. To get an editable version, please visit:
+
+		http://dojotoolkit.org
+
+	for documentation and information on getting the source.
+*/
+
+dojo.provide("dijit.util.manager");
+
+dijit.util.manager = new function(){
+	// summary
+	//	manager class for the widgets.
+
+	// registry of widgets
+	var registry = {};
+
+	var widgetTypeCtr = {};
+
+	this.getUniqueId = function(/*String*/widgetType){
+		// summary
+		//	Generates a unique id for a given widgetType
+
+		var widgetId;
+		do{
+			widgetId = widgetType + "_" +
+				(widgetTypeCtr[widgetType] !== undefined ?
+					++widgetTypeCtr[widgetType] : widgetTypeCtr[widgetType] = 0);
+		}while(registry[widgetId]);
+		return widgetId;
+	}
+
+	this.add = function(/*Widget*/ widget){
+		// summary
+		//	Adds a widget to the registry
+
+		if(!widget.id){
+			widget.id = this.getUniqueId(widget.declaredClass.replace("\.","_"));
+		}
+		registry[widget.id] = widget;
+	}
+
+	this.remove = function(id){
+		// summary
+		//	Removes a widget from the registry by id, but does not destroy the widget
+
+		delete registry.id;
+	}
+
+	this.destroyAll = function(){
+		// summary
+		//	Destroys all the widgets
+
+		for(var id in registry){
+			registry[id].destroy();
+		}
+	}
+
+	this.getWidgets = function(){
+		// summary
+		//	Returns the hash of id->widget
+		return registry;
+	}
+
+	this.byNode = function(/* DOMNode */ node){
+		// summary
+		//	Returns the widget as referenced by node.?
+		return registry[node.widgetId];
+	}
+};
+
+dojo.addOnUnload(function(){
+	dijit.util.manager.destroyAll();
+});
+
+dijit.byId = function(/*String*/id){
+	// summary
+	//	Returns a widget by its id
+	return dijit.util.manager.getWidgets()[id];
+};
+
+dojo.provide("dijit.base.Widget");
+
+
+
+dojo.declare("dijit.base.Widget", null,
+function(params, srcNodeRef){
+	// summary:
+	//		To understand the process by which widgets are instantiated, it
+	//		is critical to understand what other methods the constructor calls and
+	//		which of them you'll want to over-ride. Of course, adventurous
+	//		developers could over-ride the constructor entirely, but this should
+	//		only be done as a last resort.
+	//
+	//		Below is a list of the methods that are called, in the order
+	//		they are fired, along with notes about what they do and if/when
+	//		you should over-ride them in your widget:
+	//			
+	//			postMixInProperties:
+	//				a stub function that you can over-ride to modify
+	//				variables that may have been naively assigned by
+	//				mixInProperties
+	//			# widget is added to manager object here
+	//			buildRendering
+	//				Subclasses use this method to handle all UI initialization
+	//				Sets this.domNode.  Templated widgets do this automatically
+	//				and otherwise it just uses the source dom node. 
+	//			postCreate
+	//				a stub function that you can over-ride to modify take
+	//				actions once the widget has been placed in the UI
+
+	// store pointer to original dom tree
+	this.srcNodeRef = dojo.byId(srcNodeRef);
+
+	// for garbage collection
+	this._connects=[];
+
+	//mixin our passed parameters
+	if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
+	if(params){
+		dojo.mixin(this,params);
+	}
+
+	this.postMixInProperties();
+	dijit.util.manager.add(this);
+	this.buildRendering();
+	if(this.domNode){
+		this.domNode.widgetId = this.id;
+		if(this.srcNodeRef && this.srcNodeRef.dir){ 
+			this.domNode.dir = this.srcNodeRef.dir; 
+		}
+	}
+	this.postCreate();
+
+	// If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC.
+	if(this.srcNodeRef && !this.srcNodeRef.parentNode){
+		delete this.srcNodeRef;
+	}
+},
+{
+	// id: String
+	//		a unique, opaque ID string that can be assigned by users or by the
+	//		system. If the developer passes an ID which is known not to be
+	//		unique, the specified ID is ignored and the system-generated ID is
+	//		used instead.
+	id: "",
+
+	// lang: String
+	//	Language to display this widget in (like en-us).
+	//	Defaults to brower's specified preferred language (typically the language of the OS)
+	lang: "",
+
+	// dir: String
+	//  Bi-directional support, as defined by the HTML DIR attribute. Either left-to-right "ltr" or right-to-left "rtl".
+	dir: "",
+
+	// srcNodeRef: DomNode
+	//		pointer to original dom node
+	srcNodeRef: null,
+
+	// domNode DomNode:
+	//		this is our visible representation of the widget! Other DOM
+	//		Nodes may by assigned to other properties, usually through the
+	//		template system's dojoAttachPonit syntax, but the domNode
+	//		property is the canonical "top level" node in widget UI.
+	domNode: null, 
+
+	//////////// INITIALIZATION METHODS ///////////////////////////////////////
+
+	postMixInProperties: function(){
+		// summary
+		//	Called after the parameters to the widget have been read-in,
+		//	but before the widget template is instantiated.
+		//	Especially useful to set properties that are referenced in the widget template.
+
+//		this.lang = this.lang || null;
+	},
+
+	buildRendering: function(){
+		// summary:
+		//		Construct the UI for this widget, setting this.domNode.
+		//		Most widgets will mixin TemplatedWidget, which overrides this method.
+		this.domNode = this.srcNodeRef;
+	},
+
+	postCreate: function(){
+		// summary:
+		//		Called after a widget's dom has been setup
+	},
+
+	startup: function(){
+		// summary:
+		//		Called after a widget's children, and other widgets on the page, have been created.
+		//		Provides an opportunity to manipulate any children before they are displayed
+		//		This is useful for composite widgets that need to control or layout sub-widgets
+		//		Many layout widgets can use this as a wiring phase
+		
+	},
+
+	//////////// DESTROY FUNCTIONS ////////////////////////////////
+
+	destroyRecursive: function(/*Boolean*/ finalize){
+		// summary:
+		// 		Destroy this widget and it's descendants. This is the generic
+		// 		"destructor" function that all widget users should call to
+		// 		cleanly discard with a widget. Once a widget is destroyed, it's
+		// 		removed from the manager object.
+		// finalize: Boolean
+		//		is this function being called part of global environment
+		//		tear-down?
+
+		this.destroyDescendants();
+		this.destroy();
+	},
+	
+	destroy: function(/*Boolean*/ finalize){
+		// summary:
+		// 		Destroy this widget, but not its descendents
+		// finalize: Boolean
+		//		is this function being called part of global environment
+		//		tear-down?
+		this.uninitialize();
+		dojo.forEach(this._connects, dojo.disconnect);
+		this.destroyRendering(finalize);
+		dijit.util.manager.remove(this.id);
+	},
+
+	destroyRendering: function(/*Boolean*/ finalize){
+		// summary:
+		//		Destroys the DOM nodes associated with this widget
+		// finalize: Boolean
+		//		is this function being called part of global environment
+		//		tear-down?
+
+		if(this.bgIframe){
+			this.bgIframe.remove();
+			delete this.bgIframe;
+		}
+
+		if(this.domNode){
+			//			dojo.dom.destroyNode(this.domNode);
+			//PORT #2931
+			if(this.domNode.parentNode){
+				this.domNode.parentNode.removeChild(this.domNode);
+			}
+			delete this.domNode;
+		}
+
+		if(this.srcNodeRef && this.srcNodeRef.parentNode){
+//			dojo.dom.destroyNode(this.srcNodeRef);
+//PORT #2931
+			this.srcNodeRef.parentNode.removeChild(this.srcNodeRef);
+			delete this.srcNodeRef;
+		}
+	},
+
+	destroyDescendants: function(){
+		// summary:
+		//		Recursively destroy the children of this widget and their
+		//		descendents.
+		dojo.forEach(this.getDescendants(), function(widget){
+			widget.destroy();
+		});
+	},
+
+	uninitialize: function(){
+		// summary: 
+		//		stub function. Over-ride to implement custom widget tear-down
+		//		behavior.
+		return false;
+	},
+
+	////////////////// MISCELLANEOUS METHODS ///////////////////
+	
+	toString: function(){
+		// summary:
+		//		returns a string that represents the widget. When a widget is
+		//		cast to a string, this method will be used to generate the
+		//		output. Currently, it does not implement any sort of reversable
+		//		serialization.
+		return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String
+	},
+
+	getDescendants: function(){
+		// summary:
+		//	return all the descendent widgets
+		var allNodes = this.domNode.all || this.domNode.getElementsByTagName("*");
+		var i=0, node;
+		var nodes = [];
+		while((node = allNodes[i++])){
+			var id = node.widgetId;
+			if(id){
+				nodes.push(dijit.byId(id));
+			}
+		}
+		return nodes;
+	},
+
+	connect: function(
+			/*Object|null*/ obj, 
+			/*String*/ event, 
+			/*String|Function*/ method){
+
+		// summary:
+		//		Connects specified obj/event to specified method of this object
+		//		and registers for disconnect() on widget destroy.
+		//		Similar to dojo.connect() but takes three arguments rather than four.
+		this._connects.push(dojo.connect(obj, event, this, method));
+	},
+
+	isLeftToRight: function(){
+		// summary:
+		//		Checks the DOM to for the text direction for bi-directional support
+		//		See HTML spec, DIR attribute for more information.
+
+		if(typeof this._ltr == "undefined"){
+			this._ltr = (this.dir || dojo.getComputedStyle(this.domNode).direction) != "rtl";
+		}
+		return this._ltr; //Boolean
+	}
+});
+
+//PORT - where does this go?  dijit.util?  dojo.html?
+dijit._disableSelection = function(/*DomNode*/element){
+	// summary: disable selection on a node
+
+	if(dojo.isMozilla){
+		element.style.MozUserSelect = "none";
+	}else if(dojo.isKhtml){
+		element.style.KhtmlUserSelect = "none"; 
+	}else if(dojo.isIE){
+		element.unselectable = "on";
+	}
+	//FIXME: else?  Opera?
+};
+
+dojo.provide("dijit.base.Container");
+
+
+
+dojo.declare("dijit.base.Contained",
+	null,
+	{
+		// summary
+		//		Mixin for widgets that are children of a container widget
+
+		getParent: function(){
+			// summary:
+			//		returns parent widget
+			for(var p=this.domNode.parentNode; p; p=p.parentNode){
+				var widgetId = p.widgetId;
+				if(widgetId){
+					return dijit.byId(widgetId);
+				}
+			}
+			return null;
+		},
+
+		_getSibling: function(which){
+			var node = this.domNode;
+			do{
+				node = node[which+"Sibling"];
+			}while(node && node.nodeType != 1);
+			if(!node){ return null; } // null
+			var id = node.widgetId;
+			return dijit.byId(id);
+		},
+
+		getPreviousSibling: function(){
+			// summary:
+			//		returns null if this is the first child of the parent,
+			//		otherwise returns the next element sibling to the "left".
+
+			return this._getSibling("previous");
+		},
+	 
+		getNextSibling: function(){
+			// summary:
+			//		returns null if this is the last child of the parent,
+			//		otherwise returns the next element sibling to the "right".
+	 
+			return this._getSibling("next");
+		}
+	}
+);
+
+dojo.declare("dijit.base.Container", 
+	null,
+	{
+		// summary
+		//		Mixin for widgets that contain a list of children like SplitContainer
+
+		isContainer: true,
+
+		addChild: function(/*Widget*/ widget, /*int?*/ insertIndex){
+			// summary:
+			//		Process the given child widget, inserting it's dom node as
+			//		a child of our dom node
+
+			var containerNode = this.containerNode || this.domNode;
+			if(typeof insertIndex == "undefined"){
+				dojo.place(widget.domNode, containerNode, "last");
+			}else{
+				dojo.place(widget.domNode, containerNode, insertIndex);
+			}
+		},
+
+		removeChild: function(/*Widget*/ widget){
+			// summary: 
+			//		removes the passed widget instance from this widget but does
+			//		not destroy it
+			var node = widget.domNode;
+			node.parentNode.removeChild(node); //PORT leak #2931 -- call widget.destroy() instead?
+		},
+		
+		_nextElement: function(node){
+			do{
+				node = node.nextSibling;
+			}while(node && node.nodeType != 1);
+			return node;
+		},
+
+		_firstElement: function(node){
+			node = node.firstChild;
+			if(node && node.nodeType != 1){
+				node = this._nextElement(node);
+			}
+			return node;
+		},
+
+		getChildren: function(){
+			// summary:
+			//		returns array of children widgets
+
+			var res = [];
+			var cn = this.containerNode || this.domNode;
+			var childNode = this._firstElement(cn);
+			while(childNode){
+				var tmp = dijit.byId(childNode.widgetId);
+				if(tmp){
+					res.push(tmp);
+				}
+				childNode = this._nextElement(childNode);
+			}
+			return res;
+		},
+
+		hasChildren: function(){
+			// summary:
+			//		returns true if widget has children
+			var cn = this.containerNode || this.domNode;
+			return !!this._firstElement(cn);
+		}
+	}
+);
+
+dojo.provide("dijit.base.Layout");
+
+
+
+dojo.declare("dijit.base.Sizable", 
+	null,
+	{
+		// summary
+		//		Helper mixin for widgets that can have their size adjusted,
+		//		and that need to do some processing when their size changes (like SplitContainer)
+
+		resize: function(mb){
+			// summary:
+			//		Explicitly set this widget's size (in pixels), 
+			//		and then call layout() to resize contents (and maybe adjust child widgets)
+			//	
+			// mb: Object?
+			//		{w: int, h: int, l: int, t: int}
+
+			var node = this.domNode;
+
+			// set margin box size, unless it wasn't specified, in which case use current size
+			if(mb){
+				dojo.marginBox(node, mb);
+
+				// set offset of the node
+				if(mb.t){ node.style.top = mb.t + "px"; }
+				if(mb.l){ node.style.left = mb.l + "px"; }
+			}
+			mb = dojo.marginBox(node);
+
+			// Save the size of my content box.
+			this._contentBox = dijit.base.Layout.marginBox2contentBox(node, mb);
+			
+			// Callback for widget to adjust size of it's children
+			this.layout();
+		},
+	
+		layout: function(){
+			//	summary
+			//		Widgets override this method to size & position their contents/children.
+			//		When this is called this._contentBox is guaranteed to be set (see resize()).
+			//
+			//		This is called after startup(), and also when the widget's size has been
+			//		changed.
+		}
+	}
+);
+
+dojo.declare("dijit.base.Layout", 
+	[dijit.base.Sizable, dijit.base.Container, dijit.base.Contained, dijit.base.Showable],
+	{
+		// summary
+		//		Mixin for widgets that contain a list of children like SplitContainer.
+		//		Widgets which mixin this code must define layout() to lay out the children
+
+		isLayoutContainer: true,
+
+		startup: function(){
+			// summary:
+			//		Called after all the widgets have been instantiated and their
+			//		dom nodes have been inserted somewhere under document.body.
+			//
+			//		Widgets should override this method to do any initialization
+			//		dependent on other widgets existing, and then call
+			//		this superclass method to finish things off.
+			//
+			//		startup() in subclasses shouldn't do anything
+			//		size related because the size of the widget hasn't been set yet.
+
+			if(this._started){
+				return;
+			}
+			this._started=true;
+
+			if(this.getChildren){
+				dojo.forEach(this.getChildren(), function(child){ child.startup(); });
+			}
+
+			// If I am a top level widget
+			if(!this.getParent || !this.getParent()){
+				// Do recursive sizing and layout of all my descendants
+				this.resize();
+
+				// since my parent isn't a layout container, and my style is width=height=100% (or something similar),
+				// then I need to watch when the window resizes, and size myself accordingly
+				this.connect(window, 'onresize', "resize");
+			}
+		}
+	}
+);
+
+dijit.base.Layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
+	// summary:
+	//		Given the margin-box size of a node, return it's content box size.
+	//		Functions like dojo.contentBox() but is more reliable since it doesn't have
+	//		to wait for the browser to compute sizes.
+	var cs = dojo.getComputedStyle(node);
+	var me=dojo._getMarginExtents(node, cs);
+	var pb=dojo._getPadBorderExtents(node, cs);
+	return {
+		l: dojo._toPixelValue(this.containerNode, cs.paddingLeft),
+		t: dojo._toPixelValue(this.containerNode, cs.paddingTop),
+		w: mb.w - (me.w + pb.w),
+		h: mb.h - (me.h + pb.h)
+	};
+};
+
+dijit.base.Layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Object[]*/ children, /*String*/ layoutPriority){
+	/**
+	 * summary
+	 *		Layout a bunch of child dom nodes within a parent dom node
+	 *		Returns true if successful, returns false if any of the children would 
+	 * 		have been calculated to be hidden (typically if browser hasn't flowed the nodes)
+	 *		In the latter case, a best-effort of the layout is done and the caller can
+	 *		reschedule a layout at a later time - when the browser has more accurate metrics
+	 * container:
+	 *		parent node
+	 * dim:
+	 *		{l, t, w, h} object specifying dimensions of container into which to place children
+	 * layoutPriority:
+	 *		"top-bottom" or "left-right"
+	 * children:
+	 *		an array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ]
+	 */
+
+	dojo.addClass(container, "dijitLayoutContainer");
+
+	// Copy children array and remove elements w/out layout.
+	// Also record each child's position in the input array, for sorting purposes.
+	children = dojo.filter(children, function(child, idx){
+		child.idx = idx;
+		return dojo.indexOf(["top","bottom","left","right","client","flood"], child.layoutAlign) > -1;
+	});
+
+	// Order the children according to layoutPriority.
+	// Multiple children w/the same layoutPriority will be sorted by their position in the input array.
+	if(layoutPriority && layoutPriority!="none"){
+		var rank = function(child){
+			switch(child.layoutAlign){
+				case "flood":
+					return 1;
+				case "left":
+				case "right":
+					return (layoutPriority=="left-right") ? 2 : 3;
+				case "top":
+				case "bottom":
+					return (layoutPriority=="left-right") ? 3 : 2;
+				default:
+					return 4;
+			}
+		};
+		children.sort(function(a,b){
+			return (rank(a)-rank(b)) || (a.idx - b.idx);
+		});
+	}
+
+	// set positions/sizes
+	var ret=true;
+	dojo.forEach(children, function(child){
+		var elm=child.domNode;
+		var pos=child.layoutAlign;
+		// set elem to upper left corner of unused space; may move it later
+		var elmStyle = elm.style;
+		elmStyle.left = dim.l+"px";
+		elmStyle.top = dim.t+"px";
+		elmStyle.bottom = elmStyle.right = "auto";
+
+		var capitalize = function(word){
+			return word.substring(0,1).toUpperCase() + word.substring(1);
+		};
+		
+		dojo.addClass(elm, "dijitAlign" + capitalize(pos));
+
+		// set size && adjust record of remaining space.
+		// note that setting the width of a <div> may affect it's height.
+		if (pos=="top" || pos=="bottom"){
+			if(child.resize){
+				child.resize({w: dim.w});
+			}else{
+				dojo.marginBox(elm, { w: dim.w });
+			}
+			var h = dojo.marginBox(elm).h;
+			dim.h -= h;
+			dojo.mixin(child, {w: dim.w, h: h});	// return child size
+			if(pos=="top"){
+				dim.t += h;
+			}else{
+				elmStyle.top = dim.t + dim.h + "px";
+			}
+		}else if(pos=="left" || pos=="right"){
+			var w = dojo.marginBox(elm).w;
+
+			// TODO: this zero stuff shouldn't be necessary anymore
+			var hasZero = dijit.base.Layout._sizeChild(child, elm, w, dim.h);
+			if(hasZero){
+				ret = false;
+			}
+			dim.w -= w;
+			if(pos=="left"){
+				dim.l += w;
+			}else{
+				elmStyle.left = dim.l + dim.w + "px";
+			}
+		} else if(pos=="flood" || pos=="client"){
+			// #1635 - filter for zero dimensions (see below)
+			var hasZero = dijit.base.Layout._sizeChild(child, elm, dim.w, dim.h);
+			if(hasZero){
+				ret = false;
+			}
+		}
+	});
+	return ret;
+};
+
+dijit.base.Layout._sizeChild = function (child, elm, w, h){
+	// Note: zero dimensions can occur if we are called before the browser
+	// don't allow such values for width and height, let the browser adjust the
+	// layout itself when it reflows and report if any dimension is zero
+	var box = {};
+	
+	var hasZero = (w == 0 || h == 0);
+	if(!hasZero){
+	// TODO: Bill: this makes no sense.  If !hasZero then w!=0 and h!=0.
+	// The following two if statements are meaningless.
+		if(w != 0){
+			box.w = w;
+		}
+		if(h != 0){
+			box.h = h;
+		}
+		if(child.resize){
+			child.resize(box);
+		}else{
+			dojo.marginBox(elm, box);
+		}
+	}
+	dojo.mixin(child, box);	// return child size
+	return hasZero;
+}
+
+
+
+dojo.provide("dijit.base.Showable");
+
+//TODO: do we need this class at all?
+dojo.declare("dijit.base.Showable", null,
+{
+	// Summary
+	//		Mixin for widgets that show/hide themselves in a fancy way
+
+	isShowing: function(){
+		// summary
+		//	Tests whether widget is set to show-mode or hide-mode (see show() and 
+		//	hide() methods)
+		//
+		//	This function is poorly named.  Even if widget is in show-mode,
+		//	if it's inside a container that's hidden
+		//	(either a container widget, or just a domnode with display:none),
+		//	then it won't be displayed
+		return dojo.style(this.domNode, "display") != 'none';	// Boolean
+	},
+
+	toggleShowing: function(){
+		// summary: show or hide the widget, to switch it's state
+		if(this.isShowing()){
+			this.hide();
+		}else{
+			this.show();
+		}
+	},
+
+	show: function(){
+		// summary: show the widget
+		if(this.isShowing()){ return; }
+		this.domNode.style.display = "";
+		this.onShow();
+	},
+
+	onShow: function(){
+		// summary: callback for when widget is shown
+	},
+
+	hide: function(){
+		// summary: hide the widget (ending up with display:none)
+		if(!this.isShowing()){ return; }
+		this.domNode.style.display = "none";
+		this.onHide();
+	},
+	
+	onHide: function(){
+		// summary: callback for when widget is hidden
+	}
+});
+
+dojo.provide("dijit.util.sniff");
+
+// ported from dojo.html.applyBrowserClass (style.js)
+
+//	summary:
+//		Applies pre-set class names based on browser & version to the
+//		top-level HTML node.  Simply doing a require on this module will
+//		establish this CSS.  Modified version of Morris' CSS hack.
+(function(){
+	var d = dojo;
+	var ie = d.isIE;
+	var opera = d.isOpera;
+	var maj = Math.floor;
+	var classes = {
+		dj_ie: ie,
+//		dj_ie55: ie == 5.5,
+		dj_ie6: maj(ie) == 6,
+		dj_ie7: maj(ie) == 7,
+		dj_iequirks: ie && d.isQuirks,
+// NOTE: Opera not supported by dijit
+		dj_opera: opera,
+		dj_opera8: maj(opera) == 8,
+		dj_opera9: maj(opera) == 9,
+		dj_khtml: d.isKhtml,
+		dj_safari: d.isSafari,
+		dj_gecko: d.isMozilla
+	}; // no dojo unsupported browsers
+
+	for(var p in classes){
+		if(classes[p]){
+			var html = dojo.doc.documentElement; //TODO browser-specific DOM magic needed?
+			if(html.className){
+				html.className += " " + p;
+			}else{
+				html.className = p;
+			}
+		}
+	}
+})();
+
+dojo.provide("dijit.util.wai");
+
+dijit.util.waiNames  = ["waiRole", "waiState"];
+
+dijit.util.wai = {
+	// summary: Contains functions to set accessibility roles and states
+	//		onto widget elements
+	waiRole: { 	
+				// name: String:
+				//		information for mapping accessibility role
+				name: "waiRole", 
+				// namespace: String:
+				//		URI of the namespace for the set of roles
+				"namespace": "http://www.w3.org/TR/xhtml2", 
+				// alias: String:
+				//		The alias to assign the namespace
+				alias: "x2",
+				// prefix: String:
+				//		The prefix to assign to the role value
+				prefix: "wairole:"
+	},
+	waiState: { 
+				// name: String:
+				//		information for mapping accessibility state
+				name: "waiState", 
+				// namespace: String:
+				//		URI of the namespace for the set of states
+				"namespace": "http://www.w3.org/2005/07/aaa", 
+				// alias: String:
+				//		The alias to assign the namespace
+				alias: "aaa",
+				// prefix: String:
+				//		empty string - state value does not require prefix
+				prefix: ""
+	},
+	setAttr: function(/*DomNode*/node, /*String*/ ns, /*String*/ attr, /*String|Boolean*/value){
+		// summary: Use appropriate API to set the role or state attribute onto the element.
+		// description: In IE use the generic setAttribute() api.  Append a namespace
+		//   alias to the attribute name and appropriate prefix to the value. 
+		//   Otherwise, use the setAttribueNS api to set the namespaced attribute. Also
+		//   add the appropriate prefix to the attribute value.
+		if(dojo.isIE){
+			node.setAttribute(this[ns].alias+":"+ attr, this[ns].prefix+value);
+		}else{
+			node.setAttributeNS(this[ns]["namespace"], attr, this[ns].prefix+value);
+		}
+	},
+
+	getAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
+		// Summary:  Use the appropriate API to retrieve the role or state value
+		// Description: In IE use the generic getAttribute() api.  An alias value 
+		// 	was added to the attribute name to simulate a namespace when the attribute
+		//  was set.  Otherwise use the getAttributeNS() api to retrieve the state value
+		if(dojo.isIE){
+			return node.getAttribute(this[ns].alias+":"+attr);
+		}else{
+			return node.getAttributeNS(this[ns]["namespace"], attr);
+		}
+	},
+	removeAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
+		// summary:  Use the appropriate API to remove the role or state value
+		// description: In IE use the generic removeAttribute() api.  An alias value 
+		// 	was added to the attribute name to simulate a namespace when the attribute
+		//  was set.  Otherwise use the removeAttributeNS() api to remove the state value
+		var success = true; //only IE returns a value
+		if(dojo.isIE){
+			 success = node.removeAttribute(this[ns].alias+":"+attr);
+		}else{
+			node.removeAttributeNS(this[ns]["namespace"], attr);
+		}
+		return success;
+	},
+	
+	imageBgToSrc : function(/* Node | Node[] */ images) {
+		// summary:  
+		//		Given a single image or array of images
+		//		figure out the background-image style property
+		//		and apply that to the image.src property.
+		// description:  
+		//		For accessibility reasons, all images that are necessary to the
+		//		functioning of a widget should use <image> tags.  Using this method
+		//		allows the image URLs to come from themes (via CSS),
+		//		while still using the image tags.
+		// todo:
+		//		* have this examine background-position and, if set,
+		//			wrap the image in an inline div that allows us to crop
+		//			the image according to width and height specified in CSS.
+		if (!dojo.isArrayLike(images)) { images = [images]; }
+		dojo.forEach(images, 
+			function(image) {
+				var style = image && dojo.getComputedStyle(image);
+				if (!style) return;
+				var href = style.backgroundImage.match(/url\(['"]?(.*?)['"]?\)/);
+				if (!href) return;
+				image.src = href[1];
+				image.style.backgroundImage = "none";
+			}
+		);
+	}
+};
+
+// On page load and at intervals, detect if we are in high-contrast mode or not
+dojo._loaders.unshift(function(){
+	// create div for testing
+	var div = document.createElement("div");
+	div.id = "a11yTestNode";
+	dojo.body().appendChild(div);
+	
+	// test it
+	function check(){
+		var cs = dojo.getComputedStyle(div);
+		var bkImg = cs.backgroundImage; 
+		var needsA11y = (cs.borderTopColor==cs.borderRightColor) || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" ));
+		dojo[needsA11y ? "addClass" : "removeClass"](dojo.body(), "dijit_a11y");
+	}
+	if(dojo.isIE || dojo.isMoz){	// NOTE: checking in Safari messes things up
+		check();
+		if(dojo.isIE){
+			setInterval(check, 4000);
+		}
+	}
+});
+
+
+dojo.provide("dijit.base.FormElement");
+
+
+
+
+
+dojo.declare("dijit.base.FormElement", dijit.base.Widget,
+{
+	/*
+	Summary:
+		FormElement widgets correspond to native HTML elements such as <input> or <button> or <select>.
+		Each FormElement represents a single input value, and has a (possibly hidden) <input> element,
+		to which it serializes its input value, so that form submission (either normal submission or via FormBind?)
+		works as expected.
+		
+		All these widgets should have these attributes just like native HTML input elements.
+		You can set them during widget construction, but after that they are read only.
+		
+		They also share some common methods.
+		
+	TODO:
+		should this be a mixin or a base class?
+		automatically add CSS tags for hover and focus like *class*Hover and *class*Focus (or maybe in FormElement)
+	*/
+	// baseClass: String
+	//		Used to add CSS classes like FormElementDisabled
+	baseClass: "",
+
+	// value: String
+	//		Corresponds to the native HTML <input> element's attribute.
+	value: "", 
+
+	// name: String
+	//		Name used when submitting form; same as "name" attribute or plain HTML elements
+	name: "",
+
+	// id: String
+	//		Corresponds to the native HTML <input> element's attribute.
+	//		Also becomes the id for the widget.
+	id: "",
+
+	// alt: String
+	//		Corresponds to the native HTML <input> element's attribute.
+	alt: "",
+
+	// type: String
+	//		Corresponds to the native HTML <input> element's attribute.
+	type: "text",
+
+	// tabIndex: Integer
+	//		Order fields are traversed when user hits the tab key
+	tabIndex: "0",
+
+	// disabled: Boolean
+	//		Should this widget respond to user input?
+	//		In markup, this is specified as "disabled='disabled'", or just "disabled".
+	disabled: false,
+
+	enable: function(){
+		// summary:
+		//		enables the widget, usually involving unmasking inputs and
+		//		turning on event handlers. Not implemented here.
+		this._setDisabled(false);
+	},
+
+	disable: function(){
+		// summary:
+		//		disables the widget, usually involves masking inputs and
+		//		unsetting event handlers. Not implemented here.
+		this._setDisabled(true);
+	},
+	
+	_setDisabled: function(/*Boolean*/ disabled){
+		// summary:
+		//		Set disabled state of widget.
+		// TODO:
+		//		not sure which parts of disabling a widget should be here;
+		//		not sure which code is common to many widgets and which is specific to a particular widget.
+		this.domNode.disabled = this.disabled = disabled;
+		if(this.focusNode){
+			this.focusNode.disabled = disabled;
+		}
+		dijit.util.wai.setAttr(this.focusNode || this.domNode, "waiState", "disabled", disabled);
+		this.setStateClass(null, this.domNode);
+	},
+	
+
+	setStateClass : function(event, mouseNode, baseClass) {
+		// summary:
+		//	Update the visual state of the widget by changing the css class according to the mouse state.
+		//	State will be one of:
+		//		<baseClass> + "Enabled"|"Disabled"|"Active"|"Hover"
+		if (mouseNode == null) mouseNode = this.domNode;
+		if (event) dojo.stopEvent(event);
+		var base = mouseNode.getAttribute("baseClass") || this.baseClass || (this.baseClass = "dijit"+this.declaredClass.replace(/.*\./g,""));
+		
+		if (this.disabled) {
+			dojo.removeClass(this.domNode, base+"Enabled");
+			dojo.removeClass(this.domNode, base+"Hover");
+			dojo.removeClass(this.domNode, base+"Active");
+			dojo.addClass(this.domNode, base+"Disabled");
+		} else {
+			if (event) {
+				switch (event.type) {
+					case "mouseover" :
+						mouseNode._hovering = true;
+						break;
+						
+					case "mouseout" :	
+						mouseNode._hovering = false;	
+						break;
+						
+					case "mousedown" :
+						mouseNode._active = true;
+						// set a global event to handle mouseup, so it fires properly
+						//	even if the cursor leaves the button
+						var self = this;
+						var method = function(event) {
+							self.setStateClass(event, mouseNode);
+						}
+						mouseNode._mouseUpConnector = dojo.connect(dojo.global, "onmouseup", this, method);
+						break;
+	
+					case "mouseup" :
+						mouseNode._active = false;
+						// clear the global mouseup event, if set
+						if (this._mouseUpConnector) {
+							dojo.disconnect(mouseNode._mouseUpConnector);
+							mouseNode._mouseUpConnector = false;
+						}
+						break;
+						
+					case "click" :
+						this.onClick(event);
+						break;				
+				}
+			}
+//console.info(this.disabled, this._hovering, this._active);
+			dojo.removeClass(this.domNode, base+"Disabled");
+			dojo.toggleClass(this.domNode, base+"Active", mouseNode._active == true);
+			dojo.toggleClass(this.domNode, base+"Hover", mouseNode._hovering == true && mouseNode._active != true);
+			dojo.addClass(this.domNode, base+"Enabled");
+		}
+	},
+
+	onValueChanged: function(newValue){
+		// summary: callback when value is changed
+	},
+	
+	postCreate: function(){
+		this._setDisabled(this.disabled == true);
+	},
+
+	_lastValueReported: null,
+	setValue: function(newValue){
+		// summary: set the value of the widget.
+		if(newValue != this._lastValueReported){
+			this._lastValueReported = newValue;
+			dijit.util.wai.setAttr(this.focusNode || this.domNode, "waiState", "valuenow", newValue);
+			this.onValueChanged(newValue);
+		}
+	},
+
+	getValue: function(){
+		// summary: get the value of the widget.
+		return this._lastValueReported;
+	}
+});
+
+dojo.provide("dojo.string");
+
+dojo.string.pad = function(/*String*/text, /*int*/size, /*String?*/ch, /*boolean?*/end){
+	// summary:
+	//		Pad a string to guarantee that it is at least 'size' length by
+	//		filling with the character 'c' at either the start or end of the
+	//		string. Pads at the start, by default.
+	// text: the string to pad
+	// size: length to provide padding
+	// ch: character to pad, defaults to '0'
+	// end: adds padding at the end if true, otherwise pads at start
+
+	var out = String(text);
+	if(!ch){
+		ch = '0';
+	}
+	while(out.length < size){
+		if(end){
+			out += ch;
+		}else{
+			out = ch + out;
+		}
+	}
+	return out;	// String
+}
+
+dojo.string.substitute = function(	/*String*/template, 
+									/*Object or Array*/map, 
+									/*Function?*/transform, 
+									/*Object?*/thisObject){
+	// summary:
+	//		Performs parameterized substitutions on a string. Throws an
+	//		exception if any parameter is unmatched.
+	// description:
+	//		For example,
+	//			dojo.string.substitute("File '${0}' is not found in directory '${1}'.",["foo.html","/temp"]);
+	//			dojo.string.substitute("File '${name}' is not found in directory '${info.dir}'.",{name: "foo.html", info: {dir: "/temp"}});
+	//		both return
+	//			"File 'foo.html' is not found in directory '/temp'."
+	// template: 
+	//		a string with expressions in the form ${key} to be replaced or
+	//		${key:format} which specifies a format function.  NOTE syntax has
+	//		changed from %{key}
+	// map: where to look for substitutions
+	// transform: 
+	//		a function to process all parameters before substitution takes
+	//		place, e.g. dojo.string.encodeXML
+	// thisObject: 
+	//		where to look for optional format function; default to the global
+	//		namespace
+
+	return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(match, key, format){
+		var value = dojo.getObject(key,false,map);
+		if(format){ value = dojo.getObject(format,false,thisObject)(value);}
+		if(transform){ value = transform(value); }
+		return value.toString();
+	}); // string
+};
+
+dojo.provide("dojo.date.stamp");
+
+// Methods to convert dates to or from a wire (string) format using well-known conventions
+
+
+
+/* ISO 8601 Functions
+ *********************/
+
+dojo.date.stamp.setIso8601 = function(/*Date*/dateObject, /*String*/formattedString){
+	// summary: sets a Date object based on an ISO 8601 formatted string (uses date and time)
+	var comps = (formattedString.indexOf("T") == -1) ? formattedString.split(" ") : formattedString.split("T");
+	dateObject = dojo.date.stamp.setIso8601Date(dateObject, comps[0]);
+	if(comps.length == 2){ dateObject = dojo.date.stamp.setIso8601Time(dateObject, comps[1]); }
+	return dateObject; /* Date or null */
+};
+
+dojo.date.stamp.fromIso8601 = function(/*String*/formattedString){
+	// summary: returns a Date object based on an ISO 8601 formatted string (uses date and time)
+	return dojo.date.stamp.setIso8601(new Date(0, 0), formattedString);
+};
+
+dojo.date.stamp.setIso8601Date = function(/*String*/dateObject, /*String*/formattedString){
+	// summary: sets a Date object based on an ISO 8601 formatted string (date only)
+	var regexp = "^([0-9]{4})((-?([0-9]{2})(-?([0-9]{2}))?)|" +
+			"(-?([0-9]{3}))|(-?W([0-9]{2})(-?([1-7]))?))?$";
+	var d = formattedString.match(new RegExp(regexp));
+	if(!d){
+		console.debug("invalid date string: " + formattedString);
+		return null; // null
+	}
+	var year = d[1];
+	var month = d[4];
+	var date = d[6];
+	var dayofyear = d[8];
+	var week = d[10];
+	var dayofweek = d[12] || 1;
+
+	dateObject.setFullYear(year);
+
+	if(dayofyear){
+		dateObject.setMonth(0);
+		dateObject.setDate(Number(dayofyear));
+	}
+	else if(week){
+		dateObject.setMonth(0);
+		dateObject.setDate(1);
+		var day = dateObject.getDay() || 7;
+		var offset = Number(dayofweek) + (7 * Number(week));
+	
+		if(day <= 4){ dateObject.setDate(offset + 1 - day); }
+		else{ dateObject.setDate(offset + 8 - day); }
+	} else{
+		if(month){
+			dateObject.setDate(1);
+			dateObject.setMonth(month - 1); 
+		}
+		if(date){ dateObject.setDate(date); }
+	}
+
+	return dateObject; // Date
+};
+
+dojo.date.stamp.fromIso8601Date = function(/*String*/formattedString){
+	// summary: returns a Date object based on an ISO 8601 formatted string (date only)
+	return dojo.date.stamp.setIso8601Date(new Date(0, 0), formattedString);
+};
+
+dojo.date.stamp.setIso8601Time = function(/*Date*/dateObject, /*String*/formattedString){
+	// summary: sets a Date object based on an ISO 8601 formatted string (time only)
+
+	// first strip timezone info from the end
+	var timezone = "Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$";
+	var d = formattedString.match(new RegExp(timezone));
+
+	var offset = 0; // local time if no tz info
+	if(d){
+		if(d[0] != 'Z'){
+			offset = (Number(d[3]) * 60) + Number(d[5] || 0);
+			if(d[2] != '-'){ offset *= -1; }
+		}
+		offset -= dateObject.getTimezoneOffset();
+		formattedString = formattedString.substr(0, formattedString.length - d[0].length);
+	}
+
+	// then work out the time
+	var regexp = "^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(\.([0-9]+))?)?)?$";
+	d = formattedString.match(new RegExp(regexp));
+	if(!d){
+		console.debug("invalid time string: " + formattedString);
+		return null; // null
+	}
+	var hours = d[1];
+	var mins = Number(d[3] || 0);
+	var secs = d[5] || 0;
+	var ms = d[7] ? (Number("0." + d[7]) * 1000) : 0;
+
+	dateObject.setHours(hours);
+	dateObject.setMinutes(mins);
+	dateObject.setSeconds(secs);
+	dateObject.setMilliseconds(ms);
+
+	if(offset !== 0){
+		dateObject.setTime(dateObject.getTime() + offset * 60000);
+	}	
+	return dateObject; // Date
+};
+
+dojo.date.stamp.fromIso8601Time = function(/*String*/formattedString){
+	// summary: returns a Date object based on an ISO 8601 formatted string (time only)
+	return dojo.date.stamp.setIso8601Time(new Date(0, 0), formattedString);
+};
+
+
+/* RFC-3339 Date Functions
+ *************************/
+
+dojo.date.stamp.toRfc3339 = function(/*Date?*/dateObject, /*String?*/selector){
+//	summary:
+//		Format a JavaScript Date object as a string according to RFC 3339
+//
+//	dateObject:
+//		A JavaScript date, or the current date and time, by default
+//
+//	selector:
+//		"date" or "time" to format selected portions of the Date object.
+//		Date and time will be formatted by default.
+
+	dateObject = dateObject || new Date();
+
+	var _ = dojo.string.pad;
+	var formattedDate = [];
+	if(selector != "time"){
+		var date = [_(dateObject.getFullYear(),4), _(dateObject.getMonth()+1,2), _(dateObject.getDate(),2)].join('-');
+		formattedDate.push(date);
+	}
+	if(selector != "date"){
+		var time = [_(dateObject.getHours(),2), _(dateObject.getMinutes(),2), _(dateObject.getSeconds(),2)].join(':');
+		var timezoneOffset = dateObject.getTimezoneOffset();
+		time += (timezoneOffset > 0 ? "-" : "+") + 
+					_(Math.floor(Math.abs(timezoneOffset)/60),2) + ":" +
+					_(Math.abs(timezoneOffset)%60,2);
+		formattedDate.push(time);
+	}
+	return formattedDate.join('T'); // String
+};
+
+dojo.date.stamp.fromRfc3339 = function(/*String*/rfcDate){
+//	summary:
+//		Create a JavaScript Date object from a string formatted according to RFC 3339
+//
+//	rfcDate:
+//		A string such as 2005-06-30T08:05:00-07:00
+//		"any" is also supported in place of a time.
+
+	// backwards compatible support for use of "any" instead of just not 
+	// including the time
+	rfcDate = rfcDate.replace("Tany","");
+	return dojo.date.stamp.setIso8601(new Date(), rfcDate); // Date or null
+};
+
+dojo.provide("dijit.util.parser");
+
+
+
+
+dijit.util.parser = new function(){
+
+	function val2type(/*Object*/ value){
+		// summary:
+		//		Returns name of type of given value.
+
+		if(dojo.isString(value)){ return "string"; }
+		if(typeof value == "number"){ return "number"; }
+		if(typeof value == "boolean"){ return "boolean"; }
+		if(dojo.isFunction(value)){ return "function"; }
+		if(dojo.isArray(value)){ return "array"; } // typeof [] == "object"
+		if(value instanceof Date) { return "date"; } // assume timestamp
+		if(value instanceof dojo._Url){ return "url"; }
+		return "object";
+	}
+
+	function str2obj(/*String*/ value, /*String*/ type){
+		// summary:
+		//		Convert given string value to given type
+		switch(type){
+			case "string":
+				return value;
+			case "number":
+				return value.length ? Number(value) : null;
+			case "boolean":
+				return typeof value == "boolean" ? value : !(value.toLowerCase()=="false");
+			case "function":
+				if(dojo.isFunction(value)){
+					return value;
+				}
+				try{
+					if(value.search(/[^\w\.]+/i) != -1){
+						// TODO: "this" here won't work
+						value = dijit.util.parser._nameAnonFunc(new Function(value), this);
+					}
+					return dojo.getObject(value, false);
+				}catch(e){ return new Function(); }
+			case "array":
+				return value.split(";");
+			case "date":
+				return dojo.date.stamp.fromRfc3339(value);
+			case "url":
+//PORT FIXME: is value absolute or relative?  Need to join with "/"?
+				return dojo.baseUrl + value;
+			default:
+				try{ eval("var tmp = "+value); return tmp; }
+				catch(e){ return value; }
+		}
+	}
+
+	var widgetClasses = {
+		// map from fully qualified name (like "dijit.Button") to structure like
+		// { cls: dijit.Button, params: {caption: "string", disabled: "boolean"} }
+	};
+	
+	function getWidgetClassInfo(/*String*/ className){
+		// className:
+		//		fully qualified name (like "dijit.Button")
+		// returns:
+		//		structure like
+		//			{ 
+		//				cls: dijit.Button, 
+		//				params: { caption: "string", disabled: "boolean"}
+		//			}
+
+		if(!widgetClasses[className]){
+			// get pointer to widget class
+			var cls = dojo.getObject(className);
+			if(!dojo.isFunction(cls)){
+				throw new Error("Could not load widget '" + className +
+					"'. Did you spell the name correctly and use a full path, like 'dijit.form.Button'?");
+			}
+			var proto = cls.prototype;
+	
+			// get table of parameter names & types
+			var params={};
+			for(var name in proto){
+				if(name.charAt(0)=="_"){ continue; } 	// skip internal properties
+				var defVal = proto[name];
+				params[name]=val2type(defVal);
+			}
+
+			widgetClasses[className] = { cls: cls, params: params };
+		}
+		return widgetClasses[className];
+	}
+	
+	this.instantiate = function(nodes){
+		// summary:
+		//		Takes array of nodes, and turns them into widgets Calls their
+		//		layout method to allow them to connect with any children		
+		var thelist = [];
+		dojo.forEach(nodes, function(node){
+			if(!node){ return; }
+			var type = node.getAttribute('dojoType');
+			if((!type)||(!type.length)){ return; }
+			var clsInfo = getWidgetClassInfo(type);
+			var params = {};
+			for(var attrName in clsInfo.params){
+				var attrValue = node.getAttribute(attrName);
+				if(attrValue != null){
+					var attrType = clsInfo.params[attrName];
+					params[attrName] = str2obj(attrValue, attrType);
+				}
+			}
+			thelist.push(new clsInfo.cls(params, node));
+			var jsname = node.getAttribute('jsId');
+			if(jsname){
+				dojo.setObject(jsname, thelist[thelist.length-1]);
+			}
+		});
+
+		// Call startup on each top level widget.  Parent widgets will
+		// recursively call startup on their (non-top level) children
+		dojo.forEach(thelist, function(widget){
+			if(widget && widget.startup && (!widget.getParent || widget.getParent()==null)){
+				widget.startup();
+			}
+		});
+		return thelist;
+	};
+
+	this.parse = function(/*DomNode?*/ rootNode){
+		// summary:
+		//		Search specified node (or root node) recursively for widgets,
+		//		and instantiate them Searches for
+		//		dojoType="qualified.class.name"
+		var list = dojo.query('[dojoType]', rootNode);
+		return this.instantiate(list);
+	};
+}();
+
+dojo.addOnLoad(function(){ dijit.util.parser.parse(); });
+
+//TODO: ported from 0.4.x Dojo.  Can we reduce this?
+dijit.util.parser._anonCtr = 0;
+dijit.util.parser._anon = {}; // why is this property required?
+dijit.util.parser._nameAnonFunc = function(/*Function*/anonFuncPtr, /*Object*/thisObj, /*Boolean*/searchForNames){
+	// summary:
+	//		Creates a reference to anonFuncPtr in thisObj with a completely
+	//		unique name. The new name is returned as a String.  If
+	//		searchForNames is true, an effort will be made to locate an
+	//		existing reference to anonFuncPtr in thisObj, and if one is found,
+	//		the existing name will be returned instead. The default is for
+	//		searchForNames to be false.
+	var jpn = "$joinpoint";
+	var nso = (thisObj|| dijit.util.parser._anon);
+	if(dojo.isIE){
+		var cn = anonFuncPtr["__dojoNameCache"];
+		if(cn && nso[cn] === anonFuncPtr){
+			return anonFuncPtr["__dojoNameCache"];
+		}else if(cn){
+			// hack to see if we've been event-system mangled
+			var tindex = cn.indexOf(jpn);
+			if(tindex != -1){
+				return cn.substring(0, tindex);
+			}
+		}
+	}
+	var ret = "__"+dijit.util.parser._anonCtr++;
+	while(typeof nso[ret] != "undefined"){
+		ret = "__"+dijit.util.parser._anonCtr++;
+	}
+	nso[ret] = anonFuncPtr;
+	return ret; // String
+}
+
+dojo.provide("dijit.base.TemplatedWidget");
+
+
+
+
+
+dojo.declare("dijit.base.TemplatedWidget", 
+	null,
+	{
+		// summary:
+		//		mixin for widgets that are instantiated from a template
+			 
+		// templateNode: DomNode
+		//		a node that represents the widget template. Pre-empts both templateString and templatePath.
+		templateNode: null,
+
+		// templateString String:
+		//		a string that represents the widget template. Pre-empts the
+		//		templatePath. In builds that have their strings "interned", the
+		//		templatePath is converted to an inline templateString, thereby
+		//		preventing a synchronous network call.
+		templateString: null,
+
+		// templatePath: String
+		//	Path to template (HTML file) for this widget
+		templatePath: null,
+
+		// widgetsInTemplate Boolean:
+		//		should we parse the template to find widgets that might be
+		//		declared in markup inside it? false by default.
+		// TODO: unsupported; need to copy over code from trunk
+		widgetsInTemplate: false,
+		
+		// containerNode DomNode:
+		//		holds child elements. "containerNode" is generally set via a
+		//		dojoAttachPoint assignment and it designates where children of
+		//		the src dom node will be placed
+		containerNode: null,
+
+		// method over-ride
+		buildRendering: function(){
+			// summary:
+			//		Construct the UI for this widget from a template.
+			// description:
+			// Lookup cached version of template, and download to cache if it
+			// isn't there already.  Returns either a DomNode or a string, depending on
+			// whether or not the template contains ${foo} replacement parameters.
+
+			var cached = dijit.base.getCachedTemplate(this.templatePath, this.templateString);
+
+			var node;
+			if(dojo.isString(cached)){
+				// Cache contains a string because we need to do property replacement
+				// do the property replacement
+				var tstr = dojo.string.substitute(cached, this, function(value){
+					// Safer substitution, see heading "Attribute values" in  
+					// http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
+					return value.toString().replace(/"/g,"&quot;"); //TODO: support a more complete set of escapes?
+				}, this);
+
+				node = dijit.base._createNodesFromText(tstr)[0];
+			}else{
+				// if it's a node, all we have to do is clone it
+				node = cached.cloneNode(true);
+			}
+
+			// recurse through the node, looking for, and attaching to, our
+			// attachment points which should be defined on the template node.
+			this._attachTemplateNodes(node);
+			if(this.srcNodeRef){
+				dojo.style(node, "cssText", this.srcNodeRef.style.cssText);
+				if(this.srcNodeRef.className){
+					node.className += " " + this.srcNodeRef.className;
+				}
+			}
+
+			this.domNode = node;
+			if(this.srcNodeRef && this.srcNodeRef.parentNode){
+				this.srcNodeRef.parentNode.replaceChild(this.domNode, this.srcNodeRef);
+			}
+			if(this.widgetsInTemplate){
+				var childWidgets = dijit.util.parser.parse(this.domNode);
+				this._attachTemplateNodes(childWidgets, function(n,p){
+					return n[p];
+				});
+			}
+
+			// relocate source contents to templated container node
+			// this.containerNode must be able to receive children, or exceptions will be thrown
+			if(this.srcNodeRef && this.srcNodeRef.hasChildNodes()){
+				var dest = this.containerNode||this.domNode;
+				while(this.srcNodeRef.hasChildNodes()){
+					dest.appendChild(this.srcNodeRef.firstChild);
+				}
+			}
+		},
+
+		_attachTemplateNodes: function(rootNode, getAttrFunc){
+			// summary:
+			//		map widget properties and functions to the handlers specified in
+			//		the dom node and it's descendants. This function iterates over all
+			//		nodes and looks for these properties:
+			//			* dojoAttachPoint
+			//			* dojoAttachEvent	
+			//			* waiRole
+			//			* waiState
+			// rootNode: DomNode|Array[Widgets]
+			//		the node to search for properties. All children will be searched.
+			// getAttrFunc: function?
+			//		a function which will be used to obtain property for a given 
+			//		DomNode/Widget
+		
+			var trim = function(str){
+				return str.replace(/^\s+|\s+$/g, "");
+			};
+
+			getAttrFunc = getAttrFunc || function(n,p){ return n.getAttribute(p); } 
+
+			var nodes = dojo.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*")); 
+			var x=dojo.isArray(rootNode)?0:-1; 
+			for(; x<nodes.length; x++){
+				var baseNode = (x == -1) ? rootNode : nodes[x];
+				if(this.widgetsInTemplate && getAttrFunc(baseNode,'dojoType')){
+					return;
+				}
+				// Process dojoAttachPoint
+				var tmpAttachPoint = getAttrFunc(baseNode, "dojoAttachPoint");
+				if(tmpAttachPoint){
+					var attachPoint = tmpAttachPoint.split(";");
+					var z = 0, ap;
+					while((ap=attachPoint[z++])){
+						if(dojo.isArray(this[ap])){
+							this[ap].push(baseNode);
+						}else{
+							this[ap]=baseNode;
+						}
+					}
+				}
+
+				// dojoAttachEvent
+				var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent");
+				if(attachEvent){
+					// NOTE: we want to support attributes that have the form
+					// "domEvent: nativeEvent; ..."
+					var evts = attachEvent.split(";");
+					var y = 0, evt;
+					while((evt=evts[y++])){
+						if(!evt || !evt.length){ continue; }
+						var thisFunc = null;
+						var tevt = trim(evt);
+						if(evt.indexOf(":") != -1){
+							// oh, if only JS had tuple assignment
+							var funcNameArr = tevt.split(":");
+							tevt = trim(funcNameArr[0]);
+							thisFunc = trim(funcNameArr[1]);
+						}
+						if(!thisFunc){
+							thisFunc = tevt;
+						}
+						this.connect(baseNode, tevt, thisFunc); 
+					}
+				}
+		
+				// waiRole, waiState
+				dojo.forEach(["waiRole", "waiState"], function(name){
+					var wai = dijit.util.wai[name];
+					var val = getAttrFunc(baseNode, wai.name);
+					if(val){
+						var role = "role";
+						if(val.indexOf('-') != -1){ 
+							// this is a state-value pair
+							var statePair = val.split('-');
+							role = statePair[0];
+							val = statePair[1];
+						}
+						dijit.util.wai.setAttr(baseNode, wai.name, role, val);
+					}
+				}, this);
+			}
+		}
+	}
+);
+
+// key is either templatePath or templateString; object is either string or DOM tree
+dijit.base._templateCache = {};
+
+dijit.base.getCachedTemplate = function(templatePath, templateString){
+	// summary:
+	//		static method to get a template based on the templatePath or
+	//		templateString key
+	// templatePath: String
+	//		the URL to get the template from. dojo.uri.Uri is often passed as well.
+	// templateString: String?
+	//		a string to use in lieu of fetching the template from a URL
+	// Returns:
+	//	Either string (if there are ${} variables that need to be replaced) or just
+	//	a DOM tree (if the node can be cloned directly)
+
+	// is it already cached?
+	var tmplts = dijit.base._templateCache;
+	var key = templateString || templatePath;
+	var cached = tmplts[key];
+	if(cached){
+		return cached;
+	}
+
+	// If necessary, load template string from template path
+	if(!templateString){
+		templateString = dijit.base._sanitizeTemplateString(dojo._getText(templatePath));
+	}
+
+	templateString = templateString.replace(/^\s+|\s+$/g, "");
+
+	if(templateString.match(/\$\{([^\}]+)\}/g)){
+		// there are variables in the template so all we can do is cache the string
+		return (tmplts[key] = templateString); //String
+	}else{
+		// there are no variables in the template so we can cache the DOM tree
+		return (tmplts[key] = dijit.base._createNodesFromText(templateString)[0]); //Node
+	}
+};
+
+dijit.base._sanitizeTemplateString = function(/*String*/tString){
+	//summary: Strips <?xml ...?> declarations so that external SVG and XML
+	//documents can be added to a document without worry. Also, if the string
+	//is an HTML document, only the part inside the body tag is returned.
+	if(tString){
+		tString = tString.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
+		var matches = tString.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+		if(matches){
+			tString = matches[1];
+		}
+	}else{
+		tString = "";
+	}
+	return tString; //String
+};
+
+
+if(dojo.isIE){
+	dojo.addOnUnload(function(){
+		var cache = dijit.base._templateCache;
+		for(var key in cache){
+			var value = cache[key];
+			if(!isNaN(value.nodeType)){ // isNode equivalent
+// PORT.  Fix leak			dojo.dom.destroyNode(value);
+			}
+			cache[key] = null;
+		}
+	});
+}
+
+(function(){
+	var tagMap = {
+		cell: {re: /^<t[dh][\s\r\n>]/i, pre: "<table><tbody><tr>", post: "</tr></tbody></table>"},
+		row: {re: /^<tr[\s\r\n>]/i, pre: "<table><tbody>", post: "</tbody></table>"},
+		section: {re: /^<(thead|tbody|tfoot)[\s\r\n>]/i, pre: "<table>", post: "</table>"}
+	};
+
+	var tn;
+	var _parent;
+
+	dijit.base._createNodesFromText = function(/*String*/text){
+		//	summary
+		//	Attempts to create a set of nodes based on the structure of the passed text.
+
+		if(!tn){
+			_parent = tn = dojo.doc.createElement("div");
+			tn.style.visibility="hidden";
+		}
+		var tableType = "none";
+		var rtext = text.replace(/^\s+/);
+		for(var type in tagMap){
+			var map = tagMap[type];
+			if(map.re.test(rtext)){ //FIXME: replace with one arg?  is this a no-op?
+				tableType = type;
+				text = map.pre + text + map.post;
+				break;
+			}
+		}
+
+		tn.innerHTML = text;
+		dojo.body().appendChild(tn);
+		if(tn.normalize){
+			tn.normalize();
+		}
+
+		var tag = { cell: "tr", row: "tbody", section: "table" }[tableType];
+		if(typeof tag != "undefined"){
+			_parent = tn.getElementsByTagName(tag)[0];
+		}
+
+		var nodes = [];
+		/*
+		for(var x=0; x<_parent.childNodes.length; x++){
+			nodes.push(_parent.childNodes[x].cloneNode(true));
+		}
+		*/
+		while(_parent.firstChild){
+			nodes.push(_parent.removeChild(_parent.firstChild));
+		}
+		//PORT	dojo.html.destroyNode(tn); FIXME: need code to prevent leaks and such
+		_parent = dojo.body().removeChild(tn);
+		return nodes;	//	Array
+	}
+})();
+
+// These arguments can be specified for widgets which are used in templates.
+// Since any widget can be specified as sub widgets in template, mix it
+// into the base widget class.  (This is a hack, but it's effective.)
+dojo.extend(dijit.base.Widget,{
+	dojoAttachEvent: "",
+	dojoAttachPoint: "",
+	waiRole: "",
+	waiState:""
+})
+
+dojo.provide("dijit.util.FocusManager");
+
+dijit.util.FocusManager = new function(){
+	// summary:
+	//		This class is used to save the current focus / selection on the screen,
+	//		and restore it later.   It's typically used for popups (menus and dialogs),
+	//		but can also be used for a menubar or toolbar.   (For example, in the editor
+	//		the user might type Ctrl-T to focus the toolbar, and then when he/she selects
+	//		a menu choice, focus is returned to the editor window.)
+	//
+	//		Note that it doesn't deal with submenus off of an original menu;
+	//		From this class's perspective it's all part of one big menu.
+	//
+	//		The widget must implement a close() callback, which will close dialogs or
+	//		a context menu, and for a menubar, it will close the submenus and remove
+	//		highlighting classes on the root node.
+
+
+	/////////////////////////////////////////////////////////////
+	// Keep track of currently focused and previously focused element
+
+	var curFocus, prevFocus;	
+	function onFocus(/*DomNode*/ node){
+		if(node && node.tagName=="body"){
+			node=null;
+		}
+		if(node !== curFocus){
+			prevFocus = curFocus;
+			curFocus = node;
+			console.debug("focused on ", node ? (node.id ? node.id : node.tagName) : "nothing");
+		}
+	}
+	
+	dojo.addOnLoad(function(){
+		if(dojo.isIE){
+			// TODO: to make this more deterministic should delay updating curFocus/prevFocus for 10ms?
+			window.setInterval(function(){ onFocus(document.activeElement); }, 100);
+		}else{
+			dojo.body().addEventListener('focus', function(evt){ onFocus(evt.target); }, true);
+		}
+	});
+	
+	/////////////////////////////////////////////////////////////////
+	// Main methods, called when a dialog/menu is opened/closed
+
+	// TODO: convert this to a stack, so we can save and restore multiple times?
+	// or have save return an object that can be passed to restore?
+
+	var currentMenu = null;	// current menu/dialog
+	var closeOnScreenClick = false;	// should clicking the screen close the menu?
+	var openedForWindow;	// iframe in which menu was opened
+	var restoreFocus;		// focused node before menu opened
+	var bookmark;			// selected text before menu opened
+
+	var isCollapsed = function(){
+		// summary: return whether the current selection is empty
+		var _window = dojo.global;
+		var _document = dojo.doc;
+		if(_document.selection){ // IE
+			return _document.selection.createRange().text == "";
+		}else if(_window.getSelection){
+			var selection = _window.getSelection();
+			if(dojo.isString(selection)){ // Safari
+				return selection == "";
+			}else{ // Mozilla/W3
+				return selection.isCollapsed || selection.toString() == "";
+			}
+		}
+	};
+
+	var getBookmark = function(){
+		// summary: Retrieves a bookmark that can be used with moveToBookmark to return to the same range
+		var bookmark;
+		var _document = dojo.doc;
+		if(_document.selection){ // IE
+			var range = _document.selection.createRange();
+			if(_document.selection.type.toUpperCase()=='CONTROL'){
+				if(range.length){
+					bookmark=[];
+					var i=0;
+					while(i<range.length){
+						bookmark.push(range.item(i++));
+					}
+				}else{
+					bookmark = null;
+				}
+			}else{
+				bookmark = range.getBookmark();
+			}
+		}else{
+			var selection;
+			//TODO: why a try/catch?  check for getSelection instead?
+			try{selection = dojo.global.getSelection();}
+			catch(e){/*squelch*/}
+			if(selection){
+				var range = selection.getRangeAt(0);
+				bookmark = range.cloneRange();
+			}else{
+				console.debug("No idea how to store the current selection for this browser!");
+			}
+		}
+		return bookmark;
+	};
+
+	var moveToBookmark = function(/*Object*/bookmark){
+		// summary: Moves current selection to a bookmark
+		// bookmark: this should be a returned object from dojo.html.selection.getBookmark()
+		var _document = dojo.doc;
+		if(_document.selection){ // IE
+			if(dojo.isArray(bookmark)){
+				var range= _document.body.createControlRange();
+				var i=0;
+				while(i<bookmark.length){
+					range.addElement(bookmark[i++]);
+				}
+				range.select();
+			}else{
+				var range = _document.selection.createRange();
+				range.moveToBookmark(bookmark);
+				range.select();
+			}
+		}else{ //Moz/W3C
+			var selection;
+			//TODO: why a try/catch?  check for getSelection instead?
+			try{selection = dojo.global.getSelection();}
+			catch(e){/*squelch*/}
+			if(selection && selection.removeAllRanges){
+				selection.removeAllRanges();
+				selection.addRange(bookmark);
+			}else{
+				console.debug("No idea how to restore selection for this browser!");
+			}
+		}
+	};
+
+	this.save = function(/*Widget*/menu, /*Window*/ _openedForWindow){
+		// summary:
+		//	called when a popup appears (either a top level menu or a dialog),
+		//	or when a toolbar/menubar receives focus
+		if (menu == currentMenu){ return; }
+
+		if (currentMenu){
+			currentMenu.close();
+		}
+
+		currentMenu = menu;
+		openedForWindow = _openedForWindow;
+
+		//PORT #2804. Use isAncestor
+		var isDescendantOf = function(/*Node*/node, /*Node*/ancestor){
+			//	summary
+			//	Returns boolean if node is a descendant of ancestor
+			// guaranteeDescendant allows us to be a "true" isDescendantOf function
+
+			while(node){
+				if(node === ancestor){ 
+					return true; // boolean
+				}
+				node = node.parentNode;
+			}
+			return false; // boolean
+		};
+
+		// Find node to restore focus to, when this menu/dialog closes
+		restoreFocus = isDescendantOf(curFocus, menu.domNode) ? prevFocus : curFocus;
+		console.debug("will restore focus to " + ( restoreFocus ? (restoreFocus.id || restoreFocus.tagName) : "nothing") );
+		console.debug("prev focus is " + prevFocus);
+
+		//Store the current selection and restore it before the action for a menu item
+		//is executed. This is required as clicking on an menu item deselects current selection
+		if(!dojo.withGlobal(openedForWindow||dojo.global, isCollapsed)){
+			bookmark = dojo.withGlobal(openedForWindow||dojo.global, getBookmark);
+		}else{
+			bookmark = null;
+		}
+	};
+
+	this.restore = function(/*Widget*/menu){
+		// summary:
+		//	notify the manager that menu is closed; it will return focus to
+		//	where it was before the menu got focus
+		if(currentMenu == menu){
+			// focus on element that was focused before menu stole the focus
+			if(restoreFocus){
+				restoreFocus.focus();
+			}
+
+			//do not need to restore if current selection is not empty
+			//(use keyboard to select a menu item)
+			if(bookmark && dojo.withGlobal(openedForWindow||dojo.global, isCollapsed)){
+				if(openedForWindow){
+					openedForWindow.focus();
+				}
+				try{
+					dojo.withGlobal(openedForWindow||dojo.global, moveToBookmark, null, [bookmark]);
+				}catch(e){
+					/*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */
+				}
+			}
+
+			bookmark = null;
+			closeOnScreenClick = false;
+			currentMenu = null;
+		}
+	};
+}();
+
+dojo.provide("dijit.util.BackgroundIframe");
+
+dijit.util.BackgroundIframe = function(/* HTMLElement */node){
+	//	summary:
+	//		For IE z-index schenanigans
+	//		Two possible uses:
+	//			1. new dijit.util.BackgroundIframe(node)
+	//				Makes a background iframe as a child of node, that fills
+	//				area (and position) of node
+	//			2. new dijit.util.BackgroundIframe()
+	//				Attaches frame to dojo.body().  User must call size() to
+	//				set size.
+	if(dojo.isIE && dojo.isIE < 7){
+		var html="<iframe src='javascript:false'"
+			+ " style='position: absolute; left: 0px; top: 0px; width: 100%; height: 100%;"
+			+ "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
+		this.iframe = dojo.doc.createElement(html);
+		this.iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work.
+		if(node){
+			node.appendChild(this.iframe);
+			this.domNode=node;
+		}else{
+			dojo.body().appendChild(this.iframe);
+			this.iframe.style.display="none";
+		}
+	}
+};
+
+dojo.extend(dijit.util.BackgroundIframe, {
+	iframe: null,
+	onResized: function(){
+		//	summary:
+		//		Resize event handler.
+
+		// TODO: this function shouldn't be necessary but setting
+		// 			width=height=100% doesn't work!
+		if(this.iframe && this.domNode && this.domNode.parentNode){ 
+			// No parentElement if onResized() timeout event occurs on a removed domnode
+			var outer = dojo.marginBox(this.domNode);
+			if (!outer.w || !outer.h){
+				setTimeout(this, this.onResized, 100);
+				return;
+			}
+			this.iframe.style.width = outer.w + "px";
+			this.iframe.style.height = outer.h + "px";
+		}
+	},
+
+	size: function(/* HTMLElement */node){
+		// summary:
+		//		Call this function if the iframe is connected to dojo.body()
+		//		rather than the node being shadowed 
+
+		//	(TODO: erase)
+		if(!this.iframe){ return; }
+		var coords = dojo.coords(node, true); // PORT used BORDER_BOX
+		var s = this.iframe.style;
+		s.width = coords.w + "px";
+		s.height = coords.h + "px";
+		s.left = coords.x + "px";
+		s.top = coords.y + "px";
+	},
+
+	setZIndex: function(/* HTMLElement|int */node){
+		//	summary:
+		//		Sets the z-index of the background iframe
+		//	node:
+		//		If an element, sets zIndex of iframe to zIndex of node minus one. 
+		//		Otherwise, specifies the new zIndex as an integer.
+
+		if(!this.iframe){ return; }
+
+		this.iframe.style.zIndex = !isNaN(node) ? node : (node.style.zIndex - 1);
+	},
+
+	show: function(){
+		//	summary:
+		//		show the iframe
+		if(this.iframe){ 
+			this.iframe.style.display = "block";
+		}
+	},
+
+	hide: function(){
+		//	summary:
+		//		hide the iframe
+		if(this.iframe){ 
+			this.iframe.style.display = "none";
+		}
+	},
+
+	remove: function(){
+		//	summary:
+		//		remove the iframe
+		if(this.iframe){
+			this.iframe.parentNode.removeChild(this.iframe); // PORT: leak?
+			delete this.iframe;
+			this.iframe=null;
+		}
+	}
+});
+
+dojo.provide("dijit.util.place");
+
+// ported from dojo.html.util
+
+dijit.util.getViewport = function(){
+	//	summary
+	//	Returns the dimensions of the viewable area of a browser window
+	var _window = dojo.global;
+	var _document = dojo.doc;
+	var w = 0;
+	var h = 0;
+
+	if(dojo.isMozilla){
+		// mozilla
+		w = _document.documentElement.clientWidth;
+		h = _window.innerHeight;
+	}else if(!dojo.isOpera && _window.innerWidth){
+		//in opera9, dojo.body().clientWidth should be used, instead
+		//of window.innerWidth/document.documentElement.clientWidth
+		//so we have to check whether it is opera
+		w = _window.innerWidth;
+		h = _window.innerHeight;
+	}else if(dojo.isIE && _document.documentElement && _document.documentElement.clientHeight){
+		w = _document.documentElement.clientWidth;
+		h = _document.documentElement.clientHeight;
+	}else if(dojo.body().clientWidth){
+		// IE5, Opera
+		w = dojo.body().clientWidth;
+		h = dojo.body().clientHeight;
+	}
+	return { w: w, h: h };	//	object
+};
+
+dijit.util.getScroll = function(){
+	//	summary
+	//	Returns the scroll position of the document
+	var _window = dojo.global;
+	var _document = dojo.doc;
+	var top = _window.pageYOffset || _document.documentElement.scrollTop || dojo.body().scrollTop || 0;
+	var left = _window.pageXOffset || _document.documentElement.scrollLeft || dojo.body().scrollLeft || 0;
+	return { 
+		top: top,
+		left: left, 
+		offset:{ x: left, y: top }	//	note the change, NOT an Array with added properties. 
+	};	//	object
+};
+
+dijit.util.placeOnScreen = function(
+	/* HTMLElement */	node,
+	/* integer */		desiredX,
+	/* integer */		desiredY,
+	/* integer */		padding,
+	/* boolean? */		hasScroll,
+	/* string? */		corners,
+	/* boolean? */		tryOnly){
+	//	summary:
+	//		Keeps 'node' in the visible area of the screen while trying to
+	//		place closest to desiredX, desiredY. The input coordinates are
+	//		expected to be the desired screen position, not accounting for
+	//		scrolling. If you already accounted for scrolling, set 'hasScroll'
+	//		to true. Set padding to either a number or array for [paddingX, paddingY]
+	//		to put some buffer around the element you want to position.
+	//		Set which corner(s) you want to bind to, such as
+	//		
+	//			placeOnScreen(node, desiredX, desiredY, padding, hasScroll, "TR")
+	//			placeOnScreen(node, [desiredX, desiredY], padding, hasScroll, ["TR", "BL"])
+	//		
+	//		The desiredX/desiredY will be treated as the topleft(TL)/topright(TR) or
+	//		BottomLeft(BL)/BottomRight(BR) corner of the node. Each corner is tested
+	//		and if a perfect match is found, it will be used. Otherwise, it goes through
+	//		all of the specified corners, and choose the most appropriate one.
+	//		By default, corner = ['TL'].
+	//		If tryOnly is set to true, the node will not be moved to the place.
+	//		
+	//		NOTE: node is assumed to be absolutely or relatively positioned.
+	//		
+	//	Alternate call sig:
+	//		 placeOnScreen(node, [x, y], padding, hasScroll)
+	//		
+	//	Examples:
+	//		 placeOnScreen(node, 100, 200)
+	//		 placeOnScreen("myId", [800, 623], 5)
+	//		 placeOnScreen(node, 234, 3284, [2, 5], true)
+
+	// TODO: make this function have variable call sigs
+	//	kes(node, ptArray, cornerArray, padding, hasScroll)
+	//	kes(node, ptX, ptY, cornerA, cornerB, cornerC, paddingArray, hasScroll)
+	if(dojo.isArray(desiredX)){
+		tryOnly = corners;
+		corners = hasScroll;
+		hasScroll = padding;
+		padding = desiredY;
+		desiredY = desiredX[1];
+		desiredX = desiredX[0];
+	}
+
+	if(dojo.isString(corners)){
+		corners = corners.split(",");
+	}
+
+	if(!isNaN(padding)){
+		padding = [Number(padding), Number(padding)];
+	}else if(!dojo.isArray(padding)){
+		padding = [0, 0];
+	}
+
+	var scroll = dijit.util.getScroll().offset;
+	var view = dijit.util.getViewport();
+
+	node = dojo.byId(node);
+	var oldDisplay = node.style.display;
+	var oldVis = node.style.visibility;
+	node.style.visibility = "hidden";
+	node.style.display = "";
+//	var bb = dojo.html.getBorderBox(node);
+	var bb = dojo.marginBox(node); //PORT okay?
+	var w = bb.w;
+	var h = bb.h;
+	node.style.display = oldDisplay;
+	node.style.visibility = oldVis;
+
+	//#2670
+	var visiblew,visibleh,bestw,besth="";
+
+	if(!dojo.isArray(corners)){
+		corners = ['TL'];
+	}
+
+	var bestx, besty, bestDistance = Infinity, bestCorner;
+
+	for(var cidex=0; cidex<corners.length; ++cidex){
+		var visiblew,visibleh="";
+		var corner = corners[cidex];
+		var match = true;
+		// guess where to put the upper left corner of the popup, based on which corner was passed
+		// if you choose a corner other than the upper left, 
+		// obviously you have to move the popup
+		// so that the selected corner is at the x,y you asked for
+		var tryX = desiredX - (corner.charAt(1)=='L' ? 0 : w) + padding[0]*(corner.charAt(1)=='L' ? 1 : -1);
+		var tryY = desiredY - (corner.charAt(0)=='T' ? 0 : h) + padding[1]*(corner.charAt(0)=='T' ? 1 : -1);
+		// document => viewport
+		if(hasScroll){
+			tryX -= scroll.x;
+			tryY -= scroll.y;
+		}
+		// x component
+		// test if the popup does not fit
+		var x = tryX + w;
+		if(x > view.w){
+			match = false;
+		}
+		// viewport => document
+		// min: left side of screen
+		x = Math.max(padding[0], tryX) + scroll.x;
+		// calculate the optimal width of the popup
+		if(corner.charAt(1)=='L'){
+			if(w>view.w-tryX){
+				visiblew=view.w-tryX;
+				match=false;
+			}else{
+				visiblew=w;
+			}
+		}else{
+			if(tryX<0){
+				visiblew=w+tryX;
+				match=false;
+			}else{
+				visiblew=w;
+			}
+		}
+		// y component
+		// test if the popup does not fit
+		var y = tryY + h;
+		if(y > view.h){
+			match = false;
+		}
+		// viewport => document
+		// min: top side of screen
+		y = Math.max(padding[1], tryY) + scroll.y;
+		// calculate the optimal height of the popup
+		if(corner.charAt(0)=='T'){
+			if(h>view.h-tryY){
+				visibleh=view.h-tryY;
+				match=false;
+			}else{
+				visibleh=h;
+			}
+		}else{
+			if(tryY<0){
+				visibleh=h+tryY;
+				match=false;
+			}else{
+				visibleh=h;
+			}
+		}
+
+		if(match){ //perfect match, return now
+			bestx = x;
+			besty = y;
+			bestDistance = 0;
+			bestw = visiblew;
+			besth = visibleh;
+			bestCorner = corner;
+			break;
+		}else{
+			//not perfect, find out whether it is better than the saved one
+			// weight this position by its squared distance
+			var dist = Math.pow(x-tryX-scroll.x,2)+Math.pow(y-tryY-scroll.y,2);
+			// if there was not a perfect match but dist=0 anyway (popup too small) weight by size of popup
+			if(dist==0){dist=Math.pow(h-visibleh,2);}
+			// choose the lightest (closest or biggest popup) position
+			if(bestDistance > dist){
+				bestDistance = dist;
+				bestx = x;
+				besty = y;
+				bestw = visiblew;
+				besth = visibleh;
+				bestCorner = corner;
+			}
+		}
+	}
+
+	if(!tryOnly){
+		node.style.left = bestx + "px";
+		node.style.top = besty + "px";
+	}
+
+	return {left: bestx, top: besty, x: bestx, y: besty, dist: bestDistance, corner:  bestCorner, h:besth, w:bestw};	//	object
+}
+
+dijit.util.placeOnScreenAroundElement = function(
+	/* HTMLElement */node,
+	/* HTMLElement */aroundNode,
+	/* integer */padding,
+	/* string? */aroundCorners,
+	/* boolean? */tryOnly){
+	//	summary
+	//	Like placeOnScreen, except it accepts aroundNode instead of x,y
+	//	and attempts to place node around it.  Uses margin box dimensions.
+	//
+	//	aroundCorners
+	//		specify Which corner of aroundNode should be
+	//		used to place the node => which corner(s) of node to use (see the
+	//		corners parameter in dijit.util.placeOnScreen)
+	//		e.g. {'TL': 'BL', 'BL': 'TL'}
+
+	// This won't work if the node is inside a <div style="position: relative>,
+	// so reattach it to document.body.   (Otherwise, the positioning will be wrong
+	// and also it might get cutoff)
+	if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){
+		dojo.body().appendChild(node);
+	}
+
+	var best, bestDistance=Infinity;
+	aroundNode = dojo.byId(aroundNode);
+	var oldDisplay = aroundNode.style.display;
+	aroundNode.style.display="";
+	// #3172: use the slightly tighter border box instead of marginBox
+	//var mb = dojo.marginBox(aroundNode);
+	//aroundNode.style.borderWidth="10px";
+	var aroundNodeW = aroundNode.offsetWidth; //mb.w;
+	var aroundNodeH = aroundNode.offsetHeight; //mb.h;
+	var aroundNodePos = dojo.coords(aroundNode, true);
+	aroundNode.style.display=oldDisplay;
+
+	for(var nodeCorner in aroundCorners){
+		var pos, desiredX, desiredY;
+		var corners = aroundCorners[nodeCorner];
+
+		desiredX = aroundNodePos.x + (nodeCorner.charAt(1)=='L' ? 0 : aroundNodeW);
+		desiredY = aroundNodePos.y + (nodeCorner.charAt(0)=='T' ? 0 : aroundNodeH);
+
+		pos = dijit.util.placeOnScreen(node, desiredX, desiredY, padding, true, corners, true);
+		if(pos.dist == 0){
+			best = pos;
+			break;
+		}else{
+			//not perfect, find out whether it is better than the saved one
+			if(bestDistance > pos.dist){
+				bestDistance = pos.dist;
+				best = pos;
+			}
+		}
+	}
+
+	if(!tryOnly){
+		node.style.left = best.left + "px";
+		node.style.top = best.top + "px";
+	}
+	return best;	//	object
+}
+
+console.warn("dijit.dijit may dissapear in the 0.9 timeframe in lieu of a different rollup file!");
+dojo.provide("dijit.dijit");
+
+
+
+
+
+
+
+
+
+
+
+
+

Added: trunk/examples/typeface/root/static/dojo/dijit/form/AutoCompleter.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/AutoCompleter.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/AutoCompleter.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,618 @@
+dojo.provide("dijit.form.AutoCompleter");
+
+dojo.require("dijit.util.scroll");
+dojo.require("dijit.util.wai");
+dojo.require("dojo.data.JsonItemStore");
+dojo.require("dijit.form._DropDownTextBox");
+dojo.require("dijit.form.ValidationTextbox");
+dojo.require("dijit.base.TemplatedWidget");
+
+dojo.declare(
+	"dijit.form.AutoCompleterMixin",
+	dijit.form._DropDownTextBox,
+	{
+		// summary:
+		//		Auto-completing text box, and base class for Select widget.
+		//
+		//		The drop down box's values are populated from an class called
+		//		a data provider, which returns a list of values based on the characters
+		//		that the user has typed into the input box.
+		//
+		//		Some of the options to the AutoCompleter are actually arguments to the data
+		//		provider.
+
+		// searchLimit: Integer
+		//		Argument to data provider.
+		//		Specifies cap on maximum number of search results.
+		//		Default is Infinity.
+		searchLimit: Infinity,
+
+		// store: Object
+		//		Reference to data provider object created for this AutoCompleter
+		//		according to "dataProviderClass" argument.
+		store: null,
+
+		// autoComplete: Boolean
+		//		If you type in a partial string, and then tab out of the <input> box,
+		//		automatically copy the first entry displayed in the drop down list to
+		//		the <input> field
+		autoComplete: true,
+
+		// searchDelay: Integer
+		//		Delay in milliseconds between when user types something and we start
+		//		searching based on that value
+		searchDelay: 100,
+
+		// url: String
+		//		URL argument passed to data provider object (class name specified in "dataProviderClass")
+		//		An example of the URL format for the default data provider is
+		//		"autoCompleterData.js"
+		url: "",
+
+// Bill: not sure we want to support url parameter; if we do then we have to support it for
+// all dojo.data widgets (grid, tree)
+
+		// dataProviderClass: String
+		//		Name of data provider class (code that maps a search string to a list of values)
+		//		The class must match the interface demonstrated by dojo.data.JsonItemStore
+		dataProviderClass: "dojo.data.JsonItemStore",
+
+// Bill: not sure we want to support this; if we do then we have to support it for
+// all dojo.data widgets (grid, tree)
+
+		// data: Object
+		//		Inline data to put in store
+		//		Data must match data type of dataProviderClass
+		//		For example, data would contain JSON data if dataProviderClass is a JsonItemStore
+		data:null,
+
+		// searchAttr: String
+		//		Searches pattern match against this field
+		searchAttr: "name",
+
+		// ignoreCase: Boolean
+		//		Does the AutoCompleter menu ignore case?
+		ignoreCase: true,
+
+		// value: String
+		//		The initial value of the AutoCompleter.
+		//		This is the value that actually appears in the text area.
+		value:"",
+
+		templateString:"<fieldset class='dijit dijitInline dijitLeft dijitAutoCompleter' id=\"widget_${id}\" name=\"${name}\"\n\tdojoAttachEvent=\"onmouseover:setStateClass;onmouseout:setStateClass;\"\t\n>\n<table cellspacing=0 cellpadding=0>\n\t<tr>\n\t\t<td class='dijitReset dijitStretch dijitAutoCompleterInput'\n\t\t\t><input class='XdijitInputField' type=\"text\" autocomplete=\"off\" name=\"${name}\"\n\t\t\tdojoAttachEvent=\"onkeypress; onkeyup; onfocus; onblur; compositionend;\"\n\t\t\tdojoAttachPoint=\"textbox;focusNode\" id='${id}'\n\t\t\ttabIndex='${tabIndex}' size='${size}' maxlength='${maxlength}'\n\t></td><td class='dijitReset dijitRight dijitButtonNode dijitDownArrowButton'\n\t\t\tdojoAttachPoint=\"downArrowNode\"\n\t\t\tdojoAttachEvent=\"onclick:arrowClick;onmousedown:setStateClass;onmouseup:setStateClass;onmouseover:setStateClass;onmouseout:setStateClass;\"\n\t\t\ttabIndex=\"${tabIndex}\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true\"\n\t\t><div class='dijitRightSpacer'><span class='dijitA11yDownArrow'>&#9660;</span></div>\n\t</td></tr>\n</table>\n</fieldset>\n",
+
+		_hasMasterPopup:true,
+
+		_popupClass:"dijit.form._AutoCompleterMenu",
+
+		_getCaretPos: function(/*DomNode*/ element){
+			// khtml 3.5.2 has selection* methods as does webkit nightlies from 2005-06-22
+			if(typeof(element.selectionStart)=="number"){
+				// FIXME: this is totally borked on Moz < 1.3. Any recourse?
+				return element.selectionStart;
+			}else if(dojo.isIE){
+				// in the case of a mouse click in a popup being handled,
+				// then the document.selection is not the textarea, but the popup
+				// var r = document.selection.createRange();
+				// hack to get IE 6 to play nice. What a POS browser.
+				var tr = document.selection.createRange().duplicate();
+				var ntr = element.createTextRange();
+				tr.move("character",0);
+				ntr.move("character",0);
+				try{
+					// If control doesnt have focus, you get an exception.
+					// Seems to happen on reverse-tab, but can also happen on tab (seems to be a race condition - only happens sometimes).
+					// There appears to be no workaround for this - googled for quite a while.
+					ntr.setEndPoint("EndToEnd", tr);
+					return String(ntr.text).replace(/\r/g,"").length;
+				}
+				catch(e){
+					return 0; // If focus has shifted, 0 is fine for caret pos.
+				}
+			}
+		},
+
+		_setCaretPos: function(/*DomNode*/ element, /*Number*/ location){
+			location = parseInt(location);
+			this._setSelectedRange(element, location, location);
+		},
+
+		_setSelectedRange: function(/*DomNode*/ element, /*Number*/ start, /*Number*/ end){
+			if(!end){
+				end = element.value.length;
+			}  // NOTE: Strange - should be able to put caret at start of text?
+			// Mozilla
+			// parts borrowed from http://www.faqts.com/knowledge_base/view.phtml/aid/13562/fid/130
+			if(element.setSelectionRange){
+				element.focus();
+				element.setSelectionRange(start, end);
+			}else if(element.createTextRange){ // IE
+				var range = element.createTextRange();
+				with(range){
+					collapse(true);
+					moveEnd('character', end);
+					moveStart('character', start);
+					select();
+				}
+			}else{ //otherwise try the event-creation hack (our own invention)
+				// do we need these?
+				element.value = element.value;
+				element.blur();
+				element.focus();
+				// figure out how far back to go
+				var dist = parseInt(element.value.length)-end;
+				var tchar = String.fromCharCode(37);
+				var tcc = tchar.charCodeAt(0);
+				for(var x = 0; x < dist; x++){
+					var te = document.createEvent("KeyEvents");
+					te.initKeyEvent("keypress", true, true, null, false, false, false, false, tcc, tcc);
+					element.dispatchEvent(te);
+				}
+			}
+		},
+
+		onkeypress: function(/*Event*/ evt){
+			// summary: handles keyboard events
+			if(evt.ctrlKey || evt.altKey){
+				return;
+			}
+			var doSearch = false;
+			switch(evt.keyCode){
+				case dojo.keys.PAGE_DOWN:
+				case dojo.keys.DOWN_ARROW:
+					if(!this.isShowingNow()||this._prev_key_esc){
+						this._arrowPressed();
+						doSearch=true;
+					}else{
+						evt.keyCode==dojo.keys.PAGE_DOWN ? this._popupWidget.pageDown(): this._popupWidget._highlightNextOption();
+					}
+					dojo.stopEvent(evt);
+					this._prev_key_backspace = false;
+					this._prev_key_esc = false;
+					break;
+
+				case dojo.keys.PAGE_UP:
+				case dojo.keys.UP_ARROW:
+					if(this.isShowingNow()){
+						evt.keyCode==dojo.keys.PAGE_UP ? this._popupWidget.pageUp() : this._popupWidget._highlightPrevOption();
+					}
+					dojo.stopEvent(evt);
+					this._prev_key_backspace = false;
+					this._prev_key_esc = false;
+					break;
+
+				case dojo.keys.ENTER:
+					// prevent submitting form if user presses enter
+					dojo.stopEvent(evt);
+					// fall through
+
+				case dojo.keys.TAB:
+					if(this.isShowingNow()){
+						this._prev_key_backspace = false;
+						this._prev_key_esc = false;
+						if(this._popupWidget.getHighlightedOption()){
+							this._popupWidget.setValue({target:this._popupWidget.getHighlightedOption()});
+						}else{
+							this.setDisplayedValue(this.getDisplayedValue());
+						}
+						this._hideResultList();
+					}else{
+						// also allow arbitrary user input
+						this.setDisplayedValue(this.getDisplayedValue());
+					}
+					break;
+
+				case dojo.keys.SPACE:
+					this._prev_key_backspace = false;
+					this._prev_key_esc = false;
+					if(this.isShowingNow() && this._highlighted_option){
+						dojo.stopEvent(evt);
+						this._selectOption();
+						this._hideResultList();
+					}
+					else{doSearch=true;}
+					break;
+
+				case dojo.keys.ESCAPE:
+					this._prev_key_backspace = false;
+					this._prev_key_esc = true;
+					this._hideResultList();
+					this.setValue(this.getValue());
+					break;
+
+				case dojo.keys.BACKSPACE:
+					this._prev_key_esc = false;
+					this._prev_key_backspace = true;
+					doSearch=true;
+					if(!this.textbox.value.length){
+						this.setValue("");
+					}
+					break;
+
+				case dojo.keys.RIGHT_ARROW: // fall through
+
+				case dojo.keys.LEFT_ARROW: // fall through
+					this._prev_key_backspace = false;
+					this._prev_key_esc = false;
+					break;
+
+				default:// non char keys (F1-F12 etc..)  shouldn't open list
+					this._prev_key_backspace = false;
+					this._prev_key_esc = false;
+					if(evt.charCode!=0){
+						doSearch = true;
+					}
+			}
+			if(this.searchTimer){
+				clearTimeout(this.searchTimer);
+			}
+			if(doSearch){
+				// need to wait a tad before start search so that the event bubbles through DOM and we have value visible
+				this.searchTimer = setTimeout(dojo.hitch(this, this._startSearchFromInput), this.searchDelay);
+			}
+		},
+
+		_openResultList: function(/*Object*/ results){
+			if(this.disabled){
+				return;
+			}
+			this._popupWidget.clearResultList();
+			if(!results.length){
+				this._hideResultList();
+				return;
+			}
+
+
+			// Fill in the textbox with the first item from the drop down list, and
+			// highlight the characters that were auto-completed.   For example, if user
+			// typed "CA" and the drop down list appeared, the textbox would be changed to
+			// "California" and "ifornia" would be highlighted.
+
+			var zerothvalue=new String(this.store.getValue(results[0], this.searchAttr));
+			if(zerothvalue&&(this.autoComplete)&&
+			(!this._prev_key_backspace)&&
+			(this.textbox.value.length > 0)&&
+			(new RegExp("^"+this.textbox.value, this.ignoreCase ? "i" : "").test(zerothvalue))){
+				var cpos = this._getCaretPos(this.textbox);
+				// only try to extend if we added the last character at the end of the input
+				if((cpos+1) > this.textbox.value.length){
+					// only add to input node as we would overwrite Capitalisation of chars
+					// actually, that is ok
+					this.textbox.value = zerothvalue;//.substr(cpos);
+					// visually highlight the autocompleted characters
+					this._setSelectedRange(this.textbox, cpos, this.textbox.value.length);
+				}
+			}
+			// #2309: iterate over cache nondestructively
+			for(var i=0; i<results.length; i++){
+				var tr=results[i];
+				if(tr){
+					var td=this._createOption(tr);
+					td.className = "dijitMenuItem";
+					this._popupWidget.addItem(td);
+				}
+
+			}
+// Bill: above loop could be done w/ "dojo.forEach(results, function(tr){" or better yet map()
+//
+// But actually the interface between AutoCompleterMenu and Autocompleter is strange to me.
+// AutoCompleterMenu should be in charge of the
+// DOM manipulation (creating text nodes, etc).   autocompleter should just pass in a list of
+// items
+
+			// show our list (only if we have content, else nothing)
+			this._showResultList();
+		},
+
+		_createOption:function(/*Object*/ tr){
+			// summary: creates an option to appear on the popup menu
+			// subclassed by Select
+			var td = document.createElement("div");
+			td.appendChild(document.createTextNode(this.store.getValue(tr, this.searchAttr)));
+			td.item=tr;
+			return td;
+		},
+
+		onfocus:function(){
+			this.parentClass.onfocus.apply(this, arguments);
+		},
+
+		onblur:function(){
+			// if the user clicks away from the textbox, set the value to the textbox value
+			this.setDisplayedValue(this.getDisplayedValue());
+			dijit.form._DropDownTextBox.prototype.onblur.apply(this, arguments);
+			// don't call this since the Textbox setValue is asynchronous
+			// if you uncomment this line, when you click away from the textbox,
+			// the value in the textbox reverts to match the hidden value
+			//this.parentClass.onblur.apply(this, arguments);
+		},
+
+		_selectOption: function(/*Event*/ evt){
+			var tgt = null;
+			if(!evt){
+				// what if nothing is highlighted yet?
+				evt ={ target: this._highlighted_option };
+			}
+			if(!evt.target){
+				// handle autocompletion where the the user has hit ENTER or TAB
+				this.setDisplayedValue(this.getDisplayedValue());
+				return;
+			// otherwise the user has accepted the autocompleted value
+			}else{
+				tgt = evt.target;
+			}
+			while((tgt.nodeType!=1)||(!this.store.getValue(tgt.item, this.searchAttr))){
+				tgt = tgt.parentNode;
+				if(tgt == dojo.body()){
+					return false;
+				}
+			}
+			this._doSelect(tgt);
+			if(!evt.noHide){
+				this._hideResultList();
+				this._setSelectedRange(this.textbox, 0, null);
+			}
+			this.focus();
+			if(this._popupWidget.domNode.style.display!="none"){
+				dijit.util.PopupManager.close(this._popupWidget);
+			}
+		},
+
+		_doSelect: function(tgt){
+			this.setValue(this.store.getValue(tgt.item, this.searchAttr));
+		},
+
+		arrowClick: function(){
+// Bill: should rename to _onArrowClicked() for consistency
+			// summary: callback when arrow is clicked
+			if(this.disabled){
+				return;
+			}
+			this.focus();
+			this.makePopup();
+			if(this.isShowingNow()){
+				this._hideResultList();
+			}else{
+				// forces full population of results, if they click
+				// on the arrow it means they want to see more options
+				this._startSearch("");
+			}
+		},
+
+		_startSearchFromInput: function(){
+			this._startSearch(this.textbox.value);
+		},
+
+		_startSearch: function(/*String*/ key){
+			this.makePopup();
+			// create a new query to prevent accidentally querying for a hidden value from Select's keyField
+			var query={};
+			query[this.searchAttr]=key+"*";
+			// no need to page; no point in caching the return object
+			this.store.fetch({queryOptions:{ignoreCase:this.ignoreCase}, query: query, onComplete:dojo.hitch(this, "_openResultList"), count:this.searchLimit});
+		},
+
+		_assignHiddenValue:function(/*Object*/ keyValArr, /*DomNode*/ option){
+			// sets the hidden value of an item created from an <option value="CA">
+			// AutoCompleter does not care about the value; Select does though
+			// Select overrides this method
+		},
+
+		postCreate: function(){
+			// dojo.data code
+			var dpClass=dojo.getObject(this.dataProviderClass, false);
+			// is the store not specified?
+			if(this.store==null){
+				// if user didn't specify either url or data, then assume there are option tags
+				if(this.url==""&&this.data==null){
+					dpClass=dojo.getObject("dojo.data.JsonItemStore", false);
+					var opts = this.domNode.getElementsByTagName("option");
+					var ol = opts.length;
+					var data=[];
+					// go backwards to create the options list
+					// have to go backwards because we are removing the option nodes
+					// the option nodes are visible once the AutoCompleter initializes
+					for(var x=ol-1; x>=0; x--){
+						var text = opts[x].innerHTML;
+						var keyValArr ={};
+						keyValArr[this.searchAttr]=String(text);
+						// Select: assign the value attribute to the hidden value
+						this._assignHiddenValue(keyValArr, opts[x]);
+						data.unshift(keyValArr);
+						// remove the unnecessary node
+						// if you keep the node, it is visible on the page!
+						this.domNode.removeChild(opts[x]);
+					}
+					// pass store inline data
+					this.data={items:data};
+				}
+				this.store=new dpClass(this);
+			}
+			// call the associated Textbox postCreate
+			// ValidationTextbox for AutoCompleter; MappedTextbox for Select
+			this.parentClass=dojo.getObject(this.declaredClass, false).superclass;
+			this.parentClass.postCreate.apply(this, arguments);
+
+			// convert the arrow image from using style.background-image to the .src property (a11y)
+//			dijit.util.wai.imageBgToSrc(this.arrowImage);
+		}
+	}
+);
+
+dojo.declare(
+	"dijit.form._AutoCompleterMenu",
+	[dijit.base.FormElement, dijit.base.TemplatedWidget],
+
+// Bill: 
+// I'd like the interface to AutoCompleterMenu to be higher level,
+// taking a list of items to initialize it, and returns the selected item
+//
+//                new _AutoCompleterMenu({
+//                                 items: /*dojo.data.Item[]*/ items,
+//                                 labelFunc: dojo.hitc(this, "_makeLabel"),
+//                                 onSelectItem: dojo.hitch(this, "_itemSelected")
+//               });
+//
+// (This is dependent on NOT having a global widget for this, but rather
+// creating it on the fly, as per discussion with Bill, Adam, and Mark)
+// 
+// It could also have a method like handleKey(evt) that takes a keystroke
+// the <input> received and handles it.
+//
+// Also, doesn't seem like this should inherit from FormElement, and again I'm not
+// sure of the utility of dijit.form._DropDownTextBox.Popup;
+// all the popup functionality is supposed to be in PopupManager
+//
+
+
+	{
+		// summary:
+		//	Focus-less div based menu for internal use in AutoCompleter
+
+		templateString:"<div class='dijitMenu' dojoAttachEvent='onclick; onmouseover; onmouseout;' tabIndex='-1' style='display:none; position:absolute; overflow:\"auto\";'></div>",
+		_onkeypresshandle:null,
+		postCreate:function(){
+			// summary:
+			//	call all postCreates
+			dijit.base.FormElement.prototype.postCreate.apply(this, arguments);
+		},
+
+		open:function(/*Widget*/ widget){
+			this.onValueChanged=dojo.hitch(widget, widget._selectOption);
+			// connect onkeypress to AutoCompleter
+			this._onkeypresshandle=dojo.connect(this.domNode, "onkeypress", widget, "onkeypress");
+			return dijit.util.PopupManager.openAround(widget.domNode, this);
+		},
+
+		onClose:function(){
+			dojo.disconnect(this._onkeypresshandle);
+			this._blurOptionNode();
+		},
+
+		addItem:function(/*Node*/ item){
+			this.domNode.appendChild(item);
+		},
+// Bill: see comments above; this call is too low level for the interface
+// between Autocompleter and AutocompleterMenu
+
+		clearResultList:function(){
+			this.domNode.innerHTML="";
+		},
+
+		// these functions are called in showResultList
+		getItems:function(){
+			return this.domNode.childNodes;
+		},
+
+		getListLength:function(){
+			return this.domNode.childNodes.length;
+		},
+
+		onclick:function(/*Event*/ evt){
+			if(evt.target === this.domNode){ return; }
+			var tgt=evt.target;
+			// while the clicked node is inside the div
+			while(!tgt.item){
+				// recurse to the top
+				tgt=tgt.parentNode;
+			}
+			this.setValue({target:tgt});
+		},
+
+		onmouseover:function(/*Event*/ evt){
+			if(evt.target === this.domNode){ return; }
+			this._focusOptionNode(evt.target);
+		},
+
+		onmouseout:function(/*Event*/ evt){
+			if(evt.target === this.domNode){ return; }
+			this._blurOptionNode();
+		},
+
+		_focusOptionNode:function(/*DomNode*/ node){
+			// summary:
+			//	does the actual highlight
+			if(this._highlighted_option != node){
+				this._blurOptionNode();
+				this._highlighted_option = node;
+				dojo.addClass(this._highlighted_option, "dijitMenuItemHover");
+			}
+		},
+
+		_blurOptionNode:function(){
+			// summary:
+			//	removes highlight on highlighted option
+			if(this._highlighted_option){
+				dojo.removeClass(this._highlighted_option, "dijitMenuItemHover");
+				this._highlighted_option = null;
+			}
+		},
+
+		_highlightNextOption:function(){
+			// because each press of a button clears the menu,
+			// the highlighted option sometimes becomes detached from the menu!
+			// test to see if the option has a parent to see if this is the case.
+			if(!this.getHighlightedOption()){
+				this._focusOptionNode(this.domNode.firstChild);
+			}else if(this._highlighted_option.nextSibling){
+				this._focusOptionNode(this._highlighted_option.nextSibling);
+			}
+			dijit.util.scroll.scrollIntoView(this._highlighted_option);
+		},
+
+
+		_highlightPrevOption:function(){
+			if(!this.getHighlightedOption()){
+				dijit.util.PopupManager.close(true);
+				return;
+			}else if(this._highlighted_option.previousSibling){
+				this._focusOptionNode(this._highlighted_option.previousSibling);
+			}
+			dijit.util.scroll.scrollIntoView(this._highlighted_option);
+		},
+
+		_page:function(/*Boolean*/ up){
+			var scrollamount=0;
+			var oldscroll=this.domNode.scrollTop;
+			var height=parseInt(dojo.getComputedStyle(this.domNode).height);
+			// if no item is highlighted, highlight the first option
+			if(!this.getHighlightedOption()){this._highlightNextOption();}
+			while(scrollamount<height){
+				if(up){
+					// stop at option 1
+					if(!this.getHighlightedOption().previousSibling){break;}
+					this._highlightPrevOption();
+				}else{
+					// stop at last option
+					if(!this.getHighlightedOption().nextSibling){break;}
+					this._highlightNextOption();
+				}
+				// going backwards
+				var newscroll=this.domNode.scrollTop;
+				scrollamount+=(newscroll-oldscroll)*(up ? -1:1);
+				oldscroll=newscroll;
+			}
+		},
+
+		pageUp:function(){
+			this._page(true);
+		},
+
+		pageDown:function(){
+			this._page(false);
+		},
+
+		getHighlightedOption:function(){
+			// summary:
+			//	Returns the highlighted option.
+			return this._highlighted_option&&this._highlighted_option.parentNode ? this._highlighted_option : null;
+		}
+	}
+
+);
+
+dojo.declare(
+	"dijit.form.AutoCompleter",
+	[dijit.form.ValidationTextbox, dijit.form.AutoCompleterMixin],
+	{}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/form/Button.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/Button.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/Button.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,135 @@
+dojo.provide("dijit.form.Button");
+
+dojo.require("dijit.base.FormElement");
+dojo.require("dijit.base.TemplatedWidget");
+
+dojo.declare(
+	"dijit.form.Button",
+	[dijit.base.FormElement, dijit.base.TemplatedWidget],
+	{
+/*
+ * usage
+ *	<button dojoType="button" onClick="...">Hello world</button>
+ *
+ *  var button1 = dojo.widget.createWidget("Button", {caption: "hello world", onClick: foo});
+ *	document.body.appendChild(button1.domNode);
+ */
+		// summary
+		//	Basically the same thing as a normal HTML button, but with special styling.
+
+		// caption: String
+		//	text to display in button
+		caption: "",
+
+		type: "button",
+		baseClass: "dijitButton",
+		templateString:"<div class=\"dijit dijitLeft dijitInline dijitButton\" \n\tdojoAttachEvent=\"onclick:setStateClass;onmouseover:setStateClass;onmouseout:setStateClass;onmousedown:setStateClass\"><div class='dijitRight'>\n\t<button class=\"dijitStretch dijitButtonNode dijitButtonContents\" \n\t\ttabIndex=\"${tabIndex}\" type=\"${type}\" id=\"${id}\" name=\"${name}\" alt=\"${alt}\" \n\t\tdojoAttachPoint=\"containerNode;focusNode\">\n\t\t\t${caption}\n\t</button>\n</div></div>\n",
+		
+		onClick: function(/*Event*/ e){
+			// summary: callback for when button is clicked; user can override this function
+		},
+
+		setCaption: function(/*String*/ content){
+			// summary: reset the caption (text) of the button; takes an HTML string
+			this.containerNode.innerHTML = this.caption = content;
+			if(dojo.isMozilla){ // Firefox has re-render issues with tables
+				var oldDisplay = dojo.getComputedStyle(this.domNode).display;
+				this.domNode.style.display="none";
+				var _this = this;
+				setTimeout(function(){_this.domNode.style.display=oldDisplay;},1);
+			}
+		}		
+	}
+);
+
+/*
+ * usage
+ *	<button dojoType="DropDownButton" menuId="mymenu">Hello world</button>
+ *
+ *  var button1 = dojo.widget.createWidget("DropDownButton", {caption: "hello world", menuId: foo});
+ *	document.body.appendChild(button1.domNode);
+ */
+dojo.declare(
+	"dijit.form.DropDownButton",
+	dijit.form.Button,
+	{
+		// summary
+		//		push the button and a menu shows up
+
+		// menuId: String
+		//	widget id of the menu that this button should activate
+		menuId: "",
+		baseClass : "dijitDropDownButton",
+		
+		_orientation: {'BL':'TL', 'TL':'BL'},
+		
+		templateString:"<div class=\"dijit dijitLeft dijitInlineBox dijitDropDownButton\"\n\tdojoAttachEvent=\"onmouseover:setStateClass;onmouseout:setStateClass;onmousedown:setStateClass;onclick:arrowClick; onkeypress:arrowKey;\"\n\t><div class='dijitRight'>\n\t<button tabIndex=\"${tabIndex}\" class=\"dijitStretch dijitButtonNode\" type=\"${type}\" id=\"${id}\" name=\"${name}\" alt=\"${alt}\"\n\tdojoAttachPoint=\"popupStateNode;focusNode\" waiRole=\"button\" waiState=\"haspopup-true\"\n\t\t><span class=\"dijitButtonContents\" dojoAttachPoint=\"containerNode\">${caption}</span\n\t\t><span class='dijitA11yDownArrow'>&#9660;</span>\n\t</button>\n</div></div>\n",
+
+		postCreate: function(){
+			dijit.form.DropDownButton.superclass.postCreate.apply(this, arguments);
+			dijit.util.wai.setAttr(this.domNode, "waiState", "haspopup", this.menuId);
+		},
+
+		startup: function(){
+			this._menu = dijit.byId(this.menuId);
+			this.connect(this._menu, "onClose", function(){
+				this.popupStateNode.removeAttribute("popupActive");
+			}); 
+		},
+
+		arrowKey: function(/*Event*/ e){
+			// summary: callback when the user presses a key (on key-down)
+			if(this.disabled){ return; }
+			if(	   e.keyCode == dojo.keys.DOWN_ARROW
+				|| e.keyCode == dojo.keys.ENTER
+				|| e.keyCode == dojo.keys.SPACE){
+				if(!this._menu || this._menu.domNode.style.display=="none"){
+					this.arrowClick(e);
+				}
+			}
+		},
+
+		arrowClick: function(/*Event*/ e){
+			// summary: callback when button is clicked; user shouldn't override this function or else the menu won't toggle
+			dojo.stopEvent(e);
+			if(this.disabled){ return; }
+			this.popupStateNode.focus();
+			var menu = this._menu;
+			if(!menu){ return; }
+			if(!menu.isShowingNow){
+				dijit.util.PopupManager.openAround(this.popupStateNode, menu, this._orientation);
+				this.popupStateNode.setAttribute("popupActive", "true");
+				this._opened=true;
+			}else{
+				dijit.util.PopupManager.closeAll();
+				this._opened=false;
+			}
+		}
+	});
+
+/*
+ * usage
+ *	<button dojoType="ComboButton" onClick="..." menuId="mymenu">Hello world</button>
+ *
+ *  var button1 = dojo.widget.createWidget("DropDownButton", {caption: "hello world", onClick: foo, menuId: "myMenu"});
+ *	document.body.appendChild(button1.domNode);
+ */
+dojo.declare(
+	"dijit.form.ComboButton",
+	dijit.form.DropDownButton,
+	{
+		// summary
+		//		left side is normal button, right side displays menu
+		templateString:"<fieldset class='dijit dijitInline dijitLeft dijitComboButton' id=\"${id}\" name=\"${name}\"\n\tdojoAttachEvent=\"onmouseover:setStateClass;onmouseout:setStateClass;onmousedown:setStateClass;onclick:setStateClass; onkeypress:arrowKey;\"\t\n>\n<table cellspacing='0' cellpadding='0'  waiRole=\"presentation\" >\n\t<tr>\n\t\t<td\tclass=\"dijitStretch dijitButtonContents dijitButtonNode\"\n\t\t\ttabIndex=\"${tabIndex}\" dojoAttachPoint=\"containerNode;focusNode\"\n\t\t\twaiRole=\"button\">\n\t\t\t${caption}\n\t\t</td>\n\t\t<td class='dijitReset dijitRight dijitButtonNode dijitDownArrowButton'\n\t\t\tdojoAttachPoint=\"popupStateNode\"\n\t\t\tdojoAttachEvent=\"onmouseover:setArrowStateClass;onmouseout:setArrowStateClass;onmousedown:setArrowStateClass;onclick:arrowClick; onkeypress:arrowKey;\"\n\t\t\tbaseClass=\"dijitComboButtonDownArrow\"\n\t\t\ttitle=\"${optionsTitle}\"\n\t\t\ttabIndex=\"${tabIndex}\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true\"\n\t\t><div class='dijitRightSpacer'><span class='dijitA11yDownArrow'>&#9660;</span></div>\n\t</td></tr>\n</table>\n</fieldset>\n",
+		_orientation: {'BR':'TR', 'TR':'BR'},
+		
+		// optionsTitle: String
+		//  text that describes the options menu (accessibility)
+		optionsTitle: "",
+
+		baseClass: "dijitComboButton",
+		setArrowStateClass : function(/*Event*/ e){
+			this.setStateClass(e, this.popupStateNode);
+		}
+
+	});

Added: trunk/examples/typeface/root/static/dojo/dijit/form/Checkbox.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/Checkbox.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/Checkbox.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,279 @@
+dojo.provide("dijit.form.Checkbox");
+
+dojo.require("dijit.base.FormElement");
+dojo.require("dijit.base.TemplatedWidget");
+dojo.require("dijit.util.sniff");
+dojo.require("dijit.util.wai");
+
+dojo.declare(
+	"dijit.form.Checkbox",
+	[dijit.base.FormElement, dijit.base.TemplatedWidget],
+	{
+		// summary:
+		// 		Same as an HTML checkbox, but with fancy styling.
+		//
+		// description:
+		// Implementation details
+		//
+		// pattern: MVC
+		//   Control: User interacts with real html inputs
+		//     Event listeners are added for input node events
+		//     These handlers make sure to update the view based on input state
+		//   View: The view is basically the the dijit (tundra) sprint image.
+		//   Model: The dijit checked state is synched with the input node.
+		//
+		// There are two modes:
+		//   1. Image not used or failed to load
+		//   2. Image loaded and used.
+		// In case 1, the regular html inputs are shown and used by the user.
+		// In case 2, the regular html inputs are invisible but still used by
+		// the user. They are turned quasi-invisible and overlay the dijit image.
+		//
+		// Layout
+		//   Styling is controlled in 3 places: tundra, template, and 
+		// programmatically in Checkbox.js. The latter is required 
+		// because of two modes of dijit checkbox: image loaded, vs 
+		// image not loaded. Also for accessibility it is important 
+		// that dijit work with images off (a browser preference).
+		//
+		//	Order of images in the sprite (from L to R, checkbox and radio in same image):
+		//		checkbox	normal 	 - checked
+		//							 - unchecked
+		//					disabled - checked
+		//							 - unchecked
+		//					hover 	 - checked
+		//							 - unchecked
+		//
+		//		radio		normal 	 - checked
+		//							 - unchecked
+		//					disabled - checked
+		//							 - unchecked
+		//					hover 	 - checked
+		//							 - unchecked
+
+		templateString:"<span\n ><span dojoAttachPoint=\"imageContainer\" class=\"dijitCheckbox\" style=\"overflow:hidden;\"></span\n ><input dojoAttachPoint=\"inputNode;focusNode\" class=\"dijitCheckboxInput\" id=\"${id}\" tabIndex=\"${tabIndex}\" type=\"${_type}\" name=\"${name}\" value=\"${value}\"\n></span>\n",
+
+		//	Value of "type" attribute for <input>
+		_type: "checkbox",
+
+		// checked: Boolean 
+		// Corresponds to the native HTML <input> element's attribute. 
+		// If true, checkbox is initially marked turned on; 
+		// in markup, specified as "checked='checked'" or just "checked"
+		checked: false, 
+
+		// value: Value
+		//	equivalent to value field on normal checkbox (if checked, the value is passed as
+		//	the value when form is submitted)
+		value: "on",
+		
+		postCreate: function(){
+			// find the image to use, as notated in the CSS file, but use it as a foreground
+			var bi = dojo.getComputedStyle(this.imageContainer).backgroundImage;
+			var href = bi.charAt(4)=='"' ? bi.slice(5,-2) : bi.slice(4,-1);	// url(foo) --> foo, url("foo") --> foo
+			this.imageContainer.style.backgroundImage = "none";
+			var img = (this.imageNode = document.createElement("img"));
+			var self=this;
+
+			// inputNode.checked must be assigned before img.onload handler
+			this.inputNode.checked=this.checked;
+			// note: onImageLoad may get called as a side-effect of this assignment
+			img.onload = function(){ self.onImageLoad(); }
+			img.src = href;
+			this._setDisabled(this.disabled);
+		},
+
+		onImageLoad: function(){
+			this.imageLoaded = true;
+
+			// set image container size to just show one sprite
+			if(!this.width){
+				this.width = 16;
+			} // dojo.html.getPixelValue is not succeeding for all browsers
+			if(!this.height){
+				this.height = 16;
+			}
+
+			// Turn the input element invisible and make sure it overlays
+			// the dojo image container.
+			dojo.addClass(this.inputNode,"dijitCheckboxInputInvisible");
+			dojo.addClass(this.imageContainer,"dijitCheckboxImageContainer");
+
+			var imageContainerStyle = this.imageContainer.style;
+			var inputStyle = this.inputNode.style;
+			var domNodeStyle = this.domNode.style;
+			 
+			// Force size based on width and height.
+			inputStyle.width = imageContainerStyle.width = this.width + "px";
+			inputStyle.height = imageContainerStyle.height = this.height + "px";
+			domNodeStyle.position = "relative";
+			
+			// carve some space in the flow for this dom node
+			if(dojo.isSafari){
+				// use this hack sparingly (see ticket:2942)
+				domNodeStyle.fontFamily = "monospace";
+				var spacer = document.createTextNode("\u00a0\u00a0");
+				this.domNode.appendChild(spacer);
+			}else{
+				domNodeStyle.paddingRight = this.width + "px";
+			}
+			
+			// User will always interact with input element
+			this._connectEvents(this.inputNode);
+			
+			this.imageContainer.appendChild(this.imageNode);
+			
+			this._updateView();
+		},
+		
+		_connectEvents: function(/*DomNode*/ node){
+			this.connect(node, "onfocus", this.mouseOver);
+			this.connect(node, "onblur", this.mouseOut);
+			this.connect(node, "onmouseover", this.mouseOver);
+			this.connect(node, "onmouseout", this.mouseOut);
+			this.connect(node, "onclick", this._onClick);
+			dijit._disableSelection(node);
+		},
+
+		_setDisabled: function(/*Boolean*/ disabled){
+			// summary: set disabled state of widget.
+			dijit.form.Checkbox.superclass._setDisabled.apply(this,arguments);
+			this._updateView();
+		},
+
+		onChecked: function(/*Boolean*/ newCheckedState){
+			// summary: callback when checked state is changed
+		},
+		
+		setChecked: function(/*Boolean*/ check){
+			// summary: set the checked state of the widget.
+			if(check != this.inputNode.checked){
+				this.inputNode.checked = check;
+				this._updateView();
+			}
+		},
+	
+		getChecked: function(){
+			// summary: get the checked state of the widget.
+			return this.checked;
+		},
+
+		setValue: function(value){
+			if(value == null){ value = ""; }
+			this.inputNode.value = value;
+			dijit.form.Checkbox.superclass.setValue.call(this,value);
+		},
+
+		onClick: function(/*Event*/ e){
+			// summary: user overridable callback for click event handling 
+		},
+		
+		_onClick: function(/*Event*/ e){
+			/// summary: callback for a click event
+			this._updateView();
+			this.onClick(e);
+		},
+
+		mouseOver: function(/*Event*/ e){
+			// summary: callback when user moves mouse over checkbox
+			this.hover=true;
+			this._updateView();
+		},
+
+		mouseOut: function(/*Event*/ e){
+			// summary: callback when user moves mouse off of checkbox
+			this.hover=false;
+			this._updateView();
+		},
+
+		// offset from left of image
+		_leftOffset: 0,
+		
+		_updateView: function(/*Widget?*/ awidget){
+			var w = awidget || this;
+
+			if(w.checked != w.inputNode.checked){
+				w.checked = w.inputNode.checked;
+				w.onChecked(w.checked);
+			}
+
+			// show the right sprite, depending on state of checkbox
+			if(w.imageLoaded){
+				var left = w._leftOffset + (w.checked ? 0 : w.width) +
+					(w.disabled ? this.width*2 : (w.hover ? w.width*4 : 0));
+				w.imageNode.style.marginLeft = -1*left + "px";
+			}
+			if(!awidget){
+				this.updateContext();
+			}
+		},
+		
+		updateContext: function(){
+			// summary: specialize this function to update related GUI
+		}
+	}
+);
+
+dojo.declare(
+	"dijit.form.RadioButton",
+	dijit.form.Checkbox,
+	{
+		// summary:
+		// 		Same as an HTML radio, but with fancy styling.
+		//
+		// description:
+		// Implementation details
+		//
+		// Specialization:
+		// We keep track of dijit radio groups so that we can update the state
+		// of all the siblings (the "context") in a group based on input 
+		// events. We don't rely on browser radio grouping.
+		//
+		// At the time of implementation not all browsers fire the same events
+		// when a different radio button in a group is checked (and the previous
+		// unchecked). When the events do fire, e.g. a focus event on the newly
+		// checked radio, the checked state of that "newly checked" radio is 
+		// set to true in some browsers and false in others.
+		// It is vital that the view of the resulting input states be correct
+		// so that at the time of form submission the intended data is sent.
+		
+		_type: "radio",
+		
+		// This shared object keeps track of all widgets, grouped by name
+		_groups: {},
+
+		_register: function(){
+			// summary: add this widget to _groups
+			(this._groups[this.name] = this._groups[this.name] || []).push(this);
+		},
+
+		_deregister: function(){
+			// summary: remove this widget from _groups
+			dojo.forEach(this._groups[this.name], function(widget, i, arr){
+				if(widget === this){
+					arr.splice(i, 1);
+					return;
+				}
+			}, this);
+		},
+		
+		uninitialize: function(){
+			this._deregister();
+		},
+
+		updateContext: function(){
+			// summary: make sure the sibling radio views are correct
+			dojo.forEach(this._groups[this.name], function(widget){
+				if(widget != this){
+					widget._updateView(widget);
+				}
+			}, this);
+		},
+
+		onImageLoad: function(){
+			this._leftOffset = 96;	// this.imageNode.width/2;
+			this._register();
+			dijit.form.Checkbox.prototype.onImageLoad.call(this);
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/form/CurrencyTextbox.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/CurrencyTextbox.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/CurrencyTextbox.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,29 @@
+dojo.provide("dijit.form.CurrencyTextbox");
+
+//FIXME: dojo.experimental throws an unreadable exception?
+//dojo.experimental("dijit.form.CurrencyTextbox");
+
+dojo.require("dojo.currency");
+dojo.declare(
+	"dijit.form.CurrencyTextbox",
+	dijit.form.NumberTextbox,
+	{
+		// code: String
+		//		the ISO4217 currency code, a three letter sequence like "USD"
+		//		See http://en.wikipedia.org/wiki/ISO_4217
+		currency: "",
+
+		regExpGen: dojo.currency.regexp,
+		format: dojo.currency.format,
+		parse: dojo.currency.parse,
+
+		postMixInProperties: function(){
+			if(this.constraints === dijit.form.ValidationTextbox.prototype.constraints){
+				// declare a constraints property on 'this' so we don't overwrite the shared default object in 'prototype'
+				this.constraints = {};
+			}
+			this.constraints.currency = this.currency;
+			dijit.form.CurrencyTextbox.superclass.postMixInProperties.apply(this, arguments);
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/form/DateTextbox.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/DateTextbox.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/DateTextbox.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,81 @@
+dojo.provide("dijit.form.DateTextbox");
+
+dojo.require("dijit._Calendar");
+dojo.require("dijit.form._DropDownTextBox");
+dojo.require("dojo.date");
+dojo.require("dojo.date.locale");
+dojo.require("dojo.date.stamp");
+dojo.require("dijit.form.ValidationTextbox");
+
+dojo.declare(
+	"dijit.form.DateTextbox",
+	[dijit.form.RangeBoundTextbox, dijit.form._DropDownTextBox],
+	{
+		// summary:
+		//		A validating, serializable, range-bound date text box.
+		// constraints object: min, max
+		templateString:"<fieldset class='dijit dijitInline dijitLeft dijitAutoCompleter' id=\"widget_${id}\" name=\"${name}\"\n\tdojoAttachEvent=\"onmouseover:setStateClass;onmouseout:setStateClass;\"\t\n>\n<table cellspacing=0 cellpadding=0>\n\t<tr>\n\t\t<td class='dijitReset dijitStretch dijitAutoCompleterInput'\n\t\t\t><input class='XdijitInputField' type=\"text\" autocomplete=\"off\" name=\"${name}\"\n\t\t\tdojoAttachEvent=\"onkeypress; onkeyup; onfocus; onblur; compositionend;\"\n\t\t\tdojoAttachPoint=\"textbox;focusNode\" id='${id}'\n\t\t\ttabIndex='${tabIndex}' size='${size}' maxlength='${maxlength}'\n\t></td><td class='dijitReset dijitRight dijitButtonNode dijitDownArrowButton'\n\t\t\tdojoAttachPoint=\"downArrowNode\"\n\t\t\tdojoAttachEvent=\"onclick:arrowClick;onmousedown:setStateClass;onmouseup:setStateClass;onmouseover:setStateClass;onmouseout:setStateClass;\"\n\t\t\ttabIndex=\"${tabIndex}\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true\"\n\t\t><div class='dijitRightSpacer'><span class='dijitA11yDownArrow'>&#9660;</span></div>\n\t</td></tr>\n</table>\n</fieldset>\n",
+		regExpGen: dojo.date.locale.regexp,
+		compare: dojo.date.compare,
+		format: dojo.date.locale.format,
+		parse: dojo.date.locale.parse,
+		value: new Date(),
+		_popupClass:"dijit._Calendar",
+
+		postMixInProperties: function(){
+			this.constraints.selector = 'date';
+			// manual import of RangeBoundTextbox properties
+			dijit.form.DateTextbox.superclass.postMixInProperties.apply(this, arguments);
+			// #2999
+			if(typeof this.constraints.min == "string"){ this.constraints.min = dojo.date.stamp.fromRfc3339(this.constraints.min); }
+ 			if(typeof this.constraints.max == "string"){ this.constraints.max = dojo.date.stamp.fromRfc3339(this.constraints.max); }
+		},
+
+		serialize: function(/*Date*/date){
+			return dojo.date.stamp.toRfc3339(date, 'date'); // String
+		},
+
+		setValue:function(/*Date*/date){
+			// summary:
+			//	Sets the date on this textbox
+
+			if(!this._popupWidget||!this._popupWidget.onValueSelected){
+				dijit.form.DateTextbox.superclass.setValue.apply(this, arguments);
+			}else{
+				this._popupWidget.setValue(date);
+			}
+		},
+
+		postCreate:function(){
+			dijit.form.DateTextbox.superclass.postCreate.apply(this, arguments);
+			this._popupArgs={
+				// #3000: set popupArgs here so Calendar gets the widget's lang, not the user's lang
+				lang:this.lang,
+
+				open:function(/*Widget*/ widget){
+					// summary:
+					//	opens the Calendar, and sets the onValueSelected for the Calendar
+
+					this.constraints=widget.constraints;
+					this.setValue(widget.getValue());
+					this.onValueSelected=dojo.hitch(widget, widget._calendarOnValueSelected);
+					return dijit.util.PopupManager.openAround(widget.domNode, this);
+				},
+
+				isDisabledDate:function(/*Date*/ date){
+					// summary:
+					// 	disables dates outside of the min/max of the DateTextbox
+					return(this.constraints!=null&&(dojo.date.compare(this.constraints.min,date)>0||dojo.date.compare(this.constraints.max,date)<0));
+				}
+			};
+			// convert the arrow image from using style.background-image to the .src property (a11y)
+			dijit.util.wai.imageBgToSrc(this.arrowImage);
+		},
+
+		_calendarOnValueSelected:function(value){
+			// summary: taps into the popup Calendar onValueSelected
+			dijit.form.DateTextbox.superclass.setValue.apply(this, arguments);
+			this._hideResultList();
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/form/InlineEditBox.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/InlineEditBox.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/InlineEditBox.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,190 @@
+dojo.provide("dijit.form.InlineEditBox");
+
+dojo.require("dijit.base.FormElement");
+dojo.require("dijit.base.Container");
+dojo.require("dijit.base.TemplatedWidget");
+dojo.require("dojo.i18n");
+dojo.require("dijit.form.Button");
+
+dojo.requireLocalization("dijit", "common");
+
+dojo.declare(
+	"dijit.form.InlineEditBox",
+	[dijit.base.FormElement, dijit.base.Container, dijit.base.TemplatedWidget],
+	// summary
+	//		Wrapper widget to a text edit widget.
+	//		The text is displayed on the page using normal user-styling.
+	//		When clicked, the text is hidden, and the edit widget is
+	//		visible, allowing the text to be updated.  Additionally,
+	//		Save and Cancel button are displayed below the edit widget.
+	//		When Save is clicked, the text is pulled from the edit
+	//		widget and redisplayed and the edit widget is again hidden.
+	//		Currently all textboxes that inherit from dijit.form.Textbox
+	//		are supported edit widgets.
+	//		An edit widget must support the following API to be used:
+	//		String getTextValue() OR String getValue()
+	//		void setTextValue(String) OR void setValue(String)
+	//		void focus()
+	//		It must also be able to initialize with style="display:none;" set.
+{
+	templateString:"<span>\n\t<span class='dijitInlineValue' tabIndex=\"0\" dojoAttachPoint=\"editable;focusNode\" style=\"\" \n\t\tdojoAttachEvent=\"onkeypress:_onKeyPress;onclick:_onClick;onmouseout:_onMouseOut;onmouseover:_onMouseOver;onfocus:_onMouseOver;onblur:_onMouseOut;\"></span>\n\t<fieldset style=\"display:none;\" dojoAttachPoint=\"editNode\" class=\"dijitInlineEditor\">\n\t\t<div dojoAttachPoint=\"containerNode\" dojoAttachEvent=\"onkeyup:checkForValueChange;\"></div>\n\t\t<button class='saveButton' dojoAttachPoint=\"saveButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:save\">${buttonSave}</button>\n\t\t<button class='cancelButton' dojoAttachPoint=\"cancelButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:cancel\">${buttonCancel}</button>\n\t</fieldset>\n</span>\n",
+
+	// editing: Boolean
+	//		Is the node currently in edit mode?
+	editing: false,
+
+	// buttonSave: String
+	//              Save button label
+	buttonSave: "",
+
+	// buttonCancel: String
+	//              Cancel button label
+	buttonCancel: "",
+
+	widgetsInTemplate: true,
+
+	postCreate: function(){
+		var _this = this;
+		dojo.addOnLoad(function(){
+			// look for the input widget as a child of the containerNode
+			if(_this.editWidget){
+				_this.containerNode.appendChild(_this.editWidget.domNode);
+			}else{
+				var node = _this.containerNode.firstChild;
+				while(node != null){
+					_this.editWidget = dijit.util.manager.byNode(node);
+					if(_this.editWidget){
+						break;
+					}
+
+					node = node.nextSibling;
+				}
+			}
+			_this._setEditValue = dojo.hitch(_this.editWidget,_this.editWidget.setDisplayedValue||_this.editWidget.setValue);
+			_this._getEditValue = dojo.hitch(_this.editWidget,_this.editWidget.getDisplayedValue||_this.editWidget.getValue);
+			_this._setEditFocus = dojo.hitch(_this.editWidget,_this.editWidget.focus);
+			_this.editWidget.onValueChanged = dojo.hitch(_this,"checkForValueChange");
+			_this.checkForValueChange();
+			_this._showText();
+		});
+	},
+
+	postMixInProperties: function(){
+		dijit.form.InlineEditBox.superclass.postMixInProperties.apply(this, arguments);
+		this.messages = dojo.i18n.getLocalization("dijit", "common", this.lang);
+		dojo.forEach(["buttonSave", "buttonCancel"], function(prop){
+			if(!this[prop]){ this[prop] = this.messages[prop]; }
+		}, this);
+	},
+
+	_onKeyPress: function(e){
+		if(this.disabled || e.altKey || e.ctrlKey){ return; }
+		if(e.charCode == dojo.keys.SPACE || e.keyCode == dojo.keys.ENTER){
+			dojo.stopEvent(e);
+			this._onClick(e);
+		}
+	},
+
+	_onMouseOver: function(){
+		if(!this.editing){
+			var classname = this.disabled ? "dijitDisabledClickableRegion" : "dijitClickableRegion";
+			dojo.addClass(this.editable, classname);
+		}
+	},
+
+	_onMouseOut: function(){
+		if(!this.editing){
+			var classStr = this.disabled ? "dijitDisabledClickableRegion" : "dijitClickableRegion";
+			dojo.removeClass(this.editable, classStr);
+		}
+	},
+
+	onClick: function(/*Event*/ e){
+		// summary: callback for when button is clicked; user can override this function
+	},
+
+	_onClick: function(e){
+		// summary
+		// 		When user clicks the text, then start editing.
+		// 		Hide the text and display the form instead.
+
+		if(this.editing || this.disabled){ return; }
+		this._onMouseOut();
+		this.editing = true;
+
+		// show the edit form and hide the read only version of the text
+		this._setEditValue(this._isEmpty ? '' : this.editable.innerHTML);
+		this._initialText = this._getEditValue();
+		this._visualize();
+
+		this._setEditFocus();
+		this.saveButton.disable();
+		// moved to postCreate to always listen
+		//this.editWidget.onValueChanged = dojo.hitch(this,"checkForValueChange");
+		this.onClick();
+	},
+
+	_visualize: function(e){
+		dojo.style(this.editNode, "display", this.editing ? "" : "none");
+		dojo.style(this.editable, "display", this.editing ? "none" : "");
+	},
+
+	_showText: function(){
+		var value = this._getEditValue();
+		dijit.form.InlineEditBox.superclass.setValue.call(this, value);
+		// whitespace is really hard to click so show a ?
+		if(/^\s*$/.test(value)){ value = "?"; this._isEmpty = true; }
+		else { this._isEmpty = false; }
+		this.editable.innerHTML = value;
+		this._visualize();
+	},
+
+	save: function(e){
+		// summary: Callback when user presses "Save" button
+		if(e){ dojo.stopEvent(e); }
+		this.editing = false;
+		this._showText();
+	},
+
+	cancel: function(e){
+		// summary: Callback when user presses "Cancel" button
+		if(e){ dojo.stopEvent(e); }
+		this.editing = false;
+		this._visualize();
+	},
+
+	setValue: function(/*String*/ value){
+		// sets the text without informing the server
+		this._setEditValue(value);
+		this.editing = false;
+		this._showText();
+	},
+
+	checkForValueChange: function(){
+		// summary
+		//		Callback when user changes input value.
+		//		Enable save button if the text value is different than the original value.
+		if(this.editing){
+			(this._getEditValue() == this._initialText) ? this.saveButton.disable() : this.saveButton.enable();
+		}else{
+			this._showText();
+		}
+
+	},
+
+	disable: function(){
+		this.saveButton.disable();
+		this.cancelButton.disable();
+		this.editable.disabled = true;
+		this.editWidget.disable();
+		dijit.form.InlineEditBox.superclass.disable.apply(this, arguments);
+	},
+
+	enable: function(){
+		this.checkForValueChange();
+		this.cancelButton.enable();
+		this.editable.disabled = false;
+		this.editWidget.enable();
+		dijit.form.InlineEditBox.superclass.enable.apply(this, arguments);
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/form/NumberSpinner.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/NumberSpinner.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/NumberSpinner.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,27 @@
+dojo.provide("dijit.form.NumberSpinner");
+
+dojo.require("dijit.form._Spinner");
+dojo.require("dijit.form.NumberTextbox");
+
+dojo.declare(
+"dijit.form.NumberSpinner",
+[dijit.form._Spinner, dijit.form.NumberTextboxMixin],
+{
+	// summary: Number Spinner
+	// description: This widget is the same as NumberTextbox but with up/down arrows added
+
+	required: true,
+
+	adjust: function(/* Object */ val, /*Number*/ delta){
+		// summary: change Number val by the given amount
+		var newval = val+delta;
+		if(isNaN(val) || isNaN(newval)){ return val; }
+		if((typeof this.constraints.max == "number") && (newval > this.constraints.max)){ 
+			newval = this.constraints.max;
+		}
+		if((typeof this.constraints.min == "number") && (newval < this.constraints.min)){ 
+			newval = this.constraints.min;
+		}
+		return newval;
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/form/NumberTextbox.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/NumberTextbox.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/NumberTextbox.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,27 @@
+dojo.provide("dijit.form.NumberTextbox");
+
+dojo.require("dijit.form.ValidationTextbox");
+dojo.require("dojo.number");
+
+dojo.declare(
+	"dijit.form.NumberTextboxMixin",
+	null,
+	{
+		// summary:
+		//		A mixin for all number textboxes
+		regExpGen: dojo.number.regexp,
+		format: dojo.number.format,
+		parse: dojo.number.parse,
+		value: 0
+	}
+);
+
+dojo.declare(
+	"dijit.form.NumberTextbox",
+	[dijit.form.RangeBoundTextbox,dijit.form.NumberTextboxMixin],
+	{
+		// summary:
+		//		A validating, serializable, range-bound text box.
+		// constraints object: min, max, places
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/form/Select.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/Select.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/Select.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,144 @@
+dojo.provide("dijit.form.Select");
+
+dojo.require("dijit.form.AutoCompleter");
+
+dojo.declare(
+	"dijit.form.Select",
+	[dijit.form.MappedTextbox, dijit.form.AutoCompleterMixin],
+	{
+		/*
+		 * summary
+		 *	Enhanced version of HTML's <select> tag.
+		 *
+		 *	Similar features:
+		 *	  - There is a drop down list of possible values.
+		 *    - You can only enter a value from the drop down list.  (You can't enter an arbitrary value.)
+		 *    - The value submitted with the form is the hidden value (ex: CA),
+		 *      not the displayed value a.k.a. label (ex: California)
+		 *
+		 *	Enhancements over plain HTML version:
+		 *    - If you type in some text then it will filter down the list of possible values in the drop down list.
+		 *    - List can be specified either as a static list or via a javascript function (that can get the list from a server)
+		 */
+
+		// searchAttr: String
+		//		Searches pattern match against this field
+
+		// labelAttr: String
+		//		Optional.  The text that actually appears in the drop down.
+		//		If not specified, the searchAttr text is used instead.
+		labelAttr: "",
+
+		// labelType: String
+		//		"html" or "text"
+		labelType: "text",
+
+		// keyAttr: String
+		//		The field of the selected item that the client should send to the server on submit
+		keyAttr: "value",
+
+		_callbackSetLabel: function(/*Object*/ result){
+			// summary
+			//	Callback function that dynamically sets the label of the AutoCompleter
+
+			if(!result.length){
+				this._setValue("", "");
+			}else{
+				this._setValueFromItem(result[0]);
+			}
+		},
+
+		getValue:function(){
+			// don't get the textbox value but rather the previously set hidden value
+			return this.valueNode.value;
+		},
+
+		_setValue:function(/*String*/ value, /*String*/ displayedValue){
+			this.valueNode.value = value;
+			dijit.form.Select.superclass.setValue.apply(this, arguments);
+		},
+
+		setValue: function(/*String*/ value){
+			// summary
+			//	Sets the value of the select.
+			//	Also sets the label to the corresponding value by reverse lookup.
+
+			// test for blank value
+			if(/^\s*$/.test(value)){
+				this._setValue("", "");
+				return;
+			}
+			// Defect #1451: set the label by reverse lookup
+			var query={};
+			query[this.keyAttr]=value;
+			// use case sensitivity for the hidden value
+			this.store.fetch({queryOptions:{ignoreCase:false}, query:query, onComplete:dojo.hitch(this, "_callbackSetLabel")});
+		},
+
+		_setValueFromItem: function(/*Object*/ item){
+			// summary
+			//	Set the displayed valued in the input box, based on a selected item.
+			//	Users shouldn't call this function; they should be calling setDisplayedValue() instead
+
+			this._setValue(this.store.getValue(item, this.keyAttr), this.labelFunc(item, this.store));
+		},
+
+		labelFunc: function(/*Object*/ item, /*dojo.data.store*/ store){
+			// summary: Event handler called when the label changes
+			// returns the label that the AutoCompleter should display
+			return store.getValue(item, this.searchAttr);
+		},
+
+		_createOption:function(/*Object*/ tr){
+			// summary: creates an option to appear on the popup menu
+
+			var td=dijit.form.AutoCompleterMixin.prototype._createOption.apply(this, arguments);
+			// #3129
+			if(this.labelAttr){
+				if(this.labelType=="html"){
+					td.innerHTML=this.store.getValue(tr, this.labelAttr);
+				}else{
+					// prevent parsing of HTML
+					var textnode=document.createTextNode(this.store.getValue(tr, this.labelAttr));
+					td.innerHTML="";
+					td.appendChild(textnode);
+				}
+			}
+			return td;
+		},
+
+		onkeyup: function(/*Event*/ evt){
+			// summary: internal function
+			// Select needs to wait for the complete label before committing to a reverse lookup
+			//this.setDisplayedValue(this.textbox.value);
+		},
+
+		_assignHiddenValue:function(/*Object*/ keyValArr, /*DomNode*/ option){
+			// summary:
+			// 	Overrides AutoCompleter._assignHiddenValue for creating a data store from an options list.
+			// 	Takes the <option value="CA"> and makes the CA the hidden value of the item.
+			keyValArr[this.keyAttr]=option.value;
+		},
+
+		_doSelect: function(/*Event*/ tgt){
+			// summary:
+			//	AutoCompleter's menu callback function
+			//	Select overrides this to set both the visible and hidden value from the information stored in the menu
+
+			this._setValueFromItem(tgt.item);
+		},
+
+		setDisplayedValue:function(/*String*/ label){
+			// summary:
+			//	Set textbox to display label
+			//	Also performs reverse lookup to set the hidden value
+			//	Used in InlineEditBox
+
+			var query=[];
+			query[this.searchAttr]=label;
+			if(this.store){
+				this.store.fetch({query:query, queryOptions:{ignoreCase:this.ignoreCase}, onComplete: dojo.hitch(this, this._callbackSetLabel)});
+			}
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/form/Textarea.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/Textarea.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/Textarea.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,145 @@
+dojo.provide("dijit.form.Textarea");
+
+dojo.require("dijit.base.FormElement");
+dojo.require("dijit.base.TemplatedWidget");
+
+dojo.declare(
+	"dijit.form.Textarea",
+	[dijit.base.FormElement, dijit.base.TemplatedWidget],
+{
+	// summary
+	//	A textarea that resizes vertically to contain the data.
+	//	Takes nearly all the parameters (name, value, etc.) that a vanilla textarea takes.
+	//	Cols is not supported and the width should be specified with style width.
+	//	Rows is not supported since this widget adjusts the height.
+	// usage:
+	//	<textarea dojoType="dijit.form.ResizableTextArea">...</textarea>
+
+	templateString: (dojo.isIE || dojo.isSafari || dojo.isMozilla) ? '<fieldset id="${id}" tabIndex="${tabIndex}" class="dijitInlineBox dijitInputField dijitTextArea">'
+				+ ((dojo.isIE || dojo.isSafari) ? '<div dojoAttachPoint="editNode" style="text-decoration:none;_padding-bottom:16px;display:block;overflow:auto;" contentEditable="true"></div>' 
+					: '<iframe dojoAttachPoint="iframe" src="javascript:void(0)" style="border:0px;margin:0px;padding:0px;display:block;width:100%;height:100%;overflow-x:auto;overflow-y:hidden;"></iframe>')
+				+ '<textarea name="${name}" value="${value}" dojoAttachPoint="formValueNode" style="display:none;"></textarea>'
+				+ '</fieldset>'
+			: '<textarea id="${id}" name="${name}" value="${value}" dojoAttachPoint="formValueNode" tabIndex="${tabIndex}" class="dijitInputField dijitTextArea"></textarea>',
+
+	focus: function(){
+		// summary: Received focus, needed for the InlineEditBox widget
+		if(!this.disabled){
+			this._changing(); // set initial height
+			this.focusNode.focus();
+		}
+	},
+
+	_setFormValue: function(){
+		// blah<BR>blah --> blah\nblah
+		// <P>blah</P><P>blah</P> --> blah\nblah
+		// <DIV>blah</DIV><DIV>blah</DIV> --> blah\nblah
+		// &amp;&lt;&nbsp;&gt; --> &< >
+		value = this.editNode.innerHTML.replace(/<(br[^>]*|\/(p|div))>$|^<(p|div)[^>]*>|\r/gi,"").replace(/<\/(p|div)>\s*<\1[^>]*>|<(br|p|div)[^>]*>/gi,"\n").replace(/<[^>]*>/g,"").replace(/&amp;/gi,"\&").replace(/&nbsp;/gi," ").replace(/&lt;/gi,"<").replace(/&gt;/gi,">");
+		this.formValueNode.value = value;
+		if(this.iframe){
+			var d = this.iframe.contentWindow.document;
+			var newHeight = d.body.firstChild.scrollHeight;
+			if(d.body.scrollWidth > d.body.clientWidth){ newHeight+=16; } // scrollbar space needed?
+			if(this.lastHeight != newHeight){ // cache size so that we don't get a resize event because of a resize event
+				if(newHeight == 0){ newHeight = 16; } // height = 0 causes the browser to not set scrollHeight
+				dojo.contentBox(this.iframe, {h: newHeight});
+				this.lastHeight = newHeight;
+			}
+		}
+		dijit.form.Textarea.superclass.setValue.call(this, value);
+	},
+
+	setValue: function(/*String*/ value){
+		if(this.editNode){
+			this.editNode.innerHTML = ""; // wipe out old nodes
+			var lines = value.split("\n");
+			for(var i=0; i < lines.length; i++){
+				this.editNode.appendChild(document.createTextNode(lines[i])); // use text nodes so that imbedded tags can be edited
+				this.editNode.appendChild(document.createElement("BR")); // preserve line breaks
+			}
+		}
+		this._setFormValue();
+	},
+
+	getValue: function(){
+		return this.formValueNode.value;
+	},
+
+	postMixInProperties: function(){
+		dijit.form.Textarea.superclass.postMixInProperties.apply(this,arguments);
+		// don't let the source text be converted to a DOM structure since we just want raw text
+		if(this.srcNodeRef && this.srcNodeRef.innerHTML != ""){
+			this.value = this.srcNodeRef.innerHTML;
+			this.srcNodeRef.innerHTML = "";
+		}
+		if((!this.value || this.value == "") && this.srcNodeRef && this.srcNodeRef.value){
+			this.value = this.srcNodeRef.value;
+		}
+		if(!this.value){ this.value = ""; }
+	},
+
+	postCreate: function(){
+		if(dojo.isIE || dojo.isSafari){
+			this.domNode.style.overflowY = 'hidden';
+			this.eventNode = this.editNode;
+			this.focusNode = this.editNode;
+			this.connect(this.eventNode, "oncut", this._changing);
+			this.connect(this.eventNode, "onpaste", this._changing);
+		}else if(dojo.isMozilla){
+			this.iframe = this.domNode.firstChild;
+			var w = this.iframe.contentWindow;
+			var d = w.document;
+			d.open();
+			d.write('<html><body style="margin:0px;padding:0px;border:0px;"><div tabIndex="1" style="padding:2px;"></div></body></html>');
+			d.close();
+			try{ this.iframe.contentDocument.designMode="on"; }catch(e){/*squelch*/} // this can fail if display:none
+			this.editNode = d.body.firstChild;
+			this.domNode.style.overflowY = 'hidden';
+			this.eventNode = d;
+			this.focusNode = this.editNode;
+			this.eventNode.addEventListener("keypress", dojo.hitch(this, "_interceptTab"), false);
+			this.eventNode.addEventListener("resize", dojo.hitch(this, "_changed"), false);
+		}else{
+			this.focusNode = this.domNode;
+		}
+		this.setValue(this.value);
+		if(this.eventNode){
+			this.connect(this.eventNode, "keydown", this._changing);
+			this.connect(this.eventNode, "mousemove", this._changed);
+			this.connect(this.eventNode, "focus", this._focused);
+			this.connect(this.eventNode, "blur", this._blurred);
+		}
+	},
+
+	// event handlers, you can over-ride these in your own subclasses
+	_focused: function(){
+		dojo.addClass(this.domNode, "dijitInputFieldFocused");
+		this._changed();
+	},
+
+	_blurred: function(){
+		dojo.removeClass(this.domNode, "dijitInputFieldFocused");
+		this._changed();
+	},
+
+	_interceptTab: function(e){
+		if(e.keyCode == 9 && !e.shiftKey && !e.ctrlKey && !e.altKey){
+			this.iframe.focus();
+			e.preventDefault();
+		}
+	},
+
+	_changing: function(){
+		// summary: event handler for when a change is imminent
+		setTimeout(dojo.hitch(this,"_changed"),1);
+	},
+
+	_changed: function(){
+		// summary: event handler for when a change has already happened
+		if(this.iframe && this.iframe.contentDocument.designMode != "on"){
+			this.iframe.contentDocument.designMode="on"; // in case this failed on init due to being hidden
+		}
+		this._setFormValue();
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/form/Textbox.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/Textbox.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/Textbox.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,124 @@
+dojo.provide("dijit.form.Textbox");
+
+dojo.require("dijit.base.FormElement");
+dojo.require("dijit.base.TemplatedWidget");
+
+dojo.declare(
+	"dijit.form.Textbox",
+	[dijit.base.FormElement, dijit.base.TemplatedWidget],
+	{
+		// summary:
+		//		A generic textbox field.
+		//		Serves as a base class to derive more specialized functionality in subclasses.
+
+		//	trim: Boolean
+		//		Removes leading and trailing whitespace if true.  Default is false.
+		trim: false,
+
+		//	uppercase: Boolean
+		//		Converts all characters to uppercase if true.  Default is false.
+		uppercase: false,
+
+		//	lowercase: Boolean
+		//		Converts all characters to lowercase if true.  Default is false.
+		lowercase: false,
+
+		//	propercase: Boolean
+		//		Converts the first character of each word to uppercase if true.
+		propercase: false,
+
+		// size: String
+		//		HTML INPUT tag size declaration.
+		size: "20",
+
+		// maxlength: String
+		//		HTML INPUT tag maxlength declaration.
+		maxlength: "999999",
+
+		templateString:"<input dojoAttachPoint='textbox;focusNode' dojoAttachEvent='onblur;onfocus;onkeyup'\n\tid='${id}' name='${name}' class=\"dijitInputField\" type='${type}' size='${size}' maxlength='${maxlength}' tabIndex='${tabIndex}'>\n",
+	
+		getTextValue: function(){
+			return this.filter(this.textbox.value);
+		},
+
+		getValue: function(){
+			return this.parse(this.getTextValue(), this.constraints);
+		},
+
+		setValue: function(value, /*String, optional*/ formattedValue){
+			if(typeof formattedValue == "undefined" ){ 
+				formattedValue = (typeof value == "undefined" || value == null || value == NaN) ? null : this.filter(this.format(value, this.constraints));
+			}
+			if(formattedValue != null){
+				this.textbox.value = formattedValue;
+			}
+			dijit.form.Textbox.superclass.setValue.call(this,value);
+		},
+
+		format: function(/* String */ value, /* Object */ constraints){
+			// summary: Replacable function to convert a value to a properly formatted string
+			return value;
+		},
+
+		parse: function(/* String */ value, /* Object */ constraints){
+			// summary: Replacable function to convert a formatted string to a value
+			return value;
+		},
+
+		postCreate: function(){
+			dijit.form.Textbox.superclass.postCreate.apply(this);
+			// get the node for which the background color will be updated
+			if(typeof this.nodeWithBorder != "object"){
+				this.nodeWithBorder = this.textbox;
+			}
+			// assign value programatically in case it has a quote in it
+			this.setValue(this.value);
+			// setting the value here is needed since value="" in the template causes "undefined"
+			// and setting in the DOM (instead of the JS object) helps with form reset actions
+			this.textbox.setAttribute("value", this.getTextValue());
+		},
+
+		filter: function(val){
+			// summary: Apply various filters to textbox value
+			if(val == null){ return null; }
+			if(this.trim){
+				val = val.replace(/(^\s*|\s*$)/g, "");
+			} 
+			if(this.uppercase){
+				val = val.toUpperCase();
+			} 
+			if(this.lowercase){
+				val = val.toLowerCase();
+			} 
+			if(this.propercase){
+				val = val.replace(/[^\s]+/g, function(word){
+					return word.substring(0,1).toUpperCase() + word.substring(1);
+				});
+			} 
+			return val;
+		},
+	
+		focus: function(){
+			// summary: if the widget wants focus, then focus the textbox
+			this.textbox.focus();
+		},
+
+		// event handlers, you can over-ride these in your own subclasses
+		onfocus: function(){
+			dojo.addClass(this.nodeWithBorder, "dijitInputFieldFocused");
+		},
+
+		onblur: function(){
+			dojo.removeClass(this.nodeWithBorder, "dijitInputFieldFocused");
+
+			this.setValue(this.getValue()); 
+		},
+
+		onkeyup: function(){ 
+			// TODO: it would be nice to massage the value (ie: automatic uppercase, etc) as the user types
+			// but this messes up the cursor position if you are typing into the middle of a word, and
+			// also trimming doesn't work correctly (it prevents spaces between words too!)
+			// this.setValue(this.getValue()); 
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/form/ValidationTextbox.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/ValidationTextbox.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/ValidationTextbox.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,255 @@
+dojo.provide("dijit.form.ValidationTextbox");
+
+dojo.require("dojo.i18n");
+dojo.require("dijit.util.wai");
+
+dojo.require("dijit.form.Textbox");
+dojo.require("dijit.Tooltip");
+
+dojo.requireLocalization("dijit.form", "validate");
+
+dojo.declare(
+	"dijit.form.ValidationTextbox",
+	dijit.form.Textbox,
+	{
+		// summary:
+		//		A subclass of Textbox.
+		//		Over-ride isValid in subclasses to perform specific kinds of validation.
+
+		// default values for new subclass properties
+		// required: Boolean
+		//		Can be true or false, default is false.
+		required: false,
+		// promptMessage: String
+		//		Hint string
+		promptMessage: "",
+		// invalidMessage: String
+		// 		The message to display if value is invalid.
+		invalidMessage: "",
+		// listenOnKeyPress: Boolean
+		//		Updates messages on each key press.  Default is true.
+		listenOnKeyPress: true,
+		// constraints: Object
+		//		user-defined object needed to pass parameters to the validator functions
+		constraints: {},
+		// regExp: String
+		//		regular expression string used to validate the input
+		//		Do not specify both regExp and regExpGen
+		regExp: ".*",
+		// regExpGen: Function
+		//		user replaceable function used to generate regExp when dependent on constraints
+		//		Do not specify both regExp and regExpGen
+		regExpGen: function(constraints){ return this.regExp; },
+	
+		setValue: function(){
+			dijit.form.ValidationTextbox.superclass.setValue.apply(this, arguments);
+			this.validate(false);
+		},
+	
+		validator: function(value,constraints){
+			// summary: user replaceable function used to validate the text input against the regular expression.
+			return (new RegExp("^(" + this.regExpGen(constraints) + ")$")).test(value);
+		},
+
+		isValid: function(/* Boolean*/ isFocused){
+			// summary: Need to over-ride with your own validation code in subclasses
+			return this.validator(this.textbox.value, this.constraints);
+		},
+	
+		isEmpty: function(){
+			// summary: Checks for whitespace
+			return /^\s*$/.test(this.textbox.value); // Boolean
+		},
+
+		isMissing: function(/* Boolean*/ isFocused){
+			// summary: Checks to see if value is required and is whitespace
+			return this.required && this.isEmpty(); // Boolean
+		},
+	
+		getErrorMessage: function(/* Boolean*/ isFocused){
+			// summary: return an error message to show if appropriate
+			return this.invalidMessage;
+		},
+
+		getPromptMessage: function(/* Boolean*/ isFocused){
+			// summary: return a hint to show if appropriate
+			return this.promptMessage;
+		},
+
+		validate: function(/* Boolean*/ isFocused){
+			// summary:
+			//		Called by oninit, onblur, and onkeypress.
+			// description:
+			//		Show missing or invalid messages if appropriate, and highlight textbox field.
+			
+			var message;
+			if(!this.isValid(isFocused)){
+				this.updateClass("Error");
+				message = this.getErrorMessage(isFocused);
+			}else{
+				this.updateClass(this.isMissing() ? "Warning" : "Normal");
+				message = this.getPromptMessage(isFocused);
+			}
+			this._displayMessage(isFocused ? message : "");
+		},
+		
+		// currently displayed message
+		_message: "",		
+
+		_displayMessage: function(/*String*/ message){
+			if(this._message == message){ return; }
+			this._message = message;
+			if(message){
+				dijit.MasterTooltip.show(message, this.domNode);
+			}else{
+				dijit.MasterTooltip.hide();
+			}
+		},
+
+		updateClass: function(className){
+			// summary: used to ensure that only 1 validation class is set at a time
+			var _this = this;
+			dojo.forEach(["Normal", "Warning", "Error"], function(label){
+				dojo.removeClass(_this.nodeWithBorder, "dijitInputFieldValidation"+label); });
+			dojo.addClass(this.nodeWithBorder, "dijitInputFieldValidation"+className);
+		},
+		
+		onfocus: function(evt){
+			dijit.form.ValidationTextbox.superclass.onfocus.apply(this, arguments);
+			if(this.listenOnKeyPress){
+				this.validate(true);
+			}else{
+				this.updateClass("Warning");
+			}
+		},
+	
+		onkeyup: function(evt){
+			this.onfocus(evt);
+		},
+
+		postMixInProperties: function(){
+			if(this.constraints == dijit.form.ValidationTextbox.prototype.constraints){
+				this.constraints = {};
+			}
+			dijit.form.ValidationTextbox.superclass.postMixInProperties.apply(this, arguments);
+			this.constraints.locale=this.lang;
+			this.messages = dojo.i18n.getLocalization("dijit.form", "validate", this.lang);
+			dojo.forEach(["invalidMessage", "missingMessage"], function(prop){
+				if(!this[prop]){ this[prop] = this.messages[prop]; }
+			}, this);
+			var p = this.regExpGen(this.constraints);
+			this.regExp = p;
+			// make value a string for all types so that form reset works well
+		}
+	}
+);
+
+dojo.declare(
+	"dijit.form.MappedTextbox",
+	dijit.form.ValidationTextbox,
+	{
+		// summary:
+		//		A subclass of ValidationTextbox.
+		//		Provides a hidden input field and a serialize method to override
+
+		serialize: function(val){
+			// summary: user replaceable function used to convert the getValue() result to a String
+			return val.toString();
+		},
+		
+		toString: function(){
+			// summary: display the widget as a printable string using the widget's value
+			var val = this.getValue();
+			return val ? ((typeof val == "string") ? val : this.serialize(val)) : "";
+		},
+
+		validate: function(){
+			this.valueNode.value = this.toString();
+			dijit.form.MappedTextbox.superclass.validate.apply(this, arguments);
+		},
+
+		postCreate: function(){
+			var textbox = this.textbox;
+			var valueNode = (this.valueNode = document.createElement("input"));
+			valueNode.setAttribute("type", textbox.type);
+			valueNode.setAttribute("value", this.toString());
+			dojo.style(valueNode, "display", "none");
+			valueNode.name = this.textbox.name;
+			this.textbox.removeAttribute("name");
+
+			dojo.place(valueNode, textbox, "after"); 
+
+			dijit.form.MappedTextbox.superclass.postCreate.apply(this, arguments);
+		}
+	}
+);
+
+dojo.declare(
+	"dijit.form.RangeBoundTextbox",
+	dijit.form.MappedTextbox,
+	{
+		// summary:
+		//		A subclass of MappedTextbox.
+		//		Tests for a value out-of-range
+		/*===== contraints object:
+		// min: Number
+		//		Minimum signed value.  Default is -Infinity
+		min: undefined,
+		// max: Number
+		//		Maximum signed value.  Default is +Infinity
+		max: undefined,
+		=====*/
+
+		// rangeMessage: String
+		//              The message to display if value is out-of-range
+		rangeMessage: "",
+
+		compare: function(val1, val2){
+			// summary: compare 2 values
+			return val1 - val2;
+		},
+
+		rangeCheck: function(/* Number */ primitive, /* Object */ constraints){
+			// summary: user replaceable function used to validate the range of the numeric input value
+			var isMin = (typeof constraints.min != "undefined");
+			var isMax = (typeof constraints.max != "undefined");
+			if(isMin || isMax){
+				return (!isMin || this.compare(primitive,constraints.min) >= 0) &&
+					(!isMax || this.compare(primitive,constraints.max) <= 0);
+			}else{ return true; }
+		},
+
+		isInRange: function(/* Boolean*/ isFocused){
+			// summary: Need to over-ride with your own validation code in subclasses
+			return this.rangeCheck(this.getValue(), this.constraints);
+		},
+	
+		isValid: function(/* Boolean*/ isFocused){
+			return dijit.form.RangeBoundTextbox.superclass.isValid.call(this, isFocused) &&
+				this.isInRange(isFocused);
+		},
+	
+		getErrorMessage: function(/* Boolean*/ isFocused){
+			if(dijit.form.RangeBoundTextbox.superclass.isValid.call(this, false) && !this.isInRange(isFocused)){ return this.rangeMessage; }
+			else{ return dijit.form.RangeBoundTextbox.superclass.getErrorMessage.apply(this, arguments); }
+		},
+
+		postMixInProperties: function(){
+			dijit.form.RangeBoundTextbox.superclass.postMixInProperties.apply(this, arguments);
+			if(!this.rangeMessage){ 
+				this.messages = dojo.i18n.getLocalization("dijit.form", "validate", this.lang);
+				this.rangeMessage = this.messages.rangeMessage;
+			}
+		},
+
+		postCreate: function(){
+			dijit.form.RangeBoundTextbox.superclass.postCreate.apply(this, arguments);
+			if(typeof this.constraints.min != "undefined"){
+				dijit.util.wai.setAttr(this.domNode, "waiState", "valuemin", this.constraints.min);
+			}
+			if(typeof this.constraints.max != "undefined"){
+				dijit.util.wai.setAttr(this.domNode, "waiState", "valuemax", this.constraints.max);
+			}
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/form/_DropDownTextBox.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/_DropDownTextBox.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/_DropDownTextBox.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,207 @@
+dojo.provide("dijit.form._DropDownTextBox");
+
+dojo.require("dijit.util.PopupManager");
+dojo.require("dijit.util.wai");
+
+dojo.declare(
+	"dijit.form._DropDownTextBox",
+	null,
+	{
+		// summary:
+		//		Mixin text box with drop down
+
+		templateString:"<fieldset class='dijit dijitInline dijitLeft dijitAutoCompleter' id=\"widget_${id}\" name=\"${name}\"\n\tdojoAttachEvent=\"onmouseover:setStateClass;onmouseout:setStateClass;\"\t\n>\n<table cellspacing=0 cellpadding=0>\n\t<tr>\n\t\t<td class='dijitReset dijitStretch dijitAutoCompleterInput'\n\t\t\t><input class='XdijitInputField' type=\"text\" autocomplete=\"off\" name=\"${name}\"\n\t\t\tdojoAttachEvent=\"onkeypress; onkeyup; onfocus; onblur; compositionend;\"\n\t\t\tdojoAttachPoint=\"textbox;focusNode\" id='${id}'\n\t\t\ttabIndex='${tabIndex}' size='${size}' maxlength='${maxlength}'\n\t></td><td class='dijitReset dijitRight dijitButtonNode dijitDownArrowButton'\n\t\t\tdojoAttachPoint=\"downArrowNode\"\n\t\t\tdojoAttachEvent=\"onclick:arrowClick;onmousedown:setStateClass;onmouseup:setStateClass;onmouseover:setStateClass;onmouseout:setStateClass;\"\n\t\t\ttabIndex=\"${tabIndex}\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true\"\n\t\t><div class='dijitRightSpacer'><span class='dijitA11yDownArrow'>&#9660;</span></div>\n\t</td></tr>\n</table>\n</fieldset>\n",
+
+		// _popupWidget: Widget
+		//	link to the popup widget created by makePopop
+		_popupWidget:null,
+
+		// _hasMasterPopup: Boolean
+		//	Flag that determines if this widget should share one popup per widget prototype,
+		//	or create one popup per widget instance.
+		//	If true, then makePopup() creates one popup per widget prototype.
+		//	If false, then makePopup() creates one popup per widget instance.
+		_hasMasterPopup:false,
+
+		// _popupClass: String
+		//	Class of master popup (dijit.form._AutoCompleterMenu)
+		_popupClass:"",
+
+		// _popupArgs: Object
+		//	Object to pass to popup widget on initialization
+		_popupArgs:{},
+
+		_arrowPressed: function(){
+			if(!this.disabled){
+				dojo.addClass(this.downArrowNode, "dijitArrowButtonActive");
+			}
+		},
+
+		_arrowIdle: function(){
+			if(this.disabled){
+				return;
+			}
+			dojo.removeClass(this.downArrowNode, "dojoArrowButtonPushed");
+		},
+
+		makePopup: function(){
+			// summary:
+			//	create popup widget on demand
+			var _this=this;
+			function _createNewPopup(){
+				// common code from makePopup
+				var node=document.createElement("div");
+				document.body.appendChild(node);
+				// If you leave display="", _DropDownTextBox will think that the popup is open.
+				// _DropDownTextBox will call PopupManager.close() to close its last popup.
+				// However, because this popup was never popped up, 
+				// PopupManager has an empty popup stack and creates an error.
+				// Setting display="none" prevents this bad call to PopupManager.close().
+				with(node.style){
+					display="none";
+					position="absolute";
+					overflow="auto";
+				}
+				var popupProto=dojo.getObject(_this._popupClass, false);
+				return new popupProto(_this._popupArgs, node);
+			}
+			// this code only runs if there is no popup reference
+			if(!this._popupWidget){
+				// does this widget have one "master" popup?
+				if(this._hasMasterPopup){
+					// does the master popup not exist yet?
+					var parentClass = dojo.getObject(this.declaredClass, false);
+					if(!parentClass.prototype._popupWidget){
+						// create the master popup for the first time
+						parentClass.prototype._popupWidget=_createNewPopup();
+					}
+					// assign master popup to local link
+					this._popupWidget=parentClass.prototype._popupWidget;
+				}else{
+					// if master popup is not being used, create one popup per widget instance
+					this._popupWidget=_createNewPopup();
+				}
+			}
+		},
+
+		arrowClick: function(){
+			// summary: callback when arrow is clicked
+			if(this.disabled){
+				return;
+			}
+			this.focus();
+			this.makePopup();
+			if(this.isShowingNow()){
+				this._hideResultList();
+			}else{
+				// forces full population of results, if they click
+				// on the arrow it means they want to see more options
+				this._openResultList();
+			}
+		},
+
+		_hideResultList: function(){
+			if(this.isShowingNow()){
+				dijit.util.PopupManager.close(true);
+				this._arrowIdle();
+			}
+		},
+
+		_openResultList:function(){
+			// summary:
+			//	any code that needs to happen before the popup appears.
+			//	creating the popupWidget contents etc.
+			this._showResultList();
+		},
+
+		onblur:function(){
+			this._arrowIdle();
+			// removeClass dijitInputFieldFocused
+			dojo.removeClass(this.nodeWithBorder, "dijitInputFieldFocused");
+			// hide the Tooltip
+			this._displayMessage("");
+		},
+
+		onkeypress: function(/*Event*/ evt){
+			// summary: generic handler for popup keyboard events
+			if(evt.ctrlKey || evt.altKey){
+				return;
+			}
+			switch(evt.keyCode){
+				case dojo.keys.PAGE_DOWN:
+				case dojo.keys.DOWN_ARROW:
+					if(!this.isShowingNow()||this._prev_key_esc){
+						this.makePopup();
+						this._arrowPressed();
+						this._openResultList();
+					}
+					dojo.stopEvent(evt);
+					this._prev_key_backspace = false;
+					this._prev_key_esc = false;
+					break;
+
+				case dojo.keys.PAGE_UP:
+				case dojo.keys.UP_ARROW:
+				case dojo.keys.ENTER:
+					// prevent default actions
+					dojo.stopEvent(evt);
+					// fall through
+				case dojo.keys.ESCAPE:
+				case dojo.keys.TAB:
+					if(this.isShowingNow()){
+						this._prev_key_backspace = false;
+						this._prev_key_esc = (evt.keyCode==dojo.keys.ESCAPE);
+						this._hideResultList();
+					}
+					break;
+			}
+		},
+
+		compositionend: function(/*Event*/ evt){
+			// summary: When inputting characters using an input method, such as Asian
+			// languages, it will generate this event instead of onKeyDown event
+			this.onkeypress({charCode:-1});
+		},
+
+		_showResultList: function(){
+			// Our dear friend IE doesnt take max-height so we need to calculate that on our own every time
+			this._hideResultList();
+			var childs = this._popupWidget.getListLength ? this._popupWidget.getItems() : [this._popupWidget.domNode];
+
+			if(childs.length){
+				var visibleCount = Math.min(childs.length,this.maxListLength);
+				with(this._popupWidget.domNode.style){
+					// trick to get the dimensions of the popup
+					visibility="hidden";
+					display="";
+					width="";
+					height="";
+				}
+				this._arrowPressed();
+				// hide the tooltip
+				this._displayMessage("");
+				var best=this._popupWidget.open(this);
+				dojo.marginBox(this._popupWidget.domNode, {h:best.h,w:dojo.marginBox(this.domNode).w});
+				this._popupWidget.domNode.style.visibility="visible";
+			}
+		},
+
+		isShowingNow:function(){
+			// summary
+			//	test if the popup is visible
+			return this._popupWidget&&this._popupWidget.domNode.style.display!="none";
+		},
+
+		getDisplayedValue:function(){
+			return this.textbox.value;
+		},
+
+		setDisplayedValue:function(/*String*/ value){
+			this.textbox.value=value;
+		},
+
+		uninitialize:function(){
+			if(this._popupWidget){this._popupWidget.destroy()};
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/form/_Spinner.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/_Spinner.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/_Spinner.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,107 @@
+dojo.provide("dijit.form._Spinner");
+
+dojo.require("dijit.form.ValidationTextbox");
+dojo.require("dijit.util.typematic");
+dojo.require("dijit.util.sniff");
+
+dojo.declare(
+	"dijit.form._Spinner",
+	dijit.form.RangeBoundTextbox,
+	{
+	
+		// summary: Mixin for validation widgets with a spinner
+		// description: This class basically (conceptually) extends dijit.form.ValidationTextbox.
+		//	It modifies the template to have up/down arrows, and provides related handling code.
+
+		// defaultTimeout: Number
+		//      number of milliseconds before a held key or button becomes typematic
+		defaultTimeout: 500,
+
+		// timeoutChangeRate: Number
+		//      fraction of time used to change the typematic timer between events
+		//      1.0 means that each typematic event fires at defaultTimeout intervals
+		//      < 1.0 means that each typematic event fires at an increasing faster rate
+		timeoutChangeRate: 0.90,
+
+		// smallDelta: Number
+		//      adjust the value by this much when spinning using the arrow keys/buttons
+		smallDelta: 1,
+		// largeDelta: Number
+		//      adjust the value by this much when spinning using the PgUp/Dn keys
+		largeDelta: 10,
+
+		templateString:"<fieldset class='dijit dijitInline dijitSpinner' id=\"widget_${id}\" name=\"${name}\"\n\tdojoAttachEvent=\"onmouseover:setStateClass;onmouseout:setStateClass;\"\n\tbaseClass='dijitSpinner'\n>\n<table cellspacing='0' cellpadding='0' waiRole=\"presentation\" class='dijitReset dijitLeft'>\n\t<tr>\n\t\t<td class='dijitReset dijitStretch dijitSpinnerInput'>\n\t\t\t<input dojoAttachPoint='textbox;focusNode' type='${type}' dojoAttachEvent='onblur;onfocus;onkeyup;'\n\t\t\t\tvalue='${value}' name='${name}' size='${size}' maxlength='${maxlength}'\n\t\t\t\twaiRole=\"spinbutton\" autocomplete=\"off\" tabIndex='${tabIndex}'\n\t\t\t>\n\t\t</td><td class='dijitReset'>\n\t\t\t<div class='dijitButtonNode dijitUpArrowButton'\n\t\t\t\tdojoAttachPoint=\"upArrowNode\"\n\t\t\t\tdojoAttachEvent=\"onmousedown:_handleUpArrowEvent;onmouseup:_handleUpArrowEvent;onmouseover:_handleUpArrowEvent;onmouseout:_handleUpArrowEvent;\"\n\t\t\t\tbaseClass='dijitSpinnerUpArrow'\n\t\t\t\ttabIndex=\"${tabIndex}\"\n\t\t\t\twaiRole=\"button\"\n\t\t\t><span class='dijitA11yUpArrow'>&#9650;</span></div>\n\t\t\t<div class='dijitButtonNode dijitDownArrowButton'\n\t\t\t\tdojoAttachPoint=\"downArrowNode\"\n\t\t\t\tdojoAttachEvent=\"onmousedown:_handleDownArrowEvent;onmouseup:_handleDownArrowEvent;onmouseover:_handleDownArrowEvent;onmouseout:_handleDownArrowEvent;\"\n\t\t\t\tbaseClass='dijitSpinnerDownArrow'\n\t\t\t\ttabIndex=\"${tabIndex}\"\n\t\t\t\twaiRole=\"button\"\n\t\t\t><span class='dijitA11yDownArrow'>&#9660;</span></div>\n\t\t</td>\n\t</tr>\n</table>\n</fieldset>\n",
+
+		adjust: function(/* Object */ val, /*Number*/ delta){
+			// summary: user replaceable function used to adjust a primitive value(Number/Date/...) by the delta amount specified
+			// the val is adjusted in a way that makes sense to the object type
+			return val;
+		},
+
+		_handleUpArrowEvent : function(/*Event*/ e){
+			this.setStateClass(e, this.upArrowNode);
+		},
+
+		_handleDownArrowEvent : function(/*Event*/ e){
+			this.setStateClass(e, this.downArrowNode);
+		},
+
+
+		_arrowPressed: function(/*Node*/ nodePressed, /*Number*/ direction){
+			dojo.addClass(nodePressed, "dijitSpinnerButtonActive");
+			this.setValue(this.adjust(this.getValue(), direction*this.smallDelta));
+		},
+
+		_arrowReleased: function(/*Node*/ node){
+			this._wheelTimer = null;
+			this.textbox.focus();
+			dojo.removeClass(node, "dijitSpinnerButtonActive");
+		},
+
+		_typematicCallback: function(/*Number*/ count, /*DOMNode*/ node, /*Event*/ evt){
+			if(node == this.textbox){ node = (evt.keyCode == dojo.keys.UP_ARROW) ? this.upArrowNode : this.downArrowNode; }
+			if(count == -1){ this._arrowReleased(node); }
+			else{ this._arrowPressed(node, (node == this.upArrowNode) ? 1 : -1); }
+		},
+
+		_wheelTimer: null,
+		_mouseWheeled: function(/*Event*/ evt){
+			dojo.stopEvent(evt);
+			var scrollAmount = 0;
+			if(typeof evt.wheelDelta == 'number'){ // IE
+				scrollAmount = evt.wheelDelta;
+			}else if(typeof evt.detail == 'number'){ // Mozilla+Firefox
+				scrollAmount = -evt.detail;
+			}
+			if(scrollAmount > 0){
+				var node = this.upArrowNode;
+				var dir = +1;
+			}else if(scrollAmount < 0){
+				var node = this.downArrowNode;
+				var dir = -1;
+			}else{ return; }
+			this._arrowPressed(node, dir);
+			if(this._wheelTimer != null){
+				clearTimeout(this._wheelTimer);
+			}
+			var _this = this;
+			this._wheelTimer = setTimeout(function(){_this._arrowReleased(node);}, 50);
+		},
+
+		postCreate: function(){
+			dijit.form._Spinner.superclass.postCreate.apply(this, arguments);
+
+			// textbox and domNode get the same style but the css separates the 2 using !important
+			if(this.srcNodeRef){
+				dojo.style(this.textbox, "cssText", this.srcNodeRef.style.cssText);
+				this.textbox.className += " " + this.srcNodeRef.className;
+			}
+
+			// extra listeners
+			this.connect(this.textbox, dojo.isIE ? "onmousewheel" : 'DOMMouseScroll', "_mouseWheeled");
+			dijit.util.typematic.addListener(this.upArrowNode, this.textbox, {keyCode:dojo.keys.UP_ARROW,ctrlKey:false,altKey:false,shiftKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout);
+			dijit.util.typematic.addListener(this.downArrowNode, this.textbox, {keyCode:dojo.keys.DOWN_ARROW,ctrlKey:false,altKey:false,shiftKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout);
+
+			this._setDisabled(this.disabled == true);
+		}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/form/nls/de/validate.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/nls/de/validate.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/nls/de/validate.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+({
+		invalidMessage: "* Der eingegebene Wert ist ungültig.",
+		missingMessage: "* Der Wert wird benötigt.",
+		rangeMessage: "* Der Wert liegt außerhalb des gültigen Bereichs."
+})

Added: trunk/examples/typeface/root/static/dojo/dijit/form/nls/fr/validate.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/nls/fr/validate.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/nls/fr/validate.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+({
+		invalidMessage: "* La valeur saisie est incorrecte.",
+		missingMessage: "* Cette valeur est obligatoire.",
+		rangeMessage: "* Cette valeur est hors limites."
+})

Added: trunk/examples/typeface/root/static/dojo/dijit/form/nls/it/validate.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/nls/it/validate.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/nls/it/validate.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+({
+		invalidMessage: "* Il valore inserito non è valido.",
+		missingMessage: "* Questo valore è obbligatorio.",
+		rangeMessage: "* Questo valore è al di fuori dell'intervallo consentito"
+})

Added: trunk/examples/typeface/root/static/dojo/dijit/form/nls/ja/validate.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/nls/ja/validate.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/nls/ja/validate.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,6 @@
+/*<?xml version="1.0" encoding="UTF-8" ?>*/
+({
+		invalidMessage: "* 入力したデータに該当するものがありません。",
+		missingMessage: "* 入力が必須です。",
+		rangeMessage: "* 入力した数値は選択範囲外です。"
+})

Added: trunk/examples/typeface/root/static/dojo/dijit/form/nls/validate.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/nls/validate.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/nls/validate.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+({
+		invalidMessage: "* The value entered is not valid.",
+		missingMessage: "* This value is required.",
+		rangeMessage: "* This value is out of range."
+})

Added: trunk/examples/typeface/root/static/dojo/dijit/form/nls/zh-cn/validate.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/nls/zh-cn/validate.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/nls/zh-cn/validate.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+({
+		invalidMessage: "* 非法的输入值。",
+		missingMessage: "* 此值是必须的。",
+		rangeMessage: "* 输入数据超出值域。"
+})
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dijit/form/templates/AutoCompleter.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/templates/AutoCompleter.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/templates/AutoCompleter.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,19 @@
+<fieldset class='dijit dijitInline dijitLeft dijitAutoCompleter' id="widget_${id}" name="${name}"
+	dojoAttachEvent="onmouseover:setStateClass;onmouseout:setStateClass;"	
+>
+<table cellspacing=0 cellpadding=0>
+	<tr>
+		<td class='dijitReset dijitStretch dijitAutoCompleterInput'
+			><input class='XdijitInputField' type="text" autocomplete="off" name="${name}"
+			dojoAttachEvent="onkeypress; onkeyup; onfocus; onblur; compositionend;"
+			dojoAttachPoint="textbox;focusNode" id='${id}'
+			tabIndex='${tabIndex}' size='${size}' maxlength='${maxlength}'
+	></td><td class='dijitReset dijitRight dijitButtonNode dijitDownArrowButton'
+			dojoAttachPoint="downArrowNode"
+			dojoAttachEvent="onclick:arrowClick;onmousedown:setStateClass;onmouseup:setStateClass;onmouseover:setStateClass;onmouseout:setStateClass;"
+			tabIndex="${tabIndex}"
+			waiRole="button" waiState="haspopup-true"
+		><div class='dijitRightSpacer'><span class='dijitA11yDownArrow'>&#9660;</span></div>
+	</td></tr>
+</table>
+</fieldset>

Added: trunk/examples/typeface/root/static/dojo/dijit/form/templates/Button.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/templates/Button.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/templates/Button.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,8 @@
+<div class="dijit dijitLeft dijitInline dijitButton" 
+	dojoAttachEvent="onclick:setStateClass;onmouseover:setStateClass;onmouseout:setStateClass;onmousedown:setStateClass"><div class='dijitRight'>
+	<button class="dijitStretch dijitButtonNode dijitButtonContents" 
+		tabIndex="${tabIndex}" type="${type}" id="${id}" name="${name}" alt="${alt}" 
+		dojoAttachPoint="containerNode;focusNode">
+			${caption}
+	</button>
+</div></div>

Added: trunk/examples/typeface/root/static/dojo/dijit/form/templates/Checkbox.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/templates/Checkbox.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/templates/Checkbox.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+<span
+ ><span dojoAttachPoint="imageContainer" class="dijitCheckbox" style="overflow:hidden;"></span
+ ><input dojoAttachPoint="inputNode;focusNode" class="dijitCheckboxInput" id="${id}" tabIndex="${tabIndex}" type="${_type}" name="${name}" value="${value}"
+></span>

Added: trunk/examples/typeface/root/static/dojo/dijit/form/templates/ComboButton.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/templates/ComboButton.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/templates/ComboButton.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,21 @@
+<fieldset class='dijit dijitInline dijitLeft dijitComboButton' id="${id}" name="${name}"
+	dojoAttachEvent="onmouseover:setStateClass;onmouseout:setStateClass;onmousedown:setStateClass;onclick:setStateClass; onkeypress:arrowKey;"	
+>
+<table cellspacing='0' cellpadding='0'  waiRole="presentation" >
+	<tr>
+		<td	class="dijitStretch dijitButtonContents dijitButtonNode"
+			tabIndex="${tabIndex}" dojoAttachPoint="containerNode;focusNode"
+			waiRole="button">
+			${caption}
+		</td>
+		<td class='dijitReset dijitRight dijitButtonNode dijitDownArrowButton'
+			dojoAttachPoint="popupStateNode"
+			dojoAttachEvent="onmouseover:setArrowStateClass;onmouseout:setArrowStateClass;onmousedown:setArrowStateClass;onclick:arrowClick; onkeypress:arrowKey;"
+			baseClass="dijitComboButtonDownArrow"
+			title="${optionsTitle}"
+			tabIndex="${tabIndex}"
+			waiRole="button" waiState="haspopup-true"
+		><div class='dijitRightSpacer'><span class='dijitA11yDownArrow'>&#9660;</span></div>
+	</td></tr>
+</table>
+</fieldset>
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dijit/form/templates/DropDownButton.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/templates/DropDownButton.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/templates/DropDownButton.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+<div class="dijit dijitLeft dijitInlineBox dijitDropDownButton"
+	dojoAttachEvent="onmouseover:setStateClass;onmouseout:setStateClass;onmousedown:setStateClass;onclick:arrowClick; onkeypress:arrowKey;"
+	><div class='dijitRight'>
+	<button tabIndex="${tabIndex}" class="dijitStretch dijitButtonNode" type="${type}" id="${id}" name="${name}" alt="${alt}"
+	dojoAttachPoint="popupStateNode;focusNode" waiRole="button" waiState="haspopup-true"
+		><span class="dijitButtonContents" dojoAttachPoint="containerNode">${caption}</span
+		><span class='dijitA11yDownArrow'>&#9660;</span>
+	</button>
+</div></div>

Added: trunk/examples/typeface/root/static/dojo/dijit/form/templates/InlineEditBox.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/templates/InlineEditBox.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/templates/InlineEditBox.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+<span>
+	<span class='dijitInlineValue' tabIndex="0" dojoAttachPoint="editable;focusNode" style="" 
+		dojoAttachEvent="onkeypress:_onKeyPress;onclick:_onClick;onmouseout:_onMouseOut;onmouseover:_onMouseOver;onfocus:_onMouseOver;onblur:_onMouseOut;"></span>
+	<fieldset style="display:none;" dojoAttachPoint="editNode" class="dijitInlineEditor">
+		<div dojoAttachPoint="containerNode" dojoAttachEvent="onkeyup:checkForValueChange;"></div>
+		<button class='saveButton' dojoAttachPoint="saveButton" dojoType="dijit.form.Button" dojoAttachEvent="onClick:save">${buttonSave}</button>
+		<button class='cancelButton' dojoAttachPoint="cancelButton" dojoType="dijit.form.Button" dojoAttachEvent="onClick:cancel">${buttonCancel}</button>
+	</fieldset>
+</span>

Added: trunk/examples/typeface/root/static/dojo/dijit/form/templates/Spinner.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/templates/Spinner.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/templates/Spinner.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,30 @@
+<fieldset class='dijit dijitInline dijitSpinner' id="widget_${id}" name="${name}"
+	dojoAttachEvent="onmouseover:setStateClass;onmouseout:setStateClass;"
+	baseClass='dijitSpinner'
+>
+<table cellspacing='0' cellpadding='0' waiRole="presentation" class='dijitReset dijitLeft'>
+	<tr>
+		<td class='dijitReset dijitStretch dijitSpinnerInput'>
+			<input dojoAttachPoint='textbox;focusNode' type='${type}' dojoAttachEvent='onblur;onfocus;onkeyup;'
+				value='${value}' name='${name}' size='${size}' maxlength='${maxlength}'
+				waiRole="spinbutton" autocomplete="off" tabIndex='${tabIndex}'
+			>
+		</td><td class='dijitReset'>
+			<div class='dijitButtonNode dijitUpArrowButton'
+				dojoAttachPoint="upArrowNode"
+				dojoAttachEvent="onmousedown:_handleUpArrowEvent;onmouseup:_handleUpArrowEvent;onmouseover:_handleUpArrowEvent;onmouseout:_handleUpArrowEvent;"
+				baseClass='dijitSpinnerUpArrow'
+				tabIndex="${tabIndex}"
+				waiRole="button"
+			><span class='dijitA11yUpArrow'>&#9650;</span></div>
+			<div class='dijitButtonNode dijitDownArrowButton'
+				dojoAttachPoint="downArrowNode"
+				dojoAttachEvent="onmousedown:_handleDownArrowEvent;onmouseup:_handleDownArrowEvent;onmouseover:_handleDownArrowEvent;onmouseout:_handleDownArrowEvent;"
+				baseClass='dijitSpinnerDownArrow'
+				tabIndex="${tabIndex}"
+				waiRole="button"
+			><span class='dijitA11yDownArrow'>&#9660;</span></div>
+		</td>
+	</tr>
+</table>
+</fieldset>

Added: trunk/examples/typeface/root/static/dojo/dijit/form/templates/Textbox.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/form/templates/Textbox.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/form/templates/Textbox.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,2 @@
+<input dojoAttachPoint='textbox;focusNode' dojoAttachEvent='onblur;onfocus;onkeyup'
+	id='${id}' name='${name}' class="dijitInputField" type='${type}' size='${size}' maxlength='${maxlength}' tabIndex='${tabIndex}'>

Added: trunk/examples/typeface/root/static/dojo/dijit/form/templates/blank.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/form/templates/blank.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/layout/AccordionContainer.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/layout/AccordionContainer.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/layout/AccordionContainer.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,263 @@
+dojo.provide("dijit.layout.AccordionContainer");
+
+dojo.require("dojo.fx");
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.Layout");
+dojo.require("dijit.base.Showable");
+dojo.require("dijit.layout.PageContainer");
+dojo.require("dijit.util.BackgroundIframe");
+dojo.require("dijit.base.TemplatedWidget");
+/**
+ * description
+ *	Front view (3 panes, pane #2 open)
+ *	------------------------
+ *	|:::Pane#1 title:::    |
+ * 	|:::Pane#2 title:::    |
+ *	|                      |
+ *	|    pane#2 contents   |
+ *	|                      |
+ *	|:::Pane#3 title:::    |
+ *	------------------------
+ *
+ *	Side view (showing implementation):
+ *
+ *         viewport    pane#3     pane#2     pane#1
+ *            =                                
+ *            |                                =
+ *            |                      =         |
+ *	front     |                      |         |
+ *            |                      |         =
+ *            |                      =
+ *            |          =
+ *            =          |
+ *                       |
+ *                       =
+ *
+ *	Panes are stacked by z-index like a stack of cards, so they can be slid correctly.
+ *	The panes on the bottom extend past the bottom of the viewport (but are hidden).
+ *
+ * usage
+ *	<div dojoType="dijit.layout.AccordionContainer">
+ *		<div dojoType="dijit.layout.ContentPane" label="pane 1">...</div>
+ *		...
+ *	</div>
+ *
+ * TODO:
+ *	* this widget should extend PageContainer
+ */
+
+dojo.declare(
+	"dijit.layout.AccordionContainer",
+	[dijit.base.Widget, dijit.base.Layout, dijit.base.Showable],
+	{
+
+		// summary: 
+		//		Holds a set of panes where every pane's title is visible, but only one pane's content is visible at a time,
+		//		and switching between panes is visualized by sliding the other panes up/down.
+		
+		// labelNodeClass: String
+		//		CSS class name for dom node w/the title
+		labelNodeClass: "label",
+		
+		// containerNodeClass: String
+		//		CSS class name for dom node holding the content
+		containerNodeClass: "accBody",
+
+		// duration: Integer
+		//		Amount of time (in ms) it takes to slide panes
+		duration: 250,
+
+		postCreate: function(){
+			dijit.layout.AccordionContainer.superclass.postCreate.apply(this, arguments);
+			with(this.domNode.style){
+				// position must be either relative or absolute
+				if(position!="absolute"){
+					position="relative";
+				}
+				overflow="hidden";
+			}
+		},
+
+		addChild: function(widget){
+			var child = this._addChild(widget);
+			if(this._started){
+				this.layout();
+			}
+			return child;	// Widget
+		},
+		
+		_addChild: function(widget){
+			// summary
+			//		Internal call to add child, used during postCreate() and by the real addChild() call
+
+			if(widget.declaredClass != "dijit.layout.AccordionPane"){
+				// create a node that will be promoted to an accordionpane
+				var refNode = document.createElement("span");
+				this.domNode.appendChild(refNode);
+				var wrapper = new dijit.layout.AccordionPane({label: widget.label, 
+									selected: widget.selected, labelNodeClass: this.labelNodeClass,
+									containerNodeClass: this.containerNodeClass, allowCollapse: this.allowCollapse }, refNode);
+				wrapper.addChild(widget);
+				this.domNode.appendChild(wrapper.domNode);
+				return wrapper;	// Widget
+			}else{
+				dojo.addClass(widget.containerNode, this.containerNodeClass);
+				dojo.addClass(widget.labelNode, this.labelNodeClass);
+				dojo.place(widget.domNode, this.domNode, "last");
+				return widget;	// Widget
+			}
+		},
+
+		startup: function(){
+			var children = this.getChildren();
+			dojo.forEach(children, this._addChild, this);
+			dijit.base.Layout.prototype.startup.apply(this, arguments);
+		},
+
+		removeChild: function(widget){
+			dijit.layout.AccordionContainer.superclass.removeChild.call(this, widget);
+			this.layout();
+			// TODO: maybe base class removeChild() should call layout()?
+		},
+		
+		layout: function(){
+			// summary
+			//		Set panes' size/position based on my size, and the current open node.
+
+			// get cumulative height of all the title bars, and figure out which pane is open
+			var totalCollapsedHeight = 0;
+			var openIdx = 0;
+			dojo.forEach(this.getChildren(), function(child, idx){
+				if(child["getLabelHeight"]){
+					totalCollapsedHeight += child.getLabelHeight();
+					if(child.selected){ openIdx=idx; }
+				}
+			});
+			// size and position each pane
+			var mySize = this._contentBox;
+			var y = 0;
+			dojo.forEach(this.getChildren(), function(child, idx){
+				if(child["getLabelHeight"]){
+					var childCollapsedHeight = child.getLabelHeight();
+					child.resize({w: mySize.w, h: mySize.h -totalCollapsedHeight+childCollapsedHeight});
+					var style = child.domNode.style;
+					style.zIndex=idx+1;
+					style.position="absolute";
+					style.top = y+"px";
+					// TODO: REVISIT: PORT: was getBorderBox, now is marginBox ?
+					y += (idx==openIdx) ? dojo.marginBox(child.domNode).h : childCollapsedHeight;
+				}
+			});
+		},
+
+		selectChild: function(page){
+			// summary
+			//		close the current page and select a new one
+			dojo.forEach(this.getChildren(), function(child){child.setSelected(child==page);});
+			// slide each pane that needs to be moved
+			var y = 0;
+			var anims = [];
+			dojo.forEach(this.getChildren(), function(child, idx){
+				if(child.domNode.style.top != (y+"px")){
+					anims.push(dojo.fx.slideTo({node: child.domNode,
+								top: y, left: 0, duration: this.duration}));
+				}
+				// TODO: REVISIT: PORT: was getBorderBox, now is marginBox ?
+				y += child.selected ? dojo.marginBox(child.domNode).h : child.getLabelHeight();
+			}, this);
+			dojo.fx.combine(anims).play();
+		}
+	}
+);	
+
+dojo.declare(
+	"dijit.layout.AccordionPane",
+	[dijit.base.Widget, dijit.base.TemplatedWidget, dijit.base.Showable,
+	  dijit.base.Layout, dijit.base.Contained],
+{
+	// summary
+	//		AccordionPane is a box with a title that contains another widget (often a ContentPane).
+	//		It's a widget used internally by AccordionContainer.
+	// label: String
+	//		label to print on top of AccordionPane
+	label: "",
+
+	// class: String
+	//	CSS class name for the AccordionPane's dom node
+	"class": "dijitAccordionPane",
+
+	// labelNodeClass: String
+	//	CSS class name for the AccordionPane's label node
+	labelNodeClass: "label",
+
+	// containerNodeClass: String
+	//	CSS class name for the AccordionPane's container node
+	containerNodeClass: "accBody",
+	
+	// selected: Boolean
+	//	if true, this is the open pane
+	selected: false,
+
+	templateString:"<div dojoAttachPoint=\"domNode\"\n\t><div dojoAttachPoint=\"labelNode\" dojoAttachEvent=\"onclick:onLabelClick\" class=\"${labelNodeClass}\"\n\t\t><div class='arrow'></div><span dojoAttachPoint='labelTextNode'>${label}</span></div\n\t><div dojoAttachPoint=\"containerNode\" style=\"overflow: hidden;\" class=\"${containerNodeClass}\"\n\t></div>\n</div>\n",
+
+	postCreate: function(){
+		dijit.layout.AccordionPane.superclass.postCreate.apply(this, arguments);
+		dojo.addClass(this.domNode, this["class"]);
+		dijit._disableSelection(this.labelNode);
+		this.setSelected(this.selected);
+
+		// Prevent IE bleed-through problem
+		this.bgIframe = new dijit.util.BackgroundIframe(this.domNode);
+	},
+
+	setLabel: function(/*String*/ label){
+		// summary: set the  title of the node
+		this.labelTextNode.innerHTML=label;
+	},
+	
+	layout: function(){
+		var children = [
+			{domNode: this.labelNode, layoutAlign: "top"},
+			{domNode: this.containerNode, layoutAlign: "client"}
+		];
+		dijit.base.Layout.layoutChildren(this.domNode, this._contentBox, children);
+		var child = this.getChildren()[0];
+		if(child && child.resize){
+			child.resize(this._contentBox);
+		}
+	},
+
+	getLabelHeight: function(){
+		// summary: returns the height of the title dom node
+		return dojo.marginBox(this.labelNode).h;	// Integer
+	},
+
+	onLabelClick: function(){
+		// summary: callback when someone clicks my label
+		this.getParent().selectChild(this);
+	},
+	
+	setSelected: function(/*Boolean*/ isSelected){
+		this.selected = isSelected;
+		(isSelected ? dojo.addClass : dojo.removeClass)(this.domNode, this["class"]+"-selected");
+
+		// make sure child is showing (lazy load), and also that onShow()/onHide() is called
+		var child = this.getChildren()[0];
+		if(child){
+			if(isSelected){
+				if(child.isShowing()){
+					child.onShow();
+				}else{
+					child.show();
+				}
+			}else{
+				// #1969 - Firefox has a display glitch, force child to hide
+				// only the titlepane will get the slide animation
+				if(child.isShowing()){
+					child.hide();
+				}
+				child.onHide();
+			}
+		}
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/layout/ContentPane.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/layout/ContentPane.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/layout/ContentPane.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,575 @@
+dojo.provide("dijit.layout.ContentPane");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.Showable");
+dojo.require("dijit.base.Layout");
+
+dojo.declare(
+	"dijit.layout.ContentPane",
+	[dijit.base.Widget, dijit.base.Layout, dijit.base.Showable],
+		// summary:
+		//		A widget that can be used as a standalone widget 
+		//		or as a baseclass for other widgets
+		//		Handles replacement of document fragment using either external uri or javascript/java 
+		//		generated markup or DomNode content, instantiating widgets within content and runs scripts.
+		//		Dont confuse it with an iframe, it only needs document fragments.
+		//		It's useful as a child of LayoutContainer, SplitContainer, or TabContainer.
+		//		But note that those classes can contain any widget as a child.
+{
+		// loading options
+		// adjustPaths: Boolean
+		//		adjust relative paths in markup to fit this page
+		adjustPaths: false,
+
+		// href: String
+		//		The href of the content that displays now
+		//		Set this at construction if you want to load externally,
+		//		changing href after creation doesnt have any effect, see setUrl
+		href: "",
+
+		// extractContent Boolean: Extract visible content from inside of <body> .... </body>
+		extractContent: true,
+
+		// parseContent Boolean: Construct all widgets that is in content
+		parseContent:	true,
+
+		// cacheContent Boolean: Cache content retreived externally
+		cacheContent:	true,
+
+		// preload: Boolean
+		//		Force load of data even if pane is hidden.
+		// Note:
+		//		In order to delay download you need to initially hide the node it constructs from
+		preload: false,
+
+		// refreshOnShow: Boolean
+		//		Refresh (re-download) content when pane goes from hidden to shown
+		refreshOnShow: false,
+
+		// handler: String||Function
+		//		Generate pane content from a java function
+		//		The name of the java proxy function
+		handler: "",
+
+		// loadingMessage: String
+		//		Message that shows while downloading
+		loadingMessage: "Loading...", //TODO: i18n
+
+		// isLoaded: Boolean
+		//		Tells loading status
+		isLoaded: false,
+
+		// class: String
+		//		Class name to apply to ContentPane dom nodes
+		"class": "dijitContentPane",
+
+		postCreate: function(){
+			// per widgetImpl variables
+			this._styleNodes = [];
+			this._onLoadStack = [];
+			this._onUnloadStack = [];
+			this._callOnUnload = false;
+
+			// for programatically created ContentPane (with <span> tag), need to muck w/CSS
+			// or it's as though overflow:visible is set
+			dojo.addClass(this.domNode, this["class"]);
+
+			if(this.handler!==""){
+				this.setHandler(this.handler);
+			}
+			if(this.isShowing() || this.preload){
+				this._prepareForShow(); 
+			}
+		},
+	
+		onShow: function(){
+			// if refreshOnShow is true, reload the contents every time; otherwise, load only the first time
+			if(this.refreshOnShow){
+				this.refresh();
+			}else{
+				this._prepareForShow();
+			}
+		},
+	
+		refresh: function(){
+			// summary:
+			//		Force a refresh (re-download) of content, be sure to turn off cache
+			this.isLoaded=false;
+			this._prepareForShow();
+		},
+	
+		_prepareForShow: function(){
+			// summary:
+			//		Called whenever the ContentPane is displayed.  The first time it's called,
+			//		it will download the data from specified URL or handler (if the data isn't
+			//		inlined), and will instantiate subwidgets.
+			if( this.isLoaded ){
+				return;
+			}
+			if(dojo.isFunction(this.handler)){
+				this._runHandler();
+			}else if(this.href != ""){
+				this._downloadExternalContent(this.href, this.cacheContent && !this.refreshOnShow);
+			}
+		},
+		
+		setUrl: function(/*String||dojo.uri.Uri*/ url){
+			// summary:
+			//		Reset the (external defined) content of this pane and replace with new url
+
+			//	Note:
+			//		It delays the download until widget is shown if preload is false
+			this.href = url;
+			this.isLoaded = false;
+			if(this.preload || this.isShowing()){
+				this._prepareForShow();
+			}
+		},
+
+		abort: function(){
+			// summary
+			//		Aborts a inflight download of content
+		},
+	
+		_downloadExternalContent: function(url, useCache){
+			this.abort();
+			this._handleDefaults(this.loadingMessage, "onDownloadStart");
+			var self = this;
+			var getArgs = { 
+				url: url,
+				handleAs: "text"
+			}; 
+			var getHandler = dojo.xhrGet(getArgs); 
+			getHandler.addCallback(function(data){
+				self.onDownloadEnd.call(self, url, data);
+			}); 
+			getHandler.addErrback(function(e){
+				self._handleDefaults.call(self, e, "onDownloadError");
+				self.onLoad();
+			});
+		},
+	
+		onLoad: function(e){
+			// summary:
+			//		Event hook, is called after everything is loaded and widgetified 
+			this._runStack("_onLoadStack");
+			this.isLoaded=true;
+		},
+	
+		onUnload: function(e){
+			// summary:
+			//		Event hook, is called before old content is cleared
+			this._runStack("_onUnloadStack");
+		},
+	
+		_runStack: function(stName){
+			var st = this[stName]; var err = "";
+			var scope = window;
+			for(var i = 0;i < st.length; i++){
+				try{
+					st[i].call(scope);
+				}catch(e){ 
+					err += "\n"+st[i]+" failed: "+e.description;
+				}
+			}
+			this[stName] = [];
+	
+			if(err.length){
+				var name = (stName== "_onLoadStack") ? "addOnLoad" : "addOnUnLoad";
+				this._handleDefaults(name+" failure\n "+err, "onExecError", "debug"); //TODO: i18n
+			}
+		},
+	
+		addOnLoad: function(obj, func){
+			// summary
+			//		Stores function refs and calls them one by one in the order they came in
+			//		when load event occurs.
+			//	obj: Function||Object?
+			//		holder object
+			//	func: Function
+			//		function that will be called 
+			this._pushOnStack(this._onLoadStack, obj, func);
+		},
+	
+		addOnUnload: function(obj, func){
+			// summary
+			//		Stores function refs and calls them one by one in the order they came in
+			//		when unload event occurs.
+			//	obj: Function||Object
+			//		holder object
+			//	func: Function
+			//		function that will be called 
+			this._pushOnStack(this._onUnloadStack, obj, func);
+		},
+	
+		_pushOnStack: function(stack, obj, func){
+			if(typeof func == 'undefined'){
+				stack.push(obj);
+			}else{
+				stack.push(function(){ obj[func](); });
+			}
+		},
+
+		destroy: function(){
+			// if we have multiple controllers destroying us, bail after the first
+			if(this._beingDestroyed){
+				return;
+			}
+			// make sure we call onUnload
+			this.onUnload();
+			this._beingDestroyed = true;
+			dijit.layout.ContentPane.superclass.destroy.call(this);
+		},
+ 
+		onExecError: function(/*Object*/e){
+			// summary:
+			//		called when content script eval error or Java error occurs, preventDefault-able
+			//		default is to debug not alert as in 0.3.1
+		},
+	
+		onContentError: function(/*Object*/e){
+			// summary: 
+			//		called on DOM faults, require fault etc in content, preventDefault-able
+			//		default is to display errormessage inside pane
+		},
+	
+		onDownloadError: function(/*Object*/e){
+			// summary: 
+			//		called when download error occurs, preventDefault-able
+			//		default is to display errormessage inside pane
+		},
+	
+		onDownloadStart: function(/*Object*/e){
+			// summary:
+			//		called before download starts, preventDefault-able
+			//		default is to display loadingMessage inside pane
+			//		by changing e.text in your event handler you can change loading message
+		},
+	
+		// 
+		onDownloadEnd: function(url, data){
+			// summary:
+			//		called when download is finished
+			//
+			//	url String: url that downloaded data
+			//	data String: the markup that was downloaded
+			data = this.splitAndFixPaths(data, url);
+			this.setContent(data);
+		},
+	
+		// useful if user wants to prevent default behaviour ie: _setContent("Error...")
+		_handleDefaults: function(e, handler, messType){
+			if(!handler){ handler = "onContentError"; }
+
+			if(dojo.isString(e)){ e = {text: e}; }
+
+			if(!e.text){ e.text = e.toString(); }
+
+			e.toString = function(){ return this.text; };
+
+			if(typeof e.returnValue != "boolean"){
+				e.returnValue = true; 
+			}
+			if(typeof e.preventDefault != "function"){
+				e.preventDefault = function(){ this.returnValue = false; };
+			}
+			// call our handler
+			this[handler](e);
+			if(e.returnValue){
+				switch(messType){
+					case true: // fallthrough, old compat
+					case "alert":
+						alert(e.toString()); break;
+					case "debug":
+						console.debug(e.toString()); break;
+					default:
+					// makes sure scripts can clean up after themselves, before we setContent
+					if(this._callOnUnload){ this.onUnload(); } 
+					// makes sure we dont try to call onUnLoad again on this event,
+					// ie onUnLoad before 'Loading...' but not before clearing 'Loading...'
+					this._callOnUnload = false;
+
+					// we might end up in a endless recursion here if domNode cant append content
+					if(arguments.callee._loopStop){
+						console.debug(e.toString());
+					}else{
+						arguments.callee._loopStop = true;
+						this._setContent(e.toString());
+					}
+				}
+			}
+			arguments.callee._loopStop = false;
+		},
+	
+		// pathfixes, require calls, css stuff and neccesary content clean
+		// pathfixes, require calls, css stuff and neccesary content clean
+		// pathfixes, require calls, css stuff and neccesary content clean
+		splitAndFixPaths: function(s, url){
+			// summary:
+			// 		adjusts all relative paths in (hopefully) all cases, images, remote scripts, links etc.
+			// 		splits up content in different pieces, scripts, title, style, link and whats left becomes .xml
+			//	s String:	The markup in string
+			//	url (String||dojo.uri.Uri?) url that pulled in markup
+
+			var titles = [], scripts = [],tmp = [];// init vars
+			var match = [], requires = [], attr = [], styles = [];
+			var str = '', path = '', fix = '', tagFix = '', tag = '', origPath = '';
+	
+			if(!url){ url = "./"; } // point to this page if not set
+
+			if(s){ // make sure we dont run regexes on empty content
+
+				/************** <title> ***********/
+				// khtml is picky about dom faults, you can't attach a <style> or <title> node as child of body
+				// must go into head, so we need to cut out those tags
+				var regex = /<title[^>]*>([\s\S]*?)<\/title>/i;
+				while(match = regex.exec(s)){
+					titles.push(match[1]);
+					s = s.substring(0, match.index) + s.substr(match.index + match[0].length);
+				};
+
+				/************** adjust paths *****************/
+				if(this.adjustPaths){
+					// attributepaths one tag can have multiple paths example:
+					// <input src="..." style="url(..)"/> or <a style="url(..)" href="..">
+					// strip out the tag and run fix on that.
+					// this guarantees that we won't run replace on another tag's attribute + it was easier do
+					var regexFindTag = /<[a-z][a-z0-9]*[^>]*\s(?:(?:src|href|style)=[^>])+[^>]*>/i;
+					var regexFindAttr = /\s(src|href|style)=(['"]?)([\w()\[\]\/.,\\'"-:;#=&?\s@]+?)\2/i;
+					// these are the supported protocols, all other is considered relative
+					var regexProtocols = /^(?:[#]|(?:(?:https?|ftps?|file|javascript|mailto|news):))/;
+		
+					while(tag = regexFindTag.exec(s)){
+						str += s.substring(0, tag.index);
+						s = s.substring((tag.index + tag[0].length), s.length);
+						tag = tag[0];
+			
+						// loop through attributes
+						tagFix = '';
+						while(attr = regexFindAttr.exec(tag)){
+							path = ""; origPath = attr[3];
+							switch(attr[1].toLowerCase()){
+								case "src":// falltrough
+								case "href":
+									if(regexProtocols.exec(origPath)){
+										path = origPath;
+									}else{
+										path = (new dojo.uri.Uri(url, origPath).toString());
+									}
+									break;
+								case "style":// style
+									path = dojo.html.fixPathsInCssText(origPath, url);//PORT me
+									break;
+								default:
+									path = origPath;
+							}
+							fix = " " + attr[1] + "=" + attr[2] + path + attr[2];
+							// slices up tag before next attribute check
+							tagFix += tag.substring(0, attr.index) + fix;
+							tag = tag.substring((attr.index + attr[0].length), tag.length);
+						}
+						str += tagFix + tag; //dojo.debug(tagFix + tag);
+					}
+					s = str+s;
+				}
+
+				/****************  cut out all <style> and <link rel="stylesheet" href=".."> **************/
+				regex = /(?:<(style)[^>]*>([\s\S]*?)<\/style>|<link ([^>]*rel=['"]?stylesheet['"]?[^>]*)>)/i;
+				while(match = regex.exec(s)){
+					if(match[1] && match[1].toLowerCase() == "style"){
+						styles.push(dojo.html.fixPathsInCssText(match[2],url)); // PORT me
+					}else if(attr = match[3].match(/href=(['"]?)([^'">]*)\1/i)){
+						styles.push({path: attr[2]});
+					}
+					s = s.substring(0, match.index) + s.substr(match.index + match[0].length);
+				};
+
+				/***************** cut out all <script> tags, push them into scripts array ***************/
+				var regex = /<script([^>]*)>([\s\S]*?)<\/script>/i;
+				var regexSrc = /src=(['"]?)([^"']*)\1/i;
+				var regexDojoJs = /.*(\bdojo\b\.js(?:\.uncompressed\.js)?)$/;
+				var regexInvalid = /(?:var )?\bdjConfig\b(?:[\s]*=[\s]*\{[^}]+\}|\.[\w]*[\s]*=[\s]*[^;\n]*)?;?|dojo\.hostenv\.writeIncludes\(\s*\);?/g;
+				var regexRequires = /dojo\.(?:(?:require(?:After)?(?:If)?)|(?:widget\.(?:manager\.)?registerWidgetPackage)|(?:(?:hostenv\.)?registerModulePath)|defineNamespace)\((['"]).*?\1\)\s*;?/;
+
+				while(match = regex.exec(s)){
+					if(match[2]){
+						// remove all invalid variables etc like djConfig and dojo.hostenv.writeIncludes()
+						var sc = match[2].replace(regexInvalid, "");
+						if(!sc){ continue; }
+		
+						// cut out all dojo.require (...) calls, if we have execute 
+						// scripts false widgets dont get there require calls
+						// takes out possible widgetpackage registration as well
+						while((tmp = regexRequires.exec(sc))){
+							requires.push(tmp[0]);
+							sc = sc.substring(0, tmp.index) + sc.substr(tmp.index + tmp[0].length);
+						}
+					}
+					s = s.substr(0, match.index) + s.substr(match.index + match[0].length);
+				}
+
+				/********* extract content *********/
+				if(this.extractContent){
+					match = s.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+					if(match){ s = match[1]; }
+				}
+	 		}
+
+			return {"xml": 		s, // Object
+				"styles":		styles,
+				"titles": 		titles,
+				"requires": 	requires,
+				"scripts": 		scripts,
+				"url": 			url};
+		},
+	
+		
+		_setContent: function(cont){
+			this.destroyDescendants();
+	
+			// remove old stylenodes from HEAD
+			dojo.forEach(this._styleNodes, function(style){
+				if(style && style.parentNode){
+					style.parentNode.removeChild(style);
+				}
+			}, this);
+			this._styleNodes = [];
+
+			try{
+				var node = this.containerNode || this.domNode;
+				while(node.firstChild){
+			//PORT memory leak #2931
+					node.firstChild.parentNode.removeChild(node.firstChild);
+//					delete node.firstChild; //Q is this wrong?
+				}
+				if(typeof cont != "string"){
+					node.appendChild(cont);
+				}else{
+					node.innerHTML = cont;
+				}
+			}catch(e){
+				e.text = "Couldn't load content:"+e.description; //TODO: i18n
+				this._handleDefaults(e, "onContentError");
+			}
+		},
+
+		setContent: function(data){
+			// summary:
+			//		Replaces old content with data content, include style classes from old content
+			//	data String||DomNode:	new content, be it Document fragment or a DomNode chain
+			//			If data contains style tags, link rel=stylesheet it inserts those styles into DOM
+			this.abort();
+			if(this._callOnUnload){ this.onUnload(); }// this tells a remote script clean up after itself
+			this._callOnUnload = true;
+			
+//PORT: from dojo.dom.  get rid of isNode check and use something else instead?
+			var isNode = function(/* object */wh){
+				//	summary:
+				//		checks to see if wh is actually a node.
+				if(typeof Element == "function"){
+					return wh instanceof Element;	//	boolean
+				}else{
+					// best-guess
+					return wh && !isNaN(wh.nodeType);	//	boolean
+				}
+			};
+
+			if(!data || isNode(data)){
+				// if we do a clean using setContent(""); or setContent(#node) bypass all parsing, extractContent etc
+				this._setContent(data);
+				this.onLoad();
+			}else{
+				// need to run splitAndFixPaths? ie. manually setting content
+				// adjustPaths is taken care of inside splitAndFixPaths
+				if(typeof data.xml != "string"){ 
+					this.href = ""; // so we can refresh safely
+					data = this.splitAndFixPaths(data); 
+				}
+
+				this._setContent(data.xml);
+
+				// insert styles from content (in same order they came in)
+				/*
+				dojo.forEach(data.style, function(style){
+					this._styleNodes.push(
+						style.path ? dojo.html.insertCssFile(style.path, dojo.doc, false, true) : dojo.html.insertCssText(style));//PORT me?
+				}, this);
+				*/
+	
+				if(this.parseContent){
+					dojo.forEach(data.requires, function(require){
+						try{
+							eval(require);
+						}catch(e){
+							//TODO: i18n - user visible error.  Should this be presented in the UI at all?
+							e.text = "ContentPane: error in package loading calls, " + (e.description||e);
+							this._handleDefaults(e, "onContentError", "debug");
+						}
+					});
+				}
+				// need to allow async load, Xdomain uses it
+				// is inline function because we cant send args to dojo.addOnLoad
+				var _self = this;
+				function asyncParse(){
+					if(_self.parseContent){
+						_self._createSubWidgets();
+					}
+	
+					_self.onLoad();
+				}
+				// try as long as possible to make setContent sync call
+/*				if(dojo.hostenv.isXDomain && data.requires.length){
+					dojo.addOnLoad(asyncParse);
+				}else{
+*/					asyncParse();
+//				}
+			}
+		},
+
+		_createSubWidgets: function(){
+			// summary: scan my contents and create subwidgets
+			var rootNode = this.containerNode || this.domNode;
+			
+			// FIXME: this isn't working (see below)
+			dijit.util.parser.parse(rootNode);
+			
+/*			// temporary workaround until dojo.query works with passed in rootNode
+			// in above call first find all the descendent widget nodes
+			var allNodes = rootNode.all || rootNode.getElementsByTagName("*");
+			var i=0, node;
+			var nodes = [];
+			while((node = allNodes[i++])){
+			var djt = node.getAttribute("dojoType");
+				if(djt){
+					nodes.push(node);
+				}
+			}
+			// instantiate subwidgets
+			dijit.util.parser.instantiate(nodes);*/		
+		},
+
+		setHandler: function(/*Function*/ handler){ 
+			// summary:
+			//		Generate pane content from given java function
+			var fcn = dojo.isFunction(handler) ? handler : window[handler];
+			if(!dojo.isFunction(fcn)){
+				// FIXME: needs testing! somebody with java knowledge needs to try this
+				this._handleDefaults("Unable to set handler, '" + handler + "' not a function.", "onExecError", true); //TODO: i18n
+				return;
+			}
+			this.handler = function(){
+				return fcn.apply(this, arguments);
+			}
+		},
+	
+		_runHandler: function(){
+			var ret = true;
+			if(dojo.isFunction(this.handler)){
+				this.handler(this, this.domNode);
+				ret = false;
+			}
+			this.onLoad();
+			return ret;
+		}
+		
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/layout/Dialog.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/layout/Dialog.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/layout/Dialog.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,474 @@
+dojo.provide("dijit.layout.Dialog");
+
+dojo.require("dijit.util.place");
+dojo.require("dijit.util.BackgroundIframe");
+dojo.require("dijit.layout.ContentPane");
+dojo.require("dijit.base.TemplatedWidget");
+dojo.require("dojo.dnd.move");
+
+
+dojo.declare(
+	"dijit.layout.ModalDialogBase", 
+	null,
+	{
+		// summary
+		//	Mixin for widgets implementing a modal dialog
+
+		// focusElement: String
+		//	provide a focusable element or element id if you need to
+		//	work around FF's tendency to send focus into outer space on hide
+		focusElement: "",
+
+		// bgColor: String
+		//	color of viewport when displaying a dialog
+		bgColor: "black",
+		
+		// bgOpacity: Number
+		//	opacity (0~1) of viewport color (see bgColor attribute)
+		bgOpacity: 0.4,
+
+		// followScroll: Boolean
+		//	if true, readjusts the dialog (and dialog background) when the user moves the scrollbar
+		followScroll: true,
+
+		// closeOnBackgroundClick: Boolean
+		//	clicking anywhere on the background will close the dialog
+		closeOnBackgroundClick: false,
+
+		trapTabs: function(/*Event*/ e){
+			// summary
+			//	callback on focus
+			if(e.target == this.tabStartOuter) {
+				if(this._fromTrap) {
+					this.tabStart.focus();
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabEnd.focus();
+				}
+			} else if (e.target == this.tabStart) {
+				if(this._fromTrap) {
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabEnd.focus();
+				}
+			} else if(e.target == this.tabEndOuter) {
+				if(this._fromTrap) {
+					this.tabEnd.focus();
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabStart.focus();
+				}
+			} else if(e.target == this.tabEnd) {
+				if(this._fromTrap) {
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabStart.focus();
+				}
+			}
+		},
+
+		clearTrap: function(/*Event*/ e) {
+			// summary
+			//	callback on blur
+			var _this = this;
+			setTimeout(function() {
+				_this._fromTrap = false;
+			}, 100);
+		},
+
+		_setup: function() {
+			// summary
+			//	stuff we need to do before showing the Dialog for the first time
+			//	(but we defer it until right beforehand, for performance reasons)
+
+			with(this.domNode.style){
+				position = "absolute";
+				zIndex = 999;
+				display = "none";
+				overflow = "visible";
+			}
+			var b = dojo.body();
+			b.appendChild(this.domNode);
+
+			// make background (which sits behind the dialog but above the normal text)
+			this.bg = document.createElement("div");
+			this.bg.className = "dialogUnderlay";
+			with(this.bg.style){
+				position = "absolute";
+				left = top = "0px";
+				zIndex = 998;
+				display = "none";
+			}
+			b.appendChild(this.bg);
+			this.setBackgroundColor(this.bgColor);
+
+			this.bgIframe = new dijit.util.BackgroundIframe(this.domNode);
+            if(this.bgIframe.iframe){
+				with(this.bgIframe.iframe.style){
+					position = "absolute";
+					left = top = "0px";
+					zIndex = 90;
+					display = "none";
+				}
+			}
+
+			if(this.closeOnBackgroundClick){
+				this.connect(this.bg, "onclick", "onBackgroundClick");
+			}
+			this._modalconnects = [];
+			
+			if(this.titleBar){
+				this.titleBar.style.display = "block";
+				this.moveable = new dojo.dnd.Moveable(this.domNode, this.titleBar);
+			}
+		},
+
+		uninitialize: function(){
+			if(this.bgIframe){
+				this.bgIframe.remove();
+			}
+			if(this.bg && this.bg.parentNode){
+				this.bg.parentNode.removeChild(this.bg);
+			}
+		},
+
+		setBackgroundColor: function(/*String*/ color) {
+			// summary
+			//	changes background color specified by "bgColor" parameter
+			//	usage:
+			//		setBackgroundColor("black");
+			//		setBackgroundColor(0xff, 0xff, 0xff);
+			if(arguments.length >= 3) {
+				color = new dojo.Color(arguments[0], arguments[1], arguments[2]);
+			} else {
+				color = new dojo.Color(color);
+			}
+			this.bg.style.backgroundColor = color.toString();
+			return this.bgColor = color;	// String: the color
+		},
+
+		setBackgroundOpacity: function(/*Number*/ op) {
+			// summary
+			//	changes background opacity set by "bgOpacity" parameter
+			if(arguments.length == 0) { op = this.bgOpacity; }
+			dojo._setOpacity(this.bg, op);
+			try {
+				this.bgOpacity = dojo._getOpacity(this.bg);
+			} catch (e) {
+				this.bgOpacity = op;
+			}
+			return this.bgOpacity;	// Number: the opacity
+		},
+
+		_sizeBackground: function() {
+			if(this.bgOpacity > 0) {
+				
+				var viewport = dijit.util.getViewport();
+				var h = viewport.height;
+				var w = viewport.width;
+				with(this.bg.style){
+					width = w + "px";
+					height = h + "px";
+				}
+				var scroll_offset = dijit.util.getScroll().offset;
+				this.bg.style.top = scroll_offset.y + "px";
+				this.bg.style.left = scroll_offset.x + "px";
+				// process twice since the scroll bar may have been removed
+				// by the previous resizing
+				var viewport = dijit.util.getViewport();
+				if (viewport.width != w) { this.bg.style.width = viewport.width + "px"; }
+				if (viewport.height != h) { this.bg.style.height = viewport.height + "px"; }
+			}
+			this.bgIframe.size(this.bg);
+		},
+
+		_showBackground: function() {
+			if(this.bgOpacity > 0) {
+				this.bg.style.display = "block";
+			}
+			if(this.bgIframe.iframe){
+				this.bgIframe.iframe.style.display = "block";
+			}
+		},
+
+		placeModalDialog: function() {
+			// summary: position modal dialog in center of screen
+
+			var scroll_offset = dijit.util.getScroll().offset;
+			var viewport_size = dijit.util.getViewport();
+			
+			// find the size of the dialog (dialog needs to be showing to get the size)
+			var mb;
+			var padborder;
+			if(this.isShowing()){
+				mb = dojo.marginBox(this.domNode);
+				padborder = dojo._getPadBorderExtents(this.domNode);
+			}else{
+				dojo.style(this.domNode, "visibility", 'hidden');
+				dojo.style(this.domNode, 'display', 'block');;
+				mb = dojo.marginBox(this.domNode);
+				padborder = dojo._getPadBorderExtents(this.domNode);
+				dojo.style(this.domNode, 'display', 'none');;
+				dojo.style(this.domNode, "visibility", 'visible');
+			}
+			
+			var x = scroll_offset.x + (viewport_size.w - mb.w)/2;
+			var y = scroll_offset.y + (viewport_size.h - mb.h)/2;
+			var maxheight = viewport_size.h - padborder.h;
+
+			// dialogs can be too long or too short, try to adjust accordingly 
+			// we need to explicitly set the height on the containerNode so that 
+			// the overflow policy works correctly for the dialog - #757 and 2088 
+			if(viewport_size.h < mb.h){
+				this.containerNode.style.height = maxheight + "px";
+			} else if(this.containerNode.scrollHeight){
+				// if we've loaded dynamic content (e.g. through contentpane href)
+				// we might need to lengthen the dialog to adjust for the new content
+				var height = this.containerNode.scrollHeight + padborder.h;
+				if(height > mb.h && height < maxheight){
+					dojo.marginBox(this.domNode, { h: height});						
+				}					
+			}
+			with(this.domNode.style){
+				left = x + "px";
+				top = y + "px";
+			}
+		},
+
+		_onKey: function(/*Event*/ evt){
+			if (evt.keyCode){
+				// see if the key is for the dialog
+				var node = evt.target;
+				while (node != null){
+					if (node == this.domNode){
+						return; // yes, so just let it go
+					}
+					node = node.parentNode;
+				}
+				// this key is for the disabled document window
+				if (evt.keyCode != evt.KEY_TAB){ // allow tabbing into the dialog for a11y
+					dojo.stopEvent(evt);
+				// opera won't tab to a div
+				}else if (!dojo.isOpera){
+					try {
+						this.tabStart.focus(); 
+					} catch(e){}
+				}
+			}
+		},
+
+		showModalDialog: function() {
+			// summary
+			//	call this function in show() of subclass before calling superclass.show()
+
+			// first time we show the dialog, there's some initialization stuff to do			
+			if(!this._alreadyInitialized){
+				this._setup();
+				this._alreadyInitialized=true;
+			}
+				
+			if (this.followScroll && !this._scrollConnected){
+				this._scrollConnected = true;
+				this._modalconnects.push(dojo.connect(window, "onscroll", this._onScroll));
+			}
+			this._modalconnects.push(dojo.connect(document.documentElement, "onkeypress", this._onKey));
+
+			this.placeModalDialog();
+			this.setBackgroundOpacity();
+			this._sizeBackground();
+			this._showBackground();
+			this._fromTrap = true; 
+
+			// set timeout to allow the browser to render dialog 
+			setTimeout(dojo.hitch(this, function(){
+				try{
+					this.tabStart.focus();
+				}catch(e){}
+			}), 50);
+
+		},
+
+		hideModalDialog: function(){
+			// summary
+			//	call this function in hide() of subclass
+
+			// if we haven't been initialized yet then we aren't showing and we can just return		
+			if(!this._alreadyInitialized){
+				return;
+			}
+
+			// workaround for FF focus going into outer space
+			if (this.focusElement) {
+				dojo.byId(this.focusElement).focus(); 
+				dojo.byId(this.focusElement).blur();
+			}
+
+			this.bg.style.display = "none";
+			this.bg.style.width = this.bg.style.height = "1px";
+            if(this.bgIframe.iframe){
+				this.bgIframe.iframe.style.display = "none";
+			}
+
+			if (this._scrollConnected){
+				this._scrollConnected = false;
+			}
+			dojo.forEach(this._modalconnects, dojo.disconnect);
+			this._modalconnects = [];
+			
+		},
+
+		_onScroll: function(){
+			var scroll_offset = dijit.util.getScroll().offset;
+			this.bg.style.top = scroll_offset.y + "px";
+			this.bg.style.left = scroll_offset.x + "px";
+			this.placeModalDialog();
+		},
+
+		checkSize: function() {
+			if(this.isShowing()){
+				this._sizeBackground();
+				this.placeModalDialog();
+				this.onResized();
+			}
+		},
+		
+		onBackgroundClick: function(){
+			// summary
+			//		Callback on background click, if closeOnBackgroundClick==true.
+			if(this.lifetime - this.timeRemaining >= this.blockDuration){ return; }
+			this.hide();
+		}
+	});
+
+dojo.declare(
+	"dijit.layout.Dialog",
+	[dijit.layout.ContentPane, dijit.base.TemplatedWidget, dijit.layout.ModalDialogBase],
+	{
+		// summary
+		//	Pops up a modal dialog window, blocking access to the screen and also graying out the screen
+		//	Dialog is extended from ContentPane so it supports all the same parameters (href, etc.)
+
+		templateString:"<div class=\"dijitDialog\" dojoattachpoint=\"wrapper\">\n\t<span dojoattachpoint=\"tabStartOuter\" dojoonfocus=\"trapTabs\" dojoonblur=\"clearTrap\"\ttabindex=\"0\"></span>\n\t<span dojoattachpoint=\"tabStart\" dojoonfocus=\"trapTabs\" dojoonblur=\"clearTrap\" tabindex=\"0\"></span>\n\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\" style=\"display:none\">\n\t\t<span dojoAttachPoint=\"labelNode\" class=\"dijitDialogLabel\">${label}</span><span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\"></span>\n\t</div>\n\t<div dojoattachpoint=\"containerNode\" style=\"z-index: 2; overflow: auto;\" class=\"dijitDialogContent\"></div>\n\t<span dojoattachpoint=\"tabEnd\" dojoonfocus=\"trapTabs\" dojoonblur=\"clearTrap\" tabindex=\"0\"></span>\n\t<span dojoattachpoint=\"tabEndOuter\" dojoonfocus=\"trapTabs\" dojoonblur=\"clearTrap\" tabindex=\"0\"></span>\n</div>\n",
+
+		// label: String
+		//		Title of the dialog
+		label: "",
+		
+		// blockDuration: Integer
+		//	number of seconds for which the user cannot dismiss the dialog
+		blockDuration: 0,
+		
+		// lifetime: Integer
+		//	if set, this controls the number of seconds the dialog will be displayed before automatically disappearing
+		lifetime: 0,
+
+		// closeNode: String
+		//	Id of button or other dom node to click to close this dialog
+		closeNode: "",
+		
+		// closeButton: Boolean
+		//	Whether or not to display a standard button to close this dialog
+		closeButton: true,
+
+		postCreate: function(){
+			// hide the dialog so it doesnt show up, and also to defer processing of dialog contents
+			// (or href attribute) until the dialog is shown)
+			this.domNode.style.display="none";
+			dijit.layout.Dialog.superclass.postCreate.apply(this, arguments);
+		},
+
+		show: function() {
+		    // deal with the default close button
+			this.closeButtonNode.style.display = this.closeButton ? "inline" : "none";
+			if(this.closeButton){
+				this.connect(this.closeButtonNode, "onclick", "hide");
+			}
+			// handle the custom close node if any
+			if(this.closeNode){
+				this.setCloseControl(this.closeNode);
+			}
+			if(this.lifetime){
+				this.timeRemaining = this.lifetime;
+				if(this.timerNode){
+					this.timerNode.innerHTML = Math.ceil(this.timeRemaining/1000);
+				}
+				if(this.blockDuration && this.closeNode){
+					if(this.lifetime > this.blockDuration){
+						this.closeNode.style.visibility = "hidden";
+					}else{
+						this.closeNode.style.display = "none";
+					}
+				}
+				if (this.timer) {
+					clearInterval(this.timer);
+				}
+				this.timer = setInterval(dojo.lang.hitch(this, "_onTick"), 100);
+			}
+
+			this.showModalDialog();
+			dijit.layout.Dialog.superclass.show.call(this);
+		},
+
+		onLoad: function(){
+			// when href is specified we need to reposition
+			// the dialog after the data is loaded
+			this.placeModalDialog();
+			dijit.layout.Dialog.superclass.onLoad.call(this);
+		},
+		
+		hide: function(){
+			this.hideModalDialog();
+			dijit.layout.Dialog.superclass.hide.call(this);
+
+			if(this.timer){
+				clearInterval(this.timer);
+			}
+		},
+		
+		setTimerNode: function(node){
+			// summary
+			//	specify into which node to write the remaining # of seconds
+			// TODO: make this a parameter too
+			this.timerNode = node;
+		},
+
+		setCloseControl: function(/*String|DomNode*/ node) {
+			// summary
+			//	Specify which node is the close button for this dialog.
+			this.closeNode = dojo.byId(node);
+			this.connect(this.closeNode, "onclick", "hide");
+		},
+
+		setShowControl: function(/*String|DomNode*/ node) {
+			// summary
+			//	when specified node is clicked, show this dialog
+			// TODO: make this a parameter too
+			node = dojo.byId(node);
+			this.connect(node, "onclick", "show");
+		},
+
+		_onTick: function(){
+			// summary
+			//	callback every second that the timer clicks
+			if(this.timer){
+				this.timeRemaining -= 100;
+				if(this.lifetime - this.timeRemaining >= this.blockDuration){
+					// TODO: this block of code is executing over and over again, rather than just once
+					if(this.closeNode){
+						this.closeNode.style.visibility = "visible";
+					}
+				}
+				if(!this.timeRemaining){
+					clearInterval(this.timer);
+					this.hide();
+				}else if(this.timerNode){
+					this.timerNode.innerHTML = Math.ceil(this.timeRemaining/1000);
+				}
+			}
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dijit/layout/LayoutContainer.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/layout/LayoutContainer.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/layout/LayoutContainer.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,86 @@
+dojo.provide("dijit.layout.LayoutContainer");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.Showable");
+dojo.require("dijit.base.Layout");
+
+dojo.declare(
+	"dijit.layout.LayoutContainer",
+	[dijit.base.Widget, dijit.base.Layout, dijit.base.Showable],
+{
+	// summary
+	//	Provides Delphi-style panel layout semantics.
+	//
+	// details
+	//	A LayoutContainer is a box with a specified size (like style="width: 500px; height: 500px;"),
+	//	that contains children widgets marked with "layoutAlign" of "left", "right", "bottom", "top", and "client".
+	//	It takes it's children marked as left/top/bottom/right, and lays them out along the edges of the box,
+	//	and then it takes the child marked "client" and puts it into the remaining space in the middle.
+	//
+	//  Left/right positioning is similar to CSS's "float: left" and "float: right",
+	//	and top/bottom positioning would be similar to "float: top" and "float: bottom", if there were such
+	//	CSS.
+	//
+	//	Note that there can only be one client element, but there can be multiple left, right, top,
+	//	or bottom elements.
+	//
+	// usage
+	//	<style>
+	//		html, body{ height: 100%; width: 100%; }
+	//	</style>
+	//	<div dojoType="LayoutContainer" style="width: 100%; height: 100%">
+	//		<div dojoType="ContentPane" layoutAlign="top">header text</div>
+	//		<div dojoType="ContentPane" layoutAlign="left" style="width: 200px;">table of contents</div>
+	//		<div dojoType="ContentPane" layoutAlign="client">client area</div>
+	//	</div>
+
+	// layoutChildPriority: String
+	//	- If the value is "top-bottom", then LayoutContainer will first position the "top" and "bottom" aligned elements,
+	//	to and then put the left and right aligned elements in the remaining space, between the top and the bottom elements.
+	//	It aligns the client element at the very end, in the remaining space.
+	//
+	//	- If the value is "left-right", then it first positions the "left" and "right" elements, and then puts the
+	//	"top" and "bottom" elements in the remaining space, between the left and the right elements.
+	//	It aligns the client element at the very end, in the remaining space.
+	//
+	//	- If the value is "none", then it will lay out each child in the natural order the children occur in.
+	//	Basically each child is laid out into the "remaining space", where "remaining space" is initially
+	//	the content area of this widget, but is reduced to a smaller rectangle each time a child is added.
+	//	
+	layoutChildPriority: 'top-bottom',
+
+	layout: function(){
+		var ok = dijit.base.Layout.layoutChildren(this.domNode, this._contentBox, this.getChildren(), this.layoutChildPriority);
+	},
+
+	addChild: function(child, overrideContainerNode, pos, ref, insertIndex){
+		dijit.base.Container.prototype.addChild.apply(this, arguments);
+		dijit.base.Layout.layoutChildren(this.domNode, this._contentBox, this.getChildren(), this.layoutChildPriority);
+	},
+
+	removeChild: function(pane){
+        dijit.base.Container.prototype.removeChild.apply(this, arguments);
+		dijit.base.Layout.layoutChildren(this.domNode, this._contentBox, this.getChildren(), this.layoutChildPriority);
+	},
+
+	show: function(){
+		// If this node was created while display=="none" then it
+		// hasn't been laid out yet.  Do that now.
+		this.domNode.style.display="";
+		this.checkSize();
+		this.domNode.style.display="none";
+		this.domNode.style.visibility="";
+
+		dijit.base.Showable.prototype.show.apply(this, arguments);
+	}
+});
+
+// This argument can be specified for the children of a LayoutContainer.
+// Since any widget can be specified as a LayoutContainer child, mix it
+// into the base widget class.  (This is a hack, but it's effective.)
+dojo.extend(dijit.base.Widget, {
+	// layoutAlign: String
+	//		"none", "left", "right", "bottom", "top", and "client".
+	//		See the LayoutContainer description for details on this parameter.
+	layoutAlign: 'none'
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/layout/LinkPane.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/layout/LinkPane.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/layout/LinkPane.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,30 @@
+dojo.provide("dijit.layout.LinkPane");
+
+dojo.require("dijit.layout.ContentPane");
+dojo.require("dijit.base.TemplatedWidget");
+
+dojo.declare("dijit.layout.LinkPane", 
+	[dijit.layout.ContentPane, dijit.base.TemplatedWidget],
+{
+	// summary
+	//	LinkPane is just a ContentPane that loads data remotely (via the href attribute),
+	//	and has markup similar to an anchor.  The anchor's body (the words between <a> and </a>)
+	//	become the label of the widget (used for TabContainer, AccordionContainer, etc.)
+	// usage
+	//	<a href="foo.html">my label</a>
+
+	// I'm using a template because the user may specify the input as
+	// <a href="foo.html">label</a>, in which case we need to get rid of the
+	// <a> because we don't want a link.
+	templateString: '<div class="dijitLinkPane"></div>',
+
+	postCreate: function(){
+		
+		// If user has specified node contents, they become the label
+		// (the link must be plain text)
+		this.label += this.domNode.innerHTML;
+		
+		dijit.layout.LinkPane.superclass.postCreate.apply(this, arguments);
+
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/layout/PageContainer.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/layout/PageContainer.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/layout/PageContainer.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,426 @@
+dojo.provide("dijit.layout.PageContainer");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.TemplatedWidget");
+dojo.require("dijit.base.Layout");
+dojo.require("dijit.base.Showable");
+
+dojo.declare(
+	"dijit.layout.PageContainer",
+	[dijit.base.Widget, dijit.base.TemplatedWidget, dijit.base.Layout],
+	// summary
+	//	A container that has multiple children, but shows only
+	//	one child at a time (like looking at the pages in a book one by one).
+	//
+	//	Publishes topics <widgetId>-addChild, <widgetId>-removeChild, and <widgetId>-selectChild
+	//
+	//	Can be base class for container, Wizard, Show, etc.
+{
+	// doLayout: Boolean
+	//  if true, change the size of my currently displayed child to match my size
+	doLayout: true,
+
+	templateString: "<div dojoAttachPoint='containerNode'></div>",
+
+	// selectedChild: String
+	//   id of the currently shown page
+	selectedChild: "",
+
+	startup: function(){
+		var children = this.getChildren();
+
+		// Setup each page panel
+		dojo.forEach(children, this._setupChild, this);
+
+		// Figure out which child to initially display
+		var idx = dojo.indexOf(children, function(child){ return child.selected; });
+		if(idx == -1){ idx=0; }
+		this.selectedChildWidget = children[idx];
+		this.selectedChildWidget.show();
+		
+		// Now publish information about myself so any PageControllers can initialize..
+		dojo.publish(this.id+"-startup", [{children: children, selected: this.selectedChildWidget}]);
+
+		dijit.base.Layout.prototype.startup.apply(this, arguments);
+	},
+
+	addChild: function(/*Widget*/ child, /*Integer*/ insertIndex){
+		dijit.base.Container.prototype.addChild.apply(this, arguments);
+		this._setupChild(child);
+
+		// in case the tab labels have overflowed from one line to two lines
+		this.layout();
+
+		// if this is the first child, then select it
+		if(!this.selectedChildWidget){
+			this.selectChild(child);
+		}
+		dojo.publish(this.id+"-addChild", [child]);
+	},
+
+	_setupChild: function(/*Widget*/ page){
+		// Summary: prepare the given child
+		page.hide();
+		
+		// since we are setting the width/height of the child elements, they need
+		// to be position:relative, or IE has problems (See bug #2033)
+		page.domNode.style.position="relative";
+	},
+
+	removeChild: function(/*Widget*/ page){
+		
+		dijit.base.Container.prototype.removeChild.apply(this, arguments);
+
+		// If we are being destroyed than don't run the code below (to select another page), because we are deleting
+		// every page one by one
+		if(this._beingDestroyed){ return; }
+
+		// this will notify any tablists to remove a button; do this first because it may affect sizing
+		dojo.publish(this.id+"-removeChild", [page]);
+
+		// in case the tab labels now take up one line instead of two lines
+		this.layout();
+
+		if(this.selectedChildWidget === page){
+			this.selectedChildWidget = undefined;
+			var children = this.getChildren();
+			if(children.length){
+				this.selectChild(children[0]);
+			}
+		}
+	},
+
+	selectChild: function(/*Widget*/ page){
+		// summary
+		//	Show the given widget (which must be one of my children)
+		
+		if(!page){ return; }
+		
+		// allow indexing by widget id
+		if(page && ((typeof page == "string")||(page instanceof String))){
+			page = dijit.byId(page);
+		}
+
+		// Deselect old page and select new one
+		if(this.selectedChildWidget){
+			this._hideChild(this.selectedChildWidget);
+		}
+		this.selectedChildWidget = page;
+		this.selectedChild = page.id;
+		this._showChild(page);
+		dojo.publish(this.id+"-selectChild", [page]);
+	},
+
+	forward: function(){
+		// Summary: advance to next page
+		var index = dojo.indexOf(this.getChildren(), this.selectedChildWidget);
+		this.selectChild(this.getChildren()[index+1]);
+	},
+
+	back: function(){
+		// Summary: go back to previous page
+		var index = dojo.indexOf(this.getChildren(), this.selectedChildWidget);
+		this.selectChild(this.getChildren()[index-1]);
+	},
+
+	layout: function(){
+		// Summary: called when any page is shown, to make it fit the container correctly
+		if(this.doLayout && this.selectedChildWidget && this.selectedChildWidget.resize){
+			this.selectedChildWidget.resize(this._contentBox);
+		}
+	},
+
+	_showChild: function(/*Widget*/ page){
+		// size the current page (in case this is the first time it's being shown, or I have been resized)
+		if(this.doLayout && page.resize){
+			page.resize(this._containerContentBox || this._contentBox);
+		}
+
+		page.selected=true;
+		if(page.show){
+			page.show();
+		}
+		var children = this.getChildren();
+		page.isFirstChild = (page == children[0]);
+		page.isLastChild = (page == children[children.length-1]);
+	},
+
+	_hideChild: function(/*Widget*/ page){
+		page.selected=false;
+		if(page.hide){
+			page.hide();
+		}
+	},
+
+	closeChild: function(/*Widget*/ page){
+		// summary
+		//	callback when user clicks the [X] to remove a page
+		//	if onClose() returns true then remove and destroy the childd
+		var remove = page.onClose(this, page);
+		if(remove){
+			this.removeChild(page);
+			// makes sure we can clean up executeScripts in ContentPane onUnLoad
+			page.destroy();
+		}
+	},
+
+	destroy: function(){
+		this._beingDestroyed = true;
+		dijit.layout.PageContainer.superclass.destroy.apply(this, arguments);
+	}
+});
+
+
+dojo.declare(
+	"dijit.layout.PageController",
+	[dijit.base.Widget, dijit.base.TemplatedWidget, dijit.base.Container ],
+	{
+		// summary
+		//	Set of buttons to select a page in a page list.
+		//	Monitors the specified PageContainer, and whenever a page is
+		//	added, deleted, or selected, updates itself accordingly.
+
+		templateString: "<span wairole='tablist' dojoAttachEvent='onkeypress' class='dojoPageController'></span>",
+
+		// containerId: String
+		//	the id of the page container that I point to
+		containerId: "",
+
+		// buttonWidget: String
+		//	the name of the button widget to create to correspond to each page
+		buttonWidget: "dijit.layout.PageButton",
+
+		// class: String
+		//	Class name to apply to the top dom node
+		"class": "dijitPageController",
+		
+		postCreate: function(){
+			dijit.util.wai.setAttr(this.domNode, "waiRole", "role", "tablist");
+
+			this.pane2button = {};		// mapping from panes to buttons
+			this._subscriptions=[
+				{topic: this.containerId+"-startup", handle: dojo.subscribe(this.containerId+"-startup", this, "onStartup")},
+				{topic: this.containerId+"-addChild", handle: dojo.subscribe(this.containerId+"-addChild", this, "onAddChild")},
+				{topic: this.containerId+"-removeChild", handle: dojo.subscribe(this.containerId+"-removeChild", this, "onRemoveChild")},
+				{topic: this.containerId+"-selectChild", handle: dojo.subscribe(this.containerId+"-selectChild", this, "onSelectChild")}
+			];
+		},
+
+		onStartup: function(/*Object*/ info){
+			// summary: called after PageContainer has finished initializing
+			dojo.forEach(info.children, this.onAddChild, this);
+			this.onSelectChild(info.selected);
+		},
+
+		destroy: function(){
+			dojo.forEach(this._subscriptions, function(sub){ dojo.unsubscribe(sub.topic, sub.handle); });
+			dijit.layout.PageController.superclass.destroy.apply(this, arguments);
+		},
+
+		onAddChild: function(/*Widget*/ page){
+			// summary
+			//   Called whenever a page is added to the container.
+			//   Create button corresponding to the page.
+			
+			// add a node that will be promoted to the button widget
+			var refNode = document.createElement("span");
+			this.domNode.appendChild(refNode);
+			// create an instance of the button widget
+			var cls = dojo.getObject(this.buttonWidget);
+			var button = new cls({label: page.label, closeButton: page.closable}, refNode);
+			this.addChild(button);
+			this.pane2button[page]=button;
+			page.controlButton = button;	// this value might be overwritten if two tabs point to same container
+
+			var _this = this;
+			dojo.connect(button, "onClick", function(){ _this.onButtonClick(page); });
+			dojo.connect(button, "onCloseButtonClick", function(){ _this.onCloseButtonClick(page); });
+		},
+
+		onRemoveChild: function(/*Widget*/ page){
+			// summary
+			//   Called whenever a page is removed from the container.
+			//   Remove the button corresponding to the page.
+			if(this._currentChild == page){ this._currentChild = null; }
+			var button = this.pane2button[page];
+			if(button){
+				button.destroy();
+			}
+			this.pane2button[page] = null;
+		},
+
+		onSelectChild: function(/*Widget*/ page){
+			// Summary
+			//	Called when a page has been selected in the PageContainer, either by me or by another PageController
+			if(!page){ return; }
+			
+			if(this._currentChild){
+				var oldButton=this.pane2button[this._currentChild];
+				oldButton.clearSelected();
+			}
+			
+			var newButton=this.pane2button[page];
+			newButton.setSelected();
+			this._currentChild=page;
+		},
+
+		onButtonClick: function(/*Widget*/ page){
+			// summary
+			//   Called whenever one of my child buttons is pressed in an attempt to select a page
+			var container = dijit.byId(this.containerId);	// TODO: do this via topics?
+			container.selectChild(page);
+		},
+
+		onCloseButtonClick: function(/*Widget*/ page){
+			// summary
+			//   Called whenever one of my child buttons [X] is pressed in an attempt to close a page
+			var container = dijit.byId(this.containerId);
+			container.closeChild(page);
+		},
+
+		onkeypress: function(/*Event*/ evt){
+			// summary:
+			//   Handle keystrokes on the page list, for advancing to next/previous button
+
+			if( (evt.keyCode == dojo.keys.RIGHT_ARROW)||
+				(evt.keyCode == dojo.keys.LEFT_ARROW) ){
+				var current = 0;
+				var next = null;	// the next button to focus on
+				var children = this.getChildren();
+				// find currently focused button in children array
+				var current = dojo.indexOf(children, this.pane2button[this._currentChild]);
+				
+				// pick next button to focus on
+				if(evt.keyCode == dojo.keys.RIGHT_ARROW){
+					next = children[ (current+1) % children.length ]; 
+				}else{ // is LEFT_ARROW
+					next = children[ (current+ (children.length-1)) % children.length ];
+				}
+				
+				dojo.stopEvent(evt);
+				next.onClick();
+			}
+		}
+	}
+);
+
+dojo.declare(
+	"dijit.layout.PageButton",
+	[dijit.base.Widget, dijit.base.TemplatedWidget, dijit.base.Contained],
+{
+	// summary
+	//	Internal widget used by PageList.
+	//	The button-like or tab-like object you click to select or delete a page
+
+	templateString: "<span class='item'>" +
+						"<span dojoAttachEvent='onclick:onClick' dojoAttachPoint='titleNode' class='selectButton'>${label}</span>" +
+						"<span dojoAttachEvent='onclick:onCloseButtonClick' class='closeButton'>[X]</span>" +
+					"</span>",
+
+	// label: String
+	//  Name to print on the button
+	label: "foo",
+	
+	// closeButton: Boolean
+	//	true iff we should also print a close icon to destroy corresponding page
+	closeButton: false,
+	
+	// selectedClass: String
+	//  name of the CSS class to apply to this button when the corresponding page has been selected
+	//	override in a subclass to make it easier to style
+	selectedClass : "current",
+
+
+	// hoverClass: String
+	//  name of the CSS class to apply to this button when the cursor is over it
+	//	override in a subclass to make it easier to style
+	hoverClass : "hover",
+
+	// closeHoverClass: String
+	//  name of the CSS class to apply to the close button when the cursor is over it
+	//	override in a subclass to make it easier to style
+	closeHoverClass : "hover",
+
+
+	onClick: function(){
+		// summary
+		//  Basically this is the attach point PageController listens to, to select the page
+		this.focus();
+	},
+
+	onMouseOver: function(){
+		// summary
+		//	Mouse over the entire button
+		dojo.addClass(this.domNode, this.hoverClass);
+	},
+
+	onMouseOut: function(){
+		// summary
+		// 	Mouse out from the entire button
+		dojo.removeClass(this.domNode, this.hoverClass);
+	},
+
+	onCloseButtonMouseOver: function(){
+		// summary
+		//	The close button changes color a bit when you mouse over	
+		dojo.addClass(this.closeButtonNode, this.closeHoverClass);
+	},
+
+	onCloseButtonMouseOut: function(){
+		// summary
+		// 	Revert close button to normal color on mouse out
+		dojo.removeClass(this.closeButtonNode, this.closeHoverClass);
+	},
+
+	onCloseButtonClick: function(/*Event*/ evt){
+		// summary
+		//	Handle clicking the close button for this tab
+	},
+	
+	setSelected: function(){
+		// summary
+		//	This is run whenever the page corresponding to this button has been selected
+		dojo.addClass(this.domNode, this.selectedClass);
+		this.titleNode.setAttribute("tabIndex","0");
+	},
+	
+	clearSelected: function(){
+		// summary
+		//	This function is run whenever the page corresponding to this button has been deselected (and another page has been shown)
+		dojo.removeClass(this.domNode, this.selectedClass);
+		this.titleNode.setAttribute("tabIndex","-1");
+	},
+
+	focus: function(){
+		// summary
+		//	This will focus on the this button (for accessibility you need to do this when the button is selected)
+		if(this.titleNode.focus){	// mozilla 1.7 doesn't have focus() func
+			this.titleNode.focus();
+		}
+	}
+});
+
+// These arguments can be specified for the children of a PageContainer.
+// Since any widget can be specified as a PageContainer child, mix them
+// into the base widget class.  (This is a hack, but it's effective.)
+dojo.extend(dijit.base.Widget, {
+	// label: String
+	//		Label or title of this widget.  Used by TabContainer to the name the tab, etc.
+	label: "",
+	
+	// selected: Boolean
+	//		Is this child currently selected?
+	selected: false,
+	
+	// closable: Boolean
+	//		True if user can close (destroy) this child, such as (for example) clicking the X on the tab.
+	closable: false,	// true if user can close this tab pane
+	
+	onClose: function(){
+		// summary: Callback if someone tries to close the child, child will be closed if func returns true
+		return true;
+	}
+});
+
+
+

Added: trunk/examples/typeface/root/static/dojo/dijit/layout/SplitContainer.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/layout/SplitContainer.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/layout/SplitContainer.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,552 @@
+dojo.provide("dijit.layout.SplitContainer");
+
+//
+// TODO
+// make it prettier
+// active dragging upwards doesn't always shift other bars (direction calculation is wrong in this case)
+//
+
+dojo.require("dojo.cookie");
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.Showable");
+dojo.require("dijit.base.Layout");
+
+dojo.declare(
+	"dijit.layout.SplitContainer",
+	[dijit.base.Widget, dijit.base.Layout, dijit.base.Showable],
+{
+	// summary
+	//		Contains multiple children widgets, all of which are displayed side by side
+	//		(either horizontally or vertically); there's a bar between each of the children,
+	//		and you can adjust the relative size of each child by dragging the bars.
+	//
+	//		You must specify a size (width and height) for the SplitContainer.
+
+	// activeSizing: Boolean
+	//		If true, the children's size changes as you drag the bar;
+	//		otherwise, the sizes don't change until you drop the bar (by mouse-up)
+	activeSizing: false,
+	
+	// sizerWidget: Integer
+	//		Size in pixels of the bar between each child
+	sizerWidth: 15,
+	
+	// orientation: String
+	//		either 'horizontal' or vertical; indicates whether the children are
+	//		arranged side-by-side or up/down.
+	orientation: 'horizontal',
+	
+	// persist: Boolean
+	//		Save splitter positions in a cookie
+	persist: true,
+
+	postMixInProperties: function(){
+		dijit.layout.SplitContainer.superclass.postMixInProperties.apply(this, arguments);
+		this.isHorizontal = (this.orientation == 'horizontal');
+	},
+	
+	postCreate: function(){
+		dijit.layout.SplitContainer.superclass.postCreate.apply(this, arguments);
+		this.sizers = [];
+		dojo.addClass(this.domNode, "dijitSplitContainer");
+		// overflow has to be explicitly hidden for splitContainers using gekko (trac #1435)
+		// to keep other combined css classes from inadvertantly making the overflow visible
+		if(dojo.isMozilla){
+			this.domNode.style.overflow = '-moz-scrollbars-none'; // hidden doesn't work
+		}
+
+		var content = dojo.contentBox(this.domNode);
+		
+		this.paneWidth = content.w;
+		this.paneHeight = content.h;
+		// create the fake dragger
+		if(typeof this.sizerWidth == "object"){ 
+			try{
+				this.sizerWidth = parseInt(this.sizerWidth.toString()); 
+			}catch(e){ this.sizerWidth = 15; }
+		}
+		this.virtualSizer = document.createElement('div');
+		this.virtualSizer.style.position = 'relative';
+
+		// #1681: work around the dreaded 'quirky percentages in IE' layout bug
+		// If the splitcontainer's dimensions are specified in percentages, it
+		// will be resized when the virtualsizer is displayed in _showSizingLine
+		// (typically expanding its bounds unnecessarily). This happens because
+		// we use position: relative for .dijitSplitContainer.
+		// The workaround: instead of changing the display style attribute,
+		// switch to changing the zIndex (bring to front/move to back)
+
+		this.virtualSizer.style.zIndex = 10;
+		this.virtualSizer.className = this.isHorizontal ? 'dijitSplitContainerVirtualSizerH' : 'dijitSplitContainerVirtualSizerV';
+		this.domNode.appendChild(this.virtualSizer);
+		dijit._disableSelection(this.virtualSizer);
+
+	},
+	
+	startup: function(){
+		var children = this.getChildren();
+		// attach the children and create the draggers
+		for(var i = 0; i < children.length; i++){
+			with(children[i].domNode.style){
+				position = "absolute";
+			}
+			dojo.addClass(children[i].domNode, "dijitSplitPane");
+
+			if(i == children.length-1){
+				break;
+			}
+			this._addSizer();
+		}
+
+		if(this.persist){
+			this._restoreState();
+		}
+		dijit.base.Layout.prototype.startup.apply(this, arguments);
+	},
+
+	_injectChild: function(child){
+		with(child.domNode.style){
+			position = "absolute";
+		}
+		dojo.addClass(child.domNode, "dijitSplitPane");
+	},
+
+	_addSizer: function(){
+		var i = this.sizers.length;
+
+		// TODO: use a template for this!!!
+		var sizer = this.sizers[i] = document.createElement('div');
+		sizer.className = this.isHorizontal ? 'dijitSplitContainerSizerH' : 'dijitSplitContainerSizerV';
+
+		// add the thumb div
+		var thumb = document.createElement('div');
+		thumb.className = 'thumb';
+		sizer.appendChild(thumb);
+
+		var self = this;
+		var handler = (function(){ var sizer_i = i; return function(e){ self.beginSizing(e, sizer_i); } })();
+		dojo.connect(sizer, "onmousedown", handler);
+
+		this.domNode.appendChild(sizer);
+		dijit._disableSelection(sizer);
+	},
+
+	removeChild: function(widget){
+		// Remove sizer, but only if widget is really our child and
+		// we have at least one sizer to throw away
+		if(this.sizers.length > 0){
+			var children = this.getChildren();
+			for(var x = 0; x < children.length; x++){
+				if(children[x] === widget){
+					var i = this.sizers.length - 1;
+					this.domNode.removeChild(this.sizers[i]);
+					this.sizers.length = i;
+					break;
+				}
+			}
+		}
+
+		// Remove widget and repaint
+		dijit.base.Container.prototype.removeChild.apply(this, arguments);
+		this.layout();
+   },
+
+	addChild: function(child, insertIndex){
+		dijit.base.Container.prototype.addChild.apply(this, arguments);
+		this._injectChild(child);
+		
+		var children = this.getChildren();
+		if(children.length > 1){
+			this._addSizer();
+		}
+		this.layout();
+	},
+
+	layout: function(){
+		// summary:
+		//		Do layout of panels
+
+		// base class defines this._contentBox on initial creation and also
+		// on resize
+		this.paneWidth = this._contentBox.w;
+		this.paneHeight = this._contentBox.h;
+
+		var children = this.getChildren();
+		if(children.length == 0){ return; }
+
+		//
+		// calculate space
+		//
+
+		var space = this.isHorizontal ? this.paneWidth : this.paneHeight;
+		if(children.length > 1){
+			space -= this.sizerWidth * (children.length - 1);
+		}
+
+		//
+		// calculate total of SizeShare values
+		//
+		var out_of = 0;
+		for(var i=0; i<children.length; i++){
+			out_of += children[i].sizeShare;
+		}
+
+		//
+		// work out actual pixels per sizeshare unit
+		//
+		var pix_per_unit = space / out_of;
+
+
+		//
+		// set the SizeActual member of each pane
+		//
+		var total_size = 0;
+		for(var i = 0; i< children.length-1; i++){
+			var size = Math.round(pix_per_unit * children[i].sizeShare);
+			children[i].sizeActual = size;
+			total_size += size;
+		}
+		children[children.length-1].sizeActual = space - total_size;
+
+		//
+		// make sure the sizes are ok
+		//
+		this._checkSizes();
+
+		//
+		// now loop, positioning each pane and letting children resize themselves
+		//
+
+		var pos = 0;
+		var size = children[0].sizeActual;
+		this._movePanel(children[0], pos, size);
+		children[0].position = pos;
+		pos += size;
+
+		// if we don't have any sizers, our layout method hasn't been called yet
+		// so bail until we are called..TODO: REVISIT: need to change the startup
+		// algorithm to guaranteed the ordering of calls to layout method
+		if(!this.sizers)
+			return;
+		
+		for(var i=1; i<children.length; i++){
+			// error-checking
+			if(!this.sizers[i-1])
+				break;
+			// first we position the sizing handle before this pane
+			this._moveSlider(this.sizers[i-1], pos, this.sizerWidth);
+			this.sizers[i-1].position = pos;
+			pos += this.sizerWidth;
+
+			size = children[i].sizeActual;
+			this._movePanel(children[i], pos, size);
+			children[i].position = pos;
+			pos += size;
+		}
+	},
+
+	_movePanel: function(panel, pos, size){
+		if(this.isHorizontal){
+			panel.domNode.style.left = pos + 'px';
+			panel.domNode.style.top = 0;
+			var box = {w: size, h: this.paneHeight};
+			if(panel.resize){
+				panel.resize(box);
+			}else{
+				dojo.marginBox(panel.domNode, box);
+			}
+		}else{
+			panel.domNode.style.left = 0;
+			panel.domNode.style.top = pos + 'px';
+			var box = {w: this.paneWidth, h: size}; 
+			if(panel.resize){
+				panel.resize(box);
+			}else{
+				dojo.marginBox(panel.domNode, box);
+			}
+		}
+	},
+
+	_moveSlider: function(slider, pos, size){
+		if(this.isHorizontal){
+			slider.style.left = pos + 'px';
+			slider.style.top = 0;
+			dojo.marginBox(slider, { w: size, h: this.paneHeight });
+		}else{
+			slider.style.left = 0;
+			slider.style.top = pos + 'px';
+			dojo.marginBox(slider, { w: this.paneWidth, h: size });
+		}
+	},
+
+	_growPane: function(growth, pane){
+		if(growth > 0){
+			if(pane.sizeActual > pane.sizeMin){
+				if((pane.sizeActual - pane.sizeMin) > growth){
+
+					// stick all the growth in this pane
+					pane.sizeActual = pane.sizeActual - growth;
+					growth = 0;
+				}else{
+					// put as much growth in here as we can
+					growth -= pane.sizeActual - pane.sizeMin;
+					pane.sizeActual = pane.sizeMin;
+				}
+			}
+		}
+		return growth;
+	},
+
+	_checkSizes: function(){
+
+		var total_min_size = 0;
+		var total_size = 0;
+		var children = this.getChildren();
+
+		for(var i=0; i<children.length; i++){
+			total_size += children[i].sizeActual;
+			total_min_size += children[i].sizeMin;
+		}
+
+		// only make adjustments if we have enough space for all the minimums
+
+		if(total_min_size <= total_size){
+
+			var growth = 0;
+
+			for(var i=0; i<children.length; i++){
+
+				if(children[i].sizeActual < children[i].sizeMin){
+
+					growth += children[i].sizeMin - children[i].sizeActual;
+					children[i].sizeActual = children[i].sizeMin;
+				}
+			}
+
+			if(growth > 0){
+				if(this.isDraggingLeft){
+					for(var i=children.length-1; i>=0; i--){
+						growth = this._growPane(growth, children[i]);
+					}
+				}else{
+					for(var i=0; i<children.length; i++){
+						growth = this._growPane(growth, children[i]);
+					}
+				}
+			}
+		}else{
+
+			for(var i=0; i<children.length; i++){
+				children[i].sizeActual = Math.round(total_size * (children[i].sizeMin / total_min_size));
+			}
+		}
+	},
+
+	beginSizing: function(e, i){
+		var children = this.getChildren();
+		this.paneBefore = children[i];
+		this.paneAfter = children[i+1];
+
+		this.isSizing = true;
+		this.sizingSplitter = this.sizers[i];
+
+		if(!this.cover){
+			this.cover = dojo.doc.createElement('div');
+			this.domNode.appendChild(this.cover);
+			var s = this.cover.style;
+			s.position='absolute';
+			s.zIndex=1;
+			s.top=0;
+			s.left=0;
+			s.width="100%";
+			s.height="100%";
+		}else{
+			this.cover.style.zIndex=1;
+		}
+		this.sizingSplitter.style.zIndex=2;
+
+		// TODO: REVISIT - we want MARGIN_BOX and core hasn't exposed that yet
+		this.originPos = dojo.coords(children[0].domNode, true);
+		if(this.isHorizontal){
+			var client = (e.layerX ? e.layerX : e.offsetX);
+			var screen = e.pageX;
+			this.originPos = this.originPos.x;
+		}else{
+			var client = (e.layerY ? e.layerY : e.offsetY);
+			var screen = e.pageY;
+			this.originPos = this.originPos.y;
+		}
+		this.startPoint = this.lastPoint = screen;
+		this.screenToClientOffset = screen - client;
+		this.dragOffset = this.lastPoint - this.paneBefore.sizeActual - this.originPos - this.paneBefore.position;
+
+		if(!this.activeSizing){
+			this._showSizingLine();
+		}
+
+		//					 
+		// attach mouse events
+		//
+		this.connect(document.documentElement, "onmousemove", "changeSizing");
+		this.connect(document.documentElement, "onmouseup", "endSizing");
+
+		dojo.stopEvent(e);
+	},
+
+	changeSizing: function(e){
+		if(!this.isSizing){ return; }
+		this.lastPoint = this.isHorizontal ? e.pageX : e.pageY;
+		if(this.activeSizing){
+			this.movePoint();
+			this._updateSize();
+		}else{
+			this.movePoint();
+			this._moveSizingLine();
+		}
+		dojo.stopEvent(e);
+	},
+
+	endSizing: function(e){
+		if(!this.isSizing){ return; }
+		if(this.cover){
+			this.cover.style.zIndex=-1;
+		}
+		if(!this.activeSizing){
+			this._hideSizingLine();
+		}
+
+		this._updateSize();
+
+		this.isSizing = false;
+
+		if(this.persist){
+			this._saveState(this);
+		}
+	},
+
+	movePoint: function(){
+
+		// make sure lastPoint is a legal point to drag to
+		var p = this.lastPoint - this.screenToClientOffset;
+
+		var a = p - this.dragOffset;
+		a = this.legaliseSplitPoint(a);
+		p = a + this.dragOffset;
+
+		this.lastPoint = p + this.screenToClientOffset;
+	},
+
+	legaliseSplitPoint: function(a){
+
+		a += this.sizingSplitter.position;
+
+		this.isDraggingLeft = (a > 0) ? true : false;
+
+		if(!this.activeSizing){
+
+			if(a < this.paneBefore.position + this.paneBefore.sizeMin){
+
+				a = this.paneBefore.position + this.paneBefore.sizeMin;
+			}
+
+			if(a > this.paneAfter.position + (this.paneAfter.sizeActual - (this.sizerWidth + this.paneAfter.sizeMin))){
+
+				a = this.paneAfter.position + (this.paneAfter.sizeActual - (this.sizerWidth + this.paneAfter.sizeMin));
+			}
+		}
+
+		a -= this.sizingSplitter.position;
+
+		this._checkSizes();
+
+		return a;
+	},
+
+	_updateSize: function(){
+		var pos = this.lastPoint - this.dragOffset - this.originPos;
+
+		var start_region = this.paneBefore.position;
+		var end_region   = this.paneAfter.position + this.paneAfter.sizeActual;
+
+		this.paneBefore.sizeActual = pos - start_region;
+		this.paneAfter.position	= pos + this.sizerWidth;
+		this.paneAfter.sizeActual  = end_region - this.paneAfter.position;
+
+		var children = this.getChildren();
+		for(var i=0; i<children.length; i++){
+
+			children[i].sizeShare = children[i].sizeActual;
+		}
+
+		this.layout();
+	},
+
+	_showSizingLine: function(){
+
+		this._moveSizingLine();
+
+		if(this.isHorizontal){
+			dojo.marginBox(this.virtualSizer, { w: this.sizerWidth, h: this.paneHeight });
+		}else{
+			dojo.marginBox(this.virtualSizer, { w: this.paneWidth, h: this.sizerWidth });
+		}
+
+		this.virtualSizer.style.display = 'block';
+	},
+
+	_hideSizingLine: function(){
+		this.virtualSizer.style.display = 'none';
+	},
+
+	_moveSizingLine: function(){
+		if(this.isHorizontal){
+			var pos = this.lastPoint - this.startPoint + this.sizingSplitter.position;
+			this.virtualSizer.style.left = pos + 'px';
+		}else{
+			var pos = (this.lastPoint - this.startPoint) + this.sizingSplitter.position;
+			this.virtualSizer.style.top = pos + 'px';
+		}
+	},
+	
+	_getCookieName: function(i){
+		return this.id + "_" + i;
+	},
+
+	_restoreState: function (){
+		var children = this.getChildren();
+		for(var i = 0; i < children.length; i++){
+			var cookieName = this._getCookieName(i);
+			var cookieValue = dojo.cookie(cookieName);
+			if(cookieValue != null){
+				var pos = parseInt(cookieValue);
+				if(typeof pos == "number"){
+					children[i].sizeShare=pos;
+				}
+			}
+		}
+	},
+
+	_saveState: function (){
+		var children = this.getChildren();
+		for(var i = 0; i < children.length; i++){
+			dojo.cookie(this._getCookieName(i), children[i].sizeShare);
+		}
+	}
+});
+
+// These arguments can be specified for the children of a SplitContainer.
+// Since any widget can be specified as a SplitContainer child, mix them
+// into the base widget class.  (This is a hack, but it's effective.)
+dojo.extend(dijit.base.Widget, {
+	// sizeMin: Integer
+	//	Minimum size (width or height) of a child of a SplitContainer.
+	//	The value is relative to other children's sizeShare properties.
+	sizeMin: 10,
+
+	// sizeShare: Integer
+	//	Size (width or height) of a child of a SplitContainer.
+	//	The value is relative to other children's sizeShare properties.
+	//	For example, if there are two children and each has sizeShare=10, then
+	//	each takes up 50% of the available space.
+	sizeShare: 10
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/layout/TabContainer.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/layout/TabContainer.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/layout/TabContainer.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,194 @@
+dojo.provide("dijit.layout.TabContainer");
+
+dojo.require("dijit.layout.PageContainer");
+dojo.require("dijit.base.Layout");
+
+dojo.declare(
+	"dijit.layout.TabContainer",
+	[dijit.layout.PageContainer, dijit.base.Sizable],
+{	
+	
+	
+	// summary
+	//	A TabContainer is a container that has multiple panes, but shows only
+	//	one pane at a time.  There are a set of tabs corresponding to each pane,
+	//	where each tab has the title (aka label) of the pane, and optionally a close button.
+	//
+	//	Publishes topics <widgetId>-addChild, <widgetId>-removeChild, and <widgetId>-selectChild
+	//	(where <widgetId> is the id of the TabContainer itself.
+
+	// labelPosition: String
+	//   Defines where tab labels go relative to tab content.
+	//   "top", "bottom", "left-h", "right-h"
+	labelPosition: "top",
+	
+	templateString: null,	// override setting in PageContainer
+	templateString:"<div class=\"dijitTabContainer\">\n\t<div dojoAttachPoint=\"tablistNode\"></div>\n\t<div class=\"dijitTabPaneWrapper\" dojoAttachPoint=\"containerNode\" dojoAttachEvent=\"onkeypress:onkeypress\" waiRole=\"tabpanel\"></div>\n</div>\n",
+
+	postCreate: function() {	
+		dijit.layout.TabContainer.superclass.postCreate.apply(this, arguments);
+		// create the tab list that will have a tab (a.k.a. tab button) for each tab panel
+		this.tablist = new dijit.layout.TabController(
+			{
+				id: this.id + "_tablist",
+				labelPosition: this.labelPosition,
+				doLayout: this.doLayout,
+				containerId: this.id
+			}, this.tablistNode);		
+	},
+	
+	_setupChild: function(tab){
+		dojo.addClass(tab.domNode, "dijitTabPane");
+		dijit.layout.TabContainer.superclass._setupChild.apply(this, arguments);
+	},
+
+	startup: function(){
+		// wire up the tablist and its tabs
+		this.tablist.startup();
+		dijit.layout.TabContainer.superclass.startup.apply(this, arguments);
+	},
+
+	layout: function(){
+		// Summary: Configure the content pane to take up all the space except for where the tabs are
+		if(!this.doLayout){ return; }
+
+		// position and size the labels and the container node
+		var labelAlign=this.labelPosition.replace(/-h/,"");
+		var children = [
+			{domNode: this.tablist.domNode, layoutAlign: labelAlign},
+			{domNode: this.containerNode, layoutAlign: "client"}
+		];
+		dijit.base.Layout.layoutChildren(this.domNode, this._contentBox, children);
+
+		// Compute size to make each of my children.
+		// children[1] is the margin-box size of this.containerNode, set by layoutChildren() call above
+		this._containerContentBox = dijit.base.Layout.marginBox2contentBox(this.containerNode, children[1]);
+
+		if(this.selectedChildWidget){
+			this._showChild(this.selectedChildWidget);
+		}
+	},
+
+	onkeypress: function(e){
+		// summary
+		//	Keystroke handling for keystrokes on the tab panel itself (that were bubbled up to me)
+		//	Ctrl-up: focus is returned from the pane to the tab button
+		//	Alt-del: close tab
+		if(e.keyCode == e.KEY_UP_ARROW && e.ctrlKey){
+			// set focus to current tab
+			var button = this.correspondingTabButton || this.selectedTabWidget.tabButton;
+			button.focus();
+			dojo.stopEvent(e);
+		}else if(e.keyCode == e.KEY_DELETE && e.altKey){
+			if (this.selectedChildWidget.closable){
+				this.closeChild(this.selectedChildWidget);
+				dojo.stopEvent(e);
+			}
+		}
+	},
+
+	destroy: function(){
+		this.tablist.destroy();
+		dijit.layout.TabContainer.superclass.destroy.apply(this, arguments);
+	}
+});
+
+//TODO: make private?
+dojo.declare(
+    "dijit.layout.TabController",
+    dijit.layout.PageController,
+	{
+		// summary
+		// 	Set of tabs (the things with labels and a close button, that you click to show a tab panel).
+		//	Lets the user select the currently shown pane in a TabContainer or PageContainer.
+		//	TabController also monitors the TabContainer, and whenever a pane is
+		//	added or deleted updates itself accordingly.
+
+		templateString: "<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'></div>",
+
+		// labelPosition: String
+		//   Defines where tab labels go relative to tab content.
+		//   "top", "bottom", "left-h", "right-h"
+		labelPosition: "top",
+
+		doLayout: true,
+
+		// class: String
+		//	Class name to apply to the top dom node
+		"class": "",
+
+		// buttonWidget: String
+		//	the name of the tab widget to create to correspond to each page
+		buttonWidget: "dijit.layout.TabButton",
+
+		postMixInProperties: function(){
+			if(!this["class"]){
+				this["class"] = "dijitTabLabels-" + this.labelPosition + (this.doLayout ? "" : " dijitTabNoLayout");
+			}
+			dijit.layout.TabController.superclass.postMixInProperties.apply(this, arguments);
+		}
+	}
+);
+
+//TODO: make private?
+dojo.declare(
+	"dijit.layout.TabButton", dijit.layout.PageButton,
+{
+	// summary
+	//	A tab (the thing you click to select a pane).
+	//	Contains the title (aka label) of the pane, and optionally a close-button to destroy the pane.
+	//	This is an internal widget and should not be instantiated directly.
+
+	selectedClass: "dijitTabActive",
+	hoverClass : "dijitTabHover",
+	closeHoverClass : "closeImageHover",
+
+	templateString: "<div class='dijitTab' dojoAttachEvent='onclick:onClick; onmouseover:onMouseOver; onmouseout:onMouseOut;'>"
+						+"<div class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>"
+							+"<span dojoAttachPoint='titleNode' tabIndex='-1' waiRole='tab'>${label}</span>"
+							+"<span dojoAttachPoint='closeButtonNode' class='closeImage' style='${closeButtonStyle}'"
+							+"    dojoAttachEvent='onmouseover:onCloseButtonMouseOver; onmouseout:onCloseButtonMouseOut; onclick:onCloseButtonClick'></span>"
+						+"</div>"
+					+"</div>",
+
+	postMixInProperties: function(){
+		this.closeButtonStyle = this.closeButton ? "" : "display: none";
+		dijit.layout.TabButton.superclass.postMixInProperties.apply(this, arguments);
+	},
+
+	postCreate: function(){
+		dijit.layout.TabButton.superclass.postCreate.apply(this, arguments);
+		dijit._disableSelection(this.titleNode);
+	},
+	
+	onCloseButtonClick: function(/*Event*/ evt){
+		// since the close button is located inside the select button, make sure that the select
+		// button doesn't inadvertently get an onClick event
+		evt.stopPropagation();
+		dijit.layout.TabButton.superclass.onCloseButtonClick.apply(this, arguments);
+	}
+});
+
+
+//TODO: make private?
+//TODO: how does a11y get activated?
+dojo.declare(
+	"dijit.a11y.TabButton",
+	dijit.layout.TabButton,
+	{
+		// summary
+		//	Tab for display in high-contrast mode (where background images don't show up).
+		//	This is an internal widget and shouldn't be instantiated directly.
+
+		imgPath: dojo.moduleUrl("dijit", "themes/tundra/tab_close.gif"),
+		
+		templateString: "<div class='dijitTab' dojoAttachEvent='onclick:onClick;onkeypress:onkeypress'>"
+							+"<div class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>"
+								+"<span dojoAttachPoint='titleNode' tabIndex='-1' waiRole='tab'>${label}</span>"
+								+"<img class='close' src='${imgPath}' alt='[x]' style='${closeButtonStyle}'"
+								+"    dojoAttachEvent='onclick:onCloseButtonClick'>"
+							+"</div>"
+						+"</div>"
+	}
+);
+

Added: trunk/examples/typeface/root/static/dojo/dijit/layout/templates/AccordionPane.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/layout/templates/AccordionPane.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/layout/templates/AccordionPane.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,6 @@
+<div dojoAttachPoint="domNode"
+	><div dojoAttachPoint="labelNode" dojoAttachEvent="onclick:onLabelClick" class="${labelNodeClass}"
+		><div class='arrow'></div><span dojoAttachPoint='labelTextNode'>${label}</span></div
+	><div dojoAttachPoint="containerNode" style="overflow: hidden;" class="${containerNodeClass}"
+	></div>
+</div>

Added: trunk/examples/typeface/root/static/dojo/dijit/layout/templates/Dialog.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/layout/templates/Dialog.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/layout/templates/Dialog.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,10 @@
+<div class="dijitDialog" dojoattachpoint="wrapper">
+	<span dojoattachpoint="tabStartOuter" dojoonfocus="trapTabs" dojoonblur="clearTrap"	tabindex="0"></span>
+	<span dojoattachpoint="tabStart" dojoonfocus="trapTabs" dojoonblur="clearTrap" tabindex="0"></span>
+	<div dojoAttachPoint="titleBar" class="dijitDialogTitleBar" style="display:none">
+		<span dojoAttachPoint="labelNode" class="dijitDialogLabel">${label}</span><span dojoAttachPoint="closeButtonNode" class="dijitDialogCloseIcon"></span>
+	</div>
+	<div dojoattachpoint="containerNode" style="z-index: 2; overflow: auto;" class="dijitDialogContent"></div>
+	<span dojoattachpoint="tabEnd" dojoonfocus="trapTabs" dojoonblur="clearTrap" tabindex="0"></span>
+	<span dojoattachpoint="tabEndOuter" dojoonfocus="trapTabs" dojoonblur="clearTrap" tabindex="0"></span>
+</div>

Added: trunk/examples/typeface/root/static/dojo/dijit/layout/templates/TabContainer.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/layout/templates/TabContainer.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/layout/templates/TabContainer.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+<div class="dijitTabContainer">
+	<div dojoAttachPoint="tablistNode"></div>
+	<div class="dijitTabPaneWrapper" dojoAttachPoint="containerNode" dojoAttachEvent="onkeypress:onkeypress" waiRole="tabpanel"></div>
+</div>

Added: trunk/examples/typeface/root/static/dojo/dijit/nls/common.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/nls/common.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/nls/common.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+({
+	buttonOk: "OK",
+	buttonCancel: "Cancel",
+	buttonSave: "Save"
+})

Added: trunk/examples/typeface/root/static/dojo/dijit/nls/de/common.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/nls/de/common.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/nls/de/common.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,3 @@
+({
+	buttonCancel: "Abbrechen"
+})

Added: trunk/examples/typeface/root/static/dojo/dijit/templates/Calendar.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/templates/Calendar.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/templates/Calendar.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,37 @@
+<table cellspacing="0" cellpadding="0" class="calendarContainer">
+	<thead>
+		<tr class="dijitReset calendarMonthContainer" valign="top">
+			<th class='dijitReset'>
+				<img dojoAttachPoint="monthDecrease" dojoAttachEvent="onclick: _onDecrementMonth;" class="dijitDownArrow calendarMonthDecrement calendarIncrementControl calendarDecrease" alt="-">
+			</th>
+			<th class='dijitReset' colspan="5">
+				<div dojoAttachPoint="monthLabelSpacer" class="calendarMonthLabelSpacer"></div>
+				<div dojoAttachPoint="monthLabelNode" class="calendarMonth"></div>
+			</th>
+			<th class='dijitReset'>
+				<img dojoAttachPoint="monthIncrease" dojoAttachEvent="onclick: _onIncrementMonth;" class="dijitUpArrow calendarMonthIncrement calendarIncrementControl calendarIncrease" alt="+">
+			</th>
+		</tr>
+		<tr>
+			<th class="dijitReset calendarDayLabelTemplate"><span class="calendarDayLabel"></span></th>
+		</tr>
+	</thead>
+	<tbody dojoAttachEvent="onclick: _onDayClick;" class="dijitReset calendarBodyContainer">
+		<tr class="dijitReset calendarWeekTemplate">
+			<td class="dijitReset calendarDateTemplate"><span class="calendarDateLabel"></span></td>
+		</tr>
+	</tbody>
+	<tfoot class="dijitReset calendarYearContainer">
+		<tr>
+			<td class='dijitReset' valign="top" colspan="7">
+				<h3 class="calendarYearLabel">
+					<span dojoAttachPoint="previousYearLabelNode"
+						dojoAttachEvent="onclick: _onDecrementYear;" class="calendarPreviousYear"></span>
+					<span dojoAttachPoint="currentYearLabelNode" class="calendarSelectedYear"></span>
+					<span dojoAttachPoint="nextYearLabelNode" 
+						dojoAttachEvent="onclick: _onIncrementYear;" class="calendarNextYear"></span>
+				</h3>
+			</td>
+		</tr>
+	</tfoot>
+</table>	

Added: trunk/examples/typeface/root/static/dojo/dijit/templates/ColorPalette.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/templates/ColorPalette.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/templates/ColorPalette.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+<fieldset class="dijitInlineBox">
+	<div style="overflow: hidden" dojoAttachPoint="divNode" >
+		<img style="border-style: none;" dojoAttachPoint="imageNode" tabIndex="-1" />
+	</div>	
+</fieldset>
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dijit/templates/ProgressBar.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/templates/ProgressBar.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/templates/ProgressBar.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,10 @@
+<div class="dijitProgressBar dijitProgressBarEmpty"
+	><div dojoAttachPoint="emptyLabel" class="dijitProgressBarEmptyLabel"
+	></div
+	><div waiRole="progressbar" tabindex="0" dojoAttachPoint="internalProgress" class="dijitProgressBarFull"
+		><div class="dijitProgressBarTile"
+		></div
+		><div dojoAttachPoint="fullLabel" class="dijitProgressBarFullLabel"
+		></div
+	></div
+></div>

Added: trunk/examples/typeface/root/static/dojo/dijit/templates/TitlePane.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/templates/TitlePane.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/templates/TitlePane.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,8 @@
+<div id="${id}">
+	<div dojoAttachEvent="onclick: onLabelClick; onkeypress: onLabelKey" tabindex="0" 
+			waiRole="button" class="dijitTitlePaneLabel" dojoAttachPoint="focusNode">
+		<span class="dijitOpenCloseArrowOuter" style="float: left;"><span class="dijitOpenCloseArrowInner"></span></span>
+		<span dojoAttachPoint="labelNode" class="dijitInlineBox dijitLabelNode"></span>
+	</div>
+	<div dojoAttachPoint="containerNode" waiRole="region" tabindex="-1" class="${contentClass}"></div>
+</div>

Added: trunk/examples/typeface/root/static/dojo/dijit/templates/Tooltip.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/templates/Tooltip.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/templates/Tooltip.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+<div class="dijitTooltip" id="dojoTooltip">
+	<div class="dijitTooltipContainer dijitTooltipContents" dojoAttachPoint="containerNode" waiRole='alert'></div>
+	<div class="dijitTooltipConnector"></div>
+</div>
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dijit/templates/blank.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/templates/blank.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/templates/colors3x4.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/templates/colors3x4.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/templates/colors7x10.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/templates/colors7x10.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/countries.json
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/countries.json	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/countries.json	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,44 @@
+{ identifier: 'name',
+   items: [
+     { name:'Africa', type:'continent',
+         children:[{reference:'Egypt'}, {reference:'Kenya'}, {reference:'Sudan'}] },
+     { name:'Egypt', type:'country' },
+     { name:'Kenya', type:'country',
+         children:[{reference:'Nairobi'}, {reference:'Mombasa'}] },
+     { name:'Nairobi', type:'city' },
+     { name:'Mombasa', type:'city' },
+     { name:'Sudan', type:'country',
+         children:{reference:'Khartoum'} },
+     { name:'Khartoum', type:'city' },
+     { name:'Asia', type:'continent',
+         children:[{reference:'China'}, {reference:'India'}, 
+{reference:'Russia'}, {reference:'Mongolia'}] },
+     { name:'China', type:'country' },
+     { name:'India', type:'country' },
+     { name:'Russia', type:'country' },
+     { name:'Mongolia', type:'country' },
+     { name:'Australia', type:'continent', population:'21 million',
+         children:{reference:'Commonwealth of Australia'}},
+     { name:'Commonwealth of Australia', type:'country', population:'21 million'},
+     { name:'Europe', type:'continent',
+         children:[{reference:'Germany'}, {reference:'France'}, {reference:'Spain'}, {reference:'Italy'}] },
+     { name:'Germany', type:'country' },
+     { name:'France', type:'country' },
+     { name:'Spain', type:'country' },
+     { name:'Italy', type:'country' },
+     { name:'North America', type:'continent',
+         children:[{reference:'Mexico'}, {reference:'Canada'}, {reference:'United States of America'}] },
+     { name:'Mexico', type:'country',  population:'108 million', area:'1,972,550 sq km',
+         children:[{reference:'Mexico City'}, {reference:'Guadalajara'}] },
+     { name:'Mexico City', type:'city', population:'19 million', timezone:'-6 UTC'},
+     { name:'Guadalajara', type:'city', population:'4 million', timezone:'-6 UTC' },
+     { name:'Canada', type:'country',  population:'33 million', area:'9,984,670 sq km',
+         children:[{reference:'Ottawa'}, {reference:'Toronto'}] },
+     { name:'Ottawa', type:'city', population:'0.9 million', timezone:'-5 UTC'},
+     { name:'Toronto', type:'city', population:'2.5 million', timezone:'-5 UTC' },
+     { name:'United States of America', type:'country' },
+     { name:'South America', type:'continent',
+         children:[{reference:'Brazil'}, {reference:'Argentina'}] },
+     { name:'Brazil', type:'country', population:'186 million' },
+     { name:'Argentina', type:'country', population:'40 million' }
+]}

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/css/dijitTests.css
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/css/dijitTests.css	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/css/dijitTests.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,11 @@
+/* Test file styles for Dijit widgets */
+
+body {
+	background:#fff url("../images/testsBodyBg.gif") repeat-x top left;
+	padding:2em 2em 2em 2em;
+}
+
+h1.testTitle {
+	font-size:2em;
+	margin:0 0 1em 0;
+}
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/form/autoCompleterData.json
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/form/autoCompleterData.json	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/form/autoCompleterData.json	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,64 @@
+{identifier:"abbreviation",
+items: [
+	{name:"Alabama", label:"<img width='97px' height='127px' src='images/Alabama.jpg'/>Alabama",abbreviation:"AL"},
+	{name:"Alaska", label:"Alaska",abbreviation:"AK"},
+	{name:"American Samoa", label:"American Samoa",abbreviation:"AS"},
+	{name:"Arizona", label:"Arizona",abbreviation:"AZ"},
+	{name:"Arkansas", label:"Arkansas",abbreviation:"AR"},
+	{name:"Armed Forces Europe", label:"Armed Forces Europe",abbreviation:"AE"},
+	{name:"Armed Forces Pacific", label:"Armed Forces Pacific",abbreviation:"AP"},
+	{name:"Armed Forces the Americas", label:"Armed Forces the Americas",abbreviation:"AA"},
+	{name:"California", label:"California",abbreviation:"CA"},
+	{name:"Colorado", label:"Colorado",abbreviation:"CO"},
+	{name:"Connecticut", label:"Connecticut",abbreviation:"CT"},
+	{name:"Delaware", label:"Delaware",abbreviation:"DE"},
+	{name:"District of Columbia", label:"District of Columbia",abbreviation:"DC"},
+	{name:"Federated States of Micronesia", label:"Federated States of Micronesia",abbreviation:"FM"},
+	{name:"Florida", label:"Florida",abbreviation:"FL"},
+	{name:"Georgia", label:"Georgia",abbreviation:"GA"},
+	{name:"Guam", label:"Guam",abbreviation:"GU"},
+	{name:"Hawaii", label:"Hawaii",abbreviation:"HI"},
+	{name:"Idaho", label:"Idaho",abbreviation:"ID"},
+	{name:"Illinois", label:"Illinois",abbreviation:"IL"},
+	{name:"Indiana", label:"Indiana",abbreviation:"IN"},
+	{name:"Iowa", label:"Iowa",abbreviation:"IA"},
+	{name:"Kansas", label:"Kansas",abbreviation:"KS"},
+	{name:"Kentucky", label:"Kentucky",abbreviation:"KY"},
+	{name:"Louisiana", label:"Louisiana",abbreviation:"LA"},
+	{name:"Maine", label:"Maine",abbreviation:"ME"},
+	{name:"Marshall Islands", label:"Marshall Islands",abbreviation:"MH"},
+	{name:"Maryland", label:"Maryland",abbreviation:"MD"},
+	{name:"Massachusetts", label:"Massachusetts",abbreviation:"MA"},
+	{name:"Michigan", label:"Michigan",abbreviation:"MI"},
+	{name:"Minnesota", label:"Minnesota",abbreviation:"MN"},
+	{name:"Mississippi", label:"Mississippi",abbreviation:"MS"},
+	{name:"Missouri", label:"Missouri",abbreviation:"MO"},
+	{name:"Montana", label:"Montana",abbreviation:"MT"},
+	{name:"Nebraska", label:"Nebraska",abbreviation:"NE"},
+	{name:"Nevada", label:"Nevada",abbreviation:"NV"},
+	{name:"New Hampshire", label:"New Hampshire",abbreviation:"NH"},
+	{name:"New Jersey", label:"New Jersey",abbreviation:"NJ"},
+	{name:"New Mexico", label:"New Mexico",abbreviation:"NM"},
+	{name:"New York", label:"New York",abbreviation:"NY"},
+	{name:"North Carolina", label:"North Carolina",abbreviation:"NC"},
+	{name:"North Dakota", label:"North Dakota",abbreviation:"ND"},
+	{name:"Northern Mariana Islands", label:"Northern Mariana Islands",abbreviation:"MP"},
+	{name:"Ohio", label:"Ohio",abbreviation:"OH"},
+	{name:"Oklahoma", label:"Oklahoma",abbreviation:"OK"},
+	{name:"Oregon", label:"Oregon",abbreviation:"OR"},
+	{name:"Pennsylvania", label:"Pennsylvania",abbreviation:"PA"},
+	{name:"Puerto Rico", label:"Puerto Rico",abbreviation:"PR"},
+	{name:"Rhode Island", label:"Rhode Island",abbreviation:"RI"},
+	{name:"South Carolina", label:"South Carolina",abbreviation:"SC"},
+	{name:"South Dakota", label:"South Dakota",abbreviation:"SD"},
+	{name:"Tennessee", label:"Tennessee",abbreviation:"TN"},
+	{name:"Texas", label:"Texas",abbreviation:"TX"},
+	{name:"Utah", label:"Utah",abbreviation:"UT"},
+	{name:"Vermont", label:"Vermont",abbreviation:"VT"},
+	{name: "Virgin Islands, U.S.",label:"Virgin Islands, U.S.",abbreviation:"VI"},
+	{name:"Virginia", label:"Virginia",abbreviation:"VA"},
+	{name:"Washington", label:"Washington",abbreviation:"WA"},
+	{name:"West Virginia", label:"West Virginia",abbreviation:"WV"},
+	{name:"Wisconsin", label:"Wisconsin",abbreviation:"WI"},
+	{name:"Wyoming", label:"Wyoming",abbreviation:"WY"}
+]}
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/form/images/Alabama.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/tests/form/images/Alabama.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_AutoCompleter.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_AutoCompleter.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_AutoCompleter.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,264 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Dojo AutoCompleter Widget Test</title>
+
+<script type="text/javascript" src="../testBidi.js"></script>
+
+<script type="text/javascript"> 
+	var djConfig = {
+		isDebug: true};
+</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<script type="text/javascript">
+	dojo.require("dijit.form.AutoCompleter");
+	dojo.require("dijit.util.manager");
+	dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+</script>
+<style>
+        @import "../../../dojo/resources/dojo.css";
+        @import "../../themes/tundra/tundra.css";
+</style>
+
+<script>
+	function setVal1(val){
+		document.getElementById('value1').value=val;
+	}
+	function setVal2(val){
+		document.getElementById('value2').value=val;
+		console.debug("Value changed to ["+val+"] in second AutoCompleter (#1652)");
+	}
+	function setVal3(val){
+		document.getElementById('value3').value=val;
+	}
+	var combo;
+	function init(){
+		//var store=new dojo.data.JsonItemStore({});
+		combo = new dijit.form.AutoCompleter({data:{items:[{name:"California", label:"California"}]}, name:"prog",autocomplete:false,searchAttr:"name", labelField:"label", labelType:"text"}, document.getElementById("progCombo"));
+	}
+	dojo.addOnLoad(init);
+	
+	function toggleDisabled(button, widget){
+		widget = dijit.byId(widget);
+		button = document.getElementById(button);
+		widget.disabled ? widget.enable() : widget.disable();
+		button.innerHTML= widget.disabled ? "Enable" : "Disable";
+	}
+</script>
+</head>
+
+<body class="tundra">
+<h1>Dojo AutoCompleter Widget Test</h1>
+<p>
+A AutoCompleter is like a text &lt;input&gt; field (ie, you can input any value you want),
+but it also has a list of suggested values that you can choose from.
+The drop down list is filtered by the data you have already typed in.
+</p>
+<form action="#" method="GET">
+ 
+    <p>AutoCompleter #1: inlined data, autocomplete=false, default value of CA (California)</p>
+    <label for="setvaluetest">US State test 1: </label>
+	<select id="setvaluetest"
+			name="state1"
+			dojoType="dijit.form.AutoCompleter"
+			class="medium"
+			searchAttr="name"
+			labelField="name"
+			labelType="text"
+			style="width: 300px;font-size:20pt;background-color:cyan;"
+			name="foo.bar1"
+			autocomplete="false"
+			value="Iowa"
+			promptMessage="Please enter a state"
+			onValueChanged="setVal1"
+	>
+		<option value="Alabama">Alabama</option>
+		<option value="Alaska">Alaska</option>
+		<option value="American Samoa">American Samoa</option>
+		<option value="Arizona">Arizona</option>
+		<option value="Arkansas">Arkansas</option>
+		<option value="Armed Forces Europe">Armed Forces Europe</option>
+		<option value="Armed Forces Pacific">Armed Forces Pacific</option>
+		<option value="Armed Forces the Americas">Armed Forces the Americas</option>
+		<option value="California">California</option>
+		<option value="Colorado">Colorado</option>
+		<option value="Connecticut">Connecticut</option>
+		<option value="Delaware">Delaware</option>
+		<option value="District of Columbia">District of Columbia</option>
+		<option value="Federated States of Micronesia">Federated States of Micronesia</option>
+		<option value="Florida">Florida</option>
+		<option value="Georgia">Georgia</option>
+		<option value="Guam">Guam</option>
+		<option value="Hawaii">Hawaii</option>
+		<option value="Idaho">Idaho</option>
+		<option value="Illinois">Illinois</option>
+		<option value="Indiana">Indiana</option>
+		<option value="Iowa" selected>Iowa</option>
+		<option value="Kansas">Kansas</option>
+		<option value="Kentucky">Kentucky</option>
+		<option value="Louisiana">Louisiana</option>
+		<option value="Maine">Maine</option>
+		<option value="Marshall Islands">Marshall Islands</option>
+		<option value="Maryland">Maryland</option>
+		<option value="Massachusetts">Massachusetts</option>
+		<option value="Michigan">Michigan</option>
+		<option value="Minnesota">Minnesota</option>
+		<option value="Mississippi">Mississippi</option>
+		<option value="Missouri">Missouri</option>
+		<option value="Montana">Montana</option>
+		<option value="Nebraska">Nebraska</option>
+		<option value="Nevada">Nevada</option>
+		<option value="New Hampshire">New Hampshire</option>
+		<option value="New Jersey">New Jersey</option>
+		<option value="New Mexico">New Mexico</option>
+		<option value="New York">New York</option>
+		<option value="North Carolina">North Carolina</option>
+		<option value="North Dakota">North Dakota</option>
+		<option value="Northern Mariana Islands">Northern Mariana Islands</option>
+		<option value="Ohio">Ohio</option>
+		<option value="Oklahoma">Oklahoma</option>
+		<option value="Oregon">Oregon</option>
+		<option value="Pennsylvania">Pennsylvania</option>
+		<option value="Puerto Rico">Puerto Rico</option>
+		<option value="Rhode Island">Rhode Island</option>
+		<option value="South Carolina">South Carolina</option>
+		<option value="South Dakota">South Dakota</option>
+		<option value="Tennessee">Tennessee</option>
+		<option value="Texas">Texas</option>
+		<option value="Utah">Utah</option>
+		<option value="Vermont">Vermont</option>
+		<option value="Virgin Islands, U.S.">Virgin Islands, U.S.</option>
+		<option value="Virginia">Virginia</option>
+		<option value="Washington">Washington</option>
+		<option value="West Virginia">West Virginia</option>
+		<option value="Wisconsin">Wisconsin</option>
+		<option value="Wyoming">Wyoming</option>
+	</select>  
+	
+	<br>
+	<div>Value: <input id="value1" disabled></div>
+	<hr>
+
+	<p>AutoCompleter #2: url, autocomplete=true:</p>
+	<label for="datatest">US State test 2: </label>
+	<input dojoType="dijit.form.AutoCompleter"
+			value="California"
+			class="medium"
+			url="autoCompleterData.json"
+			searchAttr="name"
+			labelField="label"
+			labelType="html"
+			style="width: 300px;"
+			name="state2"
+			promptMessage="Please enter a state"
+			onValueChanged="setVal2"
+			id="datatest"
+	>
+	<br>
+	<div>Value: <input id="value2" disabled></div>
+	<hr>
+		
+    <p>AutoCompleter #3: initially disabled, url, autocomplete=false:</p>
+    <label for="combo3">US State test 3: </label>
+ 	<input id="combo3"
+ 			dojoType="dijit.form.AutoCompleter"
+ 			value="California"
+ 			class="medium"
+			url="autoCompleterData.json"
+			searchAttr="name"
+			labelField="label"
+			labelType="html"
+			style="width: 300px;"
+			name="state3"
+			autocomplete="false"
+			promptMessage="Please enter a state"
+			onValueChanged="setVal3"
+			disabled
+	>
+	<br>
+	<div>Value: <input id="value3" disabled></div>
+	<div>
+		<button id="but" onclick='toggleDisabled("but", "combo3"); return false;'>Enable</button>
+	</div>
+	<hr>
+    <p>Multiple autocompleters on a single line:</p>
+    <label for="one">US State 1: </label>
+ 	<input dojoType="dijit.form.AutoCompleter"
+ 			value="California"
+ 			id="one"
+			url="autoCompleterData.json"
+			searchAttr="name"
+			labelField="label"
+			labelType="html"
+			style="width: 200px;"
+			name="state4"
+			autocomplete="false"
+	>	<label for="two">US State 2: </label>
+ 	<input dojoType="dijit.form.AutoCompleter"
+ 			value="California"
+ 			id="two"
+			url="autoCompleterData.json"
+			searchAttr="name"
+			labelField="label"
+			labelType="html"
+			style="width: 200px;"
+			name="state5"
+			autocomplete="false"
+	>
+	<hr>
+
+	<p>A combo created by createWidget</p>
+	<input id="progCombo">
+	<hr>
+	<input type="button" value="Create one in a window" onclick="var win=window.open(window.location);"></input>
+	<input type="submit">
+	
+</form>
+<p>
+this is some text below the autocompleters. It shouldn't get pushed out of the way when search results get returned.
+also: adding a simple combo box to test IE bleed through problem:
+</p>
+
+<select>
+  <option>test for</option>
+  <option>IE bleed through</option>
+  <option>problem</option>
+</select>
+<h3>Some tests:</h3>
+<ol>
+<li>Type in D - dropdown shows Delaware and District of columbia. [Would be nice if it bolded the D's in the dropdown list!]</li>
+<li>Type in DX - input box shows DX and no dropdown.</li>
+<li>Open dropdown, click an item, it selects and closes dropdown.</li>
+<li>Click triangle icon - dropdown shows. Click it again - dropdown goes.</li>
+<li>Check that you can type in more than required (e.g. alaba for alabama) and it still correctly shows alabama</li>
+<li>Tab into the combo works, list should not apear.</li>
+<li>Tab out of the combo works - closes dropdown and goes to next control (focus should not go to the dropdown because tabindex="-1").</li>
+<li>Do the dropdown and click outside of it - the dropdown disappears.</li>
+<li>Javascript disabled -> fallback to old style combo?</li>
+<li>Can you paste in the start of a match? [no]</li>
+<li>Backspace to start - dropdown shows all all items</li>
+<li>Backspace deselects last character [Borked: currently you have to backspace twice]</li>
+<li>Press down key to open dropdown</li>
+<li>Down and up keys select previous/next in dropdown.</li>
+<li>Non-alpha keys (F12, ctrl-c, whatever) should not affect dropdown.</li>
+<li>Press down arrow to highlight an item, pressing enter selects it and closes dropdown.</li>
+<li>Press down arrow to highlight an item, pressing space selects it and closes dropdown.</li>
+<li>Check that pressing escape undoes the previous action and closes the dropdown</li>
+<li>Check that pressing escape again clears the input box.</li>
+<li>In IE, mouse scroll wheel scrolls through the list. Scrolls by 1 item per click even if user has set mouse to scroll more than 1 in mouse settings. Only scrolls if text input has focus (page scrolling works as normal otherwise)</li>
+<li>In IE, dropdown list does not go behind the second combo (special code to manage this).</li>
+<li>Check dropdown is aligned correctly with bottom of the text input</li>
+<li>Probably should try the combo in a relative div or absolute div and see where the dropdown ends up. (Strongly suspect problems in this area in IE - boo)</li>
+<li>Try repeatably droppingdown and closing the dropdown. Shouldnt get hung [sometimes flicks closed just after opening due to timers, but not a biggie]</li>
+<li>Check that default selection of the text makes sense. e.g. text is selected after picking an item, on tabbing in to text input etc)</li>
+<li>Check that dropdown is smooth [looks uggy on second keypress in FF - hides then shows]</li>
+<li>Clear the field. Type in A and then tab *very quickly* and see if the results make sense (the dropdown is on a timer - searchTimer)</li>
+<li>Clear the field and enter an invalid entry and tab out e.g. Qualude. Does that make sense given the combobox setup options?</li>
+<li>(Add any other tests here)</li>
+</ol>
+<div id="debugbox"></div>
+<!-- maintain state of combo box if user presses back/forward button -->
+<form name="_dojo_form" style="display:none" disabled="true"><textarea name="stabile" cols="80" rows="10"></textarea></form>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_AutoCompleter_destroy.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_AutoCompleter_destroy.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_AutoCompleter_destroy.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Dojo ComboBox Widget Destruction Issue</title>
+<link rel=stylesheet href="../../themes/tundra/tundra.css" type="text/css">
+
+<script type="text/javascript" src="../testBidi.js"></script>
+
+<script type="text/javascript"> 
+	var djConfig = {
+        debugAtAllCosts: true,
+        isDebug: true
+    };
+</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script> 
+<script type="text/javascript">
+	
+	dojo.require("dijit.form.AutoCompleter");
+	dojo.require("dijit.util.manager");
+	dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+    if ("debugAtAllCosts" in djConfig && djConfig.debugAtAllCosts) {
+     //   dojo.hostenv.writeIncludes();
+    }
+</script>
+<script type="text/javascript">
+	dojo.addOnLoad(init);
+	function init(){
+	//new dijit.form.AutoCompleter({name:"prog", id:"combo_02",autocomplete:false,url:"autoCompleterData.js",searchField:"name"}, document.getElementById("progCombo"));
+        dojo.connect(dojo.byId("killit"), "onclick", function() {
+            dijit.byId("combo_01").destroy(true);
+        });
+	}
+</script>
+</head>
+<body>
+<h1>Dojo ComboBox Widget Destruction Issue</h1>
+<p>
+<tt>ComboBox</tt> does not destroy itself properly, leading to a 
+JavaScript error.  Could it have something to do with not disconnecting
+events?
+</p>
+<p>
+Steps:
+<ol>
+    <li>Pick a state from the combo box below.</li>
+    <li>Click the "killit" button, which calls <tt>destroy</tt> on the widget.</li>
+    <li>Observe the JavaScript error.</li>
+</ol>
+</p>
+<form action="#" method="GET">
+   <input type="button" id="killit" name="killit" value="killit" />
+	<select name="state" searchField="name" keyField="abbreviation" id="combo_01" dojoType="dijit.form.AutoCompleter" style="width: 300px;" name="foo.bar1" autocomplete="false"
+	>
+		<option value="AL">Alabama</option>
+
+		<option value="AK">Alaska</option>
+		<option value="AS">American Samoa</option>
+		<option value="AZ">Arizona</option>
+		<option value="AR">Arkansas</option>
+		<option value="AE">Armed Forces Europe</option>
+		<option value="AP">Armed Forces Pacific</option>
+	</select>    
+<!--<p>A combo created by createWidget</p>
+	<input id="progCombo">-->
+</form>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Button.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Button.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Button.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,234 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>Dojo Button Widget Test</title>
+		
+		<script type="text/javascript" src="../testBidi.js"></script>
+		
+		<script type="text/javascript" src="../../../dojo/dojo.js"
+			djConfig="isDebug: true"></script>
+		<script type="text/javascript">
+			dojo.require("dijit.Menu");
+			dojo.require("dijit.Tooltip");
+			dojo.require("dijit.form.Button");
+			dojo.require("dijit.util.parser");
+			logMessage = console.debug;
+		</script>
+		<style type="text/css">
+			@import "../../../dojo/resources/dojo.css";
+			@import "../css/dijitTests.css";
+
+			/* group multiple buttons in a row */
+			.box {
+				display: block;
+				text-align: center;
+			}
+			.box .dojoButton {
+				margin-right: 10px;
+			}
+			.dojoButtonContents {
+				font-size: 1.6em;
+			}
+
+			/* todo: find good color for disabled menuitems, and teset */
+			.dojoMenuItem2Disabled .dojoMenuItem2Label span,
+			.dojoMenuItem2Disabled .dojoMenuItem2Accel span {
+				color: ThreeDShadow;
+			}
+			
+			.dojoMenuItem2Disabled .dojoMenuItem2Label span span,
+			.dojoMenuItem2Disabled .dojoMenuItem2Accel span span {
+				color: ThreeDHighlight;
+			}
+
+		</style>
+	</head>
+	<body>
+	<script language='javascript'>
+		var match = (window.location.search+"&").match(/theme=(.*?)&/);
+		var theme = (match ? match[1] : "tundra");
+		document.getElementsByTagName("BODY")[0].className = theme;
+		document.write("<style>	@import '../../themes/"+theme+"/"+theme+".css'; <\/style>");
+	</script>
+		<h1 class="testTitle">Dijit Button Test</h1>
+		<h2>Simple, drop down & combo buttons</h2>
+		<p>
+		Buttons can do an action, display a menu, or both:
+		</p>
+		<div class="box">
+			<button id="1465" dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>
+				<img src="../images/plus.gif" width="16" height="16"> Create
+			</button>
+			<span dojoType="dijit.Tooltip" connectId="1465" caption="tooltip on button"></span>
+			<button dojoType="dijit.form.Button" onclick='logMessage("clicked simple")'>
+				<img src="../images/plus.gif" width="16" height="16"><br>Create
+			</button>
+			<button dojoType="dijit.form.DropDownButton" menuId='editMenu'>
+				<img src="../images/note.gif" width="20" height="20"> Edit
+			</button>
+			<button dojoType="dijit.form.DropDownButton" menuId='editMenu'>
+				<img src="../images/note.gif" width="20" height="20"><br>Edit
+			</button>
+			<button dojoType="dijit.form.ComboButton" optionsTitle='save options' menuId='saveMenu' onClick='logMessage("clicked combo save")'>
+				<img src="../images/note.gif" width="20" height="20"> Save
+			</button>
+			<button dojoType="dijit.form.ComboButton" optionsTitle='save options' menuId='saveMenu' onclick='logMessage("clicked combo save")'>
+				<img src="../images/note.gif" width="20" height="20"><br>Save
+			</button>
+			<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")' disabled='true'>
+				<img src="../images/plus.gif" width="16" height="16"> Disabled
+			</button>
+		</div>
+		<br clear=both>
+
+		<h2>Sizing</h2>
+		<p>Short button, tall buttons, big buttons, small buttons...
+		These buttons size to their content (just like &lt;button&gt;).</p>
+		<div class="box">
+			<button dojoType="dijit.form.Button" onclick='logMessage("big");'>
+				<img src="../images/flatScreen.gif" width="32" height="32">
+				<span style="font-size:xx-large">big</span>
+			</button>
+			<button id="smallButton1" dojoType="dijit.form.Button" onclick='logMessage("small");'>
+				<img src="../images/arrowSmall.gif" width="15" height="5">
+				<span style="font-size:x-small">small</span>
+			</button>
+			<button dojoType="dijit.form.Button" onclick='logMessage("long");'>
+				<img src="../images/tube.gif" width="150" height="16">
+				long
+			</button>
+			<button dojoType="dijit.form.Button" onclick='logMessage("tall");' width2height="0.1">
+				<img src="../images/tubeTall.gif" height="75" width="35"><br>
+				<span style="font-size:medium">tall</span>
+			</button>
+			<div style="clear: both;"></div>
+		</div>
+		<br clear=both>
+
+		<h2>Customized buttons</h2>
+		<p>Dojo users can mix in their styles.
+		Here's an example:</p>
+		<style>
+			.dc {
+				font-size: x-large !important;
+				padding-top: 10px !important;
+				padding-bottom: 10px !important;
+			}
+
+			.Acme *,
+			.Acme {
+					background: rgb(96,96,96) !important;
+					color: white !important;
+				padding: 10px !important;
+			}
+
+			.Acme:hover *,
+			.Acme:hover {
+					background-color: rgb(89,94,111) !important;
+					color: cyan !important;
+			}
+
+			.Acme:active *,
+			.Acme:active {
+					background-color: white !important;
+					color: black !important;
+			}
+		</style>
+		<div class="box">
+			<button dojoType="dijit.form.Button" class="Acme" onclick='logMessage("short");'>
+				<div class="dc">short</div>
+			</button>
+			<button dojoType="dijit.form.Button" class="Acme" onclick='logMessage("longer");'>
+				<div class="dc">bit longer</div>
+			</button>
+			<button dojoType="dijit.form.Button" class="Acme" onclick='logMessage("longer yet");'>
+				<div class="dc">ridiculously long</div>
+			</button>
+			<div style="clear: both;"></div>
+		</div>
+
+		<h2>Toggling the display test</h2>
+		<p>
+		(Ticket <a href="http://trac.dojotoolkit.org/ticket/403">#403</a>)
+		</p>
+		<div class="box">
+			<button dojoType="dijit.form.Button" onclick='dojo.byId("hiddenNode").style.display="inline";'>
+				Show Hidden Buttons
+			</button>
+		</div>
+		<div class="box" style="display:none;" id="hiddenNode">
+			<button dojoType="dijit.form.Button" onclick='logMessage("clicked simple")'>
+				<img src="../images/plus.gif" width="16" height="16"> Create
+			</button>
+			<button dojoType="dijit.form.Button" onclick='logMessage("clicked simple")'>
+				<img src="../images/plus.gif" width="16" height="16"> Create
+			</button>
+		</div>
+		<div style="clear: both;"></div>
+
+		<h2>Programatically changing buttons</h2>
+		<p>clicking the buttons below will change the buttons above</p>
+		<script type="text/javascript">
+			// FIXME: doesn't the manager have a function for filtering by type?
+			function forEachButton(func){
+				var registry = dijit.util.manager.getWidgets();
+				for(var id in registry){ 
+					if(registry[id] instanceof dijit.form.Button){ 
+						func(registry[id]);
+					}
+				}
+			}
+
+			var disabled=false;
+			function toggleDisabled(){	
+				disabled=!disabled;
+				forEachButton(function(widget){ widget._setDisabled(disabled); });
+				dojo.byId("toggle").innerHTML= disabled ? "Enable all" : "Disable all";
+			}
+			var captions=["<img src='../images/note.gif' width='20' height='20'>All", "<i>work</i>", "and no", "<h1>play</h1>",
+						 "<span style='color: red'>makes</span>", "Jack", "<h3>a</h3>", "dull",
+						 "<img src='../images/plus.gif' width='16' height='16'>boy"];
+			var idx=0;
+			function changeCaptions(){
+				forEachButton(function(widget){ 
+					widget.setCaption( captions[idx++ % captions.length]); 
+				});
+			}
+		</script>
+		<div>
+			<button id="toggle" onclick='toggleDisabled()'>Disable all</button>
+			<button onclick='changeCaptions()'>Change caption</button>
+			<button onclick='location.reload()'>Revert</button>
+		</div>
+
+		<div dojoType="dijit.PopupMenu" id="editMenu" toggle="fade" toggleDuration="500" style="display: none;">
+			<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/cut.gif" caption="Cut" accelKey="Ctrl+C"
+				onClick="logMessage('not actually cutting anything, just a test!')"></div>
+			<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/copy.gif" caption="Copy" accelKey="Ctrl+X"
+				onClick="logMessage('not actually copying anything, just a test!')"></div>
+			<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/paste.gif" caption="Paste" accelKey="Ctrl+V"
+				onClick="logMessage('not actually pasting anything, just a test!')"></div>
+		</div>
+
+		<div dojoType="dijit.PopupMenu" id="saveMenu" toggle="wipe" toggleDuration="500" style="display: none;">
+			<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/save.gif" caption="Save" accelKey="Ctrl+S"
+				onClick="logMessage('not actually saving anything, just a test!')"></div>
+			<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/save.gif" caption="Save As" accelKey="Ctrl+A"
+				onClick="logMessage('not actually saving anything, just a test!')"></div>
+		</div>
+
+		<h3>Button instantiated via javacript:</h3>
+		<div id="buttonContainer"></div>
+		<script type="text/javascript">
+		// See if we can make a widget in script and attach it to the DOM ourselves.
+		dojo.addOnLoad(function(){
+			var params = {
+				caption: "hello!",
+				name: "programmatic"
+			};
+			var widget = new dijit.form.Button(params, document.getElementById("buttonContainer"));
+		});
+		</script>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Checkbox.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Checkbox.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Checkbox.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,124 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+	<title>Checkbox Widget Demo</title>
+	
+	<script type="text/javascript" src="../testBidi.js"></script>
+	
+	<script type="text/javascript" src="../../../dojo/dojo.js"
+		djConfig="isDebug: true"></script>
+	<script type="text/javascript">
+		dojo.require("dijit.form.Checkbox");
+		dojo.require("dijit.util.parser");	// find widgets
+
+		function outputValues(form){
+			var str = "";
+			for(var i=0;i<form.elements.length;i++){
+				var e = form.elements[i];
+				if(e.type=="submit") break;
+				if(e.checked){
+					str += "submit: name="+e.name+" id="+e.id+" value="+e.value+ "<br>";
+				}
+			}
+			dojo.byId("result").innerHTML = str;
+			return false;
+		}
+		
+		function reportChecked(checked) {
+			dojo.byId("oncheckedoutput").innerHTML = checked;
+		}
+		
+		function reportValueChanged(value) {
+			dojo.byId("onvaluechangedoutput").innerHTML = value;
+		}
+		
+		dojo.addOnLoad(function(){
+			var params = {id: "cb6", name: "cb6"};
+			var widget = new dijit.form.Checkbox(params, dojo.byId("checkboxContainer"));
+			widget.setChecked(true);
+		});
+	</script>
+	<style type="text/css">
+		@import "../../../dojo/resources/dojo.css";
+		@import "../../themes/tundra/tundra.css";
+		@import "../css/dijitTests.css";
+
+		label { margin-right: 0.80em; }
+	</style>
+</head>
+<body class="tundra">
+	<h1 class="testTitle">Dijit Checkbox Test</h1>
+	<p>
+	Here are some checkboxes.  Try clicking, and hovering, tabbing, and using the space bar to select:
+	</p>
+	<!--  <form onSubmit="return outputValues(this);"> -->
+	<form>
+		<input type="checkbox" name="cb0" id="cb0" />
+			<label for="cb0">cb0: Vanilla (non-dojo) checkbox (for comparison purposes)</label>
+		<br>
+		<input type="checkbox" name="cb1" id="cb1" value="foo" dojoType="dijit.form.Checkbox">
+			<label for="cb1">cb1: normal checkbox, with value=foo</label> 
+		<br>
+		<input onChecked="reportChecked" type="checkbox" name="cb2" id="cb2" dojoType="dijit.form.Checkbox" checked="checked"/>
+			<label for="cb2">cb2: normal checkbox, initially turned on.</label>
+			<span>"onChecked" handler updates: [<span id="oncheckedoutput"></span>]</span>
+		<br>
+		<input type="checkbox" name="cb3" id="cb3" dojoType="dijit.form.Checkbox" disabled="disabled">
+			<label for="cb3">cb3: disabled checkbox</label>
+		<br>
+		<input type="checkbox" name="cb4" id="cb4" dojoType="dijit.form.Checkbox" disabled="disabled" checked="checked"/>
+			<label for="cb4">cb4: disabled checkbox, turned on</label>
+		<br>
+		<input type="checkbox" name="cb5" id="cb5" />
+			<label for="cb5">cb5: Vanilla (non-dojo) checkbox (for comparison purposes)</label>
+		<br>
+		<div id="checkboxContainer"></div>
+			<label for="cb6">cb6: instantiated from script</label>
+		<br>
+		<input onValueChanged="reportValueChanged" type="checkbox" name="cb7" id="cb7" dojoType="dijit.form.Checkbox">
+			<label for="cb7">cb7: normal checkbox.</label>
+			<input type="button" onclick='dijit.byId("cb7").disable();' value="disable" />
+			<input type="button" onclick='dijit.byId("cb7").enable();' value="enable" />
+			<input type="button" onclick='dijit.byId("cb7").setValue("fish");' value='set value to "fish"' />
+			<span>"onValueChanged" handler updates: [<span id="onvaluechangedoutput"></span>]</span>
+		<br>
+	<p>
+	Here are some radio buttons.  Try clicking, and hovering, tabbing, and arrowing
+	</p>
+		<p>
+			<span>Radio group #1:</span>
+			<input type="radio" name="g1" id="g1rb1" value="news" dojoType="dijit.form.RadioButton">
+			<label for="g1rb1">news</label>
+			<input type="radio" name="g1" id="g1rb2" value="talk" dojoType="dijit.form.RadioButton" checked="checked"/>
+			<label for="g1rb2">talk</label>
+			<input type="radio" name="g1" id="g1rb3" value="weather" dojoType="dijit.form.RadioButton" disabled="disabled"/>
+			<label for="g1rb3">weather</label>
+		</p>
+		<p>
+			<span>Radio group #2: (no default value, and has breaks)</span><br>
+			<input type="radio" name="g2" id="g2rb1" value="top40" dojoType="dijit.form.RadioButton"/>
+			<label for="g2rb1">top 40</label><br>
+			<input type="radio" name="g2" id="g2rb2" value="oldies" dojoType="dijit.form.RadioButton"/>
+			<label for="g2rb2">oldies</label><br>
+			<input type="radio" name="g2" id="g2rb3" value="country" dojoType="dijit.form.RadioButton"/>
+			<label for="g2rb3">country</label><br>
+			(Note if using keyboard: tab to navigate, and use arrow or space to select)
+		</p>
+		<p>
+			<span>Radio group #3 (native radio buttons):</span>
+			<input type="radio" name="g3" id="g3rb1" value="rock"/>
+			<label for="g3rb1">rock</label>
+			<input type="radio" name="g3" id="g3rb2" value="jazz" disabled="disabled"/>
+			<label for="g3rb2">jazz</label>
+			<input type="radio" name="g3" id="g3rb3" value="classical" checked="checked"/>
+			<label for="g3rb3">classical</label>
+		</p>
+		<input type="submit" />
+	</form>
+
+	<!-- <p>Submitted data:</p>
+	<div id="result"></div>
+	 -->
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_InlineEditBox.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_InlineEditBox.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_InlineEditBox.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>Inline Edit Box Test</title>
+		
+		<script type="text/javascript" src="../testBidi.js"></script>
+		
+		<script type="text/javascript" src="../../../dojo/dojo.js"
+			djConfig="isDebug: true"></script>
+		<script type="text/javascript">
+			dojo.require("dijit.form.InlineEditBox");
+			dojo.require("dijit.form.Textarea");
+			dojo.require("dijit.form.Textbox");
+			dojo.require("dijit.form.DateTextbox");
+			dojo.require("dijit.form.Select");
+			dojo.require("dijit.util.parser");      // scan page for widgets and instantiate them
+			function myHandler(id,newValue) {
+				console.debug("onValueChanged for id = " + id + ", value: " + newValue);
+			};
+		</script>
+		<style type="text/css">
+			@import "../../../dojo/resources/dojo.css";
+			@import "../../themes/tundra/tundra.css";
+			@import "../css/dijitTests.css";
+		
+			.inlineEdit { background-color: #CCC76A; }
+		</style>
+	</head>
+	<body class="tundra">
+		<h1 class="testTitle">Dijit InlineEditBox Test</h1>
+		before
+		<span id="editable" style="font-size:larger;" dojoType="dijit.form.InlineEditBox" onValueChanged="myHandler(this.id,arguments[0])">
+			<input dojoType="dijit.form.Textbox" value="Edit me - I trigger the onValueChanged callback">
+		</span>
+		after<br>
+
+		<hr style="width:100%;">
+		<blockquote style="width:50%;">
+			<p><span id="areaEditable" dojoType="dijit.form.InlineEditBox">
+				<textarea dojoType="dijit.form.Textarea">I'm one big paragraph.  Go ahead and <i>edit</i> me.  <b>I dare you.</b> The quick brown fox jumped over the lazy dog.  Blah blah blah blah blah blah blah ...</textarea>
+			</span></p>
+		</blockquote>
+		These links will
+		<a href="#" onClick="dijit.byId('areaEditable').disable()">disable</a> /
+		<a href="#" onClick="dijit.byId('areaEditable').enable()">enable</a>
+		the text area above.
+
+		<hr style="width:100%;">
+
+		<b>Date text box:</b>
+		<p id="backgroundArea" dojoType="dijit.form.InlineEditBox" >
+			<input name="date" value="2005-12-30"
+					dojoType="dijit.form.DateTextbox"
+					constraints={datePattern:'MM/dd/yy'}
+					lang="en-us"
+					required="true"
+					promptMessage="mm/dd/yy"
+					invalidMessage="Invalid date. Use mm/dd/yy format.">
+		</p>
+		<hr style="width:100%;">
+		<b>Select:</b>
+		<span id="backgroundArea" dojoType="dijit.form.InlineEditBox" >
+			<input searchAttr="name" keyAttr="abbreviation" id="setvaluetest" dojoType="dijit.form.Select" value="IA"
+					url="autoCompleterData.json" name="state1" autocomplete="true" labelAttr="label" labelType="html"
+					dataProviderClass="dojo.data.JsonItemStore" promptMessage="Please enter a state">
+		</span>
+		<hr style="width:100%;">
+		<div style="display:block;" id="programmatic"></div>
+		<script type="text/javascript">
+			// See if we can make a widget in script
+			var refNode = dojo.byId('programmatic');
+			var editorWidget = new dijit.form.Textbox({ value: "Click here to edit a programmatically created<BR>inline edit region" }, document.createElement('span'));
+			var inlineWidget = new dijit.form.InlineEditBox({ editWidget: editorWidget }, refNode);
+		</script>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Select.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Select.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Select.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,273 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>Dojo Select Widget Test</title>
+
+<script type="text/javascript" src="../testBidi.js"></script>
+
+<script type="text/javascript"> 
+	var djConfig = {
+		isDebug: true};
+</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<script type="text/javascript">
+	dojo.require("dijit.form.Select");
+	dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+</script>
+<style>
+        @import "../../../dojo/resources/dojo.css";
+        @import "../../themes/tundra/tundra.css";
+</style>
+<script>
+	function setValue(id, val){
+		dojo.byId(id).value=val;
+	}
+	function myLabelFunc(item, store){
+		var label=store.getValue(item, 'name');
+		// DEMO: uncomment to chop off a character
+		//label=label.substr(0, label.length-1);
+		// DEMO: uncomment to set to lower case
+		label=label.toLowerCase();
+		return label;
+	}
+	myStore=new dojo.data.JsonItemStore({url:"autoCompleterData.json"});
+</script>
+</head>
+
+<body class="tundra">
+<h1>Dojo Select Widget Test</h1>
+<p>
+The Select widget is an enhanced version of HTML's &lt;select&gt; tag.
+</p>
+<p>
+Similar features:
+<ul>
+<li>There is a drop down list of possible values.</li>
+<li>You can only enter a value from the drop down list.  (You can't enter an arbitrary value.)</li>
+<li>The value submitted with the form is the hidden value (ex: CA),</li>
+<li>not the displayed value a.k.a. label (ex: California)</li>
+</ul>
+</p>
+
+<p>
+Enhancements over plain HTML version:
+<ul>
+<li>If you type in some text then it will filter down the list of possible values in the drop down list.</li>
+<li>List can be specified either as a static list or via a javascript function (that can get the list from a server)</li>
+</ul>
+</p>
+<hr>
+
+<form action="#" method="GET">
+ 
+	<p>Select #1: inlined data, autocomplete=false:</p>
+	<select searchAttr="name" 
+			keyAttr="abbreviation" 
+			id="setvaluetest2" 
+			searchLimit="Infinity" 
+			name="state1" 
+			dojoType="dijit.form.Select" 
+			style="width: 300px;" 
+			autocomplete="false" 
+			dataProviderClass="dojo.data.JsonItemStore" 
+			promptMessage="Please enter a state"
+			onValueChanged="setValue('value1', arguments[0]);" value="CA"
+	>
+		<option value="AL">Alabama</option>
+		<option value="AK">Alaska</option>
+		<option value="AS">American Samoa</option>
+		<option value="AZ">Arizona</option>
+		<option value="AR">Arkansas</option>
+		<option value="AE">Armed Forces Europe</option>
+		<option value="AP">Armed Forces Pacific</option>
+		<option value="AA">Armed Forces the Americas</option>
+		<option value="CA" selected>California</option>
+		<option value="CO">Colorado</option>
+		<option value="CT">Connecticut</option>
+		<option value="DE">Delaware</option>
+		<option value="DC">District of Columbia</option>
+		<option value="FM">Federated States of Micronesia</option>
+		<option value="FL">Florida</option>
+		<option value="GA">Georgia</option>
+		<option value="GU">Guam</option>
+		<option value="HI">Hawaii</option>
+		<option value="ID">Idaho</option>
+		<option value="IL">Illinois</option>
+		<option value="IN">Indiana</option>
+		<option value="IA">Iowa</option>
+		<option value="KS">Kansas</option>
+		<option value="KY">Kentucky</option>
+		<option value="LA">Louisiana</option>
+		<option value="ME">Maine</option>
+		<option value="MH">Marshall Islands</option>
+		<option value="MD">Maryland</option>
+		<option value="MA">Massachusetts</option>
+		<option value="MI">Michigan</option>
+		<option value="MN">Minnesota</option>
+		<option value="MS">Mississippi</option>
+		<option value="MO">Missouri</option>
+		<option value="MT">Montana</option>
+		<option value="NE">Nebraska</option>
+		<option value="NV">Nevada</option>
+		<option value="NH">New Hampshire</option>
+		<option value="NJ">New Jersey</option>
+		<option value="NM">New Mexico</option>
+		<option value="NY">New York</option>
+		<option value="NC">North Carolina</option>
+		<option value="ND">North Dakota</option>
+		<option value="MP">Northern Mariana Islands</option>
+		<option value="OH">Ohio</option>
+		<option value="OK">Oklahoma</option>
+		<option value="OR">Oregon</option>
+		<option value="PA">Pennsylvania</option>
+		<option value="PR">Puerto Rico</option>
+		<option value="RI">Rhode Island</option>
+		<option value="SC">South Carolina</option>
+		<option value="SD">South Dakota</option>
+		<option value="TN">Tennessee</option>
+		<option value="TX">Texas</option>
+		<option value="UT">Utah</option>
+		<option value="VT">Vermont</option>
+		<option value="VI">Virgin Islands, U.S.</option>
+		<option value="VA">Virginia</option>
+		<option value="WA">Washington</option>
+		<option value="WV">West Virginia</option>
+		<option value="WI">Wisconsin</option>
+		<option value="WY">Wyoming</option>
+	</select>
+	<br>
+	<div>Value: <input id="value1" disabled></div>
+	<hr>
+
+	<p>Select #2: url, autocomplete=true:</p>
+	<input searchAttr="name"
+			keyAttr="abbreviation"
+			id="setvaluetest"
+			dojoType="dijit.form.Select"
+			value="IA"
+			url="autoCompleterData.json"
+			name="state2"
+			autocomplete="true"
+			labelAttr="label"
+			labelType="html"
+			onValueChanged="setValue('value2', arguments[0]);"
+			dataProviderClass="dojo.data.JsonItemStore"
+			promptMessage="Please enter a state"
+	>
+	<br>
+	<div>Value: <input id="value2" disabled></div>
+	<hr>
+		
+	<p>Select #3: url, autocomplete=false:</p>
+ 	<input searchAttr="name"
+ 			keyAttr="abbreviation"
+ 			dojoType="dijit.form.Select"
+ 			value="VI"
+ 			url="autoCompleterData.json"
+ 			name="state3"
+ 			autocomplete="false"
+ 			labelAttr="label"
+ 			labelType="html"
+ 			onValueChanged="setValue('value3', arguments[0]);"
+ 			dataProviderClass="dojo.data.JsonItemStore"
+ 			promptMessage="Please enter a state"
+	>
+	<div>Value: <input id="value3" disabled></div>
+	<hr>
+	<p>Select #4: declarative store, autocomplete=false:</p>
+ 	<input searchAttr="name"
+ 			keyAttr="abbreviation"
+ 			dojoType="dijit.form.Select"
+ 			value="AL"
+ 			name="state4"
+ 			autocomplete="false"
+ 			labelAttr="label"
+ 			labelType="html"
+ 			store="myStore"
+ 			promptMessage="Please enter a state"
+	>
+	<br>
+	<hr>
+	<p>Select #5: custom labelFunc (value in textbox should be lower case when onValueChanged is called), autocomplete=true:</p>
+ 	<input searchAttr="name"
+ 			keyAttr="abbreviation"
+ 			dojoType="dijit.form.Select"
+ 			value="OR"
+ 			labelFunc="myLabelFunc"
+ 			url="autoCompleterData.json"
+ 			name="state5"
+ 			autocomplete="true"
+ 			labelAttr="label"
+ 			labelType="html"
+ 			dataProviderClass="dojo.data.JsonItemStore"
+ 			promptMessage="Please enter a state"
+	>
+	<br>
+	<hr>
+	<p>Select #6: No promptMessage, labelType=text</p>
+	<p>Select an item from the list.  You shouldn't get an error.</p>
+	<input
+		dojoType="dijit.form.Select"
+		store="myStore"
+		searchAttr="name"
+		keyAttr="abbreviation"
+		labelAttr="label"
+		labelType="text"
+		value="KY"
+	>
+	<br>
+	<hr>
+	<p>Select #7: Input method editor Chinese characters</p>
+	<p>Using an input method editor (see <a href="http://www.microsoft.com/windows/ie/ie6/downloads/recommended/ime/default.mspx">IME</a> for Windows) try typing &#38463; (a) or &#25226; (ba).</p>
+
+	<select dojoType="dijit.form.Select"
+		searchAttr="name"
+		keyAttr="abbreviation"
+		name="state7"
+		value="a"
+	>
+		<option value="a">&#38463;</option>
+		<option value="ba">&#25226;</option>
+	</select>
+	<br>
+	<hr>
+	<p>Select #8: Japanese</p>
+	<p>Try typing 東、西、北、南  (north, south, east west) and a few choices will pop up.</p>
+	 
+	<select name="state3" dojoType="dijit.form.Select" style="width: 300px;" autocomplete="false"
+		onValueChanged="setValue('value8', arguments[0]);">
+		<option value="nanboku">南北</option>
+		<option value="touzai">東西</option>
+		<option value="toukyou">東京</option>
+		<option value="higashiguchi">東口</option>
+		<option value="nishiguchi">西口</option>
+		<option value="minamiguchi">南口</option>
+		<option value="kitaguchi">北口</option>
+		<option value="higashiku">東区</option>
+		<option value="nishiku">西区</option>
+		<option value="minamiku">南区</option>
+		<option value="kitaku">北区</option>
+	</select>    
+	<br>
+	<div>Value: <input id="value8" disabled></div>
+	<hr>
+
+	<input type="submit">
+</form>
+<p>
+this is some text below the combo boxes. It shouldn't get pushed out of the way when search results get returned.
+also: adding a simple combo box to test IE bleed through problem:
+</p>
+
+<select>
+  <option>test for</option>
+  <option">IE bleed through</option>
+  <option>problem</option>
+</select>
+
+<!-- maintain state of select if user presses back/forward button -->
+<form name="_dojo_form" style="display:none" disabled="true"><textarea name="stabile" cols="80" rows="10"></textarea></form>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Spinner.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Spinner.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Spinner.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>Dojo Spinner Widget Test</title>
+		
+		<script type="text/javascript" src="../testBidi.js"></script>
+		
+		<script type="text/javascript" src="../../../dojo/dojo.js"
+			djConfig="isDebug: true, extraLocale: ['de-de', 'en-us']"></script>
+		<script type="text/javascript">
+			dojo.require("dijit.form.NumberSpinner");
+			dojo.require("dijit.util.parser"); // scan page for widgets
+		</script>
+		<style type="text/css">
+			@import "../../../dojo/resources/dojo.css";
+			@import "../../themes/tundra/tundra.css";
+			@import "../css/dijitTests.css";
+	
+			#integerspinner2 .dojoSpinnerUpArrow {
+				border-bottom-color: blue;
+			}
+			#integerspinner2 .dojoSpinnerDownArrow {
+				border-top-color: red;
+			}
+			#integerspinner2 .dojoSpinnerButton {
+				background-color: yellow;
+			}
+			#integerspinner2 .dojoSpinnerButtonPushed {
+				background-color: gray;
+			}
+			#integerspinner2 .dojoSpinnerButtonPushed .dojoSpinnerDownArrow {
+				border-top-color: blue;
+			}
+			#integerspinner2 .dojoSpinnerButtonPushed .dojoSpinnerUpArrow {
+				border-bottom-color: red;
+			}
+			.dojoInputFieldValidationNormal#integerspinner2 {
+				color:blue;
+				background-color:pink;
+			}
+		</style>
+	</head>
+
+	<body class=tundra>
+		<h1 class="testTitle">Dijit Spinner Test</h1>
+		Try typing values, and use the up/down arrow keys and/or the arrow push
+		buttons to spin
+		<br>
+		<h1>number spinner</h1>
+		<br>
+		initial value=900, no delta specified, no min specified, max=1550, onValueChanged debug message<br>
+		<input dojoType="dijit.form.NumberSpinner" 
+			onValueChanged="console.debug('onValueChanged fired for widget id = ' + this.id + ' with value = ' + arguments[0]);"
+			value="900" 
+			constraints="{max:1550,places:0}"
+			maxlength="20" 
+			id="integerspinner1">
+		<br>
+		<br>
+		initial value=1000, delta=10, min=9 max=1550<br>
+		with custom styling:<input dojoType="dijit.form.NumberSpinner"
+			style="font-size:20pt;border:1px solid blue;position:relative;left:30px;"
+			value="1000" 
+			smallDelta="10" 
+			constraints="{min:9,max:1550,places:0}"
+			maxlength="20" 
+			id="integerspinner2">
+		<br>
+		<br>
+		initial value not specified, delta not specified, min not specified, max not specified, signed not specified, separator not specified<br>
+		[verify no line break just after this text]<input dojoType="dijit.form.NumberSpinner" id="integertextbox3">[verify no line break just before this text]
+		<br>
+		<br>
+		Move the cursor left and right within the input field to see the effect on the spinner.
+		<br>
+		initial value=+1.0, delta=0.1, min=-10.9, max=155, places=1<br>
+		<input dojoType="dijit.form.NumberSpinner"
+			value="1.0"
+			smallDelta="0.1" 
+			constraints={min:-10.9,max:155,places:1,round:true}
+			maxlength="20" 
+			id="realspinner1">
+		<br>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Textarea.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Textarea.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_Textarea.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>Dojo Textarea Widget Demo</title>
+		
+		<script type="text/javascript" src="../testBidi.js"></script>
+		
+		<script type="text/javascript" src="../../../dojo/dojo.js"
+			djConfig="isDebug: true, debugAtAllCosts: true"></script>
+		<script type="text/javascript">
+			dojo.require("dijit.form.Textarea");
+			dojo.require("dijit.util.parser");
+		</script>
+		<style type="text/css">
+			@import "../../../dojo/resources/dojo.css";
+			@import "../../themes/tundra/tundra.css";
+			@import "../css/dijitTests.css";
+		</style>
+
+	</head>
+	<body class="tundra">
+		<h2 class="pageSubContentTitle">Test Auto-sizing Textarea Widget</h2>
+
+		<form id="form1" action="" name="example" method="post">
+		<textarea name="plainTextArea" rows=5>
+			this is a plain text area
+			for comparison
+		</textarea>
+		<script type="text/javascript">
+			// See if we can make a widget in script
+			var refNode = document.createElement('span');
+			dojo.byId('form1').appendChild(refNode);
+			var w = new dijit.form.Textarea({ 
+					name: "programmaticTextArea", 
+					value: "test value" 
+				}, refNode);
+			w.setValue('we will create this one programatically');
+		</script>
+		<div name="simpleTextArea" dojoType="dijit.form.Textarea" style="width:33%;border:20px solid red;">
+			this is a very simple resizable text area
+		</div>
+		<textarea dojoType="dijit.form.Textarea" name="largeTextArea">
+this is a textarea with a LOT of content
+
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+		</textarea>
+			<script type="text/javascript">
+				function displayData() {
+					var f = dojo.byId("form1");
+					var s = "";
+					for(var i = 0; i < f.elements.length; i++){
+						var elem = f.elements[i];
+						if(elem.name == "button" || !dojo.isString(elem.value)){ continue; }
+						s += elem.name + ":[" + elem.value + "]\n";
+					}
+					alert(s);
+				}
+			</script>
+			<div>
+				<button name="button" onclick="displayData(); return false;">view data</button>
+				<input type="submit" name="submit" />
+			</div>
+
+		</form>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_validate.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_validate.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/form/test_validate.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,518 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>Test Textbox Validation Widgets</title>
+
+		<script type="text/javascript" src="../testBidi.js"></script>
+
+		<script type="text/javascript" src="../../../dojo/dojo.js"
+			djConfig="isDebug: false, extraLocale: ['de-de', 'en-us']"></script>
+		<script type="text/javascript">
+			dojo.require("dijit.form.Textbox");
+			dojo.require("dijit.form.ValidationTextbox");
+			dojo.require("dijit.form.NumberTextbox");
+			dojo.require("dijit.form.CurrencyTextbox");
+			dojo.require("dijit.form.DateTextbox");
+//			dojo.require("dojo.validate.common");
+//			dojo.require("dojo.validate.us");
+			dojo.require("dojo.currency");
+			dojo.require("dojo.date.locale");
+			dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+		</script>
+		<style type="text/css">
+			@import "../../../dojo/resources/dojo.css";
+			@import "../../themes/tundra/tundra.css";
+			@import "../css/dijitTests.css";
+			
+			.testExample {
+				background-color:#fbfbfb;
+				padding:1em;
+				margin-bottom:1em;
+				border:1px solid #bfbfbf;
+			}
+			
+			
+			.small {
+				width: 2.5em;
+			}
+			.medium {
+				width: 10em;
+			}
+			.long {
+				width: 20em;
+			}
+	
+		
+			.noticeMessage {
+				color:#093669;
+				font-size:0.95em;
+				margin-left:0.5em;
+			}
+			
+			.dojoTitlePaneLabel label {
+				font-weight:bold;
+			}
+			
+		</style>
+	</head>
+
+	<body class="tundra">
+		<h1 class="testTitle">Dijit Validation Widgets</h1>
+		<!--	to test form submission, you'll need to create an action handler similar to
+			http://www.utexas.edu/teamweb/cgi-bin/generic.cgi -->
+		<form id="form1" action="" name="example" method="post">
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q01">First Name:  </label>
+				<span class="noticeMessage"> Textbox class, <b>tabIndex=2</b>, Attributes: {trim: true, propercase: true, class: 'medium'}, First letter of each word is upper case.</span>
+			</div>
+			<div class="testExample">
+				<input id="q01" type="text" name="firstname" value="testing testing" class="medium" tabIndex=2
+					dojoType="dijit.form.Textbox"
+					trim="true" 
+					propercase="true" />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q02">Last Name:  </label>
+				<span class="noticeMessage"> Textbox class, Attributes: {trim: true, uppercase: true, class: 'medium'}, all letters converted to upper case. </span>
+			</div>
+			<div class="testExample">
+				<input id="q02" type="text" name="lastname" value="testing testing" class="medium"
+					dojoType="dijit.form.Textbox"
+					trim="true" 
+					uppercase="true" />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q03">Age:  </label>
+				<span class="noticeMessage"> Textbox class, <b>tabIndex=1</b>, Attributes: {trim: true, digit: true, class: 'small'}, all but digits extracted.</span>
+			</div>
+			<div class="testExample">
+				<input id="q03" type="text" name="age" value="38" tabIndex=1
+					dojoType="dijit.form.NumberTextbox"
+					promptMessage="(optional) Enter an age between 0 and 120"
+					size=4
+					maxlength=3
+					constraints={places:0,min:0,max:120}
+					onValueChanged="console.debug('onValueChanged fired for widget id = ' + this.id + ' with value = ' + arguments[0]);"
+					trim="true" 
+					/>
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q04">Occupation:  </label>
+				<span class="noticeMessage">ValidationTextbox class, 
+					Attributes: {lowercase: true, required: true}. Displays a prompt message if field is missing. </span>
+			</div>
+			<div class="testExample">
+				<input id="q04" type="text" name="occupation" class="medium"
+					dojoType="dijit.form.ValidationTextbox"
+					lowercase="true" 
+					required="true"
+					promptMessage="Enter an occupation" />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q05">Elevation:  </label>
+				<span class="noticeMessage">IntegerTextbox class, 
+					Attributes: {required: true, min:-20000, max:+20000 }, Enter feet above sea level with a sign.</span>
+			</div>
+			<div class="testExample">
+				<input id="q05" class="medium"/>
+			</div>
+<script>
+	// See if we can make a widget in script and attach it to the DOM ourselves.
+	dojo.addOnLoad(function(){
+		var props = {
+			name: "elevation",
+			value: 3000,
+			constraints: {min:-20000,max:20000,places:0},
+			promptMessage: "Enter a value between -20000 and +20000",
+			required: "true" ,
+			invalidMessage: "Invalid elevation."
+		};
+		var refNode = document.getElementById("q05");
+
+		var w = new dijit.form.NumberTextbox(props, refNode);
+	});
+</script>
+<!-- 
+			<div class="dojoTitlePaneLabel">
+				<label for="attach-here">Population:  </label>
+				<span class="noticeMessage">IntegerTextbox class, 
+					Attributes: {trim: true, required: true, signed: false, separator: ","}. <br><b> This widget was added in script, not markup. </b> </span>
+			</div>
+			<div class="testExample" >
+				<input id="attach-here" type="text" name="population" class="medium" value="1500000"/>
+			</div>
+
+<script>
+	// See if we can make a widget in script and attach it to the DOM ourselves.
+	dojo.addOnLoad(function(){
+		var props = {
+			name: "population",
+			value: "1,500,000",
+			trim: "true",
+			required: "true",
+			regExpGen: dojo.regexp.integer,
+			constraints: {signed:false, separator: ","},
+			invalidMessage: "Invalid population.  Be sure to use commas."
+		};
+		var refNode = document.getElementById("attach-here");
+
+		var w = new dijit.form.ValidationTextbox(props, refNode);
+	});
+</script>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q06">Real Number:  </label>
+				<span class="noticeMessage">RealNumberTextbox class, 
+					Attributes: {trim: true, required: true}. Enter any sort of real number.</span>
+			</div>
+			<div class="testExample">
+				<input id="q06" type="text" name="real1" class="medium" value="+0.1234"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.realNumber"
+					trim="true" 
+					required="true" 
+					invalidMessage="This is not a valid real number." />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q07">Exponential Notation:  </label>
+				<span class="noticeMessage">RealNumberTextbox class, 
+					Attributes: {exponent: true}. Enter a real number in exponential notation.</span>
+			</div>
+			<div class="testExample">
+				<input id="q07" type="text" name="real2" class="medium" value="+0.12"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.realNumber"
+					trim="true" 
+					required="true" 
+					constraints={exponent:true}
+					invalidMessage="Number must be in exponential notation. Example +5E-28" />
+			</div>
+-->
+			<div class="dojoTitlePaneLabel">
+				<label for="q08">Annual Income:  </label>
+				<span class="noticeMessage">CurrencyTextbox class, 
+					Attributes: {fractional: true}. Enter whole and cents.  Currency symbol is optional.</span>
+			</div>
+			<div class="testExample">
+				<input id="q08" type="text" name="income1" class="medium" value="54775.53"
+					dojoType="dijit.form.CurrencyTextbox"
+					required="true" 
+					currency="USD"
+					invalidMessage="Invalid amount.  Include dollar sign, commas, and cents." />USD
+			</div>
+
+			<div class="testExample">
+				euro currency (locale de-de) programmatically created: <input id="q08eur" class="medium"/>EUR
+			</div>
+<script>
+	// See if we can make a widget in script and attach it to the DOM ourselves.
+	var example = dojo.currency.format(54775.53, {locale: 'de-de', currency: "EUR"});
+	dojo.addOnLoad(function(){
+		var props = {
+			name: "income2",
+			value: 54775.53,
+			constraints: {locale: 'de-de'},
+			lang: 'de-de',
+			required: "true",
+			currency: "EUR",
+			invalidMessage: "Invalid amount.  Example: " + example
+		};
+		var w = new dijit.form.CurrencyTextbox(props, "q08eur");
+	});
+</script>
+<!-- 
+			<div class="dojoTitlePaneLabel">
+				<label for="q08a">Annual Income:  </label>
+				<span class="noticeMessage">Old regexp currency textbox, 
+					Attributes: {fractional: true}. Enter dollars and cents.</span>
+			</div>
+			<div class="testExample">
+				<input id="q08a" type="text" name="income3" class="medium" value="$54,775.53"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.currency"
+					trim="true" 
+					required="true" 
+					constraints={fractional:true}
+					invalidMessage="Invalid amount.  Include dollar sign, commas, and cents. Example: $12,000.00" />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q09">IPv4 Address:  </label>
+				<span class="noticeMessage">IpAddressTextbox class, 
+					Attributes: {allowIPv6: false, allowHybrid: false}. Also Dotted Hex works, 0x18.0x11.0x9b.0x28</span>
+			</div>
+			<div class="testExample">
+				<input id="q09" type="text" name="ipv4" class="medium" value="24.17.155.40"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.ipAddress"
+					trim="true" 
+					required="true" 
+					constraints={allowIPv6:false,allowHybrid:false}
+					invalidMessage="Invalid IPv4 address." />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q10"> IPv6 Address:  </label>
+				<span class="noticeMessage">IpAddressTextbox class, 
+					Attributes: {allowDottedDecimal: false, allowDottedHex: false}. 
+					Also hybrid works, x:x:x:x:x:x:d.d.d.d</span>
+			</div>
+			<div class="testExample">
+				<input id="q10" type="text" name="ipv6" class="long" value="0000:0000:0000:0000:0000:0000:0000:0000"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.ipAddress"
+					trim="true" 
+					uppercase = "true" 
+					required="true" 
+					constraints={allowDottedDecimal:false, allowDottedHex:false, allowDottedOctal:false}
+					invalidMessage="Invalid IPv6 address, please enter eight groups of four hexadecimal digits. x:x:x:x:x:x:x:x" />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q11"> URL:  </label>
+				<span class="noticeMessage">UrlTextbox class, 
+					Attributes: {required: true, trim: true, scheme: true}. </span>
+			</div>
+			<div class="testExample">
+				<input id="q11" type="text" name="url" class="long" value="http://www.xyz.com/a/b/c?x=2#p3"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.url"
+					trim="true" 
+					required="true" 
+					constraints={scheme:true}
+					invalidMessage="Invalid URL.  Be sure to include the scheme, http://..." />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q12"> Email Address  </label>
+				<span class="noticeMessage">EmailTextbox class, 
+					Attributes: {required: true, trim: true}. </span>
+			</div>
+			<div class="testExample">
+				<input id="q12" type="text" name="email" class="long" value="fred&barney at stonehenge.com"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.emailAddress"
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid Email Address." />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q13"> Email Address List </label>
+				<span class="noticeMessage">EmailListTextbox class, 
+					Attributes: {required: true, trim: true}. </span>
+			</div>
+			<div class="testExample">
+				<input id="q13" type="text" name="email" class="long" value="a at xyz.com; b at xyz.com; c at xyz.com; "
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.emailAddressList"
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid Email Address List." />
+			</div>
+-->
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q14"> Date (American format) </label>
+				<span class="noticeMessage">DateTextbox class, 
+					Attributes: {lang: "en-us", required: true}. Works for leap years</span>
+			</div>
+			<div class="testExample">
+				<input id="q14" type="text" name="date1" class="medium" value="2005-12-30"
+					dojoType="dijit.form.DateTextbox"
+					constraints={min:'2005-01-01',max:'2006-12-31',datePattern:'MM/dd/y'}
+					lang="en-us"
+					required="true"
+					promptMessage="mm/dd/yyyy"
+					invalidMessage="Invalid date. Use mm/dd/yyyy format." />
+				<input type="button" value="Destroy" onClick="dijit.byId('q14').destroy(); return false;">
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q15"> Date (German format) </label>
+				<span class="noticeMessage">DateTextbox class, 
+					Attributes: {lang: "de-de", min:2006-01-01, max:2006-12-31}. Works for leap years</span>
+			</div>
+			<div class="testExample">
+				<input id="q15" class="medium"/>
+			</div>
+<script>
+	// See if we can make a widget in script and attach it to the DOM ourselves.
+	dojo.addOnLoad(function(){
+		var props = {
+			name: "date2",
+			value: new Date(2006,10,29),
+			constraints: {min:new Date(2006,0,1),max:new Date(2006,11,31)},
+			lang: "de-de",
+			promptMessage: "dd.mm.yy",
+			rangeMessage: "Enter a date in 2006.",
+			invalidMessage: "Invalid date. Use dd.mm.yy format."
+		};
+		var refNode = document.getElementById("q15");
+
+		var w = new dijit.form.DateTextbox(props, refNode);
+	});
+</script>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q16"> 12 Hour Time </label>
+				<span class="noticeMessage">TimeTextbox class, 
+					Attributes: {formatLength: "medium", required: true, trim: true}</span>
+			</div>
+			<div class="testExample">
+				<input id="q16" type="text" name="time1" class="medium" value="5:45:00 pm"
+					dojoType="dijit.form.ValidationTextbox"
+					validator="dojo.date.locale.parse"
+					constraints={formatLength:'medium',selector:'time'}
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid time." />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q17"> 24 Hour Time</label>
+				<span class="noticeMessage">TimeTextbox class, 
+					Attributes: {displayFormat:"HH:mm:ss", required: true, trim: true}</span>
+			</div>
+			<div class="testExample">
+				<input id="q17" type="text" name="time2" class="medium" value="17:45:00"
+					dojoType="dijit.form.ValidationTextbox"
+					validator="dojo.date.locale.parse"
+					constraints={formatLength:'short',selector:'time',timePattern:'HH:mm:ss'}
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid time. Use HH:mm:ss where HH is 00 - 23 hours." />
+			</div>
+
+<!-- 
+			<div class="dojoTitlePaneLabel">
+				<label for="q18"> US State 2 letter abbr. </label>
+				<span class="noticeMessage">UsStateTextbox class, 
+					Attributes: {required: true, trim: true, uppercase: true}</span>
+			</div>
+			<div class="testExample">
+				<input id="q18" type="text" name="state" class="small" value="CA"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.us.state"
+					constraints={allowTerritories:false}
+					trim="true" 
+					uppercase="true" 
+					required="true" 
+					invalidMessage="Invalid US state abbr." />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q19"> US Zip Code </label>
+				<span class="noticeMessage">UsZipTextbox class, 
+					Attributes: {required: true, trim: true} Five digit Zip code or 5 + 4.</span>
+			</div>
+			<div class="testExample">
+				<input id="q19" type="text" name="zip" class="medium" value="98225-1649"
+					dojoType="dijit.form.ValidationTextbox"
+					validator="dojo.validate.us.isZipCode"
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid US Zip Code." />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q20"> US Social Security Number </label>
+				<span class="noticeMessage">UsSocialSecurityNumberTextbox class, 
+					Attributes: {required: true, trim: true} </span>
+			</div>
+			<div class="testExample">
+				<input id="q20" type="text" name="ssn" class="medium" value="123-45-6789"
+					dojoType="dijit.form.ValidationTextbox"
+					validator="dojo.validate.us.isSocialSecurityNumber"
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid US Social Security Number." />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q21"> 10-digit US Phone Number </label>
+				<span class="noticeMessage">UsPhoneNumberTextbox class, 
+					Attributes: {required: true, trim: true} </span>
+			</div>
+			<div class="testExample">
+				<input id="q21" type="text" name="phone" class="medium" value="(123) 456-7890"
+					dojoType="dijit.form.ValidationTextbox"
+					validator="dojo.validate.us.isPhoneNumber"
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid US Phone Number." />
+			</div>
+ -->
+			<div class="dojoTitlePaneLabel">
+				<label for="q22"> Regular Expression </label>
+				<span class="noticeMessage">RegexpTextbox class, 
+					Attributes: {required: true} </span>
+			</div>
+			<div class="testExample">
+				<input id="q22" type="text" name="phone" class="medium" value="someTestString"
+					dojoType="dijit.form.ValidationTextbox"
+					regExp="[\w]+"
+					required="true" 
+					invalidMessage="Invalid Non-Space Text." />
+			</div>
+
+			<div class="dojoTitlePaneLabel">
+				<label for="q23"> Password </label>
+				<span class="noticeMessage">(just a test that type attribute is obeyed) </span>
+			</div>
+			<div class="testExample">
+				<input id="q23" type="password" name="password" class="medium"
+					dojoType="dijit.form.Textbox" />
+			</div>
+
+                        <div class="dojoTitlePaneLabel">
+                                <label for="ticket1651">Trac ticket 1651:  </label>
+                                <span class="noticeMessage">value: null should show up as empty</span>
+                        </div>
+                        <div class="testExample">
+                                <input id="ticket1651" class="medium" value="not null"/>
+                        </div>
+
+<script>
+        // See if we can make a widget in script and attach it to the DOM ourselves.
+        dojo.addOnLoad(function(){
+                var props = {
+                        name: "ticket1651",
+                        id: "mname",
+                        value: null
+                };
+                var refNode = document.getElementById("ticket1651");
+
+                var w = new dijit.form.Textbox(props, refNode);
+        });
+</script>
+<script>
+	function displayData() {
+		var f = document.getElementById("form1");
+		var s = "";
+		for (var i = 0; i < f.elements.length; i++) {
+			var elem = f.elements[i];
+			if (elem.name == "button")  { continue; }
+			s += elem.name + ": " + elem.value + "\n";
+		}
+		alert(s);
+	}
+</script>
+
+			<div>
+			<button name="button" onclick="displayData(); return false;">view data</button>
+			<input type="submit" name="submit" />
+			</div>
+
+		</form>
+	</body>
+</html>
+
+

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/images/arrowSmall.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/tests/images/arrowSmall.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/images/flatScreen.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/tests/images/flatScreen.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/images/note.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/tests/images/note.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/images/plus.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/tests/images/plus.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/images/testsBodyBg.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/tests/images/testsBodyBg.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/images/tube.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/tests/images/tube.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/images/tubeTall.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/tests/images/tubeTall.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/layout/doc0.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/layout/doc0.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/layout/doc0.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,16 @@
+<script>
+ 	dojo.require("dijit.form.ComboBox");
+ 	dojo.require("dijit.form.Button");
+</script>
+<h1>Document 0</h1>
+This document has <a href="http://www.dojotoolkit.org/">a link</a>.<br />
+(to check we're copying children around properly).<br />
+Also it's got a widget, a combo box:<br>
+<select dojoType="dijit.form.Combobox">
+	<option value="1">foo</option>
+	<option value="2">bar</option>
+	<option value="3">baz</option>
+</select>
+And a button too:
+<button dojoType="dijit.form.Button">hello!</button>
+Here's some text that comes AFTER the button.
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/layout/doc1.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/layout/doc1.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/layout/doc1.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,13 @@
+<!-- Used from test_RemotePane.html -->
+
+<h1> Document 1</h1>
+
+<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus risus. Praesent eu lacus et enim laoreet sollicitudin. Quisque mollis mi a lectus. Cras ante. Aliquam tempus justo laoreet justo. Vestibulum egestas feugiat nisi. Nulla ultrices consequat felis. Curabitur dignissim augue vel enim. Fusce tempus tempor mauris. Praesent suscipit pede in nunc. Duis mi neque, malesuada non, volutpat et, nonummy et, ante. Aliquam neque. Nulla rhoncus, turpis eget mattis molestie, magna nulla dictum ligula, quis tempor odio justo vel pede. Donec sit amet tellus. Phasellus sapien. Nulla id massa at nunc condimentum fringilla. Fusce suscipit ipsum et lorem consequat pulvinar. Quisque lacinia sollicitudin tellus.</p>
+
+<p>Nulla massa lectus, porttitor vitae, dignissim vel, iaculis eget, mi. Vestibulum sed lorem. Nullam convallis elit id leo. Aliquam est purus, rutrum at, sodales non, nonummy a, justo. Proin at diam vel nibh dictum rhoncus. Duis nisl. Etiam orci. Integer hendrerit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In ac erat. Sed velit orci, sodales quis, commodo ut, elementum sed, nibh. Cras mattis vulputate nisl. Mauris eu nulla sed orci dignissim laoreet. Morbi commodo, est vitae pharetra ullamcorper, ante nisl ultrices velit, sit amet vulputate turpis elit id lacus. Vestibulum diam. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
+
+<p>Praesent rutrum nunc quis felis. Morbi tempor. Quisque porta magna imperdiet magna. Ut gravida, ipsum eu euismod consectetuer, nisl lectus posuere diam, vel dignissim elit nisi sit amet lorem. Curabitur non nunc. Morbi metus. Nulla facilisi. Sed et ante. Etiam ac lectus. Duis tristique molestie sem. Pellentesque nec quam. Nullam pellentesque ullamcorper sem.</p>
+
+<p>Duis ut massa eget arcu porttitor pharetra. Curabitur malesuada nisi id eros. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Vivamus massa. Donec quis justo ut tortor faucibus suscipit. Vivamus commodo neque eget nulla. Donec imperdiet lacus condimentum justo. In sollicitudin magna vitae libero. Curabitur scelerisque libero et eros imperdiet cursus. Maecenas adipiscing. Integer imperdiet, neque ut fringilla semper, leo nisi tincidunt enim, id accumsan leo nisi a libero. Morbi rutrum hendrerit eros. Vestibulum eget augue vel urna congue faucibus.</p>
+
+<p>Morbi ante sapien, consequat non, consectetuer vitae, pharetra non, dui. Cras tempus posuere quam. Vestibulum quis neque. Duis lobortis urna in elit. Aliquam non tellus. Etiam nisi eros, posuere vel, congue id, fringilla in, risus. Duis semper rutrum risus. Nullam felis massa, lobortis sit amet, posuere tempor, mattis id, tellus. Nulla id arcu interdum risus commodo tincidunt. Vivamus pretium pulvinar pede. Vivamus eget erat. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam bibendum, enim eu venenatis tempor, nunc elit convallis tortor, sit amet vulputate turpis arcu eu pede. Praesent molestie, lacus sed vehicula convallis, enim pede fringilla nunc, at porttitor justo ante a diam. Nunc magna eros, interdum vel, varius eget, volutpat eu, orci. Nunc nec mauris. Nulla facilisi. Vivamus dictum elementum risus. Nam placerat arcu.</p>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/layout/doc2.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/layout/doc2.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/layout/doc2.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,13 @@
+<!-- Used from test_RemotePane.html -->
+
+<h1> Document 2</h1>
+
+<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus risus. Praesent eu lacus et enim laoreet sollicitudin. Quisque mollis mi a lectus. Cras ante. Aliquam tempus justo laoreet justo. Vestibulum egestas feugiat nisi. Nulla ultrices consequat felis. Curabitur dignissim augue vel enim. Fusce tempus tempor mauris. Praesent suscipit pede in nunc. Duis mi neque, malesuada non, volutpat et, nonummy et, ante. Aliquam neque. Nulla rhoncus, turpis eget mattis molestie, magna nulla dictum ligula, quis tempor odio justo vel pede. Donec sit amet tellus. Phasellus sapien. Nulla id massa at nunc condimentum fringilla. Fusce suscipit ipsum et lorem consequat pulvinar. Quisque lacinia sollicitudin tellus.</p>
+
+<p>Nulla massa lectus, porttitor vitae, dignissim vel, iaculis eget, mi. Vestibulum sed lorem. Nullam convallis elit id leo. Aliquam est purus, rutrum at, sodales non, nonummy a, justo. Proin at diam vel nibh dictum rhoncus. Duis nisl. Etiam orci. Integer hendrerit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In ac erat. Sed velit orci, sodales quis, commodo ut, elementum sed, nibh. Cras mattis vulputate nisl. Mauris eu nulla sed orci dignissim laoreet. Morbi commodo, est vitae pharetra ullamcorper, ante nisl ultrices velit, sit amet vulputate turpis elit id lacus. Vestibulum diam. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
+
+<p>Praesent rutrum nunc quis felis. Morbi tempor. Quisque porta magna imperdiet magna. Ut gravida, ipsum eu euismod consectetuer, nisl lectus posuere diam, vel dignissim elit nisi sit amet lorem. Curabitur non nunc. Morbi metus. Nulla facilisi. Sed et ante. Etiam ac lectus. Duis tristique molestie sem. Pellentesque nec quam. Nullam pellentesque ullamcorper sem.</p>
+
+<p>Duis ut massa eget arcu porttitor pharetra. Curabitur malesuada nisi id eros. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Vivamus massa. Donec quis justo ut tortor faucibus suscipit. Vivamus commodo neque eget nulla. Donec imperdiet lacus condimentum justo. In sollicitudin magna vitae libero. Curabitur scelerisque libero et eros imperdiet cursus. Maecenas adipiscing. Integer imperdiet, neque ut fringilla semper, leo nisi tincidunt enim, id accumsan leo nisi a libero. Morbi rutrum hendrerit eros. Vestibulum eget augue vel urna congue faucibus.</p>
+
+<p>Morbi ante sapien, consequat non, consectetuer vitae, pharetra non, dui. Cras tempus posuere quam. Vestibulum quis neque. Duis lobortis urna in elit. Aliquam non tellus. Etiam nisi eros, posuere vel, congue id, fringilla in, risus. Duis semper rutrum risus. Nullam felis massa, lobortis sit amet, posuere tempor, mattis id, tellus. Nulla id arcu interdum risus commodo tincidunt. Vivamus pretium pulvinar pede. Vivamus eget erat. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam bibendum, enim eu venenatis tempor, nunc elit convallis tortor, sit amet vulputate turpis arcu eu pede. Praesent molestie, lacus sed vehicula convallis, enim pede fringilla nunc, at porttitor justo ante a diam. Nunc magna eros, interdum vel, varius eget, volutpat eu, orci. Nunc nec mauris. Nulla facilisi. Vivamus dictum elementum risus. Nam placerat arcu.</p>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/layout/tab1.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/layout/tab1.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/layout/tab1.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,6 @@
+
+<h1>Tab 1</h1>
+
+<p>I am tab 1. I was loaded externally.</p>
+
+<div label="foo!">blah</div>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/layout/tab2.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/layout/tab2.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/layout/tab2.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,3 @@
+<h1>Tab 2</h1>
+
+<p>I am tab 2. I was loaded externally as well.</p>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_AccordionContainer.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_AccordionContainer.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_AccordionContainer.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,149 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>Accordion Widget Demo</title>
+		<style type="text/css">
+			@import "../../../dojo/resources/dojo.css";
+			@import "../../themes/tundra/tundra.css";
+			@import "../css/dijitTests.css";
+		</style>		
+		
+		<script type="text/javascript" src="../testBidi.js"></script>
+		
+		<script type="text/javascript" 
+			djConfig="isDebug: true"
+			src="../../../dojo/dojo.js"></script>
+		<!--
+			uncomment for profiling
+		<script type="text/javascript" 
+			src="../../../dojo/_base/html.js"></script>
+		<script type="text/javascript" 
+			src="../../base/Layout.js"></script>
+		-->
+		<script type="text/javascript">
+			dojo.require("dijit.layout.AccordionContainer");
+			dojo.require("dijit.layout.ContentPane");
+			dojo.require("dijit.layout.SplitContainer");
+//		 	dojo.require("dijit.form.ComboBox");
+		 	dojo.require("dijit.form.Button");
+			dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+		</script>
+		
+		<!-- programatic creation -->
+		<script>
+			var accordion;
+		
+			function init(){
+				accordion = new dijit.layout.AccordionContainer({}, dojo.byId("accordionShell"));
+				var label=[ "pane 1", "pane 2", "pane 3" ];
+				for(i=0; i<label.length; ++i){
+					// add a node that will be promoted to the content widget
+					var refNode = document.createElement("span");
+					document.body.appendChild(refNode);
+					var content = new dijit.layout.ContentPane({label: label[i], selected: i==1}, refNode);
+					content.setContent("this is " + label[i]);
+					console.debug("adding content pane " + content.id);
+					accordion.addChild(content);
+				}
+				accordion.startup();
+			}
+			dojo.addOnLoad(init);
+			
+			function destroyChildren(){
+				accordion.destroyDescendants();
+			}
+		</script>
+	</head>
+	<body style="padding: 50px;" class="tundra">
+
+		<h2>Accordion from markup:</h2>
+		<p>HTML before</p>
+		<p>HTML before</p>
+		<p>HTML before</p>
+
+		<div dojoType="dijit.layout.AccordionContainer" duration="200" 
+			style="float: left; margin-right: 30px;  width: 400px; height: 300px; overflow: hidden">
+			<div dojoType="dijit.layout.ContentPane" selected="true" 
+				label="Pane 1 " style="overflow: scroll;"
+				onShow="console.debug('pane 1 shown');" onHide="console.debug('pane 1 hidden');" >
+				<select>
+					<option>red</option>
+					<option>blue</option>
+					<option>green</option>
+				</select>
+				<p>
+					Nunc consequat nisi vitae quam. Suspendisse sed nunc. Proin
+					suscipit porta magna. Duis accumsan nunc in velit. Nam et nibh.
+					Nulla facilisi. Cras venenatis urna et magna. Aenean magna mauris,
+					bibendum sit amet, semper quis, aliquet nec, sapien.  Aliquam
+					aliquam odio quis erat. Etiam est nisi, condimentum non, lacinia
+					ac, vehicula laoreet, elit. Sed interdum augue sit amet quam
+					dapibus semper. Nulla facilisi. Pellentesque lobortis erat nec
+					quam.
+				</p>
+				<p>
+					Sed arcu magna, molestie at, fringilla in, sodales eu, elit.
+					Curabitur mattis lorem et est. Quisque et tortor. Integer bibendum
+					vulputate odio. Nam nec ipsum. Vestibulum mollis eros feugiat
+					augue. Integer fermentum odio lobortis odio. Nullam mollis nisl non
+					metus. Maecenas nec nunc eget pede ultrices blandit. Ut non purus
+					ut elit convallis eleifend. Fusce tincidunt, justo quis tempus
+					euismod, magna nulla viverra libero, sit amet lacinia odio diam id
+					risus. Ut varius viverra turpis. Morbi urna elit, imperdiet eu,
+					porta ac, pharetra sed, nisi. Etiam ante libero, ultrices ac,
+					faucibus ac, cursus sodales, nisl. Praesent nisl sem, fermentum eu,
+					consequat quis, varius interdum, nulla. Donec neque tortor,
+					sollicitudin sed, consequat nec, facilisis sit amet, orci. Aenean
+					ut eros sit amet ante pharetra interdum.
+				</p>
+			</div>
+
+			<!-- test lazy loading -->
+			<div dojoType="dijit.layout.ContentPane" 
+				label="Pane 2 (lazy load)" href="tab1.html" 
+				style="display:none;"></div>
+
+			<div dojoType="dijit.layout.SplitContainer" label="Pane 3 (split pane)">
+				<p dojoType="dijit.layout.ContentPane">
+					Sed arcu magna, molestie at, fringilla in, sodales eu, elit.
+					Curabitur mattis lorem et est. Quisque et tortor. Integer bibendum
+					vulputate odio. Nam nec ipsum. Vestibulum mollis eros feugiat
+					augue. Integer fermentum odio lobortis odio. Nullam mollis nisl non
+					metus. Maecenas nec nunc eget pede ultrices blandit. Ut non purus
+					ut elit convallis eleifend. Fusce tincidunt, justo quis tempus
+					euismod, magna nulla viverra libero, sit amet lacinia odio diam id
+					risus. Ut varius viverra turpis. Morbi urna elit, imperdiet eu,
+					porta ac, pharetra sed, nisi. Etiam ante libero, ultrices ac,
+					faucibus ac, cursus sodales, nisl. Praesent nisl sem, fermentum eu,
+					consequat quis, varius interdum, nulla. Donec neque tortor,
+					sollicitudin sed, consequat nec, facilisis sit amet, orci. Aenean
+					ut eros sit amet ante pharetra interdum.
+				</p>
+				<p dojoType="dijit.layout.ContentPane">
+					Sed arcu magna, molestie at, fringilla in, sodales eu, elit.
+					Curabitur mattis lorem et est. Quisque et tortor. Integer bibendum
+					vulputate odio. Nam nec ipsum. Vestibulum mollis eros feugiat
+					augue. Integer fermentum odio lobortis odio. Nullam mollis nisl non
+					metus. Maecenas nec nunc eget pede ultrices blandit. Ut non purus
+					ut elit convallis eleifend. Fusce tincidunt, justo quis tempus
+					euismod, magna nulla viverra libero, sit amet lacinia odio diam id
+					risus. Ut varius viverra turpis. Morbi urna elit, imperdiet eu,
+					porta ac, pharetra sed, nisi. Etiam ante libero, ultrices ac,
+					faucibus ac, cursus sodales, nisl. Praesent nisl sem, fermentum eu,
+					consequat quis, varius interdum, nulla. Donec neque tortor,
+					sollicitudin sed, consequat nec, facilisis sit amet, orci. Aenean
+					ut eros sit amet ante pharetra interdum.
+				</p>
+			</div>
+		</div>
+		<p style="clear: both;">HTML after</p>
+		<p>HTML after</p>
+		<p>HTML after</p>
+
+		<h2>Programatically created:</h2>
+		<button onclick="destroyChildren();">destroy children</button>
+		<br>
+		<div id="accordionShell" style="width: 400px; height: 400px;"></div>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_ContentPane.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_ContentPane.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_ContentPane.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>ContentPane Test</title>
+		
+		<script type="text/javascript" src="../testBidi.js"></script>
+		
+		<script type="text/javascript" src="../../../dojo/dojo.js" 
+			djConfig="isDebug:true"></script>
+		<script type="text/javascript">
+			dojo.require("dijit.layout.ContentPane");
+			dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+		</script>
+		<style>
+			@import "../../../dojo/resources/dojo.css";
+			@import "../../themes/tundra/tundra.css";
+			@import "css/dijitTests.css";
+
+			body {
+				margin: 1em;
+				padding: 1em;
+			}
+
+			.box {
+			  position: relative;
+				background-color: white;
+				border: 2px solid black;
+				padding: 8px;
+				margin: 4px;
+			}
+		</style>
+	</head>
+	<body class="tundra">
+		<p>pre-container paragraph</p>
+
+		<div dojoType="dijit.layout.ContentPane" class="box">
+			some text (top-level container)
+
+			<div dojoType="dijit.layout.ContentPane" class="box">
+
+				text in the inner container (1)
+
+				<div dojoType="dijit.layout.ContentPane" class="box" href="tab2.html" hasShadow="true">
+					hi
+				</div>
+
+				text in the inner container (2)
+
+				<div dojoType="dijit.layout.ContentPane" class="box">
+					inner-inner 2
+				</div>
+
+				text in the inner container (3)
+
+				<div dojoType="dijit.layout.ContentPane" class="box">
+					inner-inner 3
+				</div>
+
+				text in the inner container (4)
+
+			</div>
+
+			some more text (top-level container)
+		</div>
+
+		<p>mid-container paragraph</p>
+
+		<div dojoType="dijit.layout.ContentPane" class="box" hasShadow="true">
+			2nd top-level container
+		</div>
+
+		<p>post-container paragraph</p>
+
+		<div id="ContentPane3" class="box" hasShadow="true">
+			some content pane blah blah blah
+		</div>
+
+		<script type="text/javascript">
+			dojo.addOnLoad(function(){
+				var tmp = new dijit.layout.ContentPane({}, dojo.byId("ContentPane3"));
+				tmp.startup();
+				console.debug('created ' + tmp);	
+			});
+		</script>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_Dialog.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_Dialog.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_Dialog.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,311 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Dialog Widget Dojo Tests</title>
+		<style type="text/css">
+			@import "../../../dojo/resources/dojo.css";
+			@import "../../themes/tundra/tundra.css";
+			@import "../css/dijitTests.css";
+		</style>		
+		<script type="text/javascript" 
+			djConfig="isDebug: true"
+			src="../../../dojo/dojo.js"></script>
+<script type="text/javascript">
+	dojo.require("dijit.layout.Dialog");
+	dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+
+</script>
+
+<script type="text/javascript">
+var dlg;
+var secDlg;
+function init(e) {
+	dlg = dijit.byId("DialogContent");
+	secDlg = dijit.byId("SecondDialog");
+}
+dojo.addOnLoad(init);
+
+</script>
+<style type="text/css">
+body { font-family : sans-serif; }
+
+
+form {
+	margin-bottom : 0;
+}
+</style>
+</head>
+<body class="tundra">
+<a href="javascript:dlg.show()">Show First Dialog</a>
+
+<div dojoType="dijit.layout.Dialog" id="DialogContent" bgColor="white" bgOpacity="0.5" toggle="fade" toggleDuration="250" closeNode="hider" label="First Dialog">
+	<form onsubmit="return false;">
+		<table>
+			<tr>
+				<td>Name:</td>
+				<td><input type="text"></td>
+			</tr>
+			<tr>
+				<td>Location:</td>
+				<td><input type="text"></td>
+			</tr>
+			<tr>
+				<td>Description:</td>
+				<td><input type="text"></td>
+			</tr>
+			<tr>
+				<td>Location:</td>
+				<td><input type="file"></td>
+			</tr>
+			<tr>
+				<td colspan="2" align="center">
+					<input type="button" id="hider" value="OK"></td>
+			</tr>
+		</table>
+	</form>
+</div>
+
+<select>
+	<option>Lorem</option>
+	<option>ipsum</option>
+	<option>dolor</option>
+	<option>sit</option>
+	<option>amet</option>
+</select>
+
+<p>
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
+semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin
+porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.
+Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis.
+Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitae
+risus.
+</p>
+<p>Aliquam vitae enim. Duis scelerisque metus auctor est venenatis
+imperdiet. Fusce dignissim porta augue. Nulla vestibulum. Integer lorem
+nunc, ullamcorper a, commodo ac, malesuada sed, dolor. Aenean id mi in
+massa bibendum suscipit. Integer eros. Nullam suscipit mauris. In
+pellentesque. Mauris ipsum est, pharetra semper, pharetra in, viverra
+quis, tellus. Etiam purus. Quisque egestas, tortor ac cursus lacinia,
+felis leo adipiscing nisi, et rhoncus elit dolor eget eros. Fusce ut
+quam. Suspendisse eleifend leo vitae ligula. Nulla facilisi. Nulla
+rutrum, erat vitae lacinia dictum, pede purus imperdiet lacus, ut
+semper velit ante id metus. Praesent massa dolor, porttitor sed,
+pulvinar in, consequat ut, leo. Nullam nec est. Aenean id risus blandit
+tortor pharetra congue. Suspendisse pulvinar.
+</p>
+<p>Vestibulum convallis eros ac justo. Proin dolor. Etiam aliquam. Nam
+ornare elit vel augue. Suspendisse potenti. Etiam sed mauris eu neque
+nonummy mollis. Vestibulum vel purus ac pede semper accumsan. Vivamus
+lobortis, sem vitae nonummy lacinia, nisl est gravida magna, non cursus
+est quam sed urna. Phasellus adipiscing justo in ipsum. Duis sagittis
+dolor sit amet magna. Suspendisse suscipit, neque eu dictum auctor,
+nisi augue tincidunt arcu, non lacinia magna purus nec magna. Praesent
+pretium sollicitudin sapien. Suspendisse imperdiet. Class aptent taciti
+sociosqu ad litora torquent per conubia nostra, per inceptos
+hymenaeos.
+</p>
+<form>
+	<center>
+		<select>
+			<option>1</option>
+			<option>2</option>
+		</select>
+	</center>
+</form>
+<p>Mauris pharetra lorem sit amet sapien. Nulla libero metus, tristique
+et, dignissim a, tempus et, metus. Ut libero. Vivamus tempus purus vel
+ipsum. Quisque mauris urna, vestibulum commodo, rutrum vitae, ultrices
+vitae, nisl. Class aptent taciti sociosqu ad litora torquent per
+conubia nostra, per inceptos hymenaeos. Nulla id erat sit amet odio
+luctus eleifend. Proin massa libero, ultricies non, tincidunt a,
+vestibulum non, tellus. Nunc nunc purus, lobortis a, pulvinar at,
+egestas a, mi. Cras adipiscing velit a mauris. Morbi felis. Etiam at
+felis. Cras eget eros et justo mattis pulvinar. Nullam at justo id
+risus porttitor dignissim. Vestibulum sed velit vel metus tincidunt
+tempus. Nunc euismod nisl id dolor tristique tincidunt. Nullam placerat
+turpis sed odio. Curabitur in est id nibh tempus ultrices. Aliquam
+consectetuer dapibus eros. Aliquam nisl.
+</p>
+
+<p>
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
+semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin
+porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.
+Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis.
+Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitae
+risus.
+</p>
+<p>Aliquam vitae enim. Duis scelerisque metus auctor est venenatis
+imperdiet. Fusce dignissim porta augue. Nulla vestibulum. Integer lorem
+nunc, ullamcorper a, commodo ac, malesuada sed, dolor. Aenean id mi in
+massa bibendum suscipit. Integer eros. Nullam suscipit mauris. In
+pellentesque. Mauris ipsum est, pharetra semper, pharetra in, viverra
+quis, tellus. Etiam purus. Quisque egestas, tortor ac cursus lacinia,
+felis leo adipiscing nisi, et rhoncus elit dolor eget eros. Fusce ut
+quam. Suspendisse eleifend leo vitae ligula. Nulla facilisi. Nulla
+rutrum, erat vitae lacinia dictum, pede purus imperdiet lacus, ut
+semper velit ante id metus. Praesent massa dolor, porttitor sed,
+pulvinar in, consequat ut, leo. Nullam nec est. Aenean id risus blandit
+tortor pharetra congue. Suspendisse pulvinar.
+</p>
+<p>Vestibulum convallis eros ac justo. Proin dolor. Etiam aliquam. Nam
+ornare elit vel augue. Suspendisse potenti. Etiam sed mauris eu neque
+nonummy mollis. Vestibulum vel purus ac pede semper accumsan. Vivamus
+lobortis, sem vitae nonummy lacinia, nisl est gravida magna, non cursus
+est quam sed urna. Phasellus adipiscing justo in ipsum. Duis sagittis
+dolor sit amet magna. Suspendisse suscipit, neque eu dictum auctor,
+nisi augue tincidunt arcu, non lacinia magna purus nec magna. Praesent
+pretium sollicitudin sapien. Suspendisse imperdiet. Class aptent taciti
+sociosqu ad litora torquent per conubia nostra, per inceptos
+hymenaeos.
+</p>
+<form>
+	<center>
+		<select>
+			<option>1</option>
+			<option>2</option>
+		</select>
+	</center>
+</form>
+<p>Mauris pharetra lorem sit amet sapien. Nulla libero metus, tristique
+et, dignissim a, tempus et, metus. Ut libero. Vivamus tempus purus vel
+ipsum. Quisque mauris urna, vestibulum commodo, rutrum vitae, ultrices
+vitae, nisl. Class aptent taciti sociosqu ad litora torquent per
+conubia nostra, per inceptos hymenaeos. Nulla id erat sit amet odio
+luctus eleifend. Proin massa libero, ultricies non, tincidunt a,
+vestibulum non, tellus. Nunc nunc purus, lobortis a, pulvinar at,
+egestas a, mi. Cras adipiscing velit a mauris. Morbi felis. Etiam at
+felis. Cras eget eros et justo mattis pulvinar. Nullam at justo id
+risus porttitor dignissim. Vestibulum sed velit vel metus tincidunt
+tempus. Nunc euismod nisl id dolor tristique tincidunt. Nullam placerat
+turpis sed odio. Curabitur in est id nibh tempus ultrices. Aliquam
+consectetuer dapibus eros. Aliquam nisl.
+</p>
+
+<a href="javascript:secDlg.show()">Show Second Dialog</a>
+<p>
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
+semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin
+porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.
+Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis.
+Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitae
+risus.
+</p>
+<p>Aliquam vitae enim. Duis scelerisque metus auctor est venenatis
+imperdiet. Fusce dignissim porta augue. Nulla vestibulum. Integer lorem
+nunc, ullamcorper a, commodo ac, malesuada sed, dolor. Aenean id mi in
+massa bibendum suscipit. Integer eros. Nullam suscipit mauris. In
+pellentesque. Mauris ipsum est, pharetra semper, pharetra in, viverra
+quis, tellus. Etiam purus. Quisque egestas, tortor ac cursus lacinia,
+felis leo adipiscing nisi, et rhoncus elit dolor eget eros. Fusce ut
+quam. Suspendisse eleifend leo vitae ligula. Nulla facilisi. Nulla
+rutrum, erat vitae lacinia dictum, pede purus imperdiet lacus, ut
+semper velit ante id metus. Praesent massa dolor, porttitor sed,
+pulvinar in, consequat ut, leo. Nullam nec est. Aenean id risus blandit
+tortor pharetra congue. Suspendisse pulvinar.
+</p>
+<p>Vestibulum convallis eros ac justo. Proin dolor. Etiam aliquam. Nam
+ornare elit vel augue. Suspendisse potenti. Etiam sed mauris eu neque
+nonummy mollis. Vestibulum vel purus ac pede semper accumsan. Vivamus
+lobortis, sem vitae nonummy lacinia, nisl est gravida magna, non cursus
+est quam sed urna. Phasellus adipiscing justo in ipsum. Duis sagittis
+dolor sit amet magna. Suspendisse suscipit, neque eu dictum auctor,
+nisi augue tincidunt arcu, non lacinia magna purus nec magna. Praesent
+pretium sollicitudin sapien. Suspendisse imperdiet. Class aptent taciti
+sociosqu ad litora torquent per conubia nostra, per inceptos
+hymenaeos.
+</p>
+<p>Mauris pharetra lorem sit amet sapien. Nulla libero metus, tristique
+et, dignissim a, tempus et, metus. Ut libero. Vivamus tempus purus vel
+ipsum. Quisque mauris urna, vestibulum commodo, rutrum vitae, ultrices
+vitae, nisl. Class aptent taciti sociosqu ad litora torquent per
+conubia nostra, per inceptos hymenaeos. Nulla id erat sit amet odio
+luctus eleifend. Proin massa libero, ultricies non, tincidunt a,
+vestibulum non, tellus. Nunc nunc purus, lobortis a, pulvinar at,
+egestas a, mi. Cras adipiscing velit a mauris. Morbi felis. Etiam at
+felis. Cras eget eros et justo mattis pulvinar. Nullam at justo id
+risus porttitor dignissim. Vestibulum sed velit vel metus tincidunt
+tempus. Nunc euismod nisl id dolor tristique tincidunt. Nullam placerat
+turpis sed odio. Curabitur in est id nibh tempus ultrices. Aliquam
+consectetuer dapibus eros. Aliquam nisl.
+</p>
+
+<p>
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
+semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin
+porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.
+Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis.
+Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitae
+risus.
+</p>
+<p>Aliquam vitae enim. Duis scelerisque metus auctor est venenatis
+imperdiet. Fusce dignissim porta augue. Nulla vestibulum. Integer lorem
+nunc, ullamcorper a, commodo ac, malesuada sed, dolor. Aenean id mi in
+massa bibendum suscipit. Integer eros. Nullam suscipit mauris. In
+pellentesque. Mauris ipsum est, pharetra semper, pharetra in, viverra
+quis, tellus. Etiam purus. Quisque egestas, tortor ac cursus lacinia,
+felis leo adipiscing nisi, et rhoncus elit dolor eget eros. Fusce ut
+quam. Suspendisse eleifend leo vitae ligula. Nulla facilisi. Nulla
+rutrum, erat vitae lacinia dictum, pede purus imperdiet lacus, ut
+semper velit ante id metus. Praesent massa dolor, porttitor sed,
+pulvinar in, consequat ut, leo. Nullam nec est. Aenean id risus blandit
+tortor pharetra congue. Suspendisse pulvinar.
+</p>
+<p>Vestibulum convallis eros ac justo. Proin dolor. Etiam aliquam. Nam
+ornare elit vel augue. Suspendisse potenti. Etiam sed mauris eu neque
+nonummy mollis. Vestibulum vel purus ac pede semper accumsan. Vivamus
+lobortis, sem vitae nonummy lacinia, nisl est gravida magna, non cursus
+est quam sed urna. Phasellus adipiscing justo in ipsum. Duis sagittis
+dolor sit amet magna. Suspendisse suscipit, neque eu dictum auctor,
+nisi augue tincidunt arcu, non lacinia magna purus nec magna. Praesent
+pretium sollicitudin sapien. Suspendisse imperdiet. Class aptent taciti
+sociosqu ad litora torquent per conubia nostra, per inceptos
+hymenaeos.
+</p>
+<p>Mauris pharetra lorem sit amet sapien. Nulla libero metus, tristique
+et, dignissim a, tempus et, metus. Ut libero. Vivamus tempus purus vel
+ipsum. Quisque mauris urna, vestibulum commodo, rutrum vitae, ultrices
+vitae, nisl. Class aptent taciti sociosqu ad litora torquent per
+conubia nostra, per inceptos hymenaeos. Nulla id erat sit amet odio
+luctus eleifend. Proin massa libero, ultricies non, tincidunt a,
+vestibulum non, tellus. Nunc nunc purus, lobortis a, pulvinar at,
+egestas a, mi. Cras adipiscing velit a mauris. Morbi felis. Etiam at
+felis. Cras eget eros et justo mattis pulvinar. Nullam at justo id
+risus porttitor dignissim. Vestibulum sed velit vel metus tincidunt
+tempus. Nunc euismod nisl id dolor tristique tincidunt. Nullam placerat
+turpis sed odio. Curabitur in est id nibh tempus ultrices. Aliquam
+consectetuer dapibus eros. Aliquam nisl.
+</p>
+
+<div dojoType="dijit.layout.Dialog" id="SecondDialog" bgColor="black" closeNode="closeButton" label="Second Dialog">
+	<form onsubmit="return false;">
+		<table>
+			<tr>
+				<td>Name:</td>
+				<td><input type="text"></td>
+			</tr>
+			<tr>
+				<td>Location:</td>
+				<td><input type="text"></td>
+			</tr>
+			<tr>
+				<td>Description:</td>
+				<td><input type="text"></td>
+			</tr>
+			<tr>
+				<td>Location:</td>
+				<td><input type="file"></td>
+			</tr>
+			<tr>
+				<td colspan="2" align="center">
+					<input type="button" id="closeButton" value="OK"></td>
+			</tr>
+		</table>
+	</form>
+</div>
+
+</body>
+</html>
+

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_Layout.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_Layout.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_Layout.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+	<title>Layout Demo</title>
+	
+	<script type="text/javascript" src="../testBidi.js"></script>
+	
+	<script type="text/javascript" 
+		djConfig="isDebug: true"
+		src="../../../dojo/dojo.js"></script>
+	<script type="text/javascript">
+		dojo.require("dijit.layout.LayoutContainer");
+		dojo.require("dijit.layout.ContentPane");
+		dojo.require("dijit.layout.LinkPane");
+		dojo.require("dijit.layout.SplitContainer");
+		dojo.require("dijit.layout.TabContainer");
+		dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+
+	</script>
+	<style type="text/css">
+		@import "../../../dojo/resources/dojo.css";
+		@import "../../themes/tundra/tundra.css";
+		@import "css/dijitTests.css";
+
+		html, body{	
+			width: 100%;	/* make the body expand to fill the visible window */
+			height: 100%;
+			overflow: hidden;	/* erase window level scrollbars */
+			padding: 0 0 0 0;
+			margin: 0 0 0 0;
+		}
+		.dijitSplitPane{
+			margin: 5px;
+		}
+		#rightPane {
+			margin: 0;
+		}
+	</style>
+</head>
+<body class="tundra">
+	<div dojoType="dijit.layout.LayoutContainer"
+		layoutChildPriority='top-bottom'
+		style="width: 100%; height: 100%;">
+		<div dojoType="dijit.layout.ContentPane" layoutAlign="top" 
+			style="background-color: #274383; color: white;">
+			top bar
+		</div>
+		<div dojoType="dijit.layout.ContentPane" layoutAlign="bottom" 
+			style="background-color: #274383; color: white;">
+			bottom bar
+		</div>
+		<div dojoType="dijit.layout.SplitContainer"
+			orientation="horizontal"
+			sizerWidth="5"
+			activeSizing="0"
+			layoutAlign="client"
+		>
+			<div dojoType="dijit.layout.ContentPane"
+				 sizeMin="20" sizeShare="20">
+				Left side
+			</div>
+
+			<div dojoType="dijit.layout.SplitContainer"
+				id="rightPane"
+				orientation="vertical"
+				sizerWidth="5"
+				activeSizing="0"
+				sizeMin="50" sizeShare="80"
+			>
+				<div id="mainTabContainer" dojoType="dijit.layout.TabContainer" sizeMin="20" sizeShare="70">
+				
+					<a id="tab1" dojoType="dijit.layout.LinkPane" href="tab1.html">Tab 1</a>
+					
+					<a id="tab2" dojoType="dijit.layout.LinkPane" href="tab2.html">Tab 2</a>
+				</div>
+				<div dojoType="dijit.layout.ContentPane" sizeMin="20" sizeShare="30">
+					Bottom right
+				</div>
+			</div>
+		</div>
+	</div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_LayoutContainer.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_LayoutContainer.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_LayoutContainer.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+	<title>dijit.layout.LayoutContainer Test</title>
+	
+	<script type="text/javascript" src="../testBidi.js"></script>
+	
+	<script type="text/javascript" 
+		djConfig="isDebug: true"
+		src="../../../dojo/dojo.js"></script>
+	<script type="text/javascript">
+		dojo.require("dijit.layout.LayoutContainer");
+		dojo.require("dijit.layout.ContentPane");
+		dojo.require("dijit.form.Select");
+		dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+	</script>
+	<style type="text/css">
+		@import "../../../dojo/resources/dojo.css";
+		@import "../../themes/tundra/tundra.css";
+		@import "css/dijitTests.css";
+	</style>
+</head>
+<body>
+
+<p>Basic layout</p>
+
+<div dojoType="dijit.layout.LayoutContainer"
+	layoutChildPriority='left-right'
+	style="border: 2px solid black; width: 90%; height: 300px; padding: 10px;"
+>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="top" style="background-color: #b39b86; ">
+		top bar
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="bottom" style="background-color: #b39b86;">
+		bottom bar
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="left" style="background-color: #acb386; width: 100px;">
+		left
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="right" style="background-color: #acb386;">
+		right
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="client" style="background-color: #f5ffbf; padding: 10px;">
+		main panel with <a href="http://www.dojotoolkit.org/">a link</a>.<br />
+		(to check we're copying children around properly).<br />
+		<select dojoType="dijit.form.Select">
+			<option value="1">foo</option>
+			<option value="2">bar</option>
+			<option value="3">baz</option>
+		</select>
+		Here's some text that comes AFTER the combo box.
+	</div>
+</div>
+
+<p>Advanced layout:</p>
+<div dojoType="dijit.layout.LayoutContainer"
+	layoutChildPriority='none'
+	style="border: 2px solid black; width: 90%; height: 300px; padding: 10px;"
+>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="left" style="background-color: #acb386; width: 100px; margin: 5px;">
+		left
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="top" style="background-color: #b39b86;  margin: 5px;">
+		top bar
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="bottom" style="background-color: #b39b86; margin: 5px;">
+		bottom bar
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="left" style="background-color: #eeeeee; width: 100px; margin: 5px;">
+		inner left
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="right" style="background-color: #eeeeee; width: 100px; margin: 5px;">
+		inner right
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="client" style="background-color: #f5ffbf; padding: 10px; margin: 5px;">
+		main panel with <a href="http://www.dojotoolkit.org/">a link</a>.<br />
+		(to check we're copying children around properly).<br />
+		<select dojoType="dijit.form.Select">
+			<option value="1">foo</option>
+			<option value="2">bar</option>
+			<option value="3">baz</option>
+		</select>
+		Here's some text that comes AFTER the combo box.
+	</div>
+</div>
+
+<p>Goofy spiral layout:</p>
+<div dojoType="dijit.layout.LayoutContainer"
+	layoutChildPriority='none'
+	style="border: 2px solid black; width: 90%; height: 300px; padding: 10px;"
+>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="left" style="background-color: #663333; color: white; width: 100px;">
+		outer left
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="top" style="background-color: #333366; color: white; height: 50px;">
+		outer top
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="right" style="background-color: #663333; color: white; width: 100px;">
+		outer right
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="bottom" style="background-color: #333366; color: white; height: 50px;">
+		outer bottom
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="left" style="background-color: #99CC99; width: 100px;">
+		inner left
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="top" style="background-color: #999966; height: 50px;">
+		inner top
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="right" style="background-color: #99CC99; width: 100px;">
+		inner right
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="bottom" style="background-color: #999966; height: 50px;">
+		inner bottom
+	</div>
+	<div dojoType="dijit.layout.ContentPane" layoutAlign="client" style="padding: 10px;">
+		main panel with <a href="http://www.dojotoolkit.org/">a link</a>.<br />
+		(to check we're copying children around properly).<br />
+		<select dojoType="dijit.form.Select">
+			<option value="1">foo</option>
+			<option value="2">bar</option>
+			<option value="3">baz</option>
+		</select>
+		Here's some text that comes AFTER the combo box.
+	</div>
+</div>
+
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_PageContainer.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_PageContainer.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_PageContainer.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,67 @@
+<!DOCTYPE html
+	PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>PageContainer Demo</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
+
+<script type="text/javascript" src="../testBidi.js"></script>
+
+<script type="text/javascript">
+	var djConfig = { isDebug: true };
+</script>
+<style>
+ at import "../../../dojo/resources/dojo.css";
+ at import "../../themes/tundra/tundra.css";
+ at import "css/dijitTests.css";
+	h1 { font-family: cursive; font-size: 24pt; }
+	p { font-family: cursive; font-size: 14pt; }
+
+	/* set style for page controller */
+	.dojoPageController .item { margin: 0px 5px 0px 5px; }
+	.dojoPageController .selectButton { text-decoration: underline; cursor: pointer; margin-right: 3px;}
+	.dojoPageController .closeButton { cursor: pointer; };
+	.dojoPageController .item { color: #333366; }
+	.dojoPageController .current { color: blue; font: bold;}
+</style>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<script type="text/javascript">
+	dojo.require("dijit.layout.ContentPane");
+	dojo.require("dijit.layout.PageContainer");
+</script>
+<script type="text/javascript">
+	function selected(page){
+		console.debug("page selected " + page.id);
+		var widget=dijit.byId("myPageContainer");
+		dojo.byId("previous").disabled = page.isFirstChild;
+		dojo.byId("next").disabled = page.isLastChild;
+		dojo.byId("previous2").disabled = page.isFirstChild;
+		dojo.byId("next2").disabled = page.isLastChild;
+	}
+	dojo.subscribe("myPageContainer-selectChild", selected);
+	
+	dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+</script>
+</head>
+
+<body class="tundra">
+	<h1>A Tale Of Two Cities</h1>
+
+	<button id="previous" onClick="dijit.byId('myPageContainer').back()">&lt;</button>
+	<span dojoType="dijit.layout.PageController" containerId="myPageContainer"></span>
+	<button id="next" onClick="dijit.byId('myPageContainer').forward()">&gt;</button>
+
+	<div id="myPageContainer" dojoType="dijit.layout.PageContainer" style="width: 100%; height: 20em; border: 3px dashed aqua; margin: 1em 0 1em 0;">
+		<p id="page1" dojoType="dijit.layout.ContentPane" label="page 1">IT WAS the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only</p>
+		<p id="page2" dojoType="dijit.layout.ContentPane" label="page 2">There were a king with a large jaw and a queen with a plain face, on the throne of England; there were a king with a large jaw and a queen with a fair face, on the throne of France. In both countries it was clearer than crystal to the lords of the State preserves of loaves and fishes, that things in general were settled for ever.</p>
+		<p id="page3" dojoType="dijit.layout.ContentPane" label="page 3">It was the year of Our Lord one thousand seven hundred and seventy- five. Spiritual revelations were conceded to England at that favoured period, as at this. Mrs. Southcott had recently attained her five-and- twentieth blessed birthday, of whom a prophetic private in the Life Guards had heralded the sublime appearance by announcing that arrangements were made for the swallowing up of London and Westminster. Even the Cock-lane ghost had been laid only a round dozen of years, after rapping out its messages, as the spirits of this very year last past (supernaturally deficient in originality) rapped out theirs. Mere messages in the earthly order of events had lately come to the English Crown and People, from a congress of British subjects in America:</p>
+	</div>
+
+	<button id="previous2" onClick="dijit.byId('myPageContainer').back()">&lt;</button>
+	<span dojoType="dijit.layout.PageController" containerId="myPageContainer"></span>
+	<button id="next2" onClick="dijit.byId('myPageContainer').forward()">&gt;</button>
+	
+</body>
+</html>
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_SplitContainer.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_SplitContainer.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_SplitContainer.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+	<title>SplitContainer Widget Demo</title>
+	
+	<script type="text/javascript" src="../testBidi.js"></script>
+	
+	<script type="text/javascript" 
+		djConfig="isDebug: true"
+		src="../../../dojo/dojo.js"></script>
+	<script type="text/javascript">
+		dojo.require("dijit.layout.SplitContainer");
+		dojo.require("dijit.layout.ContentPane");
+		dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+	</script>
+	<style type="text/css">
+		@import "../../../dojo/resources/dojo.css";
+		@import "../../themes/tundra/tundra.css";
+		@import "../css/dijitTests.css";
+		.dojoContentPane {
+			padding:1em;
+		}
+	</style>
+</head>
+<body class="tundra">
+	<h1 class="testTitle">Dijit Split Container Test</h1>
+	<p>HTML before</p>
+
+	<div dojoType="dijit.layout.SplitContainer"
+		orientation="vertical"
+		sizerWidth="7"
+		activeSizing="false"
+		style="border: 1px solid #bfbfbf; float: left; margin-right: 30px;  width: 400px; height: 300px;"
+	>
+		<div dojoType="dijit.layout.ContentPane" sizeMin="10" sizeShare="50">
+			this box has three split panes
+		</div>
+		<div dojoType="dijit.layout.ContentPane" sizeMin="20" sizeShare="50" 
+			style="background-color: yellow; border: 3px solid purple;">
+			in vertical mode
+		</div>
+		<div dojoType="dijit.layout.ContentPane" sizeMin="10" sizeShare="50">
+			without active resizing
+		</div>
+	</div>
+
+	<div dojoType="dijit.layout.SplitContainer"
+		orientation="horizontal"
+		sizerWidth="7"
+		activeSizing="true"
+		style="border: 1px solid #bfbfbf; float: left; width: 400px; height: 300px;">
+		<div dojoType="dijit.layout.ContentPane" sizeMin="20" sizeShare="20">
+			this box has two horizontal panes
+		</div>
+		<div dojoType="dijit.layout.ContentPane" sizeMin="50" sizeShare="50">
+			with active resizing, a smaller sizer, different starting sizes and minimum sizes
+		</div>
+	</div>
+
+	<p style="clear: both;">HTML after</p>
+
+the following splitter contains two iframes, see whether the resizer works ok in this situation
+<div dojoType="dijit.layout.SplitContainer"
+	orientation="horizontal"
+	sizerWidth="5"
+	activeSizing="false"
+	style="border: 2px solid black; float: left; width: 100%; height: 300px;"
+>
+	<div dojoType="dijit.layout.ContentPane" sizeMin="20" sizeShare="20">
+		<iframe style="width: 100%; height: 100%"></iframe>
+	</div>
+	<div dojoType="dijit.layout.ContentPane" sizeMin="50" sizeShare="50">
+		<iframe style="width: 100%; height: 100%"></iframe>
+	</div>
+</div>
+
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_TabContainer.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_TabContainer.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/layout/test_TabContainer.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,165 @@
+<!DOCTYPE html
+	PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<!-- FIXME: why XHTML for this page? -->
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+	<title>TabContainer Demo</title>
+
+	<script type="text/javascript" src="../testBidi.js"></script>
+
+	<script type="text/javascript" djConfig="isDebug: true" 
+		src="../../../dojo/dojo.js"></script>
+	<script type="text/javascript">
+		dojo.require("dijit.layout.ContentPane");
+		dojo.require("dijit.layout.TabContainer");
+		dojo.require("dijit.Tooltip");
+		dojo.require("dijit.layout.LinkPane");
+		dojo.require("dijit.form.Button");
+
+		dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+	</script>
+
+	<style type="text/css">
+		@import "../../../dojo/resources/dojo.css";
+		@import "../../themes/tundra/tundra.css";
+		@import "css/dijitTests.css";
+
+		body {
+			font-family : sans-serif;
+			margin:20px;
+		}
+
+		/* add padding to each contentpane inside the tab container, and scrollbar if necessary */
+		.dojoTabPane {
+			padding : 10px 10px 10px 10px;
+			overflow: auto;
+		}
+	</style>
+	<script type="text/javascript">
+		function boo(panel, node) {
+			node.innerHTML = "Handlers override grabbing from URLs. They run in context of the widget, so 'this' refers to the tab widget.";
+		}
+		function testClose(pane,tab) {
+		  return confirm("Please confirm that you want tab "+tab.label+" closed");
+		}
+
+		startTime = new Date();
+		dojo.addOnLoad(function(){
+			var elapsed = new Date().getTime() - startTime;
+			var p = document.createElement("p");
+			p.appendChild(document.createTextNode("Widgets loaded in " + elapsed + "ms"));
+			document.body.appendChild(p);
+		});
+	</script>
+</head>
+<body class="tundra">
+	<p>These tabs are made up of local and external content. Tab 1 and Tab 2 are loading
+	files tab1.html and tab2.html. Tab 3 and Another Tab are using content that is already
+	part of this page.   Tab2 is initially selected.</p>
+
+	<div id="mainTabContainer" dojoType="dijit.layout.TabContainer" style="width: 100%; height: 20em;" selectedChild="tab2">
+	
+		<div id="tab1" dojoType="dijit.layout.ContentPane" href="tab1.html" label="Tab 1"></div>
+		
+		<div id="tab2" dojoType="dijit.layout.ContentPane" href="tab2.html" refreshOnShow="true" label="Tab 2"></div>
+		
+		<div dojoType="dijit.layout.ContentPane" label="Tab 3">
+			<h1>I am tab 3</h1>
+			<p>And I was already part of the page! That's cool, no?</p>
+			<p id="foo">tooltip on this paragraph</p>
+			<div dojoType="dijit.Tooltip" connectId="foo">I'm a tooltip!</div>
+			<button dojoType="dijit.form.Button">I'm a button </button>
+			<br>
+			<button dojoType="dijit.form.Button">So am I!</button>
+			<p>
+			Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
+			semper sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin
+			porta rutrum lacus. Etiam consequat scelerisque quam. Nulla facilisi.
+			Maecenas luctus venenatis nulla. In sit amet dui non mi semper iaculis.
+			Sed molestie tortor at ipsum. Morbi dictum rutrum magna. Sed vitae
+			risus.
+			</p>
+			<p>Aliquam vitae enim. Duis scelerisque metus auctor est venenatis
+			imperdiet. Fusce dignissim porta augue. Nulla vestibulum. Integer lorem
+			nunc, ullamcorper a, commodo ac, malesuada sed, dolor. Aenean id mi in
+			massa bibendum suscipit. Integer eros. Nullam suscipit mauris. In
+			pellentesque. Mauris ipsum est, pharetra semper, pharetra in, viverra
+			quis, tellus. Etiam purus. Quisque egestas, tortor ac cursus lacinia,
+			felis leo adipiscing nisi, et rhoncus elit dolor eget eros. Fusce ut
+			quam. Suspendisse eleifend leo vitae ligula. Nulla facilisi. Nulla
+			rutrum, erat vitae lacinia dictum, pede purus imperdiet lacus, ut
+			semper velit ante id metus. Praesent massa dolor, porttitor sed,
+			pulvinar in, consequat ut, leo. Nullam nec est. Aenean id risus blandit
+			tortor pharetra congue. Suspendisse pulvinar.
+			</p>
+		</div>
+		
+		<div dojoType="dijit.layout.LinkPane" label="Handler tab" handler="boo"></div>
+
+		<div dojoType="dijit.layout.ContentPane" label="Another Tab">
+			<h1>I love local content</h1>
+			<p>And I'm not ashamed to admit it.</p>
+			<p>venga venga venga venga venga venga venga venga venga venga venga venga
+			venga venga venga venga venga venga venga venga venga venga venga venga
+			venga venga venga venga venga venga venga venga venga venga venga venga
+			venga venga venga venga venga venga venga venga venga venga venga venga
+			venga venga venga venga venga venga venga venga venga venga venga venga
+			venga venga venga venga venga venga venga venga venga venga venga venga
+			venga venga venga venga venga venga venga venga venga venga venga venga</p>
+		</div>
+
+		<div dojoType="dijit.layout.TabContainer" label="Sub TabContainer">	
+			<a dojoType="dijit.layout.LinkPane" href="tab1.html">SubTab 1</a>		
+			<a dojoType="dijit.layout.LinkPane" href="tab2.html" selected="true">SubTab 2</a>
+		</div>
+
+	</div>
+
+	<p>
+		The next example is with closable tabs.
+		Tab 1 and Tab 3 can be closed; Tab 3 has a confirm box.
+	</p>
+
+	<div id="ttabs" dojoType="dijit.layout.TabContainer" labelPosition="top" style="width: 100%; height: 10em;">
+		<div id="ttab1" dojoType="dijit.layout.ContentPane" href="tab1.html" label="Tab 1" closable="true"></div>
+		<div id="ttab2" dojoType="dijit.layout.ContentPane" href="tab2.html" refreshOnShow="true" label="Tab 2"></div>
+		<div dojoType="dijit.layout.ContentPane" label="Tab 3" onClose="testClose" closable="true">
+			<h1>I am tab 3</h1>
+			<p>And I was already part of the page! That's cool, no?</p>
+			<p>If you try to close me there should be a confirm dialog.</p>
+		</div>
+	</div>
+	
+	<p>Tabs with labels on the bottom:</p>
+
+	<div id="btabs" dojoType="dijit.layout.TabContainer" labelPosition="bottom" style="width: 100%; height: 10em;">
+		<div id="btab1" dojoType="dijit.layout.ContentPane" href="tab1.html" label="Tab 1" closable="true"></div>
+		<div id="btab2" dojoType="dijit.layout.ContentPane" href="tab2.html" refreshOnShow="true" onLoad="console.debug('Tab2 onLoad');" label="Tab 2"></div>
+	</div>
+	
+	<p>Tabs with labels on the left:</p>
+
+	<div id="lhtabs" dojoType="dijit.layout.TabContainer" labelPosition="left-h" style="width: 100%; height: 10em;">
+		<div id="lhtab1" dojoType="dijit.layout.ContentPane" href="tab1.html" label="Tab 1"></div>
+		<div id="lhtab2" dojoType="dijit.layout.ContentPane" href="tab2.html" refreshOnShow="true" label="Tab 2"></div>
+	</div>
+	
+	<p>Tabs with labels on the right:</p>
+
+	<div id="lrtabs" dojoType="dijit.layout.TabContainer" labelPosition="right-h" style="width: 100%; height: 10em;">
+		<div id="rhtab1" dojoType="dijit.layout.ContentPane" href="tab1.html" label="Tab 1"></div>
+		<div id="rhtab2" dojoType="dijit.layout.ContentPane" href="tab2.html" refreshOnShow="true" label="Tab 2"></div>
+	</div>
+
+	<h3>Typical rendering time</h3>
+	<table border=1>
+	  <tr><th>IE</th><th>Firefox (mac)</th></tr>
+	  <tr><td>1719</td><td>922</td></tr>
+	</table>  
+	<h3>Rendering time</h3>
+</body>
+
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/module.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/module.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/module.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,11 @@
+dojo.provide("dijit.tests.module");
+
+dojo
+try{
+	dojo.require("dijit.tests.widgetsInTemplate");
+//	dojo.require("tests.currency");
+}catch(e){
+	doh.debug(e);
+}
+
+

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/parser.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/parser.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/parser.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+	<title>widget infrastructure test</title>
+	<script type="text/javascript" src="../../dojo/dojo.js"
+		djConfig="isDebug: true"></script>
+	<script type="text/javascript">
+		dojo.require("dijit.form.Button");
+		dojo.require("dijit.util.parser");	// find widgets
+	</script>
+	<style type="text/css">
+		@import "../../dojo/resources/dojo.css";
+		@import "../themes/tundra/tundra.css";
+	</style>
+</head>
+<body style="padding: 50px;">
+	<button dojoType="dijit.form.Button" id="b1" style="background: yellow;">button #1</button>
+	<button dojoType="dijit.form.Button" id="b2" caption="button #2" style="background: orange;"></button>
+	<button dojoType="dijit.form.Button" id="b3" style="background: violet;">button #3</button>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/runTests.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/runTests.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/runTests.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+    <head>
+    <title>Dijit Unit Test Runner</title>
+    <meta http-equiv="REFRESH" content="0;url=../../util/doh/runner.html?testModule=dijit.tests.module"></HEAD>
+    <BODY>
+        Redirecting to D.O.H runner.
+    </BODY>
+</HTML> 

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/test.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/test.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/test.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+	<title>widget infrastructure test</title>
+	<script type="text/javascript" src="../../dojo/dojo.js"
+		djConfig="isDebug: true, debugAtAllCosts: true"></script>
+	<script type="text/javascript">
+		dojo.require("dijit.form.Button");
+	</script>
+	<style type="text/css">
+		@import "../../dojo/resources/dojo.css";
+		@import "../themes/tundra/tundra.css";
+		body { padding: 5em; }
+	</style>
+</head>
+<body>
+	<button id="b1" style="background: yellow;">button #1</button>
+	<button id="b2" style="background: orange;">button #2</button>
+	<button id="b3" style="background: violet;">button #3</button>
+	<script>
+		for(var i=1; i<=3; i++){
+			var node = dojo.byId("b"+i);
+			var myButton = new dijit.form.Button(null, node);
+		}
+	</script>	
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/testBidi.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/testBidi.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/testBidi.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,6 @@
+// Include this in test pages so that ?test-bidi appended to the URL will result in a page rendered right-to-left
+// to test bi-directional support for middle eastern languages.
+
+if (window.location.href.indexOf("test-bidi") > -1) {
+	document.getElementsByTagName("html")[0].dir = "rtl";
+}

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/test_Calendar.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/test_Calendar.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/test_Calendar.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>Calendar Widget Test</title>
+		<style type="text/css">
+			@import "../../dojo/resources/dojo.css";
+			@import "../themes/tundra/tundra.css";
+			@import "css/dijitTests.css";
+		</style>
+		
+		<script type="text/javascript" src="testBidi.js"></script>
+		
+		<script type="text/javascript" src="../../dojo/dojo.js"
+			djConfig="isDebug: true, extraLocale: ['en-us', 'ar-sy', 'es-es', 'zh-cn']"></script>
+		<script type="text/javascript">
+			dojo.require("dijit._Calendar");
+			dojo.require("dojo.date.locale");
+			dojo.require("dijit.util.parser"); // scan page for widgets
+
+			function myHandler(id,newValue){
+				console.debug("onValueChanged for id = " + id + ", value: " + newValue);
+			}
+		</script>
+	</head>
+	<body class="tundra">
+		<h1 class="testTitle">Dijit Calendar Test</h1>
+
+		before
+		<input id="calendar1" dojoType="dijit._Calendar" onValueChanged="myHandler(this.id,arguments[0])" lang="en-us">
+		<input id="calendar2" dojoType="dijit._Calendar" onValueChanged="myHandler(this.id,arguments[0])" lang="es-es">
+		<input id="calendar3" dojoType="dijit._Calendar" onValueChanged="myHandler(this.id,arguments[0])" lang="zh-cn">
+		<input id="calendar4" dojoType="dijit._Calendar" onValueChanged="myHandler(this.id,arguments[0])" lang="ar-sy">
+		after
+		<p>
+			<a href="#" onClick="for(var i=1; i!=5; i++){
+									var c = dijit.byId('calendar'+i);
+									c.isDisabledDate=dojo.date.locale.isWeekend;
+									c._populateGrid();
+									
+								}									
+								">disable weekends</a>
+		</p>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/test_ColorPalette.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/test_ColorPalette.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/test_ColorPalette.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>ColorPalette Test</title>
+<style type="text/css">
+	@import "../../dojo/resources/dojo.css";
+	@import "../themes/tundra/tundra.css";
+	@import "css/dijitTests.css";
+</style>
+
+<script type="text/javascript" src="testBidi.js"></script>
+
+<script type="text/javascript" src="../../dojo/dojo.js" djConfig="isDebug: true, debugAtAllCosts: true"></script>
+<script language="JavaScript" type="text/javascript">
+	dojo.require("dijit.ColorPalette");
+	dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+</script>
+<script>
+	var palette;
+	function init(){
+		palette = new dijit.ColorPalette({palette: "7x10", id: "progPalette"}, dojo.byId("programPalette"));
+	}
+	dojo.addOnLoad(init); 
+
+	function setColor(color)
+	{
+	
+		var theSpan = dojo.byId("outputSpan");
+		theSpan.style.color = "#"+color;
+		theSpan.innerHTML = color;
+	
+	}
+</script>
+</head>
+<body class="tundra">
+<p>Default color palette (7x10):</p>
+<div dojoType="dijit.ColorPalette" onColorSelect="setColor(this.selectedColor);"></div>  
+Test color is: <span id="outputSpan"></span>.
+
+<p>Small color palette (3x4):</p>
+<div dojoType="dijit.ColorPalette" palette="3x4"></div>
+
+<p>Default color palette (7x10) created via createWidget:</p>
+<div id="programPalette"></div>
+</body>
+
+</html>
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/test_Declaration.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/test_Declaration.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/test_Declaration.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>Dojo Toolkit - ProgressBar test</title>
+		<style type="text/css">
+			@import "../../dojo/resources/dojo.css";
+			@import "../themes/tundra/tundra.css";
+			@import "css/dijitTests.css";
+		</style>
+		<script type="text/javascript" src="../../dojo/dojo.js"
+			djConfig="isDebug: true"></script>
+		<script type="text/javascript">
+			dojo.require("dijit.Declaration");
+			dojo.require("dijit.ProgressBar");
+			dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+		</script>
+	</head> 
+
+	<body class='tundra'>
+		<div dojoType="dijit.Declaration" widgetClass="foo" 
+			defaults="{ foo: 'thud', progress: 10 }">
+			<p>thinger blah stuff ${foo}</p>
+			<div style="width:400px" annotate="true"
+				maximum="200" id="setTestBar" progress="${progress}" dojoType="dijit.ProgressBar"></div>
+			<p>baz thud</p>
+		</div>
+
+		<div dojoType="foo" foo="blah" progress="50"></div>
+		<div dojoType="foo" foo="thinger" progress="73"></div>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/test_Menu.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/test_Menu.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/test_Menu.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,158 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Menu System Test</title>
+<style type="text/css">
+	@import "../../dojo/resources/dojo.css";
+	@import "../themes/tundra/tundra.css";
+	@import "css/dijitTests.css";
+</style>
+
+<script type="text/javascript" src="testBidi.js"></script>
+
+<script type="text/javascript" src="../../dojo/dojo.js" djConfig="isDebug: true, debugAtAllCosts: true"></script>
+<script language="JavaScript" type="text/javascript">
+	dojo.require("dijit.Menu");
+	dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+</script>
+</head>
+<body class="tundra">
+
+<div dojoType="dijit.PopupMenu" id="submenu1" contextMenuForWindow="true" style="display: none;">
+	<div dojoType="dijit.MenuItem" caption="Enabled Item" onClick="alert('Hello world');"></div>
+	<div dojoType="dijit.MenuItem" caption="Disabled Item" disabled="true"></div>
+	<div dojoType="dijit.MenuSeparator"></div>
+	<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/cut.gif" caption="Cut" accelKey="Ctrl+C"
+		onClick="alert('not actually cutting anything, just a test!')"></div>
+	<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/copy.gif" caption="Copy" accelKey="Ctrl+X"
+		onClick="alert('not actually copying anything, just a test!')"></div>
+	<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/paste.gif" caption="Paste" accelKey="Ctrl+V"
+		onClick="alert('not actually pasting anything, just a test!')"></div>
+	<div dojoType="dijit.MenuSeparator"></div>
+	<div dojoType="dijit.MenuItem" caption="Enabled Submenu" submenuId="submenu2"></div>
+	<div dojoType="dijit.MenuItem" caption="Disabled Submenu" submenuId="submenu2" disabled="true"></div>
+</div>
+
+<div dojoType="dijit.PopupMenu" id="submenu2" style="display: none;">
+	<div dojoType="dijit.MenuItem" caption="Submenu Item One" onClick="alert('Submenu 1!')"></div>
+	<div dojoType="dijit.MenuItem" caption="Submenu Item Two" onClick="alert('Submenu 2!')"></div>
+</div>
+<!--
+<div dojoType="dijit.MenuBar">
+	<div dojoType="dijit.MenuBarItem" caption="File" submenuId="submenu1"></div>
+	<div dojoType="dijit.MenuBarItem" caption="Edit" submenuId="submenu"></div>
+	<div dojoType="dijit.MenuBarItem" caption="View" disabled="true"></div>
+	<div dojoType="dijit.MenuBarItem" caption="Help" submenuId="submenu"></div>
+	<div dojoType="dijit.MenuBarItem" caption="Click Me" onClick="alert('you clicked a menu bar button');"></div>
+</div>
+-->
+<div style="padding: 1em">
+	<h1 class="testTitle">Dijit Menu System Test</h1>
+	
+	<h3>Form</h3>
+
+	<form>
+		<input id=input1 value=tom><br>
+		<input id=input2 value=jones><br>
+		<textarea id=textarea>hello there!</textarea><br>
+		<button id=button>push me</button>
+	</form>
+
+	<p>See also: <a href="form/test_Button.html">form/test_Button</a>
+	(PopupMenu is used with DropDownButton and ComboButton)</p>
+
+	<h3>Mouse opening tests</h3>
+
+	<ul>
+		<li>Right click on the client area of the page (ctrl-click for Macintosh). Menu should open.</li>
+		<li>Right click on each of the form controls above. Menu should open.</li>
+		<li>Right click near the righthand window border. Menu should open to the left of the pointer.</li>
+		<li>Right click near the bottom window border. Menu should open above the pointer.</li>
+	</ul>
+
+
+	<h3>Mouse hover tests</h3>
+
+	<ul>
+		<li>Hover over the first item with the pointer. Item should highlight and get focus.</li>
+		<li>Hover over the second (disabled) item. Item should highlight and get focus.</li>
+		<li>Seperator items should not highlight on hover - no items should highlight in this case.</li>
+		<li>Remove the pointer from the menu. Should de-highlight all items.</li>
+	</ul>
+
+
+	<h3>Mouse click tests</h3>
+
+	<ul>
+		<li>Click on the first menu item. Alert should open with the message "Hello world". The menu should dissapear.</li>
+		<li>Click on the second menu item (disabled). Should not do anything - focus should remain on the disabled item.</li>
+		<li>Click anywhere outside the menu. Menu should close. Focus will be set by the browser based on where the user clicks.</li>
+	</ul>
+
+
+	<h3>Mouse submenu tests</h3>
+
+	<ul>
+		<li>Hover over the "Enabled Submenu" item. Item should highlight and then pop open a submenu after a short (500ms) delay.</li>
+		<li>Hover over any of the other menu items. Submenu should close immediately and deselect the submenu parent item. The newly hovered item should become selected.</li>
+		<li>Hover over the "Disabled Submenu" item. Item should highlight, but no submenu should appear.</li>
+		<li>Clicking on the "Enabled Submenu" item before the submenu has opened (you'll have to be quick!) should immediatley open the submenu.</li>
+		<li>Clicking on the "Enabled Submenu" item <i>after</i> the submenu has opened should have no effect - the item is still selected and the submenu still open.</li>
+		<li>Hover over submenu item 1. Should select it - the parent menu item should stay selected also.</li>
+		<li>Hover over submenu item 2. Should select it - the parent menu item should stay selected also.</li>
+		<li>Remove the pointer from both menus. Should de-highlight all items in the submenu and keep the parent menu item highlighted. The submenu should remain open.</li>
+		<li>While the submenu is open, hovering over the parent menu item should keep the submenu open with no items selected, while the parent menu item stays selected.</li>
+	</ul>
+
+
+	<h3>Keyboard opening tests</h3>
+
+	<ul>
+		<li>On Windows: press shift-f10 with focus on any of the form controls. Should open the menu.</li>
+		<li>On Windows: press the context menu key (located on the right of the space bar on North American keyboards) with focus on any of the form controls. Should open the menu.</li>
+		<li>On Firefox on the Mac: press ctrl-space with focus on any of the form controls. Should open the menu.</li>
+	</ul>
+
+	
+	<h3>Keyboard closing tests</h3>
+	
+	<ul>
+		<li>Open the menu.</li>
+		<li>Press tab. Should close the menu and return focus to where it was before the menu was opened.</li>
+		<li>Open the menu.</li>
+		<li>Press escape. Should close the menu and return focus to where it was before the menu was opened.</li>
+	</ul>
+
+
+	<h3>Keyboard navigation tests</h3>
+
+	<ul>
+		<li>Open the menu.</li>
+		<li>Pressing up or down arrow should cycle focus through the items in that menu.</li>
+		<li>Pressing enter or space should invoke the menu item.</li>
+		<li>Disabled items receive focus but no action is taken upon pressing enter or space.</li>
+	</ul>
+
+
+	<h3>Keyboard submenu tests</h3>
+
+	<ul>
+		<li>Open the menu.</li>
+		<li>Press the down arrow. The first item should become selected.</li>
+		<li>Press the right arrow key. Nothing should happen.</li>
+		<li>Press the left arrow key. Nothing should happen.</li>
+		<li>Press the down arrow until "Enabled Submenu" is selected. The submenu should not appear.</li>
+		<li>Press enter. The submenu should appear with the first item selected.</li>
+		<li>Press escape. The submenu should vanish - "Enabled Submenu" should remain selected.</li>
+		<li>Press the right arrow key. The submenu should appear with the first item selected.</li>
+		<li>Press the right arrow key. Nothing should happen.</li>
+		<li>Press the left arrow key. The submenu should close - "Enabled Submenu" should remain selected.</li>
+		<li>Press the left arrow key. The menu should <i>not</i> close and "Enabled Submenu" should remain selected.</li>
+		<li>Press escape. The menu should close and focus should be returned to where it was before the menu was opened.</li>
+	</ul>
+
+</div>
+
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/test_Menu_Debuggable.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/test_Menu_Debuggable.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/test_Menu_Debuggable.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,273 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Menu System Test</title>
+<style type="text/css">
+	@import "../../dojo/resources/dojo.css";
+	@import "../themes/tundra/tundra.css";
+	@import "css/dijitTests.css";
+</style>
+
+<script type="text/javascript" src="testBidi.js"></script>
+
+<script type="text/javascript">
+	djConfig = { isDebug: true, baseUrl: "../../dojo/"  };
+</script>
+
+<script type="text/javascript" src="../../dojo/_base/_loader/bootstrap.js"></script>
+<script type="text/javascript" src="../../dojo/_base/_loader/loader.js"></script>
+<script type="text/javascript" src="../../dojo/_base/_loader/hostenv_browser.js"></script>
+<script type="text/javascript" src="../../dojo/_base/lang.js"></script>
+<script type="text/javascript" src="../../dojo/_base/declare.js"></script>
+<script type="text/javascript" src="../../dojo/_base/connect.js"></script>
+<script type="text/javascript" src="../../dojo/_base/Deferred.js"></script>
+<script type="text/javascript" src="../../dojo/_base/json.js"></script>
+<script type="text/javascript" src="../../dojo/_base/array.js"></script>
+<script type="text/javascript" src="../../dojo/_base/event.js"></script>
+<script type="text/javascript" src="../../dojo/_base/html.js"></script>
+<script type="text/javascript" src="../../dojo/_base/NodeList.js"></script>
+<script type="text/javascript" src="../../dojo/_base/query.js"></script>
+<script type="text/javascript" src="../../dojo/_base/xhr.js"></script>
+<script type="text/javascript" src="../../dojo/_base/fx.js"></script>
+
+<!--<script type="text/javascript" src="../../dojo/dojo.js" djConfig="isDebug: true, debugAtAllCosts: true"></script>-->
+
+<script type="text/javascript" src="../util/PopupManager.js"></script>
+<script type="text/javascript" src="../Menu.js"></script>
+<script type="text/javascript" src="../util/parser.js"></script>
+
+<!--<script type="text/javascript">
+	dojo.require("dijit.Menu");
+	dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+</script>-->
+
+</head>
+<body class="tundra">
+
+<div dojoType="dijit.PopupMenu" id="submenu1" contextMenuForWindow="true" style="display: none;">
+	<div dojoType="dijit.MenuItem" caption="Enabled Item" onClick="alert('Hello world');"></div>
+	<div dojoType="dijit.MenuItem" caption="Disabled Item" disabled="true"></div>
+	<div dojoType="dijit.MenuSeparator"></div>
+	<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/cut.gif" caption="Cut" accelKey="Ctrl+C"
+		onClick="alert('not actually cutting anything, just a test!')"></div>
+	<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/copy.gif" caption="Copy" accelKey="Ctrl+X"
+		onClick="alert('not actually copying anything, just a test!')"></div>
+	<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/paste.gif" caption="Paste" accelKey="Ctrl+V"
+		onClick="alert('not actually pasting anything, just a test!')"></div>
+	<div dojoType="dijit.MenuSeparator"></div>
+	<div dojoType="dijit.MenuItem" caption="Enabled Submenu" submenuId="submenu2"></div>
+	<div dojoType="dijit.MenuItem" caption="Disabled Submenu" submenuId="submenu2" disabled="true"></div>
+</div>
+
+<div dojoType="dijit.PopupMenu" id="submenu2" style="display: none;">
+	<div dojoType="dijit.MenuItem" caption="Submenu Item One" onClick="alert('Submenu 1!')"></div>
+	<div dojoType="dijit.MenuItem" caption="Submenu Item Two" onClick="alert('Submenu 2!')"></div>
+</div>
+<!--
+<div dojoType="dijit.MenuBar">
+	<div dojoType="dijit.MenuBarItem" caption="File" submenuId="submenu1"></div>
+	<div dojoType="dijit.MenuBarItem" caption="Edit" submenuId="submenu"></div>
+	<div dojoType="dijit.MenuBarItem" caption="View" disabled="true"></div>
+	<div dojoType="dijit.MenuBarItem" caption="Help" submenuId="submenu"></div>
+	<div dojoType="dijit.MenuBarItem" caption="Click Me" onClick="alert('you clicked a menu bar button');"></div>
+</div>
+-->
+<div style="padding: 1em">
+	<h1 class="testTitle">Dijit Menu System Test</h1>
+	
+	<h2>This page has a menu bar and context menu</h2>
+
+	<h3>Form</h3>
+	<p>This is for testing whether focus and selection are restored after a popup menu closes</p>
+	<form>
+		<input id=input1 value=tom><br>
+		<input id=input2 value=jones><br>
+		<textarea id=textarea>hello there!</textarea><br>
+		<button id=button>push me</button>
+	</form>
+
+	<h3>Popup opening tests</h3>
+
+	<ul>
+		<li>Right clicking on the client area of the page (ctrl-click for opera) should make a popup menu appear.</li>
+		<li>Right clicking near the righthand window border should open the menu to the left of the pointer.</li>
+		<li>Right clicking near the bottom window border should open the menu above the pointer.</li>
+		<li>Scrolling the contents of this scrollable area and right-clicking should make the menu appear at the pointer.</li>
+		<li>When the popup menu appears, it should not have any items pre-selected (blue background by default - ymmv).</li>
+		<li>In IE, test bleed through here <select><option>popupmenu</option><option>should</option><option>cover</option><option>this</option><option>select</option></select></li>
+	</ul>
+
+
+	<h3>Popup hover tests</h3>
+
+	<ul>
+		<li>Hovering over the first item with the pointer should highlight it.</li>
+		<li>Hovering over the second (disabled) item should also highlight it.</li>
+		<li>Seperator items should not highlight on hover - no items should highlight in this case.</li>
+		<li>Removing the pointer from the menu should de-highlight all items.</li>
+	</ul>
+
+
+	<h3>Popup click tests</h3>
+
+	<ul>
+		<li>Clicking on the first menu item should alert with the message "<i>Hello world</i>". The menu should dissapear.</li>
+		<li>Clicking on the second menu item (disabled) should not do anything - focus should remain on the disabled item.</li>
+		<li>Clicking anywhere outside the menu should hide the menu.</li>
+	</ul>
+
+
+	<h3>Popup submenu tests</h3>
+
+	<ul>
+		<li>Hovering over item three (enabled submenu) should highlight the item and then pop open a submenu after a short (500ms) delay</li>
+		<li>Hovering over either of the first two items should close the submenu immediately and deselect the submenu parent item. The newly hovered item should become selected.</li>
+		<li>Hovering over item four (disabled submenu) should highlight the item, but no submenu should appear.</li>
+		<li>Clicking on item 3 before the submenu has opened (you'll have to be quick!) should immediatley open the submenu.</li>
+		<li>Clicking on item 3 <i>after</i> the submenu has opened should have no effect - the item is still selected and the submenu still open.</li>
+		<li>Clicking on item 4 should do nothing - the item remains selected and the menu remains open.</li>
+		<li>Hovering over submenu item 1 should select it - the parent menu item should stay selected also.</li>
+		<li>Hovering over submenu item 2 should select it - the parent menu item should stay selected also.</li>
+		<li>Removing the pointer from both menus should de-highlight all items in the submenu and keep the parent menu item highlighted. The submenu should remain open.</li>
+		<li>While the submenu is open, hovering over the parent menu item should keep the submenu open with no items selected, while the parent menu item stays selected.</li>
+	</ul>
+
+
+	<h3>Menubar hover tests (<i>1 error</i>)</h3>
+
+	<ul>
+		<li>Hovering over any of the four menu bar items should highlight them to state 1 (raised 3D). No submenus should appear.</li>
+		<li>Removing the mouse from all menu bar items should de-highlight all items.</li>
+		<li>Clicking on the disabled item (item 3) should change it's highlight to state 2 (sunken 3D).</li>
+		<li>Removing the mouse from all menu bar items should leave item 3 highlighted in state 2.</li>
+		<li>Hovering over item 2 should cause its popups to open and it's highlight state to change to 2 - item 3 should become de-highlighted.</li>
+		<li>Hovering over item 3 again should hide the popup menu, de-highlight item 2 and change item 3's highlight to state 2.</li>
+		<li>Removing the pointer from item 3 should leave item 3 in highlighted state 2 with no submenu showing.</li>
+		<li>Clicking elsewhere on the page should de-highlight all items (<b>currently broken - disabled item stays in state 2</b>).</li>		
+		<li>Clicking on the first item should open a submenu below the item. The parent item should be highlighted in state 2 (sunken 3D) with none of the submenu items highlighted.</li>
+		<li>Hovering the pointer over the second item should hide the first submenu and show a new submenu under the newly selected item. The first parent item should become de-selected while the second parent item should be highlighted in state 2.</li>
+		<li>Removing the mouse from all menu bar items again should leave the submenu open and the parent item selected in state 2.</li>
+		<li>Clicking elsewhere on the page should close the submenu and deselect all menu bar items.</li>
+		<li>Hovering over any menu bar items again should highlight them in state 1.</li>
+	</ul>
+
+
+	<h3>Menubar click tests</h3>
+
+	<ul>
+		<li>Clicking on bar item 1 should open up a submenu.</li>
+		<li>Click on item 1 in the submenu - an alert should say "<i>hello world</i>". The submenu should dissapear and the menu bar items should all be deselected.</li>
+		<li>Clicking on bar item 1 should open up a submenu.</li>
+		<li>Click on item 3 in the submenu to open a subsubmenu. Item 1 in the menu bar should remain depressed and item 3 in the submenu should remain highlighted.</li>
+		<li>Hover over item 1 in the subsubmenu. Item 1 in the menu bar should remain depressed and item 3 in the submenu should remain highlighted.</li>
+		<li>Click on item 1 in the subsubmenu - an alert should say "<i>submenu 1!</i>". The submenu and subsubmenu should dissapear and the menu bar items should all be deselected.</li>
+		<li>Click on bar item 1 and then submenu item 3 to expand the subsubmenu as before.</li>
+		<li>Hover over bar item 2. The subsubmenu and submenu should close immediately and a new submenu open under bar item 2.</li>
+		<li>Hover over bar item 1. The submenu should appear, while item 2's submenu should vanish.</li>
+		<li>Click on submenu item 3 to expand the subsubmenu as before.</li>
+		<li>Click elsewhere on the page - the submenu and subsubmenu should dissapear and the bar items should all become deselected.</li>
+	</ul>
+
+	<h3>Popup key tests (<i>mostly failing</i>)</h3>
+
+	<ul>
+		<li>Right click on the page to show the context menu. No items should be selected.</li>
+		<li>Press the left arrow. Nothing should happen.</li>
+		<li>Press the right arrow. Nothing should happen.</li>
+		<li>Press escape. The menu should vanish.</li>
+	</ul>
+	<ul>
+		<li>Right click on the page to show the context menu. No items should be selected.</li>
+		<li>Press enter. The menu should vanish.</li>
+	</ul>
+	<ul>
+		<li>Right click on the page to show the context menu. No items should be selected.</li>
+		<li>Press the down arrow. The top item should become selected.</li>
+		<li>Press escape. The menu should vanish.</li>
+	</ul>
+	<ul>
+		<li>Right click on the page to show the context menu. No items should be selected.</li>
+		<li>Press the up arrow. The bottom item should become selected.</li>
+		<li>Press escape. The menu should vanish.</li>
+	</ul>
+	<ul>
+		<li>Right click on the page to show the context menu. No items should be selected.</li>
+		<li>Press the up arrow. The bottom item should become selected.</li>
+		<li>Press the up arrow. The next item up should become selected.</li>
+		<li>Press the up arrow until the top item becomes selected.</li>
+		<li>Press the up arrow again. The bottom item should become selected.</li>
+		<li>Press the down arrow again. The top item should become selected.</li>
+		<li>Press the down arrow until the bottom item becomes selected.</li>
+		<li>Press the down arrow again. The top item should become selected.</li>
+		<li>Press escape. The menu should vanish.</li>
+	</ul>
+	<ul>
+		<li>Select some text in this scrolling box.</li>
+		<li>Right click on the page to show the context menu. No items should be selected.</li>
+		<li>Press the up and down arrows several times. The scrolling box should not scroll when the selected menu item changes.</li>
+		<li>Press escape. The menu should vanish.</li>
+	</ul>
+	<ul>
+		<li>Right click on the page to show the context menu. No items should be selected.</li>
+		<li>Press the down arrow. The top item should become selected.</li>
+		<li>Press enter. An alert should fire with "<i>hello world</i>". The menu should vanish.</li>
+	</ul>
+
+	<h3>Submenu key tests (<i>mostly failing</i>)</h3>
+
+	<ul>
+		<li>Right click on the page to show the context menu. No items should be selected.</li>
+		<li>Press the down arrow. The first item should become selected.</li>
+		<li>Press the right arrow key. Nothing should happen.</li>
+		<li>Press the left arrow key. Nothing should happen.</li>
+		<li>Press the down arrow twice. The third item should become selected. The submenu should not appear.</li>
+		<li>Press enter. The submenu should appear with the first item selected.</li>
+		<li>Press escape. The submenu should vanish - item three should remain selected.</li>
+		<li>Press the right arrow key. The submenu should appear with the first item selected.</li>
+		<li>Press the right arrow key. Nothing should happen.</li>
+		<li>Press the left arrow key. The submenu should vanish - item three should remain selected.</li>
+		<li>Press the left arrow key. The context menu should <i>not</i> vanish and item three should remain selected.</li>
+		<li>Press escape. The context menu should vanish.</li>
+	</ul>
+
+	<ul>
+		<li>Right click on the page to show the context menu. No items should be selected.</li>
+		<li>Press the down arrow three times. The third item should become selected. The submenu should not appear.</li>
+		<li>Press enter. The submenu should appear with the first item selected.</li>
+		<li>Press the down arrow. The second item in the submenu should be selected.</li>
+		<li>Press the up arrow. The first item in the submenu should be selected.</li>
+		<li>Press the up arrow. The last item in the submenu should be selected.</li>
+		<li>Press escape. The submenu should vanish, leaving item three selected.</li>
+		<li>Press escape. The context menu should vanish.</li>
+	</ul>
+
+	<h3>Menubar key tests (<i>mostly failing</i>)</h3>
+
+	<ul>
+		<li>Hover the pointer over bar item one. It should highlight in state 1.</li>
+		<li>Press the left, right, up and down arrows - the menu should be unaffected (the window may scroll, if focused).</li>
+		<li>Click on menu bar item 1. The popup should appear with no items selected. The bar item should highlight in state 2.</li>
+		<li>Press the right arrow. The bar selection should change to item 2. Bar item 1's popup should vanish and bar item 2's popup should appear with item 1 selected.</li>
+		<li>Press the left arrow. The bar selection should change to item 1. Bar item 2's popup should vanish and bar item 1's popup should appear with item 1 selected.</li>
+		<li>Press the left arrow. The bar selection should change to item 4. Bar item 1's popup should vanish and bar item 4's popup should appear with item 1 selected.</li>
+		<li>Press the right arrow. The bar selection should change to item 1. Bar item 4's popup should vanish and bar item 1's popup should appear with item 1 selected.</li>
+		<li>Press the down arrow repeatedly - the selection within the popup should move down until it hits the bottom item, after which the top item should become selected.</li>
+		<li>Press the up arrow repeatedly - the selection within the popup should move up until it hits the top item, after which the bottom item should become selected.</li>
+		<li>Press escape. The popup should vanish but the bar item should stay highlighted in mode 2 (windows does this, but maybe we should forget it?)
+		<li>Press escape. The bar item should become unhighlighted.</li>
+	</ul>
+
+	<h3>TODO tests</h3>
+
+	<ul>
+		<li>TODO: left and right with no popups open and bar item selected (only if we allow this)</li>
+		<li>TODO: popup submenu opening tests</li>
+		<li>TODO: left and right within submenus testing</li>
+		<li>TODO: key/mouse switchover tests (these get complicated)</li>
+	</ul>
+
+</div>
+
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/test_ProgressBar.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/test_ProgressBar.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/test_ProgressBar.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,164 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>Dojo Toolkit - ProgressBar test</title>
+		<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+		<style type="text/css">
+			@import "../../dojo/resources/dojo.css";
+			@import "../themes/tundra/tundra.css";
+			@import "css/dijitTests.css";
+
+			body {
+				margin: 1em;
+			}
+
+			.smallred .dijitProgressBarTile { 
+				background:red;
+			}
+			.smallred .dijitProgressBarEmptyLabel,
+			.smallred .dijitProgressBarFullLabel {
+				display:none;
+			}
+		</style>
+		
+		<script type="text/javascript" src="testBidi.js"></script>
+		
+		<script type="text/javascript" src="../../dojo/dojo.js"
+			djConfig="isDebug: true"></script>
+		<script type="text/javascript">
+			dojo.require("dijit.ProgressBar");
+			dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+			dojo.require("dojo.string");
+		</script>
+		
+		<script type="text/javascript">
+			dojo.addOnLoad(go);
+			function go(){
+				//TODO: it's a little strange that id must be specified again?	
+				var theBar = new dijit.ProgressBar({id: "testBar", width: 400, annotate: true, maximum: 256, duration: 2000,
+					report:function(percent){
+						return dojo.string.substitute("${0} out of ${1} max chars", [this.progress, this.maximum]);
+					}
+				}, dojo.byId("testBar"));
+				dojo.connect(dojo.byId("start"), "onclick", null, dojo.hitch(theBar,theBar.startAnimation));
+				dojo.connect(dojo.byId("stop"), "onclick", null, dojo.hitch(theBar,theBar.stopAnimation));
+
+				dojo.byId("test").value="";
+				dojo.byId("progressValue").focus();
+				dojo.byId("progressValue").value = dijit.byId("setTestBar").progress;
+				dojo.byId("maximum").value = dijit.byId("setTestBar").maximum;
+				dojo.connect(dojo.byId("test"), "onkeyup", null, keyUpHandler);
+				dojo.connect(dojo.byId("set"), "onclick", null, setParameters);
+				dojo.connect(dojo.byId("startTimer"), "onclick", null,
+					function(){ remoteProgress(dijit.byId("timerBar")); } );
+			}
+
+// An example of polling on a separate (heartbeat) server thread.  This is useful when the progress is entirely server bound
+// and there is no existing interaction with the server to determine status.
+
+// We don't have a server to run against, but a simple heartbeat implementation might look something like this:
+//function getProgressReport(){
+//		var dataSource = "http://dojotoolkit.org";
+//		return dojo.xhrGet({url: dataSource, handleAs: "json", content: {key: "progress"}});
+//}
+
+// Instead, we'll just tick off intervals of 10
+var fakeProgress = 0;
+function getProgressReport(){
+	var deferred = new dojo.Deferred();
+	fakeProgress = Math.min(fakeProgress + 10, 100);
+	deferred.callback(fakeProgress+"%");
+	return deferred;
+}
+
+function remoteProgress(bar){
+
+	var _timer = setInterval(function(){
+		var report = getProgressReport();
+		report.addCallback(function(response){
+			bar.update({progress: response});
+			if(response == "100%"){
+				clearInterval(_timer);
+				_timer = null;
+				return;
+			}
+		});
+	}, 3000); // on 3 second intervals
+}
+
+			function setParameters(){
+				dijit.byId("setTestBar").update({maximum: dojo.byId("maximum").value, progress: dojo.byId("progressValue").value});
+			}
+			function keyUpHandler(){
+				dijit.byId("testBar").update({progress:dojo.byId("test").value.length});
+				dijit.byId("testBarInt").update({progress:dojo.byId("test").value.length});
+				dijit.byId("testBarVert").update({progress:dojo.byId("test").value.length});
+				dijit.byId("smallTestBar").update({progress:dojo.byId("test").value.length});
+			}
+/*
+			function moveBar(bar, progress){
+				bar.update({progress: progress});
+				if (progress >= 100) {
+					return;
+				} else {
+					setTimeout(function(){ moveBar(bar, progress + 10) }, 1000);
+				}
+			}
+*/
+		</script>
+	</head> 
+
+	<body class='tundra'>
+		<h3>Test 1</h3>
+		Progress Value <input type="text" name="progressValue" id="progressValue" />
+		<br />
+		Max Progress Value <input type="text" name="maximum" id="maximum" />
+		<br />
+		<input type="button" name="set" id="set" value="set!" />
+		<br />
+		<div style="width:400px" annotate="true"
+			maximum="200" id="setTestBar" progress="20" dojoType="dijit.ProgressBar"></div>
+		<br />
+		<br />
+		<h3>Test 2</h3>
+		Write here: <input type="text" value="" name="test" maxlength="256" id="test" style="width:300"/>
+		<br />
+		<br />
+		<div id="testBar" style='width:300px'></div>		
+		<input type="button" name="start" id="start" value="start" />
+		<input type="button" name="stop" id="stop" value="stop" />
+		<br />
+		Small, without text and background image:
+		<br />
+		<div style="width:400px; height:10px" class="smallred" orientation="horizontal" 
+			maximum="256" id="smallTestBar" dojoType="dijit.ProgressBar"></div>		
+		<br />
+		Show decimal place:
+		<div places="1" style="width:400px" annotate="true" orientation="horizontal"
+			maximum="256" id="testBarInt" dojoType="dijit.ProgressBar"></div>
+		<br />
+		<div style="position:absolute;top:70px;left:530px">
+		Vertical:
+		<div progress="0" style="height:420px; width:50px" annotate="true" orientation="vertical" 
+				maximum="256" id="testBarVert" dojoType="dijit.ProgressBar"></div>
+		</div>
+		<h3>Test 3</h3>
+		No explicit maximum (both 50%)
+		<div style="width:400px" annotate="true"
+			id="implied1" progress="50" dojoType="dijit.ProgressBar"></div>		
+		<br />
+		<div style="width:400px" annotate="true"
+			id="implied2" progress="50%" dojoType="dijit.ProgressBar"></div>
+		<h3>Test 4</h3>
+		<input type="button" name="startTimer" id="startTimer" value="Start Timer" />
+		<div style="width:400px" id="timerBar" annotate="true"
+			maximum="100" progress="0" dojoType="dijit.ProgressBar"></div>
+
+		<h3>Test 5 - indeterminate progess</h3>
+		<input type="button" name="startTimer" id="startTimer" value="Start Timer" />
+		<div style="width:400px" class='dijitProgressBarIndeterminate' progress='100' 
+			id="indeterminateBar" annotate="false"
+			dojoType="dijit.ProgressBar"></div>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/test_RichText.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/test_RichText.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/test_RichText.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>Rich Text System Test</title>
+		<style type="text/css">
+			@import "../../dojo/resources/dojo.css";
+			@import "../themes/tundra/tundra.css";
+			@import "css/dijitTests.css";
+		</style>
+		<script type="text/javascript" src="../../dojo/dojo.js" 
+			djConfig="isDebug: false, debugAtAllCosts: true"></script>
+		<script type="text/javascript" src="../_editor/selection.js"></script>
+		<script type="text/javascript" src="../_editor/RichText.js"></script>
+		<script language="JavaScript" type="text/javascript">
+			dojo.require("dijit._editor.RichText");
+			dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+		</script>
+	</head>
+	<body class="tundra">
+
+		<div style="padding: 1em">
+			<h1 class="testTitle">Rich Text Test</h1>
+			
+			<div style="border: 1px dotted black;">
+				<h3>thud</h3>
+				<textarea dojoType="dijit._editor.RichText" 
+					styleSheets="../../dojo/resources/dojo.css">
+					<ul>
+						<li>Right click on the client area of the page (ctrl-click for Macintosh). Menu should open.</li>
+						<li>Right click on each of the form controls above. Menu should open.</li>
+						<li>Right click near the righthand window border. Menu should open to the left of the pointer.</li>
+						<li>Right click near the bottom window border. Menu should open above the pointer.</li>
+					</ul>
+				</textarea>
+				<h3>..after</h3>
+			</div>
+
+			<div style="border: 1px dotted black;">
+				<h3>blah</h3>
+				<div dojoType="dijit._editor.RichText" 
+					styleSheets="../../dojo/resources/dojo.css">
+					<ul>
+						<li>Right click on the client area of the page (ctrl-click for Macintosh). Menu should open.</li>
+						<li>Right click on each of the form controls above. Menu should open.</li>
+						<li>Right click near the righthand window border. Menu should open to the left of the pointer.</li>
+						<li>Right click near the bottom window border. Menu should open above the pointer.</li>
+					</ul>
+				</div>
+				<h3>..after</h3>
+			</div>
+		</div>
+
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/test_Table.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/test_Table.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/test_Table.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,136 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Dijit Grid</title>
+<script type="text/javascript">
+	var djConfig = {isDebug: true, debugAtAllCosts: true};
+</script>
+<style type="text/css">
+	@import "../../dojo/resources/dojo.css";
+	@import "../themes/tundra/tundra.css";
+	@import "css/dijitTests.css";
+</style>
+
+<script type="text/javascript" src="testBidi.js"></script>
+
+<script type="text/javascript" src="../../dojo/dojo.js"></script>
+<script type="text/javascript">
+	dojo.registerModulePath("dijit", "../dijit");
+</script>
+<style type="text/css">
+	body{ padding:1em 3em; }
+
+	/* The following will end up being added by code. */
+	.dijitGridColumn1{ width:60px; }
+	.dijitGridColumn2{ width:100px; }
+	.dijitGridColumn3{ width:100px; }
+	.dijitGridColumn4{ width:280px; }
+	/* End code add */
+
+	div.clear { clear:both; }
+	div.dijitGrid { 
+		width:600px;
+		border:1px solid #ccc;
+		margin:1em;
+	}
+	table td {
+		border:1px solid #ccc;
+		border-collapse:none;
+	}
+	div.digitGridRow { 
+		border:1px solid #c00;
+		clear:both;
+	}
+	span.dijitGridCell{
+		padding:0.25em;
+		display:block;
+		float:left;
+	}
+	span.dijitGridSeparator{
+		display:block;
+		float:left;
+		width:1px;
+		border-left:1px solid #ccc;
+	}
+	div.dijitGridHead {
+		background-color:#efefef;
+		border-bottom:1px solid #ccc;
+		font-weight:bold;
+	}
+	div.dijitGridBody { 
+		height:200px;
+		overflow:auto;
+	}
+	div.dijitGridBodyContent {
+		overflow:visible;
+	}
+	
+	div.dijitGridFoot { }
+</style>
+</head>
+<body>
+	<h1>Dijit Grid: Table Test</h1>
+	<p>This is a pure HTML test, in order to develop the eventual markup structure for the Dijit Grid.  It is <strong>not</strong> a working Grid, nor will it be the eventual Grid test.</p>
+	<div class="dijitGrid">
+		<div class="dijitGridHead">
+			<div class="dijitGridRow">
+				<span class="dijitGridCell dijitGridColumn1">Name</span>
+				<span class="dijitGridSeparator"></span>
+				<span class="dijitGridCell dijitGridColumn2">Date Added</span>
+				<span class="dijitGridSeparator"></span>
+				<span class="dijitGridCell dijitGridColumn3">Date Modified</span>
+				<span class="dijitGridSeparator"></span>
+				<span class="dijitGridCell dijitGridColumn4">Label</span>
+				<div class="clear"></div>
+			</div>
+		</div>
+		<div class="dijitGridBody">
+			<div class="dijitGridBodyContent">
+				<table cellpadding="0" cellspacing="0" border="0" width="576" style="margin:0;border:0;">
+					<colgroup>
+						<col width="60"/>
+						<col width="100"/>
+						<col width="100"/>
+						<col width="280"/>
+					</colgroup>
+				<tr><td>Adam</td><td>3/1/2004</td><td>11/1/2003</td><td><p><strong>Lorem ipsum</strong> dolor sit amet...</p><div>consectetuer</div></td></tr>
+				<tr><td>Betty</td><td>6/15/2005</td><td>1/7/2006</td><td>Adipiscing elit, sed diam nonummy nibh euismod</td></tr>
+				<tr><td>Carla</td><td>4/23/2002</td><td>3/1/2004</td><td>tincidunt ut laoreet dolore magna aliquam erat volutpat.</td></tr>
+				<tr><td>David</td><td>11/1/2003</td><td>6/15/2005</td><td>Ut wisi enim ad minim veniam, quis</td></tr>
+				<tr><td>Esther</td><td>1/7/2006</td><td>4/23/2002</td><td>nostrud exerci tation ullamcorper</td></tr>
+				<tr><td>Fred</td><td>3/1/2004</td><td>11/1/2003</td><td>suscipit lobortis nisl ut aliquip ex ea commodo consequat.</td></tr>
+				<tr><td>Greg</td><td>6/15/2005</td><td>1/7/2006</td><td><p><strong>Lorem ipsum</strong> dolor sit amet...</p><div>consectetuer</div></td></tr>
+				<tr><td>Helga</td><td>4/23/2002</td><td>3/1/2004</td><td>adipiscing elit, sed diam nonummy nibh euismod</td></tr>
+				<tr><td>Ianna</td><td>11/1/2003</td><td>6/15/2005</td><td>tincidunt ut laoreet dolore magna aliquam erat volutpat.</td></tr>
+				<tr><td>Jane</td><td>1/7/2006</td><td>4/23/2002</td><td>Ut wisi enim ad minim veniam, quis</td></tr>
+			</table>
+			</div>
+		</div>
+		<div class="dijitGridFoot">
+		</div>
+	</div>
+	<h2>A regular table, for comparison purposes</h2>
+	<table cellpadding="0" cellspacing="0" border="0" width="600">
+	<thead>
+		<tr>
+			<th width="60" valign="top">Name</th>
+			<th width="100" align="center" valign="top">Date Added</th>
+			<th width="100" align="center" valign="top">Date Modified</th>
+			<th>Label</th>
+		</tr>
+	</thead>
+	<tbody>
+		<tr><td>Adam</td><td>3/1/2004</td><td>11/1/2003</td><td><p><strong>Lorem ipsum</strong> dolor sit amet...</p><div>consectetuer</div></td></tr>
+		<tr><td>Betty</td><td>6/15/2005</td><td>1/7/2006</td><td>Adipiscing elit, sed diam nonummy nibh euismod</td></tr>
+		<tr><td>Carla</td><td>4/23/2002</td><td>3/1/2004</td><td>tincidunt ut laoreet dolore magna aliquam erat volutpat.</td></tr>
+		<tr><td>David</td><td>11/1/2003</td><td>6/15/2005</td><td>Ut wisi enim ad minim veniam, quis</td></tr>
+		<tr><td>Esther</td><td>1/7/2006</td><td>4/23/2002</td><td>nostrud exerci tation ullamcorper</td></tr>
+		<tr><td>Fred</td><td>3/1/2004</td><td>11/1/2003</td><td>suscipit lobortis nisl ut aliquip ex ea commodo consequat.</td></tr>
+		<tr><td>Greg</td><td>6/15/2005</td><td>1/7/2006</td><td><p><strong>Lorem ipsum</strong> dolor sit amet...</p><div>consectetuer</div></td></tr>
+		<tr><td>Helga</td><td>4/23/2002</td><td>3/1/2004</td><td>adipiscing elit, sed diam nonummy nibh euismod</td></tr>
+		<tr><td>Ianna</td><td>11/1/2003</td><td>6/15/2005</td><td>tincidunt ut laoreet dolore magna aliquam erat volutpat.</td></tr>
+		<tr><td>Jane</td><td>1/7/2006</td><td>4/23/2002</td><td>Ut wisi enim ad minim veniam, quis</td></tr>
+	</tbody>
+	</table>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/test_TitlePane.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/test_TitlePane.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/test_TitlePane.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+
+<title>TitlePane Test</title>
+
+<script type="text/javascript" src="testBidi.js"></script>
+
+<script type="text/javascript" src="../../dojo/dojo.js"
+	djConfig="isDebug: true, debugAtAllCosts: true"></script>
+<script language="JavaScript" type="text/javascript">
+	dojo.require("dijit.TitlePane");
+	dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+</script>
+<style type="text/css">
+ at import "../../dojo/resources/dojo.css";
+ at import "../themes/tundra/tundra.css";
+ at import "css/dijitTests.css";
+</style>
+</head>
+<body class="tundra">
+	<h1 class="testTitle">Dijit TitlePane Test</h1>
+	<div dojoType="dijit.TitlePane" label="Title Pane #1" style="width: 300px;">
+		Lorem Ipsum
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Quisque iaculis, nulla id semper faucibus, pede tellus nonummy magna, vitae adipiscing orci arcu ut augue. Nunc condimentum, magna a vestibulum convallis, libero purus pulvinar orci, sed vestibulum urna sem ut pede.
+More Ipsum...
+
+Sed sollicitudin suscipit risus. Nam ullamcorper. Sed nisl lectus, pellentesque nec, malesuada eget, ornare a, libero. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+
+	</div>
+
+	<br>
+
+	<div dojoType="dijit.TitlePane" label="Title Pane #2" id="pane_2" style="width: 300px;">
+		<form>
+			Age: <input><br>
+			Discount card <input type=checkbox><br>
+			<button>Submit</button><br>
+		</form>
+	</div>
+
+	<br>
+
+	<div dojoType="dijit.TitlePane" label="Pane from href broken until contentPane ported to dijit" href="doc0.html"></div>
+
+	<br>
+	<div dojoType="dijit.TitlePane" label="Initially closed pane" open="false" width="200">
+		<form>
+			<label for="age">Age: </label><input id="age"><br>
+			<label for="discount">Discount card </label><input type=checkbox id="discount"><br>
+			<button>Submit</button><br>
+		</form>
+	</div>
+
+	<br>
+	
+	<div dojoType="dijit.TitlePane" label="Outer pane" width="300">
+		<p>This is a title pane, containing another title pane ...
+		<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Quisque iaculis, nulla id semper faucibus, pede tellus nonummy magna, vitae adipiscing orci arcu ut augue. Nunc condimentum, magna a vestibulum convallis, libero purus pulvinar orci, sed vestibulum urna sem ut pede.
+More Ipsum...
+
+		<div dojoType="dijit.TitlePane" label="Inner pane" width="250">
+			<p>And this is the inner title pane...
+			<p>Sed sollicitudin suscipit risus. Nam ullamcorper. Sed nisl lectus, pellentesque nec, malesuada eget, ornare a, libero. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+		</div>
+		
+		<p>And this is the closing line for the outer title pane.
+	</div>
+
+	<table style="border: solid blue 2px; margin-top: 1em;">
+		<tr>
+			<td>
+				Here's some text below the title panes (to make sure that closing a title pane releases the space that the content was taking up)
+			</td>
+		</tr>
+	</table>
+
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/test_Tooltip.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/test_Tooltip.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/test_Tooltip.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd"> 
+<html>
+<head>
+	<title>Dojo Tooltip Widget Test</title>
+	
+	<script type="text/javascript" src="testBidi.js"></script>
+	
+	<script type="text/javascript" src="../../dojo/dojo.js" djConfig="isDebug: true, debugAtAllCosts: true"></script>
+	<script type="text/javascript">
+		dojo.require("dijit.Tooltip");
+		dojo.require("dijit.util.parser");	// find widgets
+	</script>
+	
+	<style type="text/css">
+		@import "../../dojo/resources/dojo.css";
+		
+		@import "../themes/tundra/tundra.css";
+		@import "css/dijitTests.css";
+	</style>
+</head>
+
+<body class="tundra">
+	<h1 class="testTitle">Tooltip test</h1>
+	<p>Mouse-over the items below to test tooltips. <button onclick="dijit.byId('btnTt').destroy()">Remove</button> tooltip from button.</p>
+	<p>
+		<span id="one" class="tt">text</span>
+		<span dojoType="dijit.Tooltip" connectId="one" style="display:none;">
+			<b>
+				<span style="color: blue;">rich formatting</span>
+				<span style="color: red; font-size: x-large;"><i>!</i></span>
+			</b>
+		</span>
+		
+		<a id="three" href="#bogus">anchor</a>
+		<span dojoType="dijit.Tooltip" connectId="three" caption="inline caption" style="display:none;"></span>
+	</p>
+	
+	<button id="four">button</button>
+	<span id="btnTt" dojoType="dijit.Tooltip" connectId="four" caption="tooltip on button" style="display:none;"></span>
+
+    <select id="seven">
+      <option value="alpha">Alpha</option>
+      <option value="beta">Beta</option>
+      <option value="gamma">Gamma</option>
+      <option value="delta">Delta</option>
+    </select>
+	<span dojoType="dijit.Tooltip" connectId="seven" 
+		style="display:none;">tooltip on a select<br>two line tooltip.
+	</span>
+
+<p></p>
+
+	<form>
+		<input type="input" id="id1" value="#1"/><br>
+		<input type="input" id="id2" value="#2"/><br>
+		<input type="input" id="id3" value="#3"/><br>
+		<input type="input" id="id4" value="#4"/><br>
+   		<input type="input" id="id5" value="#5"/><br>
+		<input type="input" id="id6" value="#6"/><br>
+	</form>
+	<br>
+
+<div style="overflow: auto; height: 100px; position: relative; border: solid blue 3px;">
+	<span id="s1">s1 text</span><br><br><br>
+	<span id="s2">s2 text</span><br><br><br>
+	<span id="s3">s3 text</span><br><br><br>
+	<span id="s4">s4 text</span><br><br><br>
+	<span id="s5">s5 text</span><br><br><br>
+</div>
+
+	<span dojoType="dijit.Tooltip" connectId="id1" style="display:none;">
+		tooltip for #1<br>
+		long&nbsp;long&nbsp;long&nbsp;long&nbsp;long&nbsp;long&nbsp;long&nbsp;long&nbsp;long&nbsp;long&nbsp;long&nbsp;text<br>
+		make sure that this works properly with a really narrow window
+	</span>
+	<span dojoType="dijit.Tooltip" connectId="id2" style="display:none;">tooltip for #2</span>
+	<span dojoType="dijit.Tooltip" connectId="id3" style="display:none;">tooltip for #3</span>
+	<span dojoType="dijit.Tooltip" connectId="id4" style="display:none;">tooltip for #4</span>
+	<span dojoType="dijit.Tooltip" connectId="id5" style="display:none;">tooltip for #5</span>
+	<span dojoType="dijit.Tooltip" connectId="id6" style="display:none;">tooltip for #6</span>
+
+	<span dojoType="dijit.Tooltip" connectId="s1" style="display:none;">s1 tooltip</span>
+	<span dojoType="dijit.Tooltip" connectId="s2" style="display:none;">s2 tooltip</span>
+	<span dojoType="dijit.Tooltip" connectId="s3" style="display:none;">s3 tooltip</span>
+	<span dojoType="dijit.Tooltip" connectId="s4" style="display:none;">s4 tooltip</span>
+	<span dojoType="dijit.Tooltip" connectId="s5" style="display:none;">s5 tooltip</span>
+
+</body>
+</html>
+

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/test_Tree.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/test_Tree.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/test_Tree.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Dijit Tree Test</title>
+<style type="text/css">
+	@import "../../dojo/resources/dojo.css";
+	@import "../themes/tundra/tundra.css";
+	@import "css/dijitTests.css";
+</style>
+
+<script type="text/javascript" src="testBidi.js"></script>
+
+<script type="text/javascript" src="../../dojo/dojo.js"
+	djConfig="isDebug: true"></script>
+<script language="JavaScript" type="text/javascript">
+	dojo.require("dojo.data.JsonItemStore");
+	dojo.require("dijit.Tree");
+	dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+</script>
+</head>
+<body class="tundra">
+	<h1 class="testTitle">Dijit Tree Test</h1>
+	<div dojoType="dojo.data.JsonItemStore" jsId="continentStore"
+		url="../tests/countries.json"></div>
+	<div dojoType="dijit.Tree" store="continentStore" query="{type:'continent'}"
+		labelAttr="name" typeAttr="type"></div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/util/test_FocusManager.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/util/test_FocusManager.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/util/test_FocusManager.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+	<title>FocusManager Test</title>
+	<script type="text/javascript" src="../../../dojo/dojo.js"
+		djConfig="isDebug: true, debugAtAllCosts: true"></script>
+	<script type="text/javascript">
+		dojo.require("dijit.util.FocusManager");
+	</script>
+<script>
+	dojo.addOnLoad(function(){
+		fakeWidget = { domNode: dojo.byId("save") };
+	});
+	function save(){
+		console.debug("save function");
+		dijit.util.FocusManager.save(fakeWidget);
+	}
+	function restore(){
+		dijit.util.FocusManager.restore(fakeWidget);
+	}
+</script>
+</head>
+<body style="background-color: #fff; color: black; padding: 0; margin: 0">
+
+
+	<h3>Focus Manager Test</h3>
+		<p>This is for testing whether focus and selection are restored by the focus manager</p>
+		<form style="border: 2px solid blue;">
+			<input id=input1 value=tom><br>
+			<input id=input2 value=jones><br>
+			<textarea id=textarea>hello there!</textarea><br>
+			<button id=button>push me</button>
+		</form>
+
+	<button id="save" onclick="save();">Save focus/selection state</button>  <button onclick="restore();">Restore focus/selection state</button>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/util/test_placeStrict.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/util/test_placeStrict.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/util/test_placeStrict.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,401 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+	<head>
+		<title>dijit.util.place tests</title>
+		<script type="text/javascript" src="../../../dojo/dojo.js"
+			djConfig="isDebug: true, extraLocale: ['de-de', 'en-us']"></script>
+		<script type="text/javascript">
+			dojo.require("dijit.util.place");
+		</script>
+		<script>
+			dojo.addOnLoad(function(){
+				var vp = dijit.util.getViewport();
+				alert("viewport w="+vp.w + ", h=" + vp.h);
+			});
+		</script>
+		<style type="text/css">
+			@import "../../../dojo/resources/dojo.css";
+			@import "../../themes/tundra/tundra.css";
+
+			body {
+				padding: 1em;
+			}
+			.formQuestion {
+				background-color:#d0e3f5;
+				padding:0.3em;
+				font-weight:900;
+				font-family:Verdana, Arial, sans-serif;
+				font-size:0.8em;
+				color:#5a5a5a;
+			}
+			.formAnswer {
+				background-color:#f5eede;
+				padding:0.3em;
+				margin-bottom:1em;
+			}
+			.pageSubContentTitle {
+					color:#8e8e8e;
+					font-size:1em;
+					font-family:Verdana, Arial, sans-serif;
+					margin-bottom:0.75em;
+			}
+			.small {
+				width: 2.5em;
+			}
+			.medium {
+				width: 10em;
+			}
+			.long {
+				width: 20em;
+			}
+		
+			.dojoValidationTextboxMessage {
+				display: inline;
+				margin-left: 1em;
+				font-weight: bold;
+				font-style: italic;
+				font-family: Arial, Verdana, sans-serif;
+				color: #f66;
+				font-size: 0.9em;
+			}
+		
+			.noticeMessage {
+				font-weight: normal;
+				font-family:Arial, Verdana, sans-serif;
+				color:#663;
+				font-size:0.9em;
+			}
+		</style>
+	</head>
+
+	<body class=tundra>
+		<h2 class="pageSubContentTitle">Test dijit.util.place</h2>
+		<p>Currently this just tests getViewport().  Change the size of your browser window and then reload,
+		and see if it reports the browser window size correctly.<br>
+		<p>All the text below is just filler text...<br>
+		<!--	to test form submission, you'll need to create an action handler similar to
+			http://www.utexas.edu/teamweb/cgi-bin/generic.cgi -->
+		<form id="form1" action="" name="example" method="post">
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q01">First Name:  </label></span>
+				<span class="noticeMessage"> Textbox class, <b>tabIndex=2</b>, Attributes: {trim: true, ucFirst: true, class: 'medium'}, First letter of each word is upper case.</span>
+			</div>
+			<div class="formAnswer">
+				<input id="q01" type="text" name="firstname" value="testing testing" class="medium" tabIndex=2
+					dojoType="dijit.form.Textbox"
+					trim="true" 
+					ucfirst="true" />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q02">Last Name:  </label></span>
+				<span class="noticeMessage"> Textbox class, Attributes: {trim: true, uppercase: true, class: 'medium'}, all letters converted to upper case. </span>
+			</div>
+			<div class="formAnswer">
+				<input id="q02" type="text" name="lastname" value="testing testing" class="medium"
+					dojoType="dijit.form.Textbox"
+					trim="true" 
+					uppercase="true" />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q03">Age:  </label></span>
+				<span class="noticeMessage"> Textbox class, <b>tabIndex=1</b>, Attributes: {trim: true, digit: true, class: 'small'}, all but digits extracted.</span>
+			</div>
+			<div class="formAnswer">
+				<input id="q03" type="text" name="age" value="38" class="small" tabIndex=1
+					dojoType="dijit.form.NumberTextbox"
+					promptMessage="(optional) Enter an age between 0 and 120"
+					constraints={places:0,min:0,max:120}
+					onValueChanged="console.debug('onValueChanged fired for widget id = ' + this.id + ' with value = ' + arguments[0]);"
+					digit="true"
+					trim="true" 
+					/>
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q04">Occupation:  </label></span>
+				<span class="noticeMessage">ValidationTextbox class, 
+					Attributes: {lowercase: true, required: true}. Displays a prompt message if field is missing. </span>
+			</div>
+			<div class="formAnswer">
+				<input id="q04" type="text" name="occupation" class="medium"
+					dojoType="dijit.form.ValidationTextbox"
+					lowercase="true" 
+					required="true"
+					promptMessage="Enter an occupation" />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q05">Elevation:  </label></span>
+				<span class="noticeMessage">IntegerTextbox class, 
+					Attributes: {required: true, min:-20000, max:+20000 }, Enter feet above sea level with a sign.</span>
+			</div>
+			<div class="formAnswer">
+				<input id="q05" class="medium"/>
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q08">Annual Income:  </label></span>
+				<span class="noticeMessage">CurrencyTextbox class, 
+					Attributes: {fractional: true}. Enter whole and cents.  Currency symbol is optional.</span>
+			</div>
+			<div class="formAnswer">
+				<input id="q08" type="text" name="income1" class="medium" value="54775.53"
+					dojoType="dijit.form.CurrencyTextbox"
+					required="true" 
+					currency="USD"
+					invalidMessage="Invalid amount.  Include dollar sign, commas, and cents. Example: $12,000.00" />USD
+			</div>
+
+			<div class="formAnswer">
+				<input id="q08eur" type="text" name="income2" class="medium" value="54775.53"
+					dojoType="dijit.form.CurrencyTextbox"
+					required="true" 
+					currency="EUR"
+					invalidMessage="Invalid amount.  Include euro sign, commas, and cents. Example: &#x20ac;12,000.00" />EUR
+			</div>
+<!-- 
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q08a">Annual Income:  </label></span>
+				<span class="noticeMessage">Old regexp currency textbox, 
+					Attributes: {fractional: true}. Enter dollars and cents.</span>
+			</div>
+			<div class="formAnswer">
+				<input id="q08a" type="text" name="income3" class="medium" value="$54,775.53"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.currency"
+					trim="true" 
+					required="true" 
+					constraints={fractional:true}
+					invalidMessage="Invalid amount.  Include dollar sign, commas, and cents. Example: $12,000.00" />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q09">IPv4 Address:  </label></span>
+				<span class="noticeMessage">IpAddressTextbox class, 
+					Attributes: {allowIPv6: false, allowHybrid: false}. Also Dotted Hex works, 0x18.0x11.0x9b.0x28</span>
+			</div>
+			<div class="formAnswer">
+				<input id="q09" type="text" name="ipv4" class="medium" value="24.17.155.40"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.ipAddress"
+					trim="true" 
+					required="true" 
+					constraints={allowIPv6:false,allowHybrid:false}
+					invalidMessage="Invalid IPv4 address." />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q10"> IPv6 Address:  </label></span>
+				<span class="noticeMessage">IpAddressTextbox class, 
+					Attributes: {allowDottedDecimal: false, allowDottedHex: false}. 
+					Also hybrid works, x:x:x:x:x:x:d.d.d.d</span>
+			</div>
+			<div class="formAnswer">
+				<input id="q10" type="text" name="ipv6" class="long" value="0000:0000:0000:0000:0000:0000:0000:0000"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.ipAddress"
+					trim="true" 
+					uppercase = "true" 
+					required="true" 
+					constraints={allowDottedDecimal:false, allowDottedHex:false, allowDottedOctal:false}
+					invalidMessage="Invalid IPv6 address, please enter eight groups of four hexadecimal digits. x:x:x:x:x:x:x:x" />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q11"> URL:  </label></span>
+				<span class="noticeMessage">UrlTextbox class, 
+					Attributes: {required: true, trim: true, scheme: true}. </span>
+			</div>
+			<div class="formAnswer">
+				<input id="q11" type="text" name="url" class="long" value="http://www.xyz.com/a/b/c?x=2#p3"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.url"
+					trim="true" 
+					required="true" 
+					constraints={scheme:true}
+					invalidMessage="Invalid URL.  Be sure to include the scheme, http://..." />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q12"> Email Address  </label></span>
+				<span class="noticeMessage">EmailTextbox class, 
+					Attributes: {required: true, trim: true}. </span>
+			</div>
+			<div class="formAnswer">
+				<input id="q12" type="text" name="email" class="long" value="fred&barney at stonehenge.com"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.emailAddress"
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid Email Address." />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q13"> Email Address List </label></span>
+				<span class="noticeMessage">EmailListTextbox class, 
+					Attributes: {required: true, trim: true}. </span>
+			</div>
+			<div class="formAnswer">
+				<input id="q13" type="text" name="email" class="long" value="a at xyz.com; b at xyz.com; c at xyz.com; "
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.emailAddressList"
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid Email Address List." />
+			</div>
+-->
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q14"> Date (American format) </label></span>
+				<span class="noticeMessage">DateTextbox class, 
+					Attributes: {locale: "en-us", required: true}. Works for leap years</span>
+			</div>
+			<div class="formAnswer">
+				<input id="q14" type="text" name="date1" class="medium" value="2005-12-30"
+					dojoType="dijit.form.DateTextbox"
+					constraints={locale:'en-us'}
+					required="true"
+					promptMessage="mm/dd/yyyy"
+					invalidMessage="Invalid date. Use mm/dd/yyyy format." />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q15"> Date (German format) </label></span>
+				<span class="noticeMessage">DateTextbox class, 
+					Attributes: {locale: "de-de", min:2006-01-01, max:2006-12-31}. Works for leap years</span>
+			</div>
+			<div class="formAnswer">
+				<input id="q15" class="medium"/>
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q16"> 12 Hour Time </label></span>
+				<span class="noticeMessage">TimeTextbox class, 
+					Attributes: {formatLength: "medium", required: true, trim: true}</span>
+			</div>
+			<div class="formAnswer">
+				<input id="q16" type="text" name="time1" class="medium" value="5:45:00 pm"
+					dojoType="dijit.form.ValidationTextbox"
+					validator="dojo.date.local.parse"
+					constraints={formatLength:'medium',selector:'time'}
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid time." />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q17"> 24 Hour Time</label></span>
+				<span class="noticeMessage">TimeTextbox class, 
+					Attributes: {displayFormat:"HH:mm:ss", required: true, trim: true}</span>
+			</div>
+			<div class="formAnswer">
+				<input id="q17" type="text" name="time2" class="medium" value="17:45:00"
+					dojoType="dijit.form.ValidationTextbox"
+					validator="dojo.date.local.parse"
+					constraints={formatLength:'short',selector:'time',timePattern:'HH:mm:ss'}
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid time. Use HH:mm:ss where HH is 00 - 23 hours." />
+			</div>
+
+<!-- 
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q18"> US State 2 letter abbr. </label></span>
+				<span class="noticeMessage">UsStateTextbox class, 
+					Attributes: {required: true, trim: true, uppercase: true}</span>
+			</div>
+			<div class="formAnswer">
+				<input id="q18" type="text" name="state" class="small" value="CA"
+					dojoType="dijit.form.ValidationTextbox"
+					regExpGen="dojo.regexp.us.state"
+					constraints={allowTerritories:false}
+					trim="true" 
+					uppercase="true" 
+					required="true" 
+					invalidMessage="Invalid US state abbr." />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q19"> US Zip Code </label></span>
+				<span class="noticeMessage">UsZipTextbox class, 
+					Attributes: {required: true, trim: true} Five digit Zip code or 5 + 4.</span>
+			</div>
+			<div class="formAnswer">
+				<input id="q19" type="text" name="zip" class="medium" value="98225-1649"
+					dojoType="dijit.form.ValidationTextbox"
+					validator="dojo.validate.us.isZipCode"
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid US Zip Code." />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q20"> US Social Security Number </label></span>
+				<span class="noticeMessage">UsSocialSecurityNumberTextbox class, 
+					Attributes: {required: true, trim: true} </span>
+			</div>
+			<div class="formAnswer">
+				<input id="q20" type="text" name="ssn" class="medium" value="123-45-6789"
+					dojoType="dijit.form.ValidationTextbox"
+					validator="dojo.validate.us.isSocialSecurityNumber"
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid US Social Security Number." />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q21"> 10-digit US Phone Number </label></span>
+				<span class="noticeMessage">UsPhoneNumberTextbox class, 
+					Attributes: {required: true, trim: true} </span>
+			</div>
+			<div class="formAnswer">
+				<input id="q21" type="text" name="phone" class="medium" value="(123) 456-7890"
+					dojoType="dijit.form.ValidationTextbox"
+					validator="dojo.validate.us.isPhoneNumber"
+					trim="true" 
+					required="true" 
+					invalidMessage="Invalid US Phone Number." />
+			</div>
+ -->
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q22"> Regular Expression </label></span>
+				<span class="noticeMessage">RegexpTextbox class, 
+					Attributes: {required: true} </span>
+			</div>
+			<div class="formAnswer">
+				<input id="q22" type="text" name="phone" class="medium" value="someTestString"
+					dojoType="dijit.form.ValidationTextbox"
+					regExp="[\w]+"
+					required="true" 
+					invalidMessage="Invalid Non-Space Text." />
+			</div>
+
+			<div class="formQuestion">
+				<span class="emphasize"><label for="q23"> Password </label></span>
+				<span class="noticeMessage">(just a test that type attribute is obeyed) </span>
+			</div>
+			<div class="formAnswer">
+				<input id="q23" type="password" name="password" class="medium"
+					dojoType="dijit.form.Textbox" />
+			</div>
+
+                        <div class="formQuestion">
+                                <span class="emphasize"><label for="ticket1651">Trac ticket 1651:  </label></span>
+                                <span class="noticeMessage">value: null should show up as empty</span>
+                        </div>
+                        <div class="formAnswer">
+                                <input id="ticket1651" class="medium" value="not null"/>
+                        </div>
+
+			<button name="button" onclick="displayData(); return false;">view data</button>
+			<input type="submit" name="submit" />
+			</div>
+
+		</form>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/util/test_typematic.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/util/test_typematic.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/util/test_typematic.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+	<title>Typematic Test</title>
+	<script type="text/javascript" src="../../../dojo/dojo.js"
+		djConfig="isDebug: true, debugAtAllCosts: true"></script>
+	<script type="text/javascript">
+		dojo.require("dijit.util.typematic");
+	</script>
+<script>
+	var lastCount = 0;
+	function typematicCallBack(count, node, evt){
+		var inputNode = document.getElementById('typematicInput');
+		if (node == inputNode){
+			key = "a";
+		}else{
+			key = "b";
+		}
+		if (count == -1){
+			console.debug((lastCount+1) + ' ' + key + ' events');
+		}else{
+			lastCount = count;
+			inputNode.value += key;
+		}
+		inputNode.focus();
+	}
+	dojo.addOnLoad(function(){
+		var keyNode = document.getElementById('typematicInput');
+		var mouseNode = document.getElementById('typematicButton');
+		dijit.util.typematic.addKeyListener(keyNode, 
+			{keyCode:dojo.keys.F10,ctrlKey:true},
+			this, typematicCallBack, 200, 200);
+		dijit.util.typematic.addMouseListener(mouseNode, 
+			this, typematicCallBack, 0.9, 200);
+		keyNode.focus(); // make it easier to type 
+	});
+</script>
+</head>
+<body style="background-color: #fff; color: black; padding: 0; margin: 0">
+
+Press and hold the <b>ctrl+F10</b> keys to see a's typed (constant rate) in the input field,<br>
+or left-mouse click the button and hold down to see b's typed (increasing rate) in the input field.<br>
+<input id="typematicInput" size="500"><button id="typematicButton">to B or not to B</button>
+
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/widgetsInTemplate.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/widgetsInTemplate.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/widgetsInTemplate.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,111 @@
+<html>
+	<head>
+		<title>testing widgetsInTemplate support</title>
+		<script type="text/javascript" src="../../dojo/dojo.js" djConfig="isDebug: true"></script>
+		<script type="text/javascript">
+			dojo.require("doh.runner");
+			
+			dojo.require("dijit.form.Button");
+			dojo.require("dijit.form.Checkbox");
+			dojo.require("dijit.ProgressBar");
+
+			dojo.addOnLoad(function(){
+				var testW;
+				doh.register("t", 
+					[
+						{
+							name: "dojoAttachPoint",
+							runTest: function(t){
+								var testW = dijit.byId("test1Widget");
+								t.t(testW.normalNode);
+								t.f(isNaN(testW.normalNode.nodeType));
+								t.t(testW.buttonWidget instanceof dijit.form.Button);
+								t.t(testW.checkboxWidget instanceof dijit.form.Checkbox);
+								t.t(testW.progressBarWidget instanceof dijit.ProgressBar);
+//								alert((testW.buttonWidget instanceof dijit.form.Button)+(testW.checkboxWidget instanceof dijit.form.Checkbox)+(testW.progressBarWidget instanceof dijit.ProgressBar)+
+//								(testW.buttonWidget._counter==1)+(testW.checkboxWidget._counter==1)+(testW.progressBarWidget._counter==1));
+								testW = dijit.byId("test2Widget");
+								t.t(testW.containerNode);
+								t.f(isNaN(testW.containerNode.nodeType));
+								t.is(undefined,testW.buttonWidget);
+								t.t(testW.checkboxWidget instanceof dijit.form.Checkbox);
+							}
+						},
+						{
+							name: "dojoAttachEvent",
+							runTest: function(t){
+								var testW = dijit.byId("test1Widget");
+								testW.buttonWidget._counter=0;
+								testW.buttonWidget.onClick(testW.buttonWidget);
+								testW.checkboxWidget._counter=0;
+								testW.checkboxWidget.onClick(testW.checkboxWidget);
+								testW.progressBarWidget._counter=0;
+								testW.progressBarWidget.onChange(testW.progressBarWidget);
+								t.is(1,testW.buttonWidget._counter);
+								t.is(1,testW.checkboxWidget._counter);
+								t.is(1,testW.progressBarWidget._counter);
+							}
+						}
+					]
+				);
+				doh.run();
+			});
+		</script>
+	<style type="text/css">
+		@import "../themes/tundra/tundra.css";
+	</style>
+	</head>
+	<body>
+		<h1>testing widgetsInTemplate support</h1>
+		<xmp id="Test1Template" style="display:none;">
+			<div>
+				<div dojoAttachPoint="normalNode" >normal node</div>
+				<button dojoAttachPoint="buttonWidget" dojoAttachEvent="onClick:onClick" dojoType="dijit.form.Button">button #1</button>
+				<div dojoAttachPoint="checkboxWidget" dojoAttachEvent="onClick:onClick" dojoType="dijit.form.Checkbox"></div> checkbox #1
+				<div dojoAttachPoint="progressBarWidget" dojoAttachEvent="onChange:onClick" style="width:400px" annotate="true"
+					maximum="200" progress="20" dojoType="dijit.ProgressBar"></div>
+			</div>
+		</xmp>
+		<script>
+			dojo.declare('Test1Widget', 
+				[dijit.base.Widget, dijit.base.TemplatedWidget],
+			{
+				widgetsInTemplate: true,
+		//		isContainer: true,
+		
+				templateString: dojo.byId('Test1Template').textContent || dojo.byId('Test1Template').innerText,
+				onClick: function(e){
+					if(e.target){
+						alert('onClick widgetId='+e.target.id);
+					}else{
+						if(e._counter == undefined){
+							e._counter = 1;
+						}else{
+							e._counter++;
+						}
+					}
+				}
+			});
+		</script>
+	<!-- can use widget immediately in markup - no parsing occurs until document loaded and scripts run -->
+	<div dojoType="Test1Widget" id="test1Widget" ></div>
+
+
+	<xmp id="Test2Template" style="display:none;">
+		<div>
+			<div dojoAttachPoint="containerNode" ><div dojoAttachPoint="checkboxWidget" dojoType="dijit.form.Checkbox"></div> checkbox #2</div>
+		</div>
+	</xmp>
+		<script>
+			dojo.declare('Test2Widget', 
+				[dijit.base.Widget, dijit.base.TemplatedWidget],
+			{
+				widgetsInTemplate: true,
+		
+				templateString: dojo.byId('Test2Template').textContent || dojo.byId('Test2Template').innerText
+			});
+		</script>
+	<div dojoType="Test2Widget" id="test2Widget" ><button dojoAttachPoint="buttonWidget" dojoType="dijit.form.Button">button #2</button></div>
+	</body>
+</html>
+

Added: trunk/examples/typeface/root/static/dojo/dijit/tests/widgetsInTemplate.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/tests/widgetsInTemplate.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/tests/widgetsInTemplate.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+dojo.provide("dijit.tests.widgetsInTemplate");
+
+if(dojo.isBrowser){
+	doh.registerUrl("dijit.tests.widgetsInTemplate", dojo.moduleUrl("dijit", "tests/widgetsInTemplate.html"));
+}

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/blackie.css
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/blackie.css	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/blackie.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,186 @@
+ at import url("../dijit.css");
+ at import url(images/images.css);
+
+.blackie .dijit {
+	font-family:Tahoma;
+	font-size:14px;
+}
+
+.blackie .dijitUpArrowButton,
+.blackie .dijitDownArrowButton {
+	background-repeat:no-repeat;
+}
+
+.blackie .dijitA11yUpArrow,
+.blackie .dijitA11yDownArrow {
+	display:none;	
+}
+
+
+.blackie .dijitButtonNode {
+	border:0px !important;
+}
+
+.blackie .dijitButton,
+.blackie .dijitComboButton,
+.blackie .dijitDropDownButton,
+.blackie .dijitAutoCompleter {
+	height:30px;
+	padding:0px;
+	border-width:0px;
+	background-color:transparent;
+	background-repeat:no-repeat;
+	margin:5px;
+}
+
+.blackie .dijitButton .dijitRight {
+	height:30px;	
+	margin-left:15px; 
+	padding-right:15px;
+}
+.dj_ie .blackie .dijitButton .dijitRight {
+	padding-right:11px;
+}
+
+.blackie .dijitButton .dijitButtonNode,
+.blackie .dijitComboButton .dijitButtonNode, 
+.blackie .dijitDropDownButton .dijitButtonNode {
+	/* generic styles */
+	vertical-align:top;
+	height:30px;
+	font-family:inherit;
+	font-size:inherit;
+	background-color:transparent;
+	padding:0px !important;
+	line-height:25px;	/* Safari only */
+
+	/* enabled-specific styles */
+	color:#cccccc;
+}
+
+
+
+.blackie .dijitButtonHover .dijitButtonNode,
+.blackie .dijitComboButtonHover .dijitButtonNode, 
+.blackie .dijitDropDownButtonHover .dijitButtonNode {
+	/* hover styles */
+	color:#fa4242;
+}
+
+.blackie .dijitButtonActive .dijitButtonNode,
+.blackie .dijitComboButtonActive .dijitButtonNode,
+.blackie .dijitDropDownButtonActive .dijitButtonNode {
+	/* active (down) styles */
+	color:#31d397;
+}
+
+.blackie .dijitButtonDisabled .dijitButtonNode,
+.blackie .dijitComboButtonDisabled .dijitButtonNode,
+.blackie .dijitDropDownButtonDisabled .dijitButtonNode {
+	/* disabled styles */
+	color:#3f3f3f;
+}
+
+
+/* drop-down-button specific */
+
+.blackie .dijitDropDownButton .dijitRight {
+	height:30px;	
+	margin-left:15px; 
+	padding-right:31px;
+}
+
+.blackie .dijitDropDownButton .dijitA11yDownArrow {
+	display:none;	
+}
+
+
+/* combo-specific */
+.blackie .dijitComboButton TABLE {
+	margin-left:15px;
+}
+.blackie .dijitComboButton .dijitRight,
+.blackie .dijitComboButton .dijitRightSpacer {	
+	height:30px;	
+	width:35px;
+}
+
+
+
+
+/****
+		dijit.form.AutoCompleter 
+ ****/
+.blackie .dijitAutoCompleter TABLE {
+	margin-left:10px;
+}
+
+.blackie .dijitAutoCompleter .dijitStretch {	
+	height:30px;
+	#margin-top:0px;
+}
+
+.blackie .dijitAutoCompleter .dijitRight,
+.blackie .dijitAutoCompleter .dijitRightSpacer {	
+	height:30px;
+	width:32px;
+}
+
+.blackie .dijitAutoCompleter .dijitDownArrowButton {
+	padding:0px !important;
+	width:32px;
+}
+
+.blackie .dijitAutoCompleter .dijitButtonNode {
+	font-family:inherit;
+	font-size:inherit;
+	background-color:transparent;
+}
+
+
+.blackie .dijitAutoCompleterInput,
+.blackie .dijitSpinnerInput {
+	border:0px;
+	margin:0px;
+
+	/* IE7 HACK: get things to line up 
+	#top:-1px;					
+	#left:10px;
+	#padding-top:6px;
+	*/
+	/* SAFARI HACK: get things to line up (a little better) * /
+	top:4px;
+	margin-right:-10px;
+	*/
+}
+
+.blackie .dijitAutoCompleter INPUT,
+.blackie .dijitSpinner INPUT {
+	color:white;
+	background:black;
+}
+
+.blackie .dijitAutoCompleterDisabled INPUT,
+.blackie .dijitSpinnerDisabled INPUT{
+	color:#3f3f3f;
+}
+
+
+
+
+/* dijit.form.NumberSpinner */
+.blackie .dijitSpinner TABLE {
+	padding-left:10px;
+}
+
+.blackie .dijitSpinner .dijitStretch {	
+	height:30px;
+	#margin-top:0px;
+}
+
+.blackie .dijitSpinner .dijitUpArrowButton,
+.blackie .dijitSpinner .dijitDownArrowButton{
+	height:15px;
+	width:34px;
+	padding:0px !important;
+}

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/blackie.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/blackie.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/blackie.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,249 @@
+<html>
+	<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+	<script type="text/javascript" src="../../dijit.js"></script>
+	<script type="text/javascript">
+//		dojo.require("dijit.Menu");
+//		dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+	</script>
+
+<style type='text/css'>
+	@import "../tundra/tundra.css";
+	@import "blackie.css";
+
+BODY {
+	font-family:Arial;
+	font-size:12px;
+}
+
+.oReset {
+	margin:0px;
+	padding:0px;
+	box-sizing:border-box;
+	-moz-box-sizing:border-box;
+	border-width:0px;
+}
+
+
+
+
+.dijitCombo INPUT {
+	border-width:0px;
+	color:white;
+	background-color:black;
+	font-size:.8em;
+}
+
+
+
+/* put class dijit_a11y on an outer node (such as BODY) to kick us into a11y mode */
+
+.dijit_a11y * {
+	background-image:none !important;
+	color:black !important;
+	background-color:transparent !important;
+}
+
+
+/* a11y indicators are hidden unless we're in a11y mode */
+.dijitA11yIndicator,
+.dijitA11yIndicatorSpan {
+	display:none;
+}
+
+.dijit_a11y .dijitA11yIndicator {
+	display:block !important;
+}
+
+.dijit_a11y .dijitA11yIndicatorSpan {
+	display:inline !important;
+}
+
+
+/* make sure widgets have a border */
+.dijit_a11y .widgetOuter {
+	border:1px solid black;
+}
+
+</style>
+
+<script language='javascript'>
+	
+
+	function startup() {
+		var html = dojo.byId('blackie').innerHTML;
+		dojo.byId('tundra').innerHTML = html;
+		dojo.byId('a11y').innerHTML = html;
+	}
+
+	function toggleOuterClass(element, event) {
+		var baseName = element.getAttribute("toggleClass");
+		var name = "widgetOuter " + baseName + " " + baseName;
+		switch (event.type) {
+			case "mouseover":	name += "Hover";	break;
+			case "mousedown":	name += "Active";	break;
+			case "mouseup":		name += "Hover";	break;
+			case "mouseout":
+			default:			name += "Enabled";	break;
+		}
+		element.className = name;
+	}
+</script>
+
+<body onload='startup()'>
+
+<div>
+
+
+<table width='100%'>
+<tr>
+	<td><h2>Blackie</h2></td>
+	<td><h2>Tundra</h2></td>
+	<td><h2>a11y</h2></td>
+</tr>
+<tr>
+	<td id='blackie' class='blackie' valign=top>
+
+		<!-- dijit.form.Button -->
+		<div class="dijit dijitLeft dijitInline dijitButton"><div class='dijitRight'>
+			<button class="dijitStretch dijitButtonNode dijitButtonContents" 
+				tabIndex="${tabIndex}" type="${type}" id="${id}" name="${name}" alt="${alt}" 
+				dojoAttachPoint="containerNode;focusNode" 
+				dojoAttachEvent="onclick:buttonClick;">
+					${caption}
+			</button>
+		</div></div>
+&nbsp;
+		<div class="dijit dijitLeft dijitInlineBox dijitButton dijitButtonActive"><div class='dijitRight'>
+			<button class="dijitStretch dijitButtonNode dijitButtonContents" 
+				tabIndex="${tabIndex}" type="${type}" id="${id}" name="${name}" alt="${alt}" 
+				dojoAttachPoint="containerNode;focusNode" 
+				dojoAttachEvent="onclick:buttonClick;">
+					${caption}
+			</button>
+		</div></div>
+
+<br><br>
+		
+		<!-- dijit.form.DropDownButton -->
+
+		<div class="dijit dijitLeft dijitInlineBox dijitButton dijitDDButton"><div class='dijitRight'>
+			<button tabIndex="${tabIndex}" class="dijitStretch dijitButtonNode" type="${type}" id="${id}" name="${name}" alt="${alt}" dojoAttachEvent="onclick:arrowClick; onkeypress:arrowKey;"
+			dojoAttachPoint="popupStateNode;focusNode" waiRole="button" waiState="haspopup-true"
+				><span class="dijitReset dijitButtonContents dijitButtonContentsDropDown" dojoAttachPoint="containerNode">${caption}</span
+				><span class='dijitDownArrow'>&#9660;</span>
+			</button></div></div>
+&nbsp;
+
+		<div class="dijit dijitLeft dijitInlineBox dijitButton dijitDDButton dijitDDButtonActive"><div class='dijitRight'>
+			<button tabIndex="${tabIndex}" class="dijitStretch dijitButtonNode" type="${type}" id="${id}" name="${name}" alt="${alt}" dojoAttachEvent="onclick:arrowClick; onkeypress:arrowKey;"
+			dojoAttachPoint="popupStateNode;focusNode" waiRole="button" waiState="haspopup-true"
+				><span class="dijitReset dijitButtonContents dijitButtonContentsDropDown" dojoAttachPoint="containerNode">${caption}</span
+				><span class='dijitDownArrow'>&#9660;</span>
+			</button>
+		</div></div>
+
+<br><br>		
+		
+		
+		<!-- dijit.form.ComboButton -->
+		<table class="dijit dijitLeft dijitInline dijitComboButton dijitComboButtonEnabled" id="${id}" name="${name}" 
+			cellspacing=0 cellpadding=0>
+			<tr>
+				<td class='dijitReset dijitLeft'>&nbsp;</td>
+				<td	class="dijitStretch dijitButtonContents dijitButtonNode"
+					dojoAttachEvent="onclick:buttonClick; onkeypress:arrowKey;"
+					tabIndex="${tabIndex}" dojoAttachPoint="containerNode;focusNode">
+					${caption}
+				</td>
+				<td class='dijitReset dijitRight dijitComboButtonArrow dijitButtonNode'
+					dojoAttachPoint="popupStateNode"
+					dojoAttachEvent="onclick:arrowClick; onkeypress:arrowKey;"
+					tabIndex="${tabIndex}"
+					waiRole="button" waiState="haspopup-true"
+					><span class='dijitA11yDownArrow'>&#9660;</span>
+			</td></tr>
+		</table>		
+&nbsp;
+		<div class="dijit dijitLeft dijitInline dijitComboButton dijitComboButtonActive" id="${id}" name="${name}"
+		><button type="${type}"
+				class="dijitStretch dijitButtonContents dijitButtonNode"
+				dojoAttachEvent="onclick:buttonClick; onkeypress:arrowKey;"
+				tabIndex="${tabIndex}" dojoAttachPoint="containerNode;focusNode">
+				${caption}
+			</button><button type='${type}' class='dijitRight dijitComboButtonArrow dijitButtonNode'
+					dojoAttachPoint="popupStateNode"
+					dojoAttachEvent="onclick:arrowClick; onkeypress:arrowKey;"
+					tabIndex="${tabIndex}"
+					waiRole="button" waiState="haspopup-true"
+			>&nbsp;<span class='dijitDownArrow'>&#9660;</span>
+			</button></div>		
+
+<br><br>
+
+		<!-- dijit.form.Select 
+			 dijit.form.AutoCompleter 
+		-->
+
+<table class="dijitReset dijit dijitInline dijitAutoCompleter" id='widget_${id}' waiRole="presentation" cellspacing=0 cellpadding=0
+	><tr>
+		<td class='dijitReset dijitLeft'>&nbsp;</td>
+		<td class='dijitReset dijitStretch XdijitInputField XdijitAutoCompleterInput'
+			><input type="text" autocomplete="off" name="${name}" style='border:0px;padding:.2em;'
+			dojoAttachEvent="onkeypress; onkeyup; onfocus; onblur; compositionend;onmouseover:setStateClass;onmouseout:setStateClass;"
+			dojoAttachPoint="textbox;focusNode" id='${id}'
+			tabIndex='${tabIndex}' size='${size}' maxlength='${maxlength}'
+	></td><td class='dijitReset dijitRight dijitButtonNode dijitArrowButton'
+			dojoAttachPoint="downArrowNode"
+			dojoAttachEvent="onclick:arrowClicked;onmousedown:setStateClass;onmouseup:setStateClass;onmouseover:setStateClass;onmouseout:setStateClass;"
+			tabIndex="${tabIndex}"
+			waiRole="button" waiState="haspopup-true"
+		><span class='dijitA11yDownArrow'>&#9660;</span
+	></td
+></tr></table>
+
+
+<!--
+<div class="dijit dijitLeft dijitInline dijitAutoCompleter dijitAutoCompleterDisabled" id='widget_${id}' waiRole="presentation"
+	><input type="text" autocomplete="off" class="dijitStretch dijitInputField dijitAutoCompleterInput" name="${name}"
+			dojoAttachEvent="onkeypress; onkeyup; onfocus; onblur; compositionend;onmouseover:setStateClass;onmouseout:setStateClass;"
+			dojoAttachPoint="textbox;focusNode" id='${id}'
+			tabIndex='${tabIndex}' size='${size}' maxlength='${maxlength}'
+	><button class='dijitRight dijitButtonNode dijitArrowButton'
+			dojoAttachPoint="downArrowNode"
+			dojoAttachEvent="onclick:arrowClicked;onmousedown:setStateClass;onmouseup:setStateClass;onmouseover:setStateClass;onmouseout:setStateClass;"
+			tabIndex="${tabIndex}"
+			waiRole="button" waiState="haspopup-true"
+		><span class='dijitTeeny'>&nbsp;</span><span class='dijitA11yDownArrow'>&#9660;</span
+	>&nbsp;</button
+></div>
+-->
+
+<!--
+		<span class='dijit dijitInlineBlock widgetLeft dijitCombo dijitComboEnabled' toggleClass="dijitCombo">
+			<div class='widgetRight' onclick='console.info("right")'>
+				<div class='a11yIndicator a11yDownArrow'>&#9660;</div>
+				<div class='widgetStretch label' onclick='console.info("center");'>
+					Select
+				</div>	
+			</div>
+		</span>
+		
+		<br><br>
+		
+		<!- - dijit.form.AutoCompleter 
+		<span class='dijit dijitInlineBlock widgetLeft dijitCombo dijitComboEnabled'>
+			<div class='widgetRight' style='position:relative;' onclick='console.info("right")'>
+				<div class='a11yIndicator a11yDownArrow'>&#9660;</div>
+				<div class='widgetStretch label' onclick='console.info("center");'>
+					<input type='text' class='' value='Combo'>
+				</div>
+			</div>
+		</span>
+-->
+	</td>
+	<td id='tundra' class='tundra' valign=top></td>
+	<td id='a11y' class='dijit_a11y' valign=top></td>
+</tr>
+</table>
+</body>
+</html>
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/blackie.psd
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/blackie.psd
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonActive-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonActive-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonActive-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonActive-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonActive-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonActive-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonDisabled-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonDisabled-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonDisabled-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonDisabled-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonDisabled-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonDisabled-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonEnabled-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonEnabled-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonEnabled-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonEnabled-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonEnabled-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonEnabled-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonHover-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonHover-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonHover-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonHover-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonHover-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/buttonHover-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/close.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/close.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/closeActive.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/closeActive.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/closeHover.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/closeHover.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowActive-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowActive-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowActive-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowActive-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowActive-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowActive-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowHover-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowHover-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowHover-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowHover-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowHover-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonArrowHover-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnActive-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnActive-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnActive-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnActive-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnActive-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnActive-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnHover-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnHover-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnHover-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnHover-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnHover-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonBtnHover-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonDisabled-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonDisabled-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonDisabled-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonDisabled-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonDisabled-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonDisabled-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonEnabled-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonEnabled-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonEnabled-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonEnabled-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonEnabled-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/comboButtonEnabled-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonActive-center.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonActive-center.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonActive-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonActive-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonActive-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonActive-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonActive-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonActive-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonDisabled-center.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonDisabled-center.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonDisabled-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonDisabled-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonDisabled-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonDisabled-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonDisabled-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonDisabled-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonEnabled-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonEnabled-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonEnabled-right-06.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonEnabled-right-06.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonEnabled-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonEnabled-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonEnabled-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonEnabled-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonHover-center.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonHover-center.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonHover-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonHover-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonHover-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonHover-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonHover-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/ddButtonHover-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/images.css
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/images.css	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/images.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,103 @@
+
+/* 	dijit.form.Button */	
+.blackie .dijitButton							{	background-image:url('buttonEnabled-left.png');		}
+.blackie .dijitButton .dijitRight				{	background-image:url('buttonEnabled-right.png');	}
+.blackie .dijitButton .dijitStretch				{	background-image:url('buttonEnabled-stretch.png');	}
+	
+.blackie .dijitButtonHover 						{	background-image:url('buttonHover-left.png');		}
+.blackie .dijitButtonHover .dijitRight			{	background-image:url('buttonHover-right.png');		}
+.blackie .dijitButtonHover .dijitStretch		{	background-image:url('buttonHover-stretch.png');	}
+	
+.blackie .dijitButtonActive						{	background-image:url('buttonActive-left.png');		}
+.blackie .dijitButtonActive .dijitRight			{	background-image:url('buttonActive-right.png');		}
+.blackie .dijitButtonActive .dijitStretch		{	background-image:url('buttonActive-stretch.png');	}
+	
+.blackie .dijitButtonDisabled					{	background-image:url('buttonDisabled-left.png');	}
+.blackie .dijitButtonDisabled .dijitRight		{	background-image:url('buttonDisabled-right.png');	}
+.blackie .dijitButtonDisabled .dijitStretch		{	background-image:url('buttonDisabled-stretch.png');	}
+
+
+
+/* 	dijit.form.ComboButton */
+.blackie .dijitComboButton						{	background-image:url('comboButtonEnabled-left.png');	}
+.blackie .dijitComboButton .dijitRight			{	background-image:url('comboButtonEnabled-right.png');	}
+.blackie .dijitComboButton .dijitStretch		{	background-image:url('comboButtonEnabled-stretch.png');	}
+
+.blackie .dijitComboButtonHover 				{	background-image:url('comboButtonBtnHover-left.png');		}
+.blackie .dijitComboButtonHover .dijitRight		{	background-image:url('comboButtonBtnHover-right.png');		}
+.blackie .dijitComboButtonHover .dijitStretch	{	background-image:url('comboButtonBtnHover-stretch.png');	}
+
+.blackie .dijitComboButtonActive				{	background-image:url('comboButtonBtnActive-left.png');		}
+.blackie .dijitComboButtonActive .dijitRight	{	background-image:url('comboButtonBtnActive-right.png');		}
+.blackie .dijitComboButtonActive .dijitStretch	{	background-image:url('comboButtonBtnActive-stretch.png');	}
+
+
+.blackie .dijitComboButtonDownArrowHover 				{	background-image:url('comboButtonArrowHover-left.png');		}
+.blackie .dijitComboButtonDownArrowHover .dijitRight	{	background-image:url('comboButtonArrowHover-right.png');		}
+.blackie .dijitComboButtonDownArrowHover .dijitStretch	{	background-image:url('comboButtonArrowHover-stretch.png');	}
+
+.blackie .dijitComboButtonDownArrowActive				{	background-image:url('comboButtonArrowActive-left.png');		}
+.blackie .dijitComboButtonDownArrowActive .dijitRight	{	background-image:url('comboButtonArrowActive-right.png');		}
+.blackie .dijitComboButtonDownArrowActive .dijitStretch	{	background-image:url('comboButtonArrowActive-stretch.png');	}
+
+.blackie .dijitComboButtonDisabled				{	background-image:url('comboButtonDisabled-left.png') !important;	}
+.blackie .dijitComboButtonDisabled .dijitRight	{	background-image:url('comboButtonDisabled-right.png') !important;	}
+.blackie .dijitComboButtonDisabled .dijitStretch{	background-image:url('comboButtonDisabled-stretch.png') !important;	}
+
+
+/* 	dijit.form.DropDownButton */
+.blackie .dijitDropDownButton						{	background-image:url('ddButtonEnabled-left.png');		}
+.blackie .dijitDropDownButton .dijitRight			{	background-image:url('ddButtonEnabled-right.png');	}
+.blackie .dijitDropDownButton .dijitStretch			{	background-image:url('ddButtonEnabled-stretch.png');	}
+
+.blackie .dijitDropDownButtonHover 					{	background-image:url('ddButtonHover-left.png');		}
+.blackie .dijitDropDownButtonHover .dijitRight		{	background-image:url('ddButtonHover-right.png');		}
+.blackie .dijitDropDownButtonHover .dijitStretch	{	background-image:url('ddButtonHover-stretch.png');	}
+
+.blackie .dijitDropDownButtonActive					{	background-image:url('ddButtonActive-left.png');		}
+.blackie .dijitDropDownButtonActive .dijitRight		{	background-image:url('ddButtonActive-right.png');		}
+.blackie .dijitDropDownButtonActive .dijitStretch	{	background-image:url('ddButtonActive-stretch.png');	}
+
+.blackie .dijitDropDownButtonDisabled				{	background-image:url('ddButtonDisabled-left.png');	}
+.blackie .dijitDropDownButtonDisabled .dijitRight	{	background-image:url('ddButtonDisabled-right.png');	}
+.blackie .dijitDropDownButtonDisabled .dijitStretch	{	background-image:url('ddButtonDisabled-stretch.png');	}
+
+
+
+/* dijit.form.AutoCompleter */
+
+.blackie .dijitAutoCompleter					{	background-image:url('selectEnabled-left.png');		}
+.blackie .dijitAutoCompleter .dijitRight		{	background-image:url('selectEnabled-right.png');	}
+.blackie .dijitAutoCompleter .dijitStretch		{	background-image:url('selectEnabled-stretch.png');	}
+
+.blackie .dijitAutoCompleterHover				{	background-image:url('selectHover-left.png');		}
+.blackie .dijitAutoCompleterHover .dijitRight	{	background-image:url('selectHover-right.png');		}
+.blackie .dijitAutoCompleterHover .dijitStretch	{	background-image:url('selectHover-stretch.png');	}
+	
+.blackie .dijitAutoCompleterActive				{	background-image:url('selectActive-left.png');		}
+.blackie .dijitAutoCompleterActive .dijitRight	{	background-image:url('selectActive-right.png');	}
+.blackie .dijitAutoCompleterActive .dijitStretch{	background-image:url('selectActive-stretch.png');	}
+
+.blackie .dijitAutoCompleterDisabled			{	background-image:url('selectDisabled-left.png');	}
+.blackie .dijitAutoCompleterDisabled .dijitRight{	background-image:url('selectDisabled-right.png');	}
+.blackie .dijitAutoCompleterDisabled .dijitStretch{	background-image:url('selectDisabled-stretch.png');	}
+
+
+
+/* dijit.form.Spinner */
+
+.blackie .dijitSpinner .dijitLeft							{	background-image:url('spinnerEnabled-left.png') }
+.blackie .dijitSpinner .dijitUpArrowButton					{	background-image:url('spinnerEnabled-top.png');	}
+.blackie .dijitSpinner .dijitDownArrowButton				{	background-image:url('spinnerEnabled-bottom.png');	}
+.blackie .dijitSpinner .dijitStretch						{	background-image:url('spinnerEnabled-stretch.png');	}
+
+.blackie .dijitSpinnerUpArrowHover .dijitUpArrowButton		{	background-image:url('spinnerHover-top.png');	}
+.blackie .dijitSpinnerDownArrowHover .dijitDownArrowButton	{	background-image:url('spinnerHover-bottom.png');	}
+
+.blackie .dijitSpinnerUpArrowActive .dijitUpArrowButton		{	background-image:url('spinnerActive-top.png');	}
+.blackie .dijitSpinnerDownArrowActive .dijitDownArrowButton	{	background-image:url('spinnerActive-bottom.png');	}
+
+.blackie .dijitSpinnerDisabled .dijitLeft					{	background-image:url('spinnerDisabled-left.png');	}
+.blackie .dijitSpinnerDisabled .dijitUpArrowButton			{	background-image:url('spinnerDisabled-top.png');	}
+.blackie .dijitSpinnerDisabled .dijitDownArrowButton		{	background-image:url('spinnerDisabled-bottom.png');	}
+.blackie .dijitSpinnerDisabled .dijitStretch				{	background-image:url('spinnerDisabled-stretch.png');	}

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectActive-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectActive-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectActive-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectActive-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectActive-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectActive-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectDisabled-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectDisabled-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectDisabled-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectDisabled-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectDisabled-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectDisabled-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectEnabled-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectEnabled-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectEnabled-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectEnabled-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectEnabled-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectEnabled-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectHover-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectHover-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectHover-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectHover-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectHover-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/selectHover-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerActive-bottom.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerActive-bottom.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerActive-top.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerActive-top.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerDisabled-bottom.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerDisabled-bottom.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerDisabled-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerDisabled-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerDisabled-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerDisabled-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerDisabled-top.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerDisabled-top.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerEnabled-bottom.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerEnabled-bottom.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerEnabled-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerEnabled-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerEnabled-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerEnabled-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerEnabled-top.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerEnabled-top.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerHover-bottom.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerHover-bottom.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerHover-top.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/spinnerHover-top.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabActive-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabActive-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabActive-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabActive-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabActive-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabActive-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabDisabled-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabDisabled-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabDisabled-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabDisabled-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabDisabled-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabDisabled-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabEnabled-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabEnabled-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabEnabled-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabEnabled-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabEnabled-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabEnabled-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabHover-left.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabHover-left.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabHover-right.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabHover-right.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabHover-stretch.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/blackie/images/tabHover-stretch.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/dijit.css
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/themes/dijit.css	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/themes/dijit.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,1003 @@
+/*
+	Essential styles that themes can inherit.
+	In other words, works but doesn't look great.
+*/
+
+
+
+/**** 
+		GENERIC PIECES 
+ ****/
+
+.dijitReset {
+	/* Use this style to null out padding, margin, border in your template elements
+		so that page specific styles don't break them.
+		- Use in all TABLE, TR and TD tags.	
+		- If there is more than one class on the tag, place this first so other classes override.
+	*/
+	margin:0px;
+	border:0px;
+	padding:0px;
+	line-height:auto;
+}
+
+.dijitInline {
+	/* MOW: similar to InlineBox below, but this has fewer side-effects in Moz.  
+		Also, apparently works on a DIV as well as a FIELDSET.
+		Consider abandoning inlineBox in favor of this.  ???
+	*/
+	display:inline-block;			/* webkit */
+	display:-moz-inline-box;		/* gecko */
+	#display:inline;				/* MSIE   */
+	border:0px;
+	padding:0px;
+	vertical-align:middle;
+}
+
+.dijitInlineBox {
+	/* To inline block elements, surround them with <fieldset class="dijitInlineBox"> */
+	display:inline-block;			/* webkit */
+	display: -moz-inline-stack;		/* gecko  */
+	#display:inline;				/* MSIE   */
+	border:0px;
+	padding:0px;
+	vertical-align:middle;
+}
+.dj_ie6 .dijitInlineBox {
+	#display:inline;				/* IE */
+}
+
+
+.dijitTeeny {
+	font-size:1px;
+	line-height:1px;
+}
+
+.dijitPopup {
+	/* For popup items, such as menu */
+	position: absolute;
+}
+
+.dijitPositionOnly {
+	/* Null out all position-related properties */
+	padding: 0px !important;
+	border: 0px !important;
+	background-color: transparent !important;
+	background-image: none !important;
+	height: auto !important;
+	width: auto !important;
+}
+
+.dijitNonPositionOnly {
+	/* Null position-related properties */
+	float: none !important;
+	position: static !important;
+	margin: 0px 0px 0px 0px !important;
+	vertical-align: middle !important;
+}
+
+
+.dijitClickableRegion {
+	/* a region we expect the user to click on */
+	cursor : pointer;
+}
+
+.dijitDisabledClickableRegion {
+	/* a region the user would be able to click on, but it's disabled */
+	cursor: default;        /* makes opera happy */
+	cursor: url("no.gif"), not-allowed, default;
+}
+
+.dijitDisplayNone {
+	/* hide something.  Use this as a class rather than element.style so another class can override */
+	display:none !important;
+}
+
+
+
+.dijitButtonDisabled *,
+.dijitDropDownButtonDisabled *,
+.dijitComboButtonDisabled *,
+.dijitAutoCompleterDisabled * {
+	cursor: default;
+	cursor: not-allowed !important;
+	cursor: url("no.gif"), not-allowed, default;
+}
+
+
+
+
+
+/**** 
+		A11Y CHECK 
+ ****/
+#a11yTestNode {
+	/* used to test if high contrast mode is on or images are turned off */
+	border: 1px solid;
+	border-color:red green;
+	position: absolute;
+	left: -999px;
+	top: -999px;
+	background-image: url("../form/templates/blank.gif");
+}  
+
+
+.dijit_a11y * {
+	background-image:none !important;
+	background-color:transparent !important;
+}
+
+.dijitA11yDownArrow,
+.dijitA11yUpArrow    {
+	/* down arrow shown when in a11y mode */
+	font-family:Arial, sans serif;
+	font-size:.5em;
+	line-height:.5em;
+	padding:0em .25em;
+}
+
+
+.dj_ie .dijitA11yDownArrow,
+.dj_ie .dijitA11yUpArrow  {
+	font-size:.8em;
+}
+
+
+
+
+.dijit_a11y .dijitButton .dijitButtonNode,
+.dijit_a11y .dijitDropDownButton .dijitButtonNode,
+.dijit_a11y .dijitComboButton .dijitButtonNode,
+.dijit_a11y .dijitAutoCompleter .dijitAutoCompleterInput,
+.dijit_a11y .dijitAutoCompleter .dijitButtonNode {
+	border:1px solid black !important;
+	background:white !important;
+	color:black !important;
+}
+
+.dijit_a11y .dijitButtonDisabled .dijitButtonNode,
+.dijit_a11y .dijitDropDownButtonDisabled .dijitButtonNode,
+.dijit_a11y .dijitComboButtonDisabled .dijitButtonNode,
+.dijit_a11y .dijitAutoCompleterDisabled .dijitAutoCompleterInput,
+.dijit_a11y .dijitAutoCompleterDisabled .dijitButtonNode,
+.dijit_a11y .dijitSpinnerDisabled .dijitButtonNode,
+.dijit_a11y .dijitSpinnerDisabled .dijitSpinnerInput {
+	border:1px dotted #999999 !important;
+	color:#999999 !important;
+}
+
+.dijit_a11y .dijitComboButton .dijitDownArrowButton,
+.dijit_a11y .dijitAutoCompleter .dijitDownArrowButton {
+	border-left:0px !important;
+}
+
+
+
+
+/****
+		3-element borders:  ( dijitLeft + dijitStretch + dijitRight ) 
+ ****/
+	
+.dijitLeft {
+	/* Left part of a 3-element border */
+	background-position:left top;
+	background-repeat:no-repeat;
+}
+
+.dijitStretch {
+	/* Middle (stretchy) part of a 3-element border */
+	white-space:nowrap;			/* MOW: move somewhere else */
+	background-repeat:repeat-x;
+}
+
+.dijitRight {
+	/* Right part of a 3-element border */
+	#display:inline;				/* IE7 sizes to outer size w/o this */
+	background-position:right top;
+	background-repeat:no-repeat;
+}
+
+
+/****
+		Right-to-left rules
+ ****/
+.dijitRTL .dijitRightArrow {
+	/* it becomes a left arrow for LTR locales */
+	/* MOW: TODO... */
+	margin-left:-2.1em;
+}
+
+
+
+
+
+/****
+		dijit.form.Button
+		dijit.form.DropDownButton
+		dijit.form.ComboButton
+		dijit.form.AutoCompleter (partial)
+ ****/
+.dijitButton,
+.dijitDropDownButton,
+.dijitComboButton,
+.dijitAutoCompleter {
+	/* outside of button */
+	margin:.2em;
+}
+
+.dijitButtonNode {
+	/* Node that is acting as a button -- may or may not be a BUTTON element */
+	border:1px outset gray;
+	margin:0px;
+	padding:.2em .2em .1em .2em;
+	overflow:visible;
+	line-height:normal;
+	font-family:inherit;
+	font-size:inherit;
+	color: inherit;
+	cursor:pointer;
+	vertical-align:middle;	
+	text-align:center;
+	white-space: nowrap;
+}
+
+.dijitDownArrowButton,
+.dijitUpArrowButton {
+	/* Node that is acting as a arrow button -- drop down or spinner.  Also gets dijitButtonNode */
+	/* place AFTER dijitButtonNode so it overrides */
+	padding:0em .4em;
+	margin:0px;
+}
+
+
+.dijitButtonContents {
+	color:inherit;
+}
+
+.dijitDropDownButton .dijitA11yDownArrow {
+	margin-left:.8em;
+}
+
+.dijitComboButton TABLE {
+	/* each cell in a combo-table should have its own separate border */
+	border-collapse: separate;
+	border:0px;
+	padding:0px;
+	margin:0px;
+}
+
+.dijitComboButton .dijitButtonContents {
+	border-right-width:0px !important;
+}
+
+
+table .dijitButton .dijitButtonNode,
+table .dijitComboButton .dijitButtonNode {
+	#overflow:hidden; /* visible messes up if the button is inside a table on IE */
+}
+
+
+
+.dijitButtonNode IMG {
+	/* make text and images line up cleanly */
+	vertical-align:middle;
+	margin-bottom:.2em;
+}
+
+
+
+
+
+/****
+		dijit.form.AutoCompleter 
+		dijit.form.NumberSpinner  (template: form/templates/Spinner.html)
+
+		Note: these works differently than other Textbox types:
+			The outer fieldset element is the one that shows the border, etc.
+			rather than the actual INPUT element. 
+
+ ****/
+.dijitAutoCompleter {
+	/* Allow user to specify width without messing up defaults; other attributes are put on parent node */
+	width:auto !important;
+}
+
+.dijitAutoCompleter TABLE,
+.dijitSpinner TABLE {
+	/* each cell in a combo-table should have its own separate border */
+	border-collapse: separate;
+	border:0px;
+	padding:0px;
+	margin:0px;
+}
+
+.dijitAutoCompleterInput,
+.dijitSpinnerInput {
+	/* container for the input element */
+	font-family:inherit;
+	font-size:inherit;
+	font-weight:inherit;
+	border:1px inset gray;
+	padding:.1em .2em .2em .2em;
+	border-right-width:0px !important;
+}
+
+.dijitAutoCompleter INPUT,
+.dijitSpinner INPUT {
+	/* turn off the border on the actual input element */
+	border:0px !important;
+	background-color:transparent;
+}
+
+.dj_safari .dijitAutoCompleterInput,
+.dj_safari .dijitSpinnerInput {
+	padding:0px;
+	border:0px !important;
+}
+.dj_safari .dijitAutoCompleter INPUT,
+.dj_safari .dijitSpinner INPUT{
+	margin:-2px -4px -3px -3px;
+	line-height:2em;
+	font-size:1em;
+}
+
+
+.dijitSpinner {
+	/* outer element, which in the spinner case actually shows the border */
+	display:inline;
+	vertical-align:middle;
+	padding:0px !important;
+	width:auto !important;
+	height:auto !important;
+}
+
+.dijitSpinner INPUT {
+	/* The .style assigned to the spinner dijit is actually copied 
+		on to the INPUT element as well as the outer element.
+		The below turns off things on the input that should apply to the outer element.
+	*/
+	display:inline;
+	position:static !important;
+	float:none !important;
+	vertical-align:middle !important;
+	padding:0px !important;
+	margin:auto !important;
+	border:0px !important;
+	visibility:visible !important;
+	font-size:100% !important;
+	background-color:transparent !important;
+}
+
+.dijitSpinner .dijitDownArrowButton,
+.dijitSpinner .dijitUpArrowButton {
+	line-height:0px;
+	padding:.3em .3em .1em .25em;
+	height:50%;
+}
+
+
+/* total hacks to get IE to work */
+.dj_ie .dijitSpinner .dijitDownArrowButton,
+.dj_ie .dijitSpinner .dijitUpArrowButton {
+	vertical-align:top;
+	padding:0px;
+	margin:0px;
+}
+
+.dj_ie .dijitSpinner .dijitDownArrowButton {
+	border-top-width:0px;
+}
+
+.dj_ie .dijitSpinner .dijitA11yUpArrow    {
+	vertical-align:top;
+}
+.dj_ie .dijitSpinner .dijitA11yDownArrow {
+	vertical-align:middle;
+}
+
+.dj_ie .dijitSpinner .dijitA11yDownArrow,
+.dj_ie .dijitSpinner .dijitA11yUpArrow    {
+	font-size:.6em;
+	line-height:1.6em;
+	padding:0em .25em;
+	margin:0px;
+}
+
+
+
+/****
+		dijit.form.Checkbox
+ 	 & 
+  		dijit.form.RadioButton 
+ ****/
+
+.dijitCheckbox {
+	position: relative;
+}
+
+.dijitCheckboxImageContainer,
+.dijitCheckboxInputInvisible {
+	/* place the checkbox and the actual input on top of each other */
+	position: absolute;
+	left: 0;
+	top: 0;
+	border: 0;
+	margin: 0;
+	padding: 0;
+}
+
+
+.dj_ie .dijitCheckboxImageContainer, 
+.dj_ie .dijitCheckboxInputInvisible {
+	top: 3px;
+}
+
+.dijitCheckboxInputInvisible {
+	/* place the actual input on top, but all-but-invisible */
+	z-index: 100;
+	opacity: 0.01;
+}
+
+.dj_ie .dijitCheckboxInputInvisible {
+	filter: alpha(opacity=0);
+}
+
+
+
+
+/****
+		dijit.Toaster (?)
+ ****/
+ 
+.dijitToasterClip {
+	position: absolute;
+	overflow: hidden;
+}
+
+.dijitToasterContainer {
+	display: block;
+	position: absolute;
+	width: 17.5em;
+	z-index: 5000;
+	margin: 0px;
+	font:0.75em Tahoma, Helvetica, Verdana, Arial;
+}
+
+
+/****
+		dijit.ProgressBar
+ ****/
+ 
+.dijitProgressBarEmpty{
+	/* outer container and background of the bar that's not finished yet*/
+	position:relative;overflow:hidden;
+	border:1px solid black; 	/* a11y: border necessary for high-contrast mode */
+	height:20px;
+}
+
+
+.dijitProgressBarFull {
+	/* outer container for background of bar that is finished */
+	position:absolute;
+	overflow:hidden;
+	width:100%;
+	height:100%;
+}
+
+.dijitProgressBarTile{
+	/* inner container for finished portion */
+	position:absolute;
+	overflow:hidden;
+	top:0px;
+	left:0px;
+	bottom:0px;
+	right:0px;
+	margin:0px;
+	padding:0px;
+	width:auto;
+	height:auto;
+	background-color:#aaa;
+	background-attachment: fixed;
+}
+
+.dijit_a11y .dijitProgressBarTile{
+	/* a11y:  The border provides visibility in high-contrast mode */
+	border-width:4px;
+	border-style:solid;
+	background-color:transparent !important;
+}
+
+.dj_iequirks .dijitProgressBarTile{
+	width:100%;
+	height:100%;
+}
+
+.dj_ie6 .dijitProgressBarTile{
+	/* width:auto works in IE6 with position:static but not position:absolute */
+	position:static;
+	/* height:auto does not work in IE6 */
+	height:100%;
+}
+
+.dj_ie6 .dijitProgressBarVertical .dijitProgressBarTile{
+	position:absolute;
+	/* can't use position:static here -- need absolute positioning to place
+	   the bar at the bottom of a vertical progressbar */
+	width:100%;
+}
+
+.dijitProgressBarIndeterminate dijitProgressBarTile{
+	/* animated gif for 'indeterminate' mode */
+}
+
+
+
+.dijitProgressBarEmptyLabel{
+	/* label for portion of the bar that's not finished yet */
+	display:block;
+	position:absolute;
+	width:100%;
+	text-align:center
+}
+.dijitProgressBarFullLabel{
+	/* label for portion of the bar that is finished */
+	display:block;
+	position:absolute;
+	width:100%;
+	text-align:center;
+}
+
+/* progress bar in vertical mode */
+.dijitProgressBarVertical .dijitProgressBarFull{
+	bottom:0px;		/* start at the bottom */
+}
+
+
+
+
+
+/****
+		dijit.Tooltip
+ ****/
+
+.dijitTooltip {
+	position: absolute;
+	z-index: 10;
+	display: block;
+	margin-top: 10px;
+	/* make visible but off screen */
+	left: -10000px;
+	top: -10000px;
+	overflow: visible;
+}
+
+.dijitTooltipContainer {
+	border: solid black 2px;
+	background: #b8b5b5;
+	color: black;
+	font-size: small;
+	padding: 2px 2px 2px 2px;
+}
+
+
+.dijitTooltipConnector {
+	position: absolute;
+}
+
+/* MOW: using actual images at this time
+/* draw an arrow with CSS only * /
+.dijitTooltipConnector {
+	/* the border on the triangle * /
+	font-size: 0px; line-height: 0%; width: 0px;
+	border-top: none;
+	border-bottom: 14px solid black;
+	border-left: 7px solid transparent;
+	border-right: 7px solid transparent;
+	top: -14px;
+	left: 3px;
+	z-index: 2;
+}
+
+.dijitTooltipConnector div {
+	/* the background of the triangle * /
+	font-size: 0px; line-height: 0%; width: 0px;
+	position: absolute;
+	border-bottom: 10px solid #b8b5b5;
+	border-left: 5px solid transparent;
+	border-right: 5px solid transparent;
+	top: 6px;
+	left: -5px;
+	z-index: 3;
+}
+
+*/
+
+
+
+/* Layout widgets. This is essential CSS to make layout work (it isn't "styling" CSS)
+   make sure that the position:absolute in dijitAlign* overrides other classes */
+
+.dijitLayoutContainer{ 
+	position: relative;
+	display: block;
+	overflow: hidden; 
+}
+
+body .dijitAlignTop,
+body .dijitAlignBottom,
+body .dijitAlignLeft,
+body .dijitAlignRight {
+	position: absolute;
+	overflow: hidden; 
+}
+
+body .dijitAlignClient { position: absolute; }
+
+.dijitAlignClient { overflow: auto; }
+
+
+
+/* SplitContainer 
+
+	'V' == container that splits vertically (up/down)
+	'H' = horizontal (left/right)
+*/
+.dijitSplitContainer{
+	position: relative;
+	overflow: hidden;
+	display: block;
+}
+
+.dijitSplitPane{
+	position: absolute;
+}
+
+.dijitSplitContainerSizerH,
+.dijitSplitContainerSizerV {
+	position:absolute;
+	font-size: 1px;
+	cursor: move;
+	cursor: w-resize;
+	background-color: ThreeDFace;
+	border: 1px solid;
+	border-color: ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight;
+	margin: 0;
+}
+
+.dijitSplitContainerSizerV {
+	cursor: n-resize;
+}
+
+.dijitSplitContainerSizerH .thumb {
+	position:absolute;
+	top:49%;
+}
+
+.dijitSplitContainerSizerV .thumb {
+	position:absolute;
+	left:49%;
+}
+
+.dijitSplitContainerVirtualSizerH,
+.dijitSplitContainerVirtualSizerV {
+	font-size: 1px;
+	cursor: move;
+	cursor: w-resize;
+	background-color: ThreeDShadow;
+	-moz-opacity: 0.5;
+	opacity: 0.5;
+	filter: Alpha(Opacity=50);
+	margin: 0;
+}
+
+.dijitSplitContainerVirtualSizerV {
+	cursor: n-resize;
+}
+
+
+/* ContentPane */
+
+.dijitContentPane {
+	display: block;
+	overflow: auto;	/* if we don't have this (or overflow:hidden), then Widget.resizeTo() doesn't make sense for ContentPane */
+}
+
+/* Color Palette */
+.dijitPaletteImg {
+	width: 16px; /*This is the width of one color in the provided palettes. */
+	height: 13px; /* Height of one color in the provided palettes. */
+	position: absolute;
+	overflow: hidden;
+	cursor: default;
+	z-index: 10;
+	border-style: solid;
+	border-bottom-width: 1px;
+	border-right-width: 1px;
+	border-color: #000000;		
+}
+
+.dijitPaletteImgHighlight {
+	width: 14px; /*This is the width of one color in the provided palettes. */
+	height: 12px; /* Height of one color in the provided palettes. */
+	position: absolute;
+	overflow: hidden;
+	cursor: default;
+	z-index: 10;
+}
+
+.dijitPaletteImg:hover, 
+.dijitPaletteImgHighlight {
+	width: 14px; /*This is the width of one color in the provided palettes. */
+	height: 12px; /* Height of one color in the provided palettes. */
+	border-style: solid;
+	border-width: 2px;
+	border-color: #ffffff;
+}
+
+
+.dijitColorPaletteCell {
+	width:16px;
+	height:16px;
+	border:1px outset;
+}
+
+.dijitColorPaletteCell:hover {
+	border-style:inset;
+}
+
+/* AccordionPane */
+.dijitAccordionPane .accBody {
+	overflow: auto;
+}
+
+.dijitAccordionPane .label:hover {
+	cursor: pointer;
+}
+
+.dijitAccordionPane .label .arrow {
+	float:right;
+}
+
+
+/* Calendar */
+
+.calendarContainer thead tr th, .calendarContainer thead tr td, .calendarContainer tbody tr td, .calendarContainer tfoot tr td { 
+	padding: 0;
+}
+
+.calendarNextYear {
+	margin:0 0 0 0.55em;
+}
+
+.calendarPreviousYear {
+	margin:0 0.55em 0 0;
+}
+
+.calendarIncrementControl {
+	cursor:pointer;
+	cursor:hand;
+	width:1em;
+}
+
+.calendarIncrease {}
+
+.calendarDecrease {}
+
+
+.calendarDisabledDate {
+	color:gray !important;
+}
+
+
+.calendarBodyContainer tbody tr td {
+	cursor:pointer;
+	cursor:hand;
+}
+
+.calendarPreviousMonthDisabled {
+	cursor:default !important
+}
+
+.calendarCurrentMonthDisabled {
+	cursor:default !important
+}
+
+.calendarNextMonthDisabled {
+	cursor:default !important;
+}
+
+.calendarDateTemplate {
+	cursor:pointer;
+}
+
+.calendarSelectedYear {
+	cursor:pointer;
+}
+.calendarNextYear, 
+.calendarPreviousYear {
+	cursor:pointer;
+}
+
+.tundra .calendarMontLabel {}
+
+.tundra .calendarMonthLabelSpacer {
+	/* don't display it, but make it affect the width */
+  	position: relative;
+  	height: 1px;
+  	overflow: hidden;
+  	visibility: hidden;
+}
+
+
+/* Menu */
+
+.dijitMenu {
+	border:1px solid black;
+	background-color:white;
+}
+.dijitMenuTable {
+	margin:1px 0px;
+	border-collapse:collapse;
+	border-width:0px;
+}
+
+.dijitMenuItem{
+	white-space: nowrap;
+	padding:.1em .2em;
+}
+
+.dijitMenuItemHover {
+	cursor:pointer;
+	cursor:hand;
+	background-color:black;
+	color:white;
+}
+
+.tundra .dijitMenuItemIcon {
+	position: relative;
+	background-position: center center;
+	background-repeat: no-repeat;
+}
+
+.dijitMenuItemDisabled * {
+	/* for a disabled menu item, just set it to mostly transparent */
+	opacity:0.3;
+	cursor:default;
+}
+.dj_ie .dijitMenuItemDisabled * {
+	color:gray;
+}
+
+.dijitMenuItemLabel {
+	position: relative;
+	vertical-align: middle;
+}
+
+/* separator can be two pixels -- set border of either one to 0px to have only one */
+.tundra .dijitMenuSeparatorTop {
+	height: 50%;
+	margin: 0px;
+	margin-top:3px;
+	font-size: 1px;
+}
+
+.tundra .dijitMenuSeparatorBottom {
+	height: 50%;
+	margin: 0px;
+	margin-bottom:3px;
+	font-size: 1px;
+}
+
+
+
+/* Tab */
+
+
+.dijitTabContainer .dijitAlignTop {
+/* position the tab labels row down by 1 px, and on top of the dijitTabPaneWrapper
+	so the buttons can overlay the tab pane properly		*/
+	top:1px !important;
+	z-index:10;	
+}
+
+.dijitTabContainer .dijitAlignBottom {
+/* position the tab labels row up by 1 px so they overlap	*/
+	margin-top:-1px !important;
+	z-index:10;	
+}
+
+.dijitTabContainer .dijitAlignLeft {
+/* position the tab labels left by 1 px so they overlap		*/
+	margin-right:-1px !important;
+	z-index:10;	
+}
+
+.dijitTabContainer .dijitAlignRight {
+/* position the tab labels row up by 1 px, and on top of the dijitTabPaneWrapper
+	so the buttons can overlay the tab pane properly		*/
+	margin-left:-1px !important;
+	z-index:10;	
+}
+
+.dijitTabPaneWrapper {
+	z-index:0;
+}
+
+.dijitTabPane {
+	clear:left;
+}
+
+.dijitTab {
+	position:relative;
+	float:left;
+	cursor:pointer;
+	white-space:nowrap;
+	z-index:3;
+}
+
+.dijitTabContainer .dijitAlignLeft .dijitTab,
+.dijitTabContainer .dijitAlignRight .dijitTab {
+	float:none;
+}
+
+.dijitTabInnerDiv {
+	position:relative;
+}
+
+.dijitTab .close {
+	display : inline-block;
+	cursor : default;
+	font-size: small;
+}
+
+
+
+
+
+.dijitInlineEditor {
+	/* span around an inline-editable value when in edit mode */
+}
+
+.dijitInlineValue {
+	/* span around an inline-editable value when NOT in edit mode */
+}
+
+
+
+
+
+
+/* Tree */
+
+.TreeExpando {
+    float: left;
+    display: inline;
+    clear:both;
+}
+
+
+.TreeExpand {
+    float: left;
+    display: inline;
+}
+
+.TreeContent {
+    cursor: default;
+    /* can't make inline - multiline bugs */
+}
+
+.dijitExpandoText { 
+	display: none; 
+} 
+ 
+.dijit_a11y .dijitExpandoText { 
+	float: left; 
+	display: inline; 
+	padding-right: 3px; 
+	font: 0.75em Arial; 
+} 
+
+
+
+
+

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/templateThemeTest.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/themes/templateThemeTest.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/themes/templateThemeTest.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,157 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>Test Widget Templates in Multiple Themes</title>
+		
+		<script type="text/javascript" src="../../dojo/dojo.js"
+			djConfig="isDebug: true"></script>
+		<script type="text/javascript">
+			dojo.require("dijit.util.sniff");
+			dojo.require("dijit.Menu");
+			dojo.require("dijit.form.Button");
+			dojo.require("dijit.form.AutoCompleter");
+			dojo.require("dijit.form.NumberSpinner");
+			dojo.require("dijit.util.manager");
+			dojo.require("dijit.util.parser");
+			logMessage = console.debug;
+		</script>
+		<style type="text/css">
+			@import "../../dojo/resources/dojo.css";
+			@import "blackie/blackie.css";
+			@import "tundra/tundra.css";
+
+			/* group multiple buttons in a row */
+			body {
+				margin:10px;
+			}
+			.box {
+				display: block;
+			}
+			.box .dijitButton {
+				margin-right: 10px;
+			}
+
+		</style>
+	</head>
+	<body>
+	<script language='javascript'>
+	/*
+		var match = (window.location.search+"&").match(/theme=(.*?)&/);
+		var theme = (match ? match[1] : "tundra");
+		document.getElementsByTagName("BODY")[0].className = theme;
+		document.write("<style>	@import '../../themes/"+theme+"/"+theme+".css'; <\/style>");
+	*/
+	</script>
+		<h2>Tundra</h2>
+		<div id='tundra' class="box tundra">
+			<button id='foo' dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>
+				Button
+			</button>
+			<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")'>
+				<img src="../images/note.gif" width="16" height="16"> Button w/image
+			</button>
+			<button dojoType="dijit.form.Button" onClick='logMessage("clicked simple")' disabled='true'>
+				Disabled Button
+			</button>
+		<br><br>
+			<button dojoType="dijit.form.DropDownButton" menuId='editMenu'>
+				Drop Down Button
+			</button>
+			<button dojoType="dijit.form.DropDownButton" menuId='editMenu'>
+				<img src="../images/note.gif" width="20" height="20"> Button w/image
+			</button>
+			<button dojoType="dijit.form.DropDownButton" menuId='editMenu' disabled='true'>
+				Drop Down Disabled
+			</button>
+		<br><br>
+			<button dojoType="dijit.form.ComboButton" menuId='saveMenu' onClick='logMessage("clicked combo save")'>
+				Combo Button
+			</button>
+			<button dojoType="dijit.form.ComboButton" menuId='saveMenu' onClick='logMessage("clicked combo save")'>
+				<img src="../images/note.gif" width="20" height="20"> Combo w/image
+			</button>
+			<button dojoType="dijit.form.ComboButton" menuId='saveMenu' onClick='logMessage("clicked combo save")' disabled='true'>
+				Combo Disabled
+			</button>
+		<br><br>
+			<input dojoType="dijit.form.AutoCompleter"
+					value="California"
+					class="medium"
+					url="autoCompleterData.json"
+					searchAttr="name"
+					labelField="label"
+					labelType="html"
+					style="width: 300px;"
+					name="state2"
+					promptMessage="Please enter a state"
+					id="datatest"
+			>
+
+			<input dojoType="dijit.form.AutoCompleter"
+					value="California"
+					class="medium"
+					url="autoCompleterData.json"
+					searchAttr="name"
+					labelField="label"
+					labelType="html"
+					style="width: 300px;"
+					name="state2"
+					promptMessage="Please enter a state"
+					id="datatest"
+					disabled="true"
+			>
+
+		<br><br>
+		<input dojoType="dijit.form.NumberSpinner" 
+			onValueChanged="console.debug('onValueChanged fired for widget id = ' + this.id + ' with value = ' + arguments[0]);"
+			value="900" 
+			constraints={max:1550,places:0}
+			maxlength="10" 
+			id="integerspinner1">
+
+
+		<input dojoType="dijit.form.NumberSpinner" 
+			onValueChanged="console.debug('onValueChanged fired for widget id = ' + this.id + ' with value = ' + arguments[0]);"
+			value="900" 
+			disabled='true'
+			constraints={max:1550,places:0}
+			maxlength="10" 
+			id="integerspinner1">
+
+		</div>
+		<br clear=both>
+
+		<h2>Blackie</h2>
+		<div id='blackie' class="box blackie">
+		</div>
+		<br clear=both>
+
+		<h2>a11y mode</h2>
+		<div id='a11y' class="box dijit_a11y">
+		</div>
+		<br clear=both>
+<script language='javascript'>
+	var html = dojo.byId("tundra").innerHTML;
+	dojo.byId("blackie").innerHTML = html;
+	dojo.byId("a11y").innerHTML = html;
+</script>
+
+		<div dojoType="dijit.PopupMenu" id="editMenu" toggle="fade" toggleDuration="500" style="display: none;">
+			<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/cut.gif" caption="Cut" accelKey="Ctrl+C"
+				onClick="logMessage('not actually cutting anything, just a test!')"></div>
+			<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/copy.gif" caption="Copy" accelKey="Ctrl+X"
+				onClick="logMessage('not actually copying anything, just a test!')"></div>
+			<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/paste.gif" caption="Paste" accelKey="Ctrl+V"
+				onClick="logMessage('not actually pasting anything, just a test!')"></div>
+		</div>
+
+		<div dojoType="dijit.PopupMenu" id="saveMenu" toggle="wipe" toggleDuration="500" style="display: none;">
+			<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/save.gif" caption="Save" accelKey="Ctrl+S"
+				onClick="logMessage('not actually saving anything, just a test!')"></div>
+			<div dojoType="dijit.MenuItem" iconSrc="../../src/widget/templates/buttons/save.gif" caption="Save As" accelKey="Ctrl+A"
+				onClick="logMessage('not actually saving anything, just a test!')"></div>
+		</div>
+
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/themeTester.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/themes/themeTester.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/themes/themeTester.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,495 @@
+<html>
+<head>
+	<title>Dijit Theme Tester</title>
+	<script type="text/javascript" src="../../dojo/dojo.js"></script>
+	<script type="text/javascript" src="../dijit.js"></script>
+	<script type="text/javascript">
+
+	var themeBase = location.search.match(/theme=([a-zA-Z.]*)/);
+	var themeName = (themeBase ? themeBase[1] : "tundra");
+	document.write('<link rel="stylesheet" href="'+themeName+'/'+themeName+'.css" />');
+
+	var availableThemes = [
+		{ theme:"tundra", author:"Dojo", baseUri:"../themes/"},
+		{ theme:"inversetundra", author:"sfoster", baseUri:"../themes/" }
+	];
+
+	</script>
+	<script type="text/javascript"> // dojo.reuires()
+
+		dojo.require("dijit.Menu");
+		dojo.require("dijit._Calendar");
+		dojo.require("dijit.ColorPalette");
+		dojo.require("dijit.ProgressBar");
+		dojo.require("dijit.TitlePane");
+		dojo.require("dijit.Tooltip");
+		dojo.require("dijit.Tree");
+
+		// various Form elemetns
+		dojo.require("dijit.form.Checkbox"); 
+		dojo.require("dijit.form.Textarea");
+		dojo.require("dijit.form.Select");
+		dojo.require("dijit.form.Textbox");
+		dojo.require("dijit.form.DateTextbox");	
+		dojo.require("dijit.form.Button");
+		dojo.require("dijit.form.InlineEditBox");
+		dojo.require("dijit.form.NumberSpinner"); 
+
+		// layouts used in page
+		dojo.require("dijit.layout.AccordionContainer");
+		dojo.require("dijit.layout.ContentPane");
+		dojo.require("dijit.layout.SplitContainer");
+		dojo.require("dijit.layout.TabContainer");
+
+		dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+
+		// humm?		
+		dojo.require("dojo.date.locale");
+
+		// for the Tree
+		dojo.require("dojo.data.JsonItemStore");
+
+		// for the colorpalette
+		function setColor(color){
+	
+			var theSpan = dojo.byId("outputSpan");
+			theSpan.style.color = "#"+color;
+			theSpan.innerHTML = color;
+		}
+
+		// for the calendar
+		function myHandler(id,newValue){
+				console.debug("onValueChanged for id = " + id + ", value: " + newValue);
+		};
+
+	</script>
+	<style type="text/css">
+	
+	@import "../../dojo/resources/dojo.css";
+	@import "../tests/css/dijitTests.css";
+
+	body { padding:10px; }	
+
+	/* FIXME: this may or may not be good. need to ask becka11y the implications of disabling 
+           focus, or how to make it asthetically pleasing to imply focus on an element 
+	   it DEFINATELY breaks 'tree', so perhaps a nicer way to highlight the selected node in a 
+           tree would be a Good Thing (tm). below is general, and bad, but is the 'idea'
+	*/
+	/* 
+	:focus { outline:0; }
+	*/
+
+	/* for custom menu buttons, do not appear to have any effect */
+	.dc {
+		font-size: x-large !important;
+		padding-top: 10px !important;
+		padding-bottom: 10px !important;
+	}
+		
+	.Acme *,
+	.Acme {
+		background: rgb(96,96,96) !important;
+		color: white !important;
+		padding: 10px !important;
+	}
+
+	.Acme:hover *,
+	.Acme:hover {
+		background-color: rgb(89,94,111) !important;
+		color: cyan !important;
+	}
+
+	.Acme:active *,
+	.Acme:active {
+			background-color: white !important;
+			color: black !important;
+	}
+
+	</style>
+
+</head>
+<body class="tundra">
+	<h1 style="margin:15px; margin-left:0px;" >Dijit Theme Test Page</h1>
+	<div dojoType="dojo.data.JsonItemStore" jsId="continentStore"
+		url="../tests/countries.json"></div>
+
+	<div dojoType="dijit.PopupMenu" id="submenu1" contextMenuForWindow="true" style="display: none;">
+		<div dojoType="dijit.MenuItem" caption="Enabled Item" onClick="alert('Hello world');"></div>
+		<div dojoType="dijit.MenuItem" caption="Disabled Item" disabled="true"></div>
+		<div dojoType="dijit.MenuSeparator"></div>
+		<!-- FIXME: there's no cut.gif!! -->
+		<div dojoType="dijit.MenuItem" iconSrc="../tests/images/cut.gif" caption="Cut" accelKey="Ctrl+C"
+			onClick="alert('not actually cutting anything, just a test!')"></div>
+		<div dojoType="dijit.MenuItem" iconSrc="../tests/images/copy.gif" caption="Copy" accelKey="Ctrl+X"
+			onClick="alert('not actually copying anything, just a test!')"></div>
+		<div dojoType="dijit.MenuItem" iconSrc="../tests/images/paste.gif" caption="Paste" accelKey="Ctrl+V"
+			onClick="alert('not actually pasting anything, just a test!')"></div>
+
+		<div dojoType="dijit.MenuSeparator"></div>
+		<div dojoType="dijit.MenuItem" caption="Enabled Submenu" submenuId="submenu2"></div>
+		<div dojoType="dijit.MenuItem" caption="Disabled Submenu" submenuId="submenu2" disabled="true"></div>
+		<div dojoType="dijit.MenuItem" caption="Enabled Item" onClick="alert('Hello world');"></div>
+	</div>
+	<div dojoType="dijit.PopupMenu" id="submenu2" style="display: none;">
+		<div dojoType="dijit.MenuItem" caption="Submenu Item One" onClick="alert('Submenu 1!')"></div>
+		<div dojoType="dijit.MenuItem" caption="Submenu Item Two" onClick="alert('Submenu 2!')"></div>
+	</div>
+
+	<div dojoType="dijit.layout.SplitContainer" orientation="horizontal" sizerWidth="7"
+		style="width: 100%; height: 87%; ">
+
+		<div dojoType="dijit.layout.AccordionContainer" duration="200" 
+			sizeMin="20" sizeShare="38"
+			labelNodeClass="label" containerNodeClass="accBody">
+			<div dojoType="dijit.layout.ContentPane" label="Dojo Countries Tree" style="display:none; padding:5px; ">
+				<div dojoType="dijit.Tree" store="continentStore" query="{type:'continent'}"
+					labelAttr="name" typeAttr="type"></div>
+			</div>
+			<div dojoType="dijit.layout.ContentPane" label="Calendar" style="padding:10px;" selected="true">
+				<input id="calendar1" dojoType="dijit._Calendar" onValueChanged="myHandler(this.id,arguments[0])" lang="en-us">
+			</div>
+			<div dojoType="dijit.layout.ContentPane" label="Color Picker" style="padding:10px; display:none; ">
+					<h2 class="testHeader">Dijit Color Palette(7x10)</h2>
+					<div dojoType="dijit.ColorPalette" onColorSelect="setColor(this.selectedColor);"></div>  
+					<br>
+					Test color is: <span id="outputSpan"></span>.
+			</div>
+			<div dojoType="dijit.layout.ContentPane" label="Tooltips" style="padding:10px;">
+				<h2>Dijit Tooltips:</h2>
+				<span id="ttRich">rich text tooltip</span>
+				<span dojoType="dijit.Tooltip" connectId="ttRich" style="display:none;">
+					Embedded <b>bold</b> <i>RICH</i> text <span style="color:#309; font-size:x-large;">weirdness!</span>
+				</span>
+
+				<a id="ttOne" href="#bogus">anchor tooltip</a>
+				<span dojoType="dijit.Tooltip" connectId="ttOne" caption="inline caption." style="display:none;"></span>
+			</div>
+
+		</div><!-- end AccordionContainer -->
+
+		<div dojoType="dijit.layout.SplitContainer" orientation="vertical" sizerWidth="7" sizeShare="75">
+
+			<div dojoType="dijit.layout.TabContainer" style="width: 100%; height: 30em;" selectedChild="tab11" sizeShare="40">
+				<div id="tab2" dojoType="dijit.layout.ContentPane" label="Form Feel" 
+					style="padding:10px; background:#fff; display:none;" >
+
+					<h2>Various Form Elements:</h2>
+					<form name="dijitFormTest">
+				
+						[plain] Text Input: <input type="text" name="textInfo" value="Lorem" size="10">
+						<br />
+
+						<p><input type="checkbox" dojoType="dijit.form.Checkbox" checked="checked"> Standard Dijit Checkbox
+						<br /><input type="checkbox" dojoType="dijit.form.Checkbox" disabled="disabled" /> Disabled Dijit
+						<br /><input type="checkbox" dojoType="dijit.form.Checkbox" disabled="disabled" checked="checked" /> Checked and Disabled Dijit
+						<br /><input type="checkbox"> Standard
+						<br /><input type="checkbox" disabled="disabled"> Standard [disabled]
+						</p>
+
+						<p>
+						<span>Radio group #1:</span>
+						<input type="radio" name="g1" id="g1rb1" value="news" dojoType="dijit.form.RadioButton">
+							<label for="g1rb1">news</label>
+						<input type="radio" name="g1" id="g1rb2" value="talk" dojoType="dijit.form.RadioButton" checked="checked"/>
+						<label for="g1rb2">talk</label>
+						<input type="radio" name="g1" id="g1rb3" value="weather" dojoType="dijit.form.RadioButton" disabled="disabled"/>
+						<label for="g1rb3">weather</label>
+						<input type="radio" name="g1" id="g1r4" value="standard" /><label for="glr4">Standard</label>
+						</p>	
+
+						<p>	
+						<span>Radio group #2: (no default value, and has breaks)</span><br>
+						<input type="radio" name="g2" id="g2rb1" value="top40" dojoType="dijit.form.RadioButton">
+						<label for="g2rb1">top 40</label><br>
+
+						<input type="radio" name="g2" id="g2rb2" value="oldies" dojoType="dijit.form.RadioButton">
+						<label for="g2rb2">oldies</label><br>
+
+						<input type="radio" name="g2" id="g2rb3" value="country" dojoType="dijit.form.RadioButton">
+						<label for="g2rb3">country</label><br />
+						
+						<input type="radio" name="g2" id="g2rb4" value="standard">
+						<label for="g2rb4">standard</label><br />
+						
+						<br />
+						(Note if using keyboard: tab to navigate, and use arrow or space to select)
+						</p>
+					
+						<p><span>Autocompleting dijit.form.Select: (from tree datastore?)</span>
+						<!-- FIXME: 
+
+							<input searchAttr="name" keyField="name" dojoType="dijit.form.Select" 
+								value="" name="state4" autocomplete="true" 
+								labelField="type" labelType="html"
+								store="continentStore" promptMessage="Please enter a Continent" />
+						-->
+						</p>			
+
+						<p><span>Number Spinner:</span>
+						<input dojoType="dijit.form.NumberSpinner" id="integertextbox3"> (enter a number or text)
+						</p>
+
+						<p><span>Text Area: (sans <i>any</i> styling...)</span><br />
+						<textarea dojoType="dijit.form.Textarea" name="areText">Lorem ipsum dolor sit amet,
+						consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet 
+						dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci
+						tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis 
+						autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, 
+						vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio
+						dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait 
+						nulla facilisi.
+						</textarea>
+						</p>
+
+					</form>
+				</div>
+
+				<div id="tab11" dojoType="dijit.layout.ContentPane" label="Some Dijits" 
+					style="padding:10px; background:#fff; display:none;">
+
+					<h2>Dijit ProgressBar</h2>
+					<div style="width:400px" annotate="true" maximum="200" id="setTestBar" 
+						progress="20" dojoType="dijit.ProgressBar"></div>
+
+					<h2>Dijit TitlePane (nested)</h2>
+					<div dojoType="dijit.TitlePane" label="Outer pane" width="275">
+						<p>This is a title pane, containing another title pane ...</p>
+						<div dojoType="dijit.TitlePane" label="Inner pane" width="125">
+
+							<p>And this is the inner title pane...</p>
+
+							<p>Sed sollicitudin suscipit risus. Nam 
+							ullamcorper. Sed nisl lectus, pellentesque nec, 
+							malesuada eget, ornare a, libero. Lorem ipsum dolor 
+							sit amet, consectetuer adipiscing elit.</p>
+
+						</div>
+						<p>And this is the closing line for the outer title pane.</p>
+					</div>
+
+					<h2>HTML After, check indent</h2>
+
+				</div>
+				<!-- end:some dijits -->
+				<div id="tab3" dojoType="dijit.layout.ContentPane" label="Buttons" 
+					style="background:#fff;padding:10px; display:none;  ">
+
+					<h2>Simple, drop down & combo buttons</h2>
+					<p>Buttons can do an action, display a menu, or both:</p>
+
+					<div class="box">
+						<button dojoType="dijit.form.Button" onClick='console.debug("clicked simple")'>
+							<img src="../tests/images/plus.gif" width="16" height="16"> Create
+						</button>
+
+						<button dojoType="dijit.form.Button" onclick='console.debug("clicked simple")'>
+							<img src="../tests/images/plus.gif" width="16" height="16"><br>Create
+						</button>
+
+						<button dojoType="dijit.form.DropDownButton" menuId='editMenu'>
+							<img src="../tests/images/note.gif" width="20" height="20"> Edit
+						</button>
+
+						<button dojoType="dijit.form.DropDownButton" menuId='editMenu'>
+							<img src="../tests/images/note.gif" width="20" height="20"><br>Edit
+						</button>
+
+						<button dojoType="dijit.form.ComboButton" menuId='saveMenu' 
+							optionsTitle='save options'
+							onClick='console.debug("clicked combo save")'>
+						<img src="../tests/images/note.gif" width="20" height="20"> Save
+						</button>
+
+						<button dojoType="dijit.form.ComboButton" menuId='saveMenu' 
+							optionsTitle='save options' 
+							onclick='console.debug("clicked combo save")'>
+						<img src="../tests/images/note.gif" width="20" height="20"><br>Save
+						</button>
+
+						<button dojoType="dijit.form.Button" onClick='console.debug("clicked simple")' 
+							disabled='true'>
+							<img src="../tests/images/plus.gif" width="16" height="16"> Disabled
+						</button>
+					</div>
+
+					<br clear=both>
+
+					<h2>Sizing</h2>
+					<p>Short button, tall buttons, big buttons, small buttons... These buttons 
+					size to their content (just like &lt;button&gt;).</p>
+
+					<div class="box">
+						<button dojoType="dijit.form.Button" onclick='console.debug("big");'>
+							<img src="../tests/images/flatScreen.gif" width="32" height="32">
+							<span style="font-size:xx-large">big</span>
+						</button>
+
+						<button id="smallButton1" dojoType="dijit.form.Button" onclick='console.debug("small");'>
+							<img src="../tests/images/arrowSmall.gif" width="15" height="5">
+							<span style="font-size:x-small">small</span>
+						</button>
+
+						<button dojoType="dijit.form.Button" onclick='console.debug("long");'>
+							<img src="../tests/images/tube.gif" width="150" height="16"> long
+						</button>
+
+						<button dojoType="dijit.form.Button" onclick='console.debug("tall");' width2height="0.1">
+							<img src="../tests/images/tubeTall.gif" height="75" width="35"><br>
+							<span style="font-size:medium">tall</span>
+						</button>
+						<div style="clear: both;"></div>
+					</div>
+
+					<br clear=both>
+
+					<h2>Customized buttons</h2>
+					<p>Dojo users can mix in their styles.  Here's an example:</p>
+					
+					<div class="box">
+						<button dojoType="dijit.form.Button" class="Acme" 
+							onclick='console.debug("short");'>
+							<div class="dc">short</div>
+						</button>
+
+						<button dojoType="dijit.form.Button" class="Acme" 
+							onclick='console.debug("longer");'>
+							<div class="dc">bit longer</div>
+						</button>
+
+						<button dojoType="dijit.form.Button" class="Acme" 
+							onclick='console.debug("longer yet");'>
+							<div class="dc">ridiculously long</div>
+						</button>
+
+						<div style="clear: both;"></div>
+					</div>
+
+					<div dojoType="dijit.PopupMenu" id="editMenu" toggle="fade" 
+						toggleDuration="500" style="display: none;">
+						<div dojoType="dijit.MenuItem" 
+							iconSrc="../tests/images/cut.gif" 
+							caption="Cut" accelKey="Ctrl+C"
+							onClick="console.debug('not actually cutting anything, just a test!')">
+						</div>
+
+						<div dojoType="dijit.MenuItem" 
+							iconSrc="../tests/images/copy.gif" 
+							caption="Copy" accelKey="Ctrl+X"
+							onClick="console.debug('not actually copying anything, just a test!')">
+						</div>
+
+						<div dojoType="dijit.MenuItem" 
+							iconSrc="../tests/images/paste.gif" 
+							caption="Paste" accelKey="Ctrl+V"
+							onClick="console.debug('not actually pasting anything, just a test!')">
+						</div>
+	
+					</div>
+
+					<div dojoType="dijit.PopupMenu" id="saveMenu" toggle="wipe" 
+						toggleDuration="500" style="display: none;">
+						<div dojoType="dijit.MenuItem" 
+							iconSrc="../tests/images/save.gif" 
+							caption="Save" accelKey="Ctrl+S"
+							onClick="console.debug('not actually saving anything, just a test!')">
+						</div>
+						<div dojoType="dijit.MenuItem" 
+							iconSrc="../tests/images/save.gif" 
+							caption="Save As" accelKey="Ctrl+A"
+							onClick="console.debug('not actually saving anything, just a test!')">
+						</div>
+					</div>
+	
+				</div><!-- end: buttons tab -->
+
+				<div id="tab32" dojoType="dijit.layout.ContentPane" label="Inline Edit Boxes" 
+					style="background:#fff; padding:10px; display:none; ">
+
+					<h2 class="testTitle">Dijit InlineEditBox Test</h2>
+
+					before
+					<span id="editable" style="font-size:larger;" dojoType="dijit.form.InlineEditBox" onValueChanged="myHandler(this.id,arguments[0])">
+						<input dojoType="dijit.form.Textbox" value="Edit me - I trigger the onValueChanged callback">
+					</span>
+					after
+	
+					<h2>Dijit InlineEditBox vs. Textarea dijit</h2>
+
+					<blockquote style="width:300px;">
+						<p><span id="areaEditable" dojoType="dijit.form.InlineEditBox">
+						<textarea dojoType="dijit.form.Textarea">I'm one big paragraph.  Go ahead and <i>edit</i> me.  <b>I dare you.</b> The quick brown fox jumped over the lazy dog.  Blah blah blah blah blah blah blah ...</textarea>
+						</span></p>
+					</blockquote>
+					<p>
+						These links will
+						<a href="#" onClick="dijit.byId('areaEditable').disable()">disable</a> /
+						<a href="#" onClick="dijit.byId('areaEditable').enable()">enable</a>
+						the text area above.
+					</p>
+					<!-- why does promptMessage dump to screen? -->
+
+					<b>Date text box:</b>
+					<p id="backgroundArea" dojoType="dijit.form.InlineEditBox" >
+					<input name="date" value="2005-12-30"
+						dojoType="dijit.form.DateTextbox"
+						constraints={locale:'en-us'}
+						required="true"
+						promptMessage="mm/dd/yyyy"
+						invalidMessage="Invalid date. Use mm/dd/yyyy format.">
+					</p>
+					<p/>
+					<b>Select Dijit with JsonItemStore of States::</b>
+					<p id="backgroundArea" dojoType="dijit.form.InlineEditBox" >
+					<input searchField="name" keyField="abbreviation" id="setvaluetest" 
+						dojoType="dijit.form.Select" value="IA"
+						url="../tests/form/autoCompleterData.json" name="state1" autocomplete="true" 
+						labelField="label" labelType="html"
+						dataProviderClass="dojo.data.JsonItemStore" promptMessage="Please enter a state">
+					</p>
+
+					<b>HTML After</b><br /><br />
+
+				</div>
+				<div id="tab4" dojoType="dijit.layout.ContentPane" label="Closable"
+					style="display:none; background:transparent; padding:10px; " closable="true"> 
+					This pane is closable, just for the icon ... background:transparent; in this box.
+				</div>
+			</div> 
+
+			<div dojoType="dijit.layout.TabContainer" labelPosition="bottom" sizeMin="10" sizeShare="40"
+				style="width: 100%; height: 30em;" selectedChild="btab1">
+
+				<div id="btab1" dojoType="dijit.layout.ContentPane" label="Info" 
+					style="background:#fff; padding:10px; ">
+					<p>You can explore this single page after applying a Theme 
+					for use in creation of your own theme.</p>
+
+					<p>I am a Split Container, containing a Split Container on 
+					the right. TabContainer on the top right, Bottom-aligned Tab Container 
+					bottom right. AccordionPane on the left.</p>
+					
+					<p>There is a right-click [context] pop-up menu here, as well.</p>
+				</div><!-- end:info tab -->
+				<div id="btab2" dojoType="dijit.layout.ContentPane" Label="Remote" 
+					href="../changes.txt" style="white-space:pre; padding:10px; display:none;"></div>
+				<div id="btab21" dojoType="dijit.layout.ContentPane" label="Alternate Themes" style="padding:20px;">
+					<span id="themeData"></span>
+				</div>
+				<div id="btab3" dojoType="dijit.layout.ContentPane" label="Bottom 3" closable="true">
+					<p>I am the last Tab</p>
+
+				</div>
+
+
+			</div>
+
+
+		</div>
+
+	</div>
+
+</body>
+</html>
+
+
+

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/bar.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/bar.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/bubble.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/bubble.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/bubble.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,29 @@
+<html>
+	<head>
+		<script>
+			function show(){ document.getElementById("dialog").style.display=""; }
+			function hide(){ document.getElementById("dialog").style.display="none"; }
+		</script>
+	</head>
+	<body style="background: #aaccff;">
+		<p>Test for tooltip-dialogs that can be displayed via focus or rollover.
+		There's a dialog off of the button.</p>
+		<input tabindex="1"><br>
+		<input tabindex="2"><br>
+		<button onmouseover="show();" onmouseout="hide();" onfocus="show();" onblur="hide();" tabindex="3">test button</button><br>
+		<div id="dialog" class="tooltipDialog" style="position: absolute; display: none;">
+			<img src="bubbleConnector.gif" style="position: absolute; left: 20px; margin: 0; z-index: 2;">
+			<div style="border: solid black 2px; background: #b8b5b5; position: absolute; top: 26px; left: 0px; margin: 0;">
+				<p>This is the tooltip, or a dialog attached to the button.</p>
+				<a href="#">a link</a>
+				<form style="border: dotted 1px blue;">
+					<label>Name: </label><input><br>
+					<button>a button</button>
+				</form>
+			</div>
+		</div>
+		Some other text below the button<br>
+		<input tabindex="4"><br>
+		<input tabindex="5">
+	</body>
+</html>
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/checkmark.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/checkmark.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/decrementMonth.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/decrementMonth.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/dojoTundraGradientBg.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/dojoTundraGradientBg.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/dojoTundraGradientBgActive.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/dojoTundraGradientBgActive.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/dojoTundraTabActiveBg.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/dojoTundraTabActiveBg.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/dojoUITundra06.psd
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/dojoUITundra06.psd
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/expand_leaf.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/expand_leaf.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/expand_loading.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/expand_loading.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/expand_minus.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/expand_minus.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/expand_plus.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/expand_plus.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/h-bar.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/h-bar.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/i.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/i.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/i_half.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/i_half.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/arrowDown.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/arrowDown.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/arrowLeft.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/arrowLeft.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/arrowRight.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/arrowRight.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/arrowUp.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/arrowUp.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/buttonActive.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/buttonActive.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/buttonDisabled.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/buttonDisabled.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/buttonEnabled.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/buttonEnabled.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/buttonHover.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/buttonHover.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/calendarDayLabel.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/calendarDayLabel.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/calendarMonthLabel.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/calendarMonthLabel.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/calendarYearLabel.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/calendarYearLabel.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkboxActive.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkboxActive.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkboxDisabled.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkboxDisabled.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkboxEnabled.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkboxEnabled.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkboxHover.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkboxHover.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkmark.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/checkmark.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/dijitProgressBarAnim.psd
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/dijitProgressBarAnim.psd
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/doubleArrowDown.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/doubleArrowDown.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/doubleArrowUp.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/doubleArrowUp.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/menu.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/menu.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/preciseSliderThumb.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/preciseSliderThumb.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-1.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-1.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-2.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-2.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-3.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-3.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-4.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-4.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-5.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-5.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-6.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-6.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-7.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-7.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-8.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-8.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-9.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim-9.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim.psd
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarAnim.psd
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarEmpty.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarEmpty.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarFull.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/progressBarFull.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonActive.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonActive.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonActiveDisabled.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonActiveDisabled.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonActiveHover.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonActiveHover.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonDisabled.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonDisabled.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonEnabled.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonEnabled.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonHover.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/radioButtonHover.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/sliderEmpty.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/sliderEmpty.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/sliderFull.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/sliderFull.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/sliderThumb.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/sliderThumb.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/smallArrowDown.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/smallArrowDown.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/smallArrowUp.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/smallArrowUp.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/splitContainerSizerH-thumb.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/splitContainerSizerH-thumb.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/splitContainerSizerH.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/splitContainerSizerH.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/splitContainerSizerV-thumb.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/splitContainerSizerV-thumb.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/splitContainerSizerV.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/splitContainerSizerV.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabActive.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabActive.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabClose.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabClose.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabCloseHover.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabCloseHover.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabDisabled.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabDisabled.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabEnabled.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabEnabled.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabHover.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/tabHover.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/titleBar.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/images/titleBar.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/incrementMonth.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/incrementMonth.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/index.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/index.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/index.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,48 @@
+<html>
+	<head>
+		<title>Dojo Tundra Look and Feel</title>
+		<link href="tundra.css" rel="stylesheet" type="text/css" />
+		<style type="text/css">
+			
+			body {
+				background:#cddde9;
+				background:#fff;
+			}
+			
+			input {
+				margin:3px 0;
+			}
+			
+			.dojoTabPane {
+				padding:1.5em;
+			}
+			
+		</style>
+	</head>
+	<body>
+		<div class="dojoTabContainer">
+			<div class="dojoTabLabels">
+				<div class="dojoTab dojoTabActive"><span class="dojoInlineBox">Tab Active</span></div>
+				<div class="dojoTab"><span class="dojoInlineBox">Tab Inactive</span></div>
+				<div class="dojoTab dojoTabDisabled"><span class="dojoInlineBox">Disabled Tab</span></div>
+			</div>
+		</div>
+		<div class="dojoTabPane">
+			<h4>Button Widget Example</h4>
+			<span class="dojoButton dojoInlineBox"><button>Button</button></span>
+			
+			<span class="dojoButton dojoButtonDisabled dojoInlineBox"><button disabled="disabled">Disabled</button></span>
+			
+			<h4>Form Fields</h4>
+			<input type="text" class="dojoinputField" id="loginId" /><br />
+			<input type="text" class="dojoInputField dojoInputFieldDisabled" disabled="disabled" value="Test" /><br />
+			<input type="text" class="dojoInputField dojoInputFieldValidationError" value="Test" /><br />
+			<input type="password" class="dojoinputField" id="passwordField" /><br />
+			<span class="dojoButton dojoInlineBox"><button>Login</button></span>
+			
+		</div>
+		
+		
+		
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/no.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/no.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/popupMenuBg.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/popupMenuBg.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/shadow.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/shadow.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/splitContainerHBg.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/splitContainerHBg.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/splitContainerVBg.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/splitContainerVBg.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tab_close.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tab_close.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tab_close_h.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tab_close_h.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/titleBarBg.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/titleBarBg.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tooltipConnector.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tooltipConnector.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tooltipConnector.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tooltipConnector.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tundra.css
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tundra.css	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/tundra.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,821 @@
+/*
+	Adds cosmetic styling to Dijit.  Users may swap with a custom theme CSS file.
+*/
+
+ at import url("../dijit.css");
+
+
+/*
+ * IE6: can't display PNG images with gradient transparency.
+ * Want to use filter property for those images, but then need to specify a path relative
+ * to the main page, rather than relative to this file... using gifs for now
+ */
+.dj_ie6 .tundra .dijitInputField,
+.dj_ie6 .tundra .dijitAutoCompleterInput {
+	background-image: none;
+	/* TODO: won't work; path is wrong; use gif instead? */
+	filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="dijitTundraGradientBg.png", sizingMethod="scale");
+}
+
+.dj_ie6 .tundra .dijitTooltipConnector {
+	background-image: url(tooltipConnector.gif);
+}
+
+/** TODO: add all other PNGs here that need this */
+
+
+
+/*****
+		dijit.form.Button
+		dijit.form.DropDownButton
+		dijit.form.ComboButton
+		dijit.form.AutoCompleter (partial)
+ *****/
+
+
+.tundra .dijitButtonNode {
+	/* enabled state - inner */
+	border:1px outset #a0a0a0;
+	padding:.3em .4em .1em .4em;
+	background:#e9e9e9 url("images/buttonEnabled.png") repeat-x top;
+}
+
+.tundra .dijitButtonDisabled .dijitButtonNode,
+.tundra .dijitDropDownButtonDisabled .dijitButtonNode,
+.tundra .dijitComboButtonDisabled .dijitButtonNode,
+.tundra .dijitAutoCompleterDisabled .dijitDownArrowButton,
+.tundra .dijitAutoCompleterDisabled .dijitAutoCompleterInput,
+.tundra .dijitSpinnerDisabled .dijitSpinnerInput,
+.tundra .dijitSpinnerDisabled .dijitButtonNode {
+	/* disabled state - inner */
+	border-style: solid;
+	border-color: #d5d5d5;
+	color:#b4b4b4;
+	background:#e4e4e4 url("images/buttonDisabled.png") top repeat-x;
+}
+
+.tundra .dijitButtonHover .dijitButtonNode,
+.tundra .dijitDropDownButtonHover .dijitButtonNode,
+.tundra .dijitComboButtonHover .dijitButtonContents,
+.tundra .dijitComboButtonDownArrowHover .dijitDownArrowButton,
+.tundra .dijitAutoCompleterHover .dijitDownArrowButton,
+.tundra .dijitSpinnerUpArrowHover .dijitUpArrowButton,
+.tundra .dijitSpinnerDownArrowHover .dijitDownArrowButton {
+	/* hover state - inner */
+	border-color:#366dba;
+	color:#366dba;
+	background-image: url("images/buttonHover.png") bottom;
+}
+
+.tundra .dijitButtonActive .dijitButtonNode,
+.tundra .dijitDropDownButtonActive .dijitButtonNode,
+.tundra .dijitComboButtonActive .dijitButtonContents,
+.tundra .dijitDownArrowActive .dijitDownArrowButton,
+.tundra .dijitAutoCompleterActive .dijitDownArrowButton {
+	/* active state - inner */
+	border-color:#366dba;
+	border-style:inset;
+	background: #ededed url("images/buttonActive.png") bottom repeat-x;
+}
+
+
+/** ???
+.tundra .dijitButtonEnabled *[popupActive],
+.tundra .dijitButtonEnabled *:active {
+	background-image: url("buttonActive.png");
+}
+*/
+
+
+
+
+/****
+		dijit.form.Textbox
+		dijit.form.ValidationTextbox
+		dijit.form.SerializableTextbox
+		dijit.form.RangeBoundTextbox
+		dijit.form.NumberTextbox
+		dijit.form.CurrencyTextbox
+		dijit.form.NumberSpinner
+		dijit.form.AutoCompleter (partial)
+ ****/
+
+.tundra .dijitAutoCompleter {
+	/* put margin on the outer element of the autocompleter rather than the input */
+	margin:.0em .1em .2em .1em;
+}
+
+
+
+/*.tundra .dijitInputField,		MOW TODO */
+.tundra .dijitAutoCompleterInput,
+.tundra .dijitSpinnerInput {
+	/* 	For all except dijit.form.NumberSpinner:  the actual input element.
+		For dijit.form.NumberSpinner: the outer fieldset that contains the input.
+	*/
+	font-size:inherit;
+	background:#fff url("validationInputBg.png") repeat-x top left;
+	border:1px inset #9b9b9b;
+	line-height:normal;
+	padding:.2em .3em;
+}
+
+/*
+.tundra .dijitAutoCompleterInput {
+	margin:0em;
+	padding:.1em .3em;
+}
+*/
+
+.tundra .dijitAutoCompleterFocused .dijitAutoCompleterInput {
+	/* input field when focused (eg: typing affects it) */
+	border-color:#366dba;
+	border-style:inset;
+}
+
+.tundra .dijitAutoCompleterDisabled .dijitAutoCompleterInput {
+	/* input field when disabled (also set above) */
+}
+
+.tundra .dijitAutoCompleterHover .dijitAutoCompleterInput  {
+	/* input field when hovered over */
+	border-color:#366dba;
+}
+
+.tundra .dijitAutoCompleterActive .dijitAutoCompleterInput {
+	/* input field when mouse is down (?) */
+}
+
+
+
+
+
+
+
+
+
+/* Dojo Input Field */
+
+.tundra .dijitInputFieldValidationNormal {
+	
+}
+
+.tundra .dijitInputFieldValidationWarning {
+	border:1px solid #f3d118;
+}
+
+.tundra .dijitInputFieldValidationError {
+	border:1px solid #f3d118;
+	background:#f9f7ba;
+}
+
+.tundra .dijitInputFieldValidationError:hover,
+.tundra .dijitInputFieldValidationError:focus {
+	
+}
+
+.tundra .dijitCheckbox {
+	background-image: url('images/checkmark.png'); /* checkbox sprite image */
+	width: 16px;
+	height: 16px;
+}
+
+
+/* Menu */
+.tundra .dijitMenu{
+	border: solid;
+	border-color: #7788a0 #344257 #344257 #7788a0;
+	border-width:1px 2px 2px 1px;
+	-moz-border-radius:0px 2px 0px 2px;	/* make BL and TR corners indent on Moz so it looks like we have a shadow */
+	background:#fff url("images/dijitMenu.gif") repeat-x bottom;
+	margin: 0px;
+	padding: 0px;
+}
+
+.tundra .dijitMenuItem{
+	font: menu;
+	margin: 0;
+}
+
+.tundra .dijitMenuItem TD {
+	padding:2px;
+}
+
+.tundra .dijitMenuItemHover {
+	background-color:#60a1ea;
+	color:#fff;
+}
+
+.tundra .dijitMenuItemIcon {
+	width: 16px;
+	height: 16px;
+	padding-right: 3px;
+}
+
+
+/* MOW: I don't think this is used anymore:
+.tundra .dijitMenuItemHover .dijitMenuItemSubmenu {
+	background-image: url(images/submenu_on.gif);
+}
+
+.tundra .dijitRTL .dijitMenuItemHover .dijitMenuItemSubmenu {
+	background-image: url(images/submenu_on_rtl.gif);
+}
+*/
+
+/* MOW: I don't think this is used anymore:
+.tundra .dijitMenuItemDisabled .dijitMenuItemSubmenu {
+	background-image: url(images/submenu_disabled.gif);
+}
+
+.tundra .dijitRTL .dijitMenuItemDisabled .dijitMenuItemSubmenu {
+	background-image: url(images/submenu_disabled_rtl.gif);
+}
+*/
+
+
+
+.tundra .dijitMenuSeparator {}
+
+/* separator can be two pixels -- set border of either one to 0px to have only one */
+.tundra .dijitMenuSeparatorTop {
+	border-bottom: 1px solid #97adcb;
+}
+
+.tundra .dijitMenuSeparatorBottom {
+	border-top: 1px solid #c9deff;
+}
+
+
+
+
+
+/* Toaster */
+
+.tundra .dijitToasterContent{
+	padding:1em;
+	padding-top:0.25em;
+	background:#73c74a;
+}
+
+.tundra .dijitToasterMessage{ 
+	color:#fff;
+}
+.tundra .dijitToasterWarning{ }
+.tundra .dijitToasterError,
+.tundra .dijitToasterFatal{
+	font-weight:bold;
+	color:#fff;
+}
+
+.tundra .dijitToasterWarning .dijitToasterContent{
+	padding:1em;
+	padding-top:0.25em;
+	background:#d4d943;
+} 
+
+.tundra .dijitToasterError .dijitToasterContent{
+	padding:1em;
+	padding-top:0.25em;
+	background:#c46600;
+} 
+
+
+/* TitlePane */
+
+.tundra .dijitTitlePaneLabel {
+	background: #cccccc;
+	background:#fafafa url("titleBarBg.gif") repeat-x bottom left;
+	border:1px solid #bfbfbf;
+	padding:4px 4px 2px 4px;
+}
+
+.tundra .dijitTitlePaneLabel .dijitOpenCloseArrowOuter {
+	margin-right:5px;
+}
+
+.tundra .dijitOpen .dijitTitlePaneLabel .dijitOpenCloseArrowOuter {
+	position:relative;
+	top:2px;
+}
+
+.tundra .dijitTitlePaneContent {
+	background: #ffffff;
+	border:1px solid #bfbfbf;
+	border-top: 1px solid #cddde9;	/* w/out this, an <h1> on the top line causes a gap between the .content and .label */
+	padding:10px;
+}
+
+.tundra .dijitClickableRegion {
+	background-color : #ffc !important;
+}
+
+
+.tundra .dijitTextArea {
+	width:50%;
+	overflow:auto;
+	border:1px solid #7788a0;
+}
+
+
+/* Tabs */
+
+
+.tundra .dijitTabPaneWrapper {
+	border:1px solid #ccc;
+}
+
+.tundra .dijitTab {
+	line-height:normal;
+	margin-right:5px;		/* space between one tab and the next in top/bottom mode */
+	padding:0px;
+	border:1px solid #afafaf;
+	background:#e2e2e2 url("images/tabEnabled.png") repeat-x;
+}
+
+.tundra .dijitAlignLeft .dijitTab,
+.tundra .dijitAlignRight .dijitTab {
+	margin-right:0px;
+	margin-bottom:5px;	/* space between one tab and the next in left/right mode */
+}
+
+
+.tundra .dijitTabInnerDiv {
+/*	min-height:16px;	*/
+	padding:6px 10px 4px 10px;
+	border-left:1px solid #fff;
+	border-bottom:1px solid #fff;
+}
+
+.tundra .dijitTabActive {
+	background:#e2e2e2 url("images/tabActive.png") repeat-x bottom !important;
+}
+
+
+
+/* make the active tab white on the side next to the content pane */
+.tundra .dijitAlignTop .dijitTabActive {
+	border-bottom-color:white;
+	vertical-align:bottom;
+}
+
+.tundra .dijitAlignBottom .dijitTabActive {
+	border-top-color:white;
+	-moz-border-radius:2px 2px 0px 0px;	/* eliminate some border detritrus on moz */
+}
+
+.tundra .dijitAlignLeft .dijitTabActive {
+	border-right-color:white;
+}
+
+.tundra .dijitAlignRight .dijitTabActive {
+	border-left-color:white;
+}
+
+
+.tundra .dijitTabHover {
+	color: #243C5F;
+	border-top-color:#92a0b3;
+	border-left-color:#92a0b3;
+	border-right-color:#92a0b3;
+	background:#e2e2e2 url("images/tabHover.png") repeat-x bottom;
+}
+
+
+.tundra .dijitTab .closeImage {
+	position:relative;
+	top: 2px;
+	height : 12px;
+	width : 12px;
+	padding : 0 12px 0 0;
+	margin : 0px 0px 0px 10px;
+}
+
+.tundra .dijitTab .closeImage {
+	background : url("images/tabClose.png") no-repeat right top;
+}
+
+.tundra .dijitTab .closeImageHover {
+	background-image : url("images/tabCloseHover.png") !important;
+}
+
+
+
+/* SplitContainer */
+
+.tundra .dijitSplitContainerSizerH {
+	background:url("images/splitContainerSizerH.png") repeat-y #fff;
+	border:0;
+	border-left:1px solid #bfbfbf;
+	border-right:1px solid #bfbfbf;
+	width:7px;
+}
+
+.tundra .dijitSplitContainerSizerH .thumb {
+	background:url("images/splitContainerSizerHThumb.png") no-repeat #ccc;
+	left:1px;
+	width:3px;
+	height:19px;
+}
+
+.tundra .dijitSplitContainerSizerV {
+	background:url("images/splitContainerSizerV.png") repeat-x #fff;
+	border:0;
+	border-top:1px solid #bfbfbf;
+	border-bottom:1px solid #bfbfbf;
+	height:7px;
+}
+
+.tundra .dijitSplitContainerSizerV .thumb {
+	background:url("images/splitContainerSizerVThumb.png") no-repeat #ccc;
+	top:1px;
+	width:19px;
+	height:3px;
+}
+
+
+/*Tooltip*/
+
+.tundra .dijitTooltip {
+	opacity: 0.9;
+}
+
+.tundra .dijitTooltipContainer {
+	border: solid;
+	border-color: #7788a0 #344257 #344257 #7788a0;
+	border-width:1px 2px 2px 1px;
+	-moz-border-radius:0px 2px 0px 2px;	/* make BL and TR corners indent on Moz so it looks like we have a shadow */
+	padding:0.45em;
+	background:#fff url("popupMenuBg.gif") repeat-x bottom left;
+}
+
+.tundra .dijitTooltipConnector {
+	border:0px;
+	top: -13px;
+	left: 3px;
+	z-index: 2;
+	background:url("tooltipConnector.png") no-repeat top left;
+	width:16px;
+	height:14px;
+}
+
+/*Accordion*/
+
+.tundra .dijitAccordionPane-selected {
+	/* background-color:#85aeec; */
+	background-color: #e7e7e7;
+}
+
+.tundra .dijitAccordionPane .label {
+	background:#fafafa url("images/titleBar.png") repeat-x bottom left;
+	border: 1px solid #bfbfbf;
+	padding:4px 4px 2px 4px;
+}
+
+.tundra .dijitAccordionPane-selected .label {
+	background: #ededed url("images/buttonActive.png") bottom repeat-x;
+	font-weight: bold;
+	/* border:1px solid #84a3d1; */
+	border: 1px solid #aaaaaa;
+	padding: 4px 4px 2px 4px;
+}
+
+.tundra .dijitAccordionPane .label .arrow {
+	background:url("images/doubleArrowUp.png") no-repeat;
+	width:9px;
+	height:9px;
+	margin-top:2px;
+}
+
+.tundra .dijitAccordionPane-selected .label .arrow {
+	background:url("images/doubleArrowDown.png") no-repeat;
+	margin-top:3px;
+}
+
+.tundra .dijitAccordionPane .accBody {
+	background: #fff;
+	/* 
+	border:1px solid #84a3d1; 
+	border:1px solid #d5d5d5;
+	*/
+	border:1px solid #bfbfbf;
+}
+
+
+
+/* Tree */
+.tundra .TreeNode {
+    background-image : url('i.gif');
+    background-position : top left;
+    background-repeat : repeat-y;
+    margin-left: 19px;
+    zoom: 1;	/* MOW: what the heck is this doing in here? */
+}
+.tundra .TreeIsRoot {
+    margin-left: 0;
+}
+ 
+/* left vertical line (grid) for all nodes */
+.tundra .TreeIsLast {
+    background: url('i_half.gif') no-repeat;
+}
+
+.tundra .TreeExpando {
+    width: 18px;
+    height: 18px;
+}
+
+.tundra .TreeContent {
+    min-height: 18px;
+    min-width: 18px;
+    margin-left:18px;
+    padding-top:3px;
+    padding-left:1px;
+}
+
+.tundra .TreeIEContent {
+	height: 18px;
+}
+ 
+.tundra .TreeExpand {
+    width: 18px;
+    height: 18px;
+    background-repeat : no-repeat;
+}
+ 
+/* same style as IE selection */
+.tundra .TreeNodeEmphasized {
+    background-color: Highlight;
+    color: HighlightText;
+}
+
+/* don't use :focus due to opera and IE's lack of support on div's */
+.tundra .TreeLabelFocused {
+	outline: 1px invert dotted;
+}
+
+.tundra .TreeExpandoOpened {
+	background-image: url('expand_minus.gif');
+}
+ 
+.tundra .TreeExpandoClosed {
+	background-image: url('expand_plus.gif');
+}
+ 
+.tundra .TreeExpandoLeaf {
+	background-image: url('expand_leaf.gif');
+}
+
+.tundra .TreeExpandoLoading {
+	background-image: url('expand_loading.gif');
+}
+
+
+/* Calendar*/
+
+
+.tundra .calendarIncrementControl {
+	/* next/prev month buttons */
+	padding:2px;
+}
+
+.tundra table.calendarContainer {
+/*	border:1px solid #566f8f;*/
+	font-size: 100%;
+	border-collapse: collapse; 
+	border-spacing: 0; 
+	border: 1px solid #ccc; 
+	margin: 0;
+}
+
+
+
+.tundra .calendarMonthContainer th {
+	/* month header cell */
+	background:white url("images/calendarMonthLabel.png") repeat-x top;
+	padding-top:.2em;
+}
+
+.tundra .calendarDayLabelTemplate {
+	/* day of week labels */
+	background:white url("images/calendarDayLabel.png") repeat-x bottom;
+	font-weight:normal;
+	padding-top:.15em;
+	padding-bottom:0em;
+	border-top:1px solid #eeeeee;
+	border-bottom:
+	color:#293a4b;
+	text-align:center;
+}
+
+.tundra .calendarMonthLabel {
+	/* day of week labels */
+	color:#293a4b;
+	font-size: 0.75em;
+	font-weight: bold;
+	text-align:center;
+}
+
+.tundra .calendarDateTemplate {
+	/* style for each day cell */
+	font-size: 0.7em;
+	font-weight: bold;
+	text-align:center;
+	padding:0.1em 0.3em 0.05em .3em;
+	letter-spacing:1px;
+}
+
+
+.tundra .calendarPreviousMonth,
+.tundra .calendarNextMonth 		{
+	/* days that are part of the previous or next month */
+	color:#999999;
+	background-color:#f8f8f8 !important;
+}
+
+.tundra .calendarPreviousMonthDisabled,
+.tundra .calendarNextMonthDisabled	{
+	/* days that are part of the previous or next month - disabled*/
+	background-color:#a4a5a6 !important;
+}
+
+.tundra .calendarCurrentMonth {
+	/* days that are part of this month */
+	background-color:white !important;
+}
+
+.tundra .calendarCurrentMonthDisabled {
+	/* days that are part of this month - disabled */	
+	background-color:#bbbbbc !important;
+}
+
+
+.tundra .calendarCurrentDate {
+	/* cell for today's date */
+	text-decoration:underline;
+	font-weight:bold;
+}
+
+.tundra .calendarSelectedDate {
+	/* cell for the selected date */
+	background-color:#bbc4d0 !important;
+	color:black !important;
+}
+
+
+.tundra .calendarYearContainer {
+	/* footer of the table that contains the year display/selector */
+	background:white url("images/calendarYearLabel.png") repeat-x bottom;
+	border-top:1px solid #ccc;
+}
+
+.tundra .calendarYearLabel {
+	/* container for all of 3 year labels */
+	margin:0;
+	padding:0.4em 0 0.25em 0;
+	text-align:center;
+}
+
+.tundra .calendarSelectedYear {
+	/* label for selected year */
+	color:black;
+	padding:0.2em;
+	padding-bottom:0.1em;
+	background-color:#bbc4d0 !important;
+}
+
+.tundra .calendarNextYear, 
+.tundra .calendarPreviousYear {
+	/* label for next/prev years */
+	color:black !important;
+	font-weight:normal;
+}
+
+
+
+
+
+/* inline edit boxen */
+.tundra .dijitInlineValue {
+	/* span around an inline-editable value when NOT in edit mode */
+	border:1px solid #eeeeee;
+	padding:3px;
+	margin:4px;
+}
+
+
+/* MOW: trying to get this to look like a mini-dialog.  Advised? */
+.tundra .dijitInlineEditor {
+	/* fieldset surrounding an inlineEditor in edit mode */
+	display:inline-block;
+	display: -moz-inline-stack;
+	#display:inline;
+	border: solid;
+	border-color: #7788a0 #344257 #344257 #7788a0;
+	border-width:1px 2px 2px 1px;
+	-moz-border-radius:0px 2px 0px 2px;	/* make BL and TR corners indent on Moz so it looks like we have a shadow */
+	background-color:white;
+}
+
+.dijitInlineEditor .saveButton,
+.dijitInlineEditor .cancelButton {
+	margin:3px;
+}
+
+
+/* spinner */
+
+.tundra .dijitSpinner {}
+
+.tundra .dijitSpinner INPUT {
+}
+
+.tundra .dijitSpinnerArrowGroup {}
+
+
+
+
+/****
+		dijit.ProgressBar
+ ****/
+ 
+.tundra .dijitProgressBar {
+	margin:2px 0px 2px 0px;
+}
+
+ 
+.tundra .dijitProgressBarEmpty{
+	/* outer container and background of the bar that's not finished yet*/
+	background:#ececec url("images/progressBarEmpty.png") repeat-x bottom left;
+	border-color: #84a3d1;
+}
+
+
+.dijitProgressBarFull {
+	/* outer container for background of bar that is finished */
+}
+
+.tundra .dijitProgressBarTile{
+	/* inner container for finished portion when in 'tile' (image) mode */
+	background:#cad2de url("images/progressBarFull.png") repeat-x top left;
+}
+
+.tundra .dijitProgressBarEmptyLabel{
+	/* label for portion of the bar that's not finished yet 
+		Set to a color that contrasts with the "Empty" part.  
+	*/
+	color:#293a4b;
+}
+
+.tundra .dijitProgressBarFullLabel{
+	/* label for portion of the bar that is finished 
+		set to a color that contrasts with the "Full" part
+	*/
+	color:#2963b9;
+}
+
+
+.tundra .dijitProgressBarIndeterminate .dijitProgressBarTile {
+	/* use an animated gif for the progress bar in 'indeterminate' mode */
+	background:#cad2de url("images/dijitProgressBarAnim.gif") repeat-x top left;
+}
+
+/* Dialog */
+
+.tundra .dijitDialog {
+	background: #eee;
+	border: 1px solid #999;
+	-moz-border-radius: 5px;
+}
+
+.tundra .dijitDialogTitleBar {
+	/* outer container for the titlebar of the dialog */
+	background: #fafafa url("titleBarBg.gif") repeat-x bottom left;
+	border: 1px solid #bfbfbf;
+	padding: 4px 8px 2px 4px;
+	cursor: move;
+}
+
+.tundra .dijitDialogLabel {
+	/* typography and styling of the dialog title */
+	font-weight: bold;
+	padding: 8px 12px 8px 12px;
+}
+
+.tundra .dijitDialogCloseIcon {
+	/* the default close icon for the dialog */
+	background : url("tab_close.gif") no-repeat right top;
+    float: right;
+	position: absolute;
+	vertical-align: middle;
+	right: 5px;
+	top: 5px;
+	height: 22px;
+	width: 22px;
+	cursor: pointer;
+}
+
+.tundra .dijitDialogContent {
+	/* the body of the dialog */
+	padding: 8px;
+}

Added: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/validationInputBg.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dijit/themes/tundra/validationInputBg.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dijit/util/BackgroundIframe.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/util/BackgroundIframe.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/util/BackgroundIframe.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,101 @@
+dojo.provide("dijit.util.BackgroundIframe");
+
+dijit.util.BackgroundIframe = function(/* HTMLElement */node){
+	//	summary:
+	//		For IE z-index schenanigans
+	//		Two possible uses:
+	//			1. new dijit.util.BackgroundIframe(node)
+	//				Makes a background iframe as a child of node, that fills
+	//				area (and position) of node
+	//			2. new dijit.util.BackgroundIframe()
+	//				Attaches frame to dojo.body().  User must call size() to
+	//				set size.
+	if(dojo.isIE && dojo.isIE < 7){
+		var html="<iframe src='javascript:false'"
+			+ " style='position: absolute; left: 0px; top: 0px; width: 100%; height: 100%;"
+			+ "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
+		this.iframe = dojo.doc.createElement(html);
+		this.iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work.
+		if(node){
+			node.appendChild(this.iframe);
+			this.domNode=node;
+		}else{
+			dojo.body().appendChild(this.iframe);
+			this.iframe.style.display="none";
+		}
+	}
+};
+
+dojo.extend(dijit.util.BackgroundIframe, {
+	iframe: null,
+	onResized: function(){
+		//	summary:
+		//		Resize event handler.
+
+		// TODO: this function shouldn't be necessary but setting
+		// 			width=height=100% doesn't work!
+		if(this.iframe && this.domNode && this.domNode.parentNode){ 
+			// No parentElement if onResized() timeout event occurs on a removed domnode
+			var outer = dojo.marginBox(this.domNode);
+			if (!outer.w || !outer.h){
+				setTimeout(this, this.onResized, 100);
+				return;
+			}
+			this.iframe.style.width = outer.w + "px";
+			this.iframe.style.height = outer.h + "px";
+		}
+	},
+
+	size: function(/* HTMLElement */node){
+		// summary:
+		//		Call this function if the iframe is connected to dojo.body()
+		//		rather than the node being shadowed 
+
+		//	(TODO: erase)
+		if(!this.iframe){ return; }
+		var coords = dojo.coords(node, true); // PORT used BORDER_BOX
+		var s = this.iframe.style;
+		s.width = coords.w + "px";
+		s.height = coords.h + "px";
+		s.left = coords.x + "px";
+		s.top = coords.y + "px";
+	},
+
+	setZIndex: function(/* HTMLElement|int */node){
+		//	summary:
+		//		Sets the z-index of the background iframe
+		//	node:
+		//		If an element, sets zIndex of iframe to zIndex of node minus one. 
+		//		Otherwise, specifies the new zIndex as an integer.
+
+		if(!this.iframe){ return; }
+
+		this.iframe.style.zIndex = !isNaN(node) ? node : (node.style.zIndex - 1);
+	},
+
+	show: function(){
+		//	summary:
+		//		show the iframe
+		if(this.iframe){ 
+			this.iframe.style.display = "block";
+		}
+	},
+
+	hide: function(){
+		//	summary:
+		//		hide the iframe
+		if(this.iframe){ 
+			this.iframe.style.display = "none";
+		}
+	},
+
+	remove: function(){
+		//	summary:
+		//		remove the iframe
+		if(this.iframe){
+			this.iframe.parentNode.removeChild(this.iframe); // PORT: leak?
+			delete this.iframe;
+			this.iframe=null;
+		}
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dijit/util/FocusManager.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/util/FocusManager.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/util/FocusManager.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,206 @@
+dojo.provide("dijit.util.FocusManager");
+
+dijit.util.FocusManager = new function(){
+	// summary:
+	//		This class is used to save the current focus / selection on the screen,
+	//		and restore it later.   It's typically used for popups (menus and dialogs),
+	//		but can also be used for a menubar or toolbar.   (For example, in the editor
+	//		the user might type Ctrl-T to focus the toolbar, and then when he/she selects
+	//		a menu choice, focus is returned to the editor window.)
+	//
+	//		Note that it doesn't deal with submenus off of an original menu;
+	//		From this class's perspective it's all part of one big menu.
+	//
+	//		The widget must implement a close() callback, which will close dialogs or
+	//		a context menu, and for a menubar, it will close the submenus and remove
+	//		highlighting classes on the root node.
+
+
+	/////////////////////////////////////////////////////////////
+	// Keep track of currently focused and previously focused element
+
+	var curFocus, prevFocus;	
+	function onFocus(/*DomNode*/ node){
+		if(node && node.tagName=="body"){
+			node=null;
+		}
+		if(node !== curFocus){
+			prevFocus = curFocus;
+			curFocus = node;
+			console.debug("focused on ", node ? (node.id ? node.id : node.tagName) : "nothing");
+		}
+	}
+	
+	dojo.addOnLoad(function(){
+		if(dojo.isIE){
+			// TODO: to make this more deterministic should delay updating curFocus/prevFocus for 10ms?
+			window.setInterval(function(){ onFocus(document.activeElement); }, 100);
+		}else{
+			dojo.body().addEventListener('focus', function(evt){ onFocus(evt.target); }, true);
+		}
+	});
+	
+	/////////////////////////////////////////////////////////////////
+	// Main methods, called when a dialog/menu is opened/closed
+
+	// TODO: convert this to a stack, so we can save and restore multiple times?
+	// or have save return an object that can be passed to restore?
+
+	var currentMenu = null;	// current menu/dialog
+	var closeOnScreenClick = false;	// should clicking the screen close the menu?
+	var openedForWindow;	// iframe in which menu was opened
+	var restoreFocus;		// focused node before menu opened
+	var bookmark;			// selected text before menu opened
+
+	var isCollapsed = function(){
+		// summary: return whether the current selection is empty
+		var _window = dojo.global;
+		var _document = dojo.doc;
+		if(_document.selection){ // IE
+			return _document.selection.createRange().text == "";
+		}else if(_window.getSelection){
+			var selection = _window.getSelection();
+			if(dojo.isString(selection)){ // Safari
+				return selection == "";
+			}else{ // Mozilla/W3
+				return selection.isCollapsed || selection.toString() == "";
+			}
+		}
+	};
+
+	var getBookmark = function(){
+		// summary: Retrieves a bookmark that can be used with moveToBookmark to return to the same range
+		var bookmark;
+		var _document = dojo.doc;
+		if(_document.selection){ // IE
+			var range = _document.selection.createRange();
+			if(_document.selection.type.toUpperCase()=='CONTROL'){
+				if(range.length){
+					bookmark=[];
+					var i=0;
+					while(i<range.length){
+						bookmark.push(range.item(i++));
+					}
+				}else{
+					bookmark = null;
+				}
+			}else{
+				bookmark = range.getBookmark();
+			}
+		}else{
+			var selection;
+			//TODO: why a try/catch?  check for getSelection instead?
+			try{selection = dojo.global.getSelection();}
+			catch(e){/*squelch*/}
+			if(selection){
+				var range = selection.getRangeAt(0);
+				bookmark = range.cloneRange();
+			}else{
+				console.debug("No idea how to store the current selection for this browser!");
+			}
+		}
+		return bookmark;
+	};
+
+	var moveToBookmark = function(/*Object*/bookmark){
+		// summary: Moves current selection to a bookmark
+		// bookmark: this should be a returned object from dojo.html.selection.getBookmark()
+		var _document = dojo.doc;
+		if(_document.selection){ // IE
+			if(dojo.isArray(bookmark)){
+				var range= _document.body.createControlRange();
+				var i=0;
+				while(i<bookmark.length){
+					range.addElement(bookmark[i++]);
+				}
+				range.select();
+			}else{
+				var range = _document.selection.createRange();
+				range.moveToBookmark(bookmark);
+				range.select();
+			}
+		}else{ //Moz/W3C
+			var selection;
+			//TODO: why a try/catch?  check for getSelection instead?
+			try{selection = dojo.global.getSelection();}
+			catch(e){/*squelch*/}
+			if(selection && selection.removeAllRanges){
+				selection.removeAllRanges();
+				selection.addRange(bookmark);
+			}else{
+				console.debug("No idea how to restore selection for this browser!");
+			}
+		}
+	};
+
+	this.save = function(/*Widget*/menu, /*Window*/ _openedForWindow){
+		// summary:
+		//	called when a popup appears (either a top level menu or a dialog),
+		//	or when a toolbar/menubar receives focus
+		if (menu == currentMenu){ return; }
+
+		if (currentMenu){
+			currentMenu.close();
+		}
+
+		currentMenu = menu;
+		openedForWindow = _openedForWindow;
+
+		//PORT #2804. Use isAncestor
+		var isDescendantOf = function(/*Node*/node, /*Node*/ancestor){
+			//	summary
+			//	Returns boolean if node is a descendant of ancestor
+			// guaranteeDescendant allows us to be a "true" isDescendantOf function
+
+			while(node){
+				if(node === ancestor){ 
+					return true; // boolean
+				}
+				node = node.parentNode;
+			}
+			return false; // boolean
+		};
+
+		// Find node to restore focus to, when this menu/dialog closes
+		restoreFocus = isDescendantOf(curFocus, menu.domNode) ? prevFocus : curFocus;
+		console.debug("will restore focus to " + ( restoreFocus ? (restoreFocus.id || restoreFocus.tagName) : "nothing") );
+		console.debug("prev focus is " + prevFocus);
+
+		//Store the current selection and restore it before the action for a menu item
+		//is executed. This is required as clicking on an menu item deselects current selection
+		if(!dojo.withGlobal(openedForWindow||dojo.global, isCollapsed)){
+			bookmark = dojo.withGlobal(openedForWindow||dojo.global, getBookmark);
+		}else{
+			bookmark = null;
+		}
+	};
+
+	this.restore = function(/*Widget*/menu){
+		// summary:
+		//	notify the manager that menu is closed; it will return focus to
+		//	where it was before the menu got focus
+		if(currentMenu == menu){
+			// focus on element that was focused before menu stole the focus
+			if(restoreFocus){
+				restoreFocus.focus();
+			}
+
+			//do not need to restore if current selection is not empty
+			//(use keyboard to select a menu item)
+			if(bookmark && dojo.withGlobal(openedForWindow||dojo.global, isCollapsed)){
+				if(openedForWindow){
+					openedForWindow.focus();
+				}
+				try{
+					dojo.withGlobal(openedForWindow||dojo.global, moveToBookmark, null, [bookmark]);
+				}catch(e){
+					/*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */
+				}
+			}
+
+			bookmark = null;
+			closeOnScreenClick = false;
+			currentMenu = null;
+		}
+	};
+}();

Added: trunk/examples/typeface/root/static/dojo/dijit/util/PopupManager.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/util/PopupManager.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/util/PopupManager.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,243 @@
+dojo.provide("dijit.util.PopupManager");
+
+dojo.require("dijit.util.BackgroundIframe");
+dojo.require("dijit.util.FocusManager");
+dojo.require("dijit.util.place");
+dojo.require("dijit.util.window");
+
+dijit.util.PopupManager = new function(){
+	// summary:
+	//		This class is used to show/hide popups.
+	//
+	//		The widget must implement a close() callback, which is called when someone
+	//		clicks somewhere random on the screen.  It will hide the [chain of] context menus
+
+	var stack = [];
+	var beginZIndex=1000;
+
+	this.open = function(/*Event*/ e, /*Widget*/widget, /*Object*/ padding){
+		// summary:
+		//		Open the widget at mouse position
+		//		TODO: if widget has href, attach to onLoaded() and reposition
+
+		var x = e.pageX, y = e.pageY;
+		// FIXME: consider skipping everything up to _open
+		// if x == y == 0, allowing the popup to appear 
+		// wherever it was last time. 
+		var win = dijit.util.window.getDocumentWindow(e.target.ownerDocument);
+		var iframe = win._frameElement || win.frameElement;
+		if(iframe){
+			var cood = dojo.coords(iframe, true);
+			x += cood.x - dojo.withGlobal(win, dijit.util.getScroll).left;
+			y += cood.y - dojo.withGlobal(win, dijit.util.getScroll).top;
+		}
+		dijit.util.placeOnScreen(widget.domNode, x, y, padding, true);
+		
+		this._open(widget);
+	}
+
+	this.openAround = function(/*Widget*/parent, /*Widget*/widget, /*String?*/orient, /*Array?*/padding){
+		// summary:
+		//		Open the widget relative to parent widget (typically as a drop down to that widget)
+		//		TODO: if widget has href attach to onLoaded and reposition
+
+		// default values for args
+		if(!orient){ orient={'BL':'TL', 'TL':'BL'}; }
+		if(!padding){ padding=[0,0]; }
+
+		var best=dijit.util.placeOnScreenAroundElement(widget.domNode, parent, padding, orient);
+		this._open(widget);
+		return best;
+	};
+
+	this._open = function(widget){
+		// summary:
+		//		Utility function to help opening
+
+		// display temporarily, and move into position, then hide again
+		with(widget.domNode.style){
+			zIndex = beginZIndex + stack.length;
+			position = "absolute";
+		}
+
+		if(stack.length == 0){
+			this._beforeTopOpen(null, widget);
+		}
+
+		stack.push(widget);
+
+		// TODO: use effects
+		dojo.style(widget.domNode, "display", "");
+
+		if(dojo.isIE && dojo.isIE < 7){
+			if(!widget.bgIframe){
+				widget.bgIframe = new dijit.util.BackgroundIframe();
+				widget.bgIframe.setZIndex(widget.domNode);
+			}
+			widget.bgIframe.size(widget.domNode);
+			widget.bgIframe.show();
+		}
+
+		if(widget.onOpen){
+			widget.onOpen();
+		}
+	};
+
+	this.close = function(){
+		// summary:
+		//		Close popup on the top of the stack (the highest z-index popup)
+
+		var widget = stack.pop();
+
+		dojo.style(widget.domNode, "display", "none");
+		if(dojo.isIE && dojo.isIE < 7){
+			widget.bgIframe.hide();
+		}
+
+		if(widget.onClose){
+			widget.onClose();
+		}
+
+		if(stack.length == 0){
+			this._afterTopClose(widget);
+		}
+	};
+
+	this.closeAll = function(){
+		// summary: close every popup, from top of stack down to the first one
+		while(stack.length){
+			this.close();
+		}
+	};
+
+	this.closeTo = function(/*Widget*/ widget){
+		// summary: closes every popup above specified widget
+		while(stack.length && stack[stack.length-1] != widget){
+			this.close();
+		}
+	};
+
+	///////////////////////////////////////////////////////////////////////
+	// Utility functions for making mouse click close popup chain
+	var currentTrigger;
+	
+	this._beforeTopOpen = function(/*Widget*/ button, /*Widget*/menu){
+		// summary:
+		//	Called when a popup is opened, typically a button opening a menu.
+		//	Registers handlers so that clicking somewhere else on the screen will close the popup
+
+		// TODO: should do this at every level of popup?
+		dijit.util.FocusManager.save(menu);
+
+		currentTrigger=button;
+
+		// setup handlers to catch screen clicks and close current menu	
+		this._connectHandlers();
+	};
+
+	this._afterTopClose = function(/*Widget*/menu){
+		// summary:
+		//	called when the top level popup is closed, but before it performs it's actions
+		//	removes handlers for mouse movement detection
+
+		// remove handlers to catch screen clicks and close current menu
+		this._disconnectHandlers();
+
+		currentTrigger = null;
+
+		dijit.util.FocusManager.restore(menu);
+	};
+
+	this._onKeyPress = function(/*Event*/e){
+		// summary
+		//	Handles keystrokes, passing them up the chain of menus
+		if((!e.keyCode) && (e.charCode != dojo.keys.SPACE)){ return; }
+		if(stack.length==0){ return; }
+
+		// loop from child menu up ancestor chain, ending at button that spawned the menu
+		var m = stack[stack.length-1];
+		while(m){
+			if(m.processKey && m.processKey(e)){
+				e.preventDefault();
+				e.stopPropagation();
+				break;
+			}
+			m = m.parentPopup || m.parentMenu;
+		}
+	};
+
+	this._onMouse = function(/*Event*/e){
+		// summary
+		// Monitor clicks in the screen.  If popup has requested it than
+		// clicking anywhere on the screen will close the current menu hierarchy
+
+		if(stack.length==0){ return; }
+
+		//PORT #2804. Use isAncestor
+		var isDescendantOf = function(/*Node*/node, /*Node*/ancestor){
+			//	summary
+			//	Returns boolean if node is a descendant of ancestor
+			// guaranteeDescendant allows us to be a "true" isDescendantOf function
+
+			while(node){
+				if(node === ancestor){ 
+					return true; // boolean
+				}
+				node = node.parentNode;
+			}
+			return false; // boolean
+		}
+
+		// if they clicked on the trigger node (often a button), ignore the click
+		if(currentTrigger && isDescendantOf(e.target, currentTrigger)){
+			return;
+		}
+
+		// if they clicked on the popup itself then ignore it
+		if(dojo.some(stack, function(widget){
+			return isDescendantOf(e.target, widget.domNode);
+		}))
+		{
+			return;
+		}
+
+		// the click didn't fall within the open popups so close all open popups
+		this.closeAll();
+	};
+
+	// List of everything we need to disconnect
+	this._connects = [];
+
+	this._connectHandlers = function(/*Window?*/targetWindow){
+		// summary:
+		//		Listens on top window and all the iframes so that whereever 
+		//		the user clicks in the page, the popup menu will be closed
+
+		if(!targetWindow){ //see comment below
+			targetWindow = dijit.util.window.getDocumentWindow(window.top && window.top.document || window.document);
+		}
+
+		this._connects.push(dojo.connect(targetWindow.document, "onmousedown", this, "_onMouse"));
+		this._connects.push(dojo.connect(targetWindow, "onscroll", this, "_onMouse"));
+		this._connects.push(dojo.connect(targetWindow.document, "onkeypress", this, "_onKeyPress"));
+
+		dojo.forEach(targetWindow.frames, function(frame){
+			try{
+				//do not remove dijit.util.window.getDocumentWindow, see comment in it
+				var win = dijit.util.window.getDocumentWindow(frame.document);
+				if(win){
+					this._connectHandlers(win);
+				}
+			}catch(e){ /* squelch error for cross domain iframes */ }
+		}, this);
+	};
+
+	this._disconnectHandlers = function(){
+		// summary:
+		//		Disconnects handlers for mouse click etc. setup by _connectHandlers()
+		dojo.forEach(this._connects, dojo.disconnect);
+		this._connects=[];
+	};
+
+	dojo.addOnUnload(this, "_disconnectHandlers");
+}();

Added: trunk/examples/typeface/root/static/dojo/dijit/util/manager.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/util/manager.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/util/manager.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,72 @@
+dojo.provide("dijit.util.manager");
+
+dijit.util.manager = new function(){
+	// summary
+	//	manager class for the widgets.
+
+	// registry of widgets
+	var registry = {};
+
+	var widgetTypeCtr = {};
+
+	this.getUniqueId = function(/*String*/widgetType){
+		// summary
+		//	Generates a unique id for a given widgetType
+
+		var widgetId;
+		do{
+			widgetId = widgetType + "_" +
+				(widgetTypeCtr[widgetType] !== undefined ?
+					++widgetTypeCtr[widgetType] : widgetTypeCtr[widgetType] = 0);
+		}while(registry[widgetId]);
+		return widgetId;
+	}
+
+	this.add = function(/*Widget*/ widget){
+		// summary
+		//	Adds a widget to the registry
+
+		if(!widget.id){
+			widget.id = this.getUniqueId(widget.declaredClass.replace("\.","_"));
+		}
+		registry[widget.id] = widget;
+	}
+
+	this.remove = function(id){
+		// summary
+		//	Removes a widget from the registry by id, but does not destroy the widget
+
+		delete registry.id;
+	}
+
+	this.destroyAll = function(){
+		// summary
+		//	Destroys all the widgets
+
+		for(var id in registry){
+			registry[id].destroy();
+		}
+	}
+
+	this.getWidgets = function(){
+		// summary
+		//	Returns the hash of id->widget
+		return registry;
+	}
+
+	this.byNode = function(/* DOMNode */ node){
+		// summary
+		//	Returns the widget as referenced by node.?
+		return registry[node.widgetId];
+	}
+};
+
+dojo.addOnUnload(function(){
+	dijit.util.manager.destroyAll();
+});
+
+dijit.byId = function(/*String*/id){
+	// summary
+	//	Returns a widget by its id
+	return dijit.util.manager.getWidgets()[id];
+};

Added: trunk/examples/typeface/root/static/dojo/dijit/util/parser.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/util/parser.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/util/parser.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,171 @@
+dojo.provide("dijit.util.parser");
+
+dojo.require("dijit.util.manager");
+dojo.require("dojo.date.stamp");
+
+dijit.util.parser = new function(){
+
+	function val2type(/*Object*/ value){
+		// summary:
+		//		Returns name of type of given value.
+
+		if(dojo.isString(value)){ return "string"; }
+		if(typeof value == "number"){ return "number"; }
+		if(typeof value == "boolean"){ return "boolean"; }
+		if(dojo.isFunction(value)){ return "function"; }
+		if(dojo.isArray(value)){ return "array"; } // typeof [] == "object"
+		if(value instanceof Date) { return "date"; } // assume timestamp
+		if(value instanceof dojo._Url){ return "url"; }
+		return "object";
+	}
+
+	function str2obj(/*String*/ value, /*String*/ type){
+		// summary:
+		//		Convert given string value to given type
+		switch(type){
+			case "string":
+				return value;
+			case "number":
+				return value.length ? Number(value) : null;
+			case "boolean":
+				return typeof value == "boolean" ? value : !(value.toLowerCase()=="false");
+			case "function":
+				if(dojo.isFunction(value)){
+					return value;
+				}
+				try{
+					if(value.search(/[^\w\.]+/i) != -1){
+						// TODO: "this" here won't work
+						value = dijit.util.parser._nameAnonFunc(new Function(value), this);
+					}
+					return dojo.getObject(value, false);
+				}catch(e){ return new Function(); }
+			case "array":
+				return value.split(";");
+			case "date":
+				return dojo.date.stamp.fromRfc3339(value);
+			case "url":
+//PORT FIXME: is value absolute or relative?  Need to join with "/"?
+				return dojo.baseUrl + value;
+			default:
+				try{ eval("var tmp = "+value); return tmp; }
+				catch(e){ return value; }
+		}
+	}
+
+	var widgetClasses = {
+		// map from fully qualified name (like "dijit.Button") to structure like
+		// { cls: dijit.Button, params: {caption: "string", disabled: "boolean"} }
+	};
+	
+	function getWidgetClassInfo(/*String*/ className){
+		// className:
+		//		fully qualified name (like "dijit.Button")
+		// returns:
+		//		structure like
+		//			{ 
+		//				cls: dijit.Button, 
+		//				params: { caption: "string", disabled: "boolean"}
+		//			}
+
+		if(!widgetClasses[className]){
+			// get pointer to widget class
+			var cls = dojo.getObject(className);
+			if(!dojo.isFunction(cls)){
+				throw new Error("Could not load widget '" + className +
+					"'. Did you spell the name correctly and use a full path, like 'dijit.form.Button'?");
+			}
+			var proto = cls.prototype;
+	
+			// get table of parameter names & types
+			var params={};
+			for(var name in proto){
+				if(name.charAt(0)=="_"){ continue; } 	// skip internal properties
+				var defVal = proto[name];
+				params[name]=val2type(defVal);
+			}
+
+			widgetClasses[className] = { cls: cls, params: params };
+		}
+		return widgetClasses[className];
+	}
+	
+	this.instantiate = function(nodes){
+		// summary:
+		//		Takes array of nodes, and turns them into widgets Calls their
+		//		layout method to allow them to connect with any children		
+		var thelist = [];
+		dojo.forEach(nodes, function(node){
+			if(!node){ return; }
+			var type = node.getAttribute('dojoType');
+			if((!type)||(!type.length)){ return; }
+			var clsInfo = getWidgetClassInfo(type);
+			var params = {};
+			for(var attrName in clsInfo.params){
+				var attrValue = node.getAttribute(attrName);
+				if(attrValue != null){
+					var attrType = clsInfo.params[attrName];
+					params[attrName] = str2obj(attrValue, attrType);
+				}
+			}
+			thelist.push(new clsInfo.cls(params, node));
+			var jsname = node.getAttribute('jsId');
+			if(jsname){
+				dojo.setObject(jsname, thelist[thelist.length-1]);
+			}
+		});
+
+		// Call startup on each top level widget.  Parent widgets will
+		// recursively call startup on their (non-top level) children
+		dojo.forEach(thelist, function(widget){
+			if(widget && widget.startup && (!widget.getParent || widget.getParent()==null)){
+				widget.startup();
+			}
+		});
+		return thelist;
+	};
+
+	this.parse = function(/*DomNode?*/ rootNode){
+		// summary:
+		//		Search specified node (or root node) recursively for widgets,
+		//		and instantiate them Searches for
+		//		dojoType="qualified.class.name"
+		var list = dojo.query('[dojoType]', rootNode);
+		return this.instantiate(list);
+	};
+}();
+
+dojo.addOnLoad(function(){ dijit.util.parser.parse(); });
+
+//TODO: ported from 0.4.x Dojo.  Can we reduce this?
+dijit.util.parser._anonCtr = 0;
+dijit.util.parser._anon = {}; // why is this property required?
+dijit.util.parser._nameAnonFunc = function(/*Function*/anonFuncPtr, /*Object*/thisObj, /*Boolean*/searchForNames){
+	// summary:
+	//		Creates a reference to anonFuncPtr in thisObj with a completely
+	//		unique name. The new name is returned as a String.  If
+	//		searchForNames is true, an effort will be made to locate an
+	//		existing reference to anonFuncPtr in thisObj, and if one is found,
+	//		the existing name will be returned instead. The default is for
+	//		searchForNames to be false.
+	var jpn = "$joinpoint";
+	var nso = (thisObj|| dijit.util.parser._anon);
+	if(dojo.isIE){
+		var cn = anonFuncPtr["__dojoNameCache"];
+		if(cn && nso[cn] === anonFuncPtr){
+			return anonFuncPtr["__dojoNameCache"];
+		}else if(cn){
+			// hack to see if we've been event-system mangled
+			var tindex = cn.indexOf(jpn);
+			if(tindex != -1){
+				return cn.substring(0, tindex);
+			}
+		}
+	}
+	var ret = "__"+dijit.util.parser._anonCtr++;
+	while(typeof nso[ret] != "undefined"){
+		ret = "__"+dijit.util.parser._anonCtr++;
+	}
+	nso[ret] = anonFuncPtr;
+	return ret; // String
+}

Added: trunk/examples/typeface/root/static/dojo/dijit/util/place.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/util/place.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/util/place.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,291 @@
+dojo.provide("dijit.util.place");
+
+// ported from dojo.html.util
+
+dijit.util.getViewport = function(){
+	//	summary
+	//	Returns the dimensions of the viewable area of a browser window
+	var _window = dojo.global;
+	var _document = dojo.doc;
+	var w = 0;
+	var h = 0;
+
+	if(dojo.isMozilla){
+		// mozilla
+		w = _document.documentElement.clientWidth;
+		h = _window.innerHeight;
+	}else if(!dojo.isOpera && _window.innerWidth){
+		//in opera9, dojo.body().clientWidth should be used, instead
+		//of window.innerWidth/document.documentElement.clientWidth
+		//so we have to check whether it is opera
+		w = _window.innerWidth;
+		h = _window.innerHeight;
+	}else if(dojo.isIE && _document.documentElement && _document.documentElement.clientHeight){
+		w = _document.documentElement.clientWidth;
+		h = _document.documentElement.clientHeight;
+	}else if(dojo.body().clientWidth){
+		// IE5, Opera
+		w = dojo.body().clientWidth;
+		h = dojo.body().clientHeight;
+	}
+	return { w: w, h: h };	//	object
+};
+
+dijit.util.getScroll = function(){
+	//	summary
+	//	Returns the scroll position of the document
+	var _window = dojo.global;
+	var _document = dojo.doc;
+	var top = _window.pageYOffset || _document.documentElement.scrollTop || dojo.body().scrollTop || 0;
+	var left = _window.pageXOffset || _document.documentElement.scrollLeft || dojo.body().scrollLeft || 0;
+	return { 
+		top: top,
+		left: left, 
+		offset:{ x: left, y: top }	//	note the change, NOT an Array with added properties. 
+	};	//	object
+};
+
+dijit.util.placeOnScreen = function(
+	/* HTMLElement */	node,
+	/* integer */		desiredX,
+	/* integer */		desiredY,
+	/* integer */		padding,
+	/* boolean? */		hasScroll,
+	/* string? */		corners,
+	/* boolean? */		tryOnly){
+	//	summary:
+	//		Keeps 'node' in the visible area of the screen while trying to
+	//		place closest to desiredX, desiredY. The input coordinates are
+	//		expected to be the desired screen position, not accounting for
+	//		scrolling. If you already accounted for scrolling, set 'hasScroll'
+	//		to true. Set padding to either a number or array for [paddingX, paddingY]
+	//		to put some buffer around the element you want to position.
+	//		Set which corner(s) you want to bind to, such as
+	//		
+	//			placeOnScreen(node, desiredX, desiredY, padding, hasScroll, "TR")
+	//			placeOnScreen(node, [desiredX, desiredY], padding, hasScroll, ["TR", "BL"])
+	//		
+	//		The desiredX/desiredY will be treated as the topleft(TL)/topright(TR) or
+	//		BottomLeft(BL)/BottomRight(BR) corner of the node. Each corner is tested
+	//		and if a perfect match is found, it will be used. Otherwise, it goes through
+	//		all of the specified corners, and choose the most appropriate one.
+	//		By default, corner = ['TL'].
+	//		If tryOnly is set to true, the node will not be moved to the place.
+	//		
+	//		NOTE: node is assumed to be absolutely or relatively positioned.
+	//		
+	//	Alternate call sig:
+	//		 placeOnScreen(node, [x, y], padding, hasScroll)
+	//		
+	//	Examples:
+	//		 placeOnScreen(node, 100, 200)
+	//		 placeOnScreen("myId", [800, 623], 5)
+	//		 placeOnScreen(node, 234, 3284, [2, 5], true)
+
+	// TODO: make this function have variable call sigs
+	//	kes(node, ptArray, cornerArray, padding, hasScroll)
+	//	kes(node, ptX, ptY, cornerA, cornerB, cornerC, paddingArray, hasScroll)
+	if(dojo.isArray(desiredX)){
+		tryOnly = corners;
+		corners = hasScroll;
+		hasScroll = padding;
+		padding = desiredY;
+		desiredY = desiredX[1];
+		desiredX = desiredX[0];
+	}
+
+	if(dojo.isString(corners)){
+		corners = corners.split(",");
+	}
+
+	if(!isNaN(padding)){
+		padding = [Number(padding), Number(padding)];
+	}else if(!dojo.isArray(padding)){
+		padding = [0, 0];
+	}
+
+	var scroll = dijit.util.getScroll().offset;
+	var view = dijit.util.getViewport();
+
+	node = dojo.byId(node);
+	var oldDisplay = node.style.display;
+	var oldVis = node.style.visibility;
+	node.style.visibility = "hidden";
+	node.style.display = "";
+//	var bb = dojo.html.getBorderBox(node);
+	var bb = dojo.marginBox(node); //PORT okay?
+	var w = bb.w;
+	var h = bb.h;
+	node.style.display = oldDisplay;
+	node.style.visibility = oldVis;
+
+	//#2670
+	var visiblew,visibleh,bestw,besth="";
+
+	if(!dojo.isArray(corners)){
+		corners = ['TL'];
+	}
+
+	var bestx, besty, bestDistance = Infinity, bestCorner;
+
+	for(var cidex=0; cidex<corners.length; ++cidex){
+		var visiblew,visibleh="";
+		var corner = corners[cidex];
+		var match = true;
+		// guess where to put the upper left corner of the popup, based on which corner was passed
+		// if you choose a corner other than the upper left, 
+		// obviously you have to move the popup
+		// so that the selected corner is at the x,y you asked for
+		var tryX = desiredX - (corner.charAt(1)=='L' ? 0 : w) + padding[0]*(corner.charAt(1)=='L' ? 1 : -1);
+		var tryY = desiredY - (corner.charAt(0)=='T' ? 0 : h) + padding[1]*(corner.charAt(0)=='T' ? 1 : -1);
+		// document => viewport
+		if(hasScroll){
+			tryX -= scroll.x;
+			tryY -= scroll.y;
+		}
+		// x component
+		// test if the popup does not fit
+		var x = tryX + w;
+		if(x > view.w){
+			match = false;
+		}
+		// viewport => document
+		// min: left side of screen
+		x = Math.max(padding[0], tryX) + scroll.x;
+		// calculate the optimal width of the popup
+		if(corner.charAt(1)=='L'){
+			if(w>view.w-tryX){
+				visiblew=view.w-tryX;
+				match=false;
+			}else{
+				visiblew=w;
+			}
+		}else{
+			if(tryX<0){
+				visiblew=w+tryX;
+				match=false;
+			}else{
+				visiblew=w;
+			}
+		}
+		// y component
+		// test if the popup does not fit
+		var y = tryY + h;
+		if(y > view.h){
+			match = false;
+		}
+		// viewport => document
+		// min: top side of screen
+		y = Math.max(padding[1], tryY) + scroll.y;
+		// calculate the optimal height of the popup
+		if(corner.charAt(0)=='T'){
+			if(h>view.h-tryY){
+				visibleh=view.h-tryY;
+				match=false;
+			}else{
+				visibleh=h;
+			}
+		}else{
+			if(tryY<0){
+				visibleh=h+tryY;
+				match=false;
+			}else{
+				visibleh=h;
+			}
+		}
+
+		if(match){ //perfect match, return now
+			bestx = x;
+			besty = y;
+			bestDistance = 0;
+			bestw = visiblew;
+			besth = visibleh;
+			bestCorner = corner;
+			break;
+		}else{
+			//not perfect, find out whether it is better than the saved one
+			// weight this position by its squared distance
+			var dist = Math.pow(x-tryX-scroll.x,2)+Math.pow(y-tryY-scroll.y,2);
+			// if there was not a perfect match but dist=0 anyway (popup too small) weight by size of popup
+			if(dist==0){dist=Math.pow(h-visibleh,2);}
+			// choose the lightest (closest or biggest popup) position
+			if(bestDistance > dist){
+				bestDistance = dist;
+				bestx = x;
+				besty = y;
+				bestw = visiblew;
+				besth = visibleh;
+				bestCorner = corner;
+			}
+		}
+	}
+
+	if(!tryOnly){
+		node.style.left = bestx + "px";
+		node.style.top = besty + "px";
+	}
+
+	return {left: bestx, top: besty, x: bestx, y: besty, dist: bestDistance, corner:  bestCorner, h:besth, w:bestw};	//	object
+}
+
+dijit.util.placeOnScreenAroundElement = function(
+	/* HTMLElement */node,
+	/* HTMLElement */aroundNode,
+	/* integer */padding,
+	/* string? */aroundCorners,
+	/* boolean? */tryOnly){
+	//	summary
+	//	Like placeOnScreen, except it accepts aroundNode instead of x,y
+	//	and attempts to place node around it.  Uses margin box dimensions.
+	//
+	//	aroundCorners
+	//		specify Which corner of aroundNode should be
+	//		used to place the node => which corner(s) of node to use (see the
+	//		corners parameter in dijit.util.placeOnScreen)
+	//		e.g. {'TL': 'BL', 'BL': 'TL'}
+
+	// This won't work if the node is inside a <div style="position: relative>,
+	// so reattach it to document.body.   (Otherwise, the positioning will be wrong
+	// and also it might get cutoff)
+	if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){
+		dojo.body().appendChild(node);
+	}
+
+	var best, bestDistance=Infinity;
+	aroundNode = dojo.byId(aroundNode);
+	var oldDisplay = aroundNode.style.display;
+	aroundNode.style.display="";
+	// #3172: use the slightly tighter border box instead of marginBox
+	//var mb = dojo.marginBox(aroundNode);
+	//aroundNode.style.borderWidth="10px";
+	var aroundNodeW = aroundNode.offsetWidth; //mb.w;
+	var aroundNodeH = aroundNode.offsetHeight; //mb.h;
+	var aroundNodePos = dojo.coords(aroundNode, true);
+	aroundNode.style.display=oldDisplay;
+
+	for(var nodeCorner in aroundCorners){
+		var pos, desiredX, desiredY;
+		var corners = aroundCorners[nodeCorner];
+
+		desiredX = aroundNodePos.x + (nodeCorner.charAt(1)=='L' ? 0 : aroundNodeW);
+		desiredY = aroundNodePos.y + (nodeCorner.charAt(0)=='T' ? 0 : aroundNodeH);
+
+		pos = dijit.util.placeOnScreen(node, desiredX, desiredY, padding, true, corners, true);
+		if(pos.dist == 0){
+			best = pos;
+			break;
+		}else{
+			//not perfect, find out whether it is better than the saved one
+			if(bestDistance > pos.dist){
+				bestDistance = pos.dist;
+				best = pos;
+			}
+		}
+	}
+
+	if(!tryOnly){
+		node.style.left = best.left + "px";
+		node.style.top = best.top + "px";
+	}
+	return best;	//	object
+}

Added: trunk/examples/typeface/root/static/dojo/dijit/util/scroll.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/util/scroll.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/util/scroll.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,29 @@
+dojo.provide("dijit.util.scroll");
+
+dijit.util.scroll.scrollIntoView = function(/* HTMLElement */node){
+	//	summary
+	//	Scroll the passed node into view, if it is not.
+
+	// don't rely on that node.scrollIntoView works just because the function is there
+	// it doesnt work in Konqueror or Opera even though the function is there and probably
+	// not safari either
+	// dont like browser sniffs implementations but sometimes you have to use it
+	if(dojo.isIE){
+		//only call scrollIntoView if there is a scrollbar for this menu,
+		//otherwise, scrollIntoView will scroll the window scrollbar
+		if(dojo.marginBox(node.parentNode).h <= node.parentNode.scrollHeight){ //PORT was getBorderBox
+			node.scrollIntoView(false);
+		}
+	}else if(dojo.isMozilla){
+		node.scrollIntoView(false);
+	}else{
+		var parent = node.parentNode;
+		var parentBottom = parent.scrollTop + dojo.marginBox(parent).h; //PORT was getBorderBox
+		var nodeBottom = node.offsetTop + dojo.marginBox(node).h;
+		if(parentBottom < nodeBottom){
+			parent.scrollTop += (nodeBottom - parentBottom);
+		}else if(parent.scrollTop > node.offsetTop){
+			parent.scrollTop -= (parent.scrollTop - node.offsetTop);
+		}
+	}
+};

Added: trunk/examples/typeface/root/static/dojo/dijit/util/sniff.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/util/sniff.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/util/sniff.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,39 @@
+dojo.provide("dijit.util.sniff");
+
+// ported from dojo.html.applyBrowserClass (style.js)
+
+//	summary:
+//		Applies pre-set class names based on browser & version to the
+//		top-level HTML node.  Simply doing a require on this module will
+//		establish this CSS.  Modified version of Morris' CSS hack.
+(function(){
+	var d = dojo;
+	var ie = d.isIE;
+	var opera = d.isOpera;
+	var maj = Math.floor;
+	var classes = {
+		dj_ie: ie,
+//		dj_ie55: ie == 5.5,
+		dj_ie6: maj(ie) == 6,
+		dj_ie7: maj(ie) == 7,
+		dj_iequirks: ie && d.isQuirks,
+// NOTE: Opera not supported by dijit
+		dj_opera: opera,
+		dj_opera8: maj(opera) == 8,
+		dj_opera9: maj(opera) == 9,
+		dj_khtml: d.isKhtml,
+		dj_safari: d.isSafari,
+		dj_gecko: d.isMozilla
+	}; // no dojo unsupported browsers
+
+	for(var p in classes){
+		if(classes[p]){
+			var html = dojo.doc.documentElement; //TODO browser-specific DOM magic needed?
+			if(html.className){
+				html.className += " " + p;
+			}else{
+				html.className = p;
+			}
+		}
+	}
+})();

Added: trunk/examples/typeface/root/static/dojo/dijit/util/typematic.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/util/typematic.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/util/typematic.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,128 @@
+dojo.provide("dijit.util.typematic");
+
+dijit.util.typematic = {
+	// summary:
+	//              These functions are used to repetitively call a user specified callback 
+	//		method when a specific key or mouse click over a specific DOM node is 
+	//		held down for a specific amount of time.
+	//		Only 1 such event is allowed to occur on the browser page at 1 time.
+
+	_fireEventAndReload: function(){
+		this._timer = null;
+		this._callback(++this._count, this._node, this._evt);
+		this._currentTimeout = (this._currentTimeout < 0) ? this._initialDelay : ((this._subsequentDelay > 1) ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay));
+		this._timer = setTimeout(dojo.hitch(this, "_fireEventAndReload"), this._currentTimeout);
+	},
+
+	trigger: function(/*Event*/ evt, /* Object */ _this, /*DOMNode*/ node, /* Function */ callback, /* Object */ obj, /* Number */ subsequentDelay, /* Number */ initialDelay){
+		// summary:
+		//      Start a timed, repeating callback sequence.
+		//	If already started, the function call is ignored.
+		//	This method is not normally called by the user but can be
+		//	when the normal listener code is insufficient.
+		//	_this: pointer to the user's widget space.
+		//	callback: function name to call until the sequence is stopped.
+		//	obj: any user space object to pass to the callback.
+		//	subsequentDelay: if > 1, the number of milliseconds until the 3->n events occur
+		//		or else the fractional time multiplier for the next event.
+		//	initialDelay: the number of milliseconds until the 2nd event occurs.
+		if (obj != this._obj){ 
+			this.stop();
+			this._initialDelay = initialDelay ? initialDelay : 500;
+			this._subsequentDelay = subsequentDelay ? subsequentDelay : 0.90;
+			this._obj = obj;
+			this._evt = evt;
+			this._node = node;
+			this._currentTimeout = -1;
+			this._count = -1;
+			this._callback = dojo.hitch(_this, callback);
+			this._fireEventAndReload();
+		}
+	},
+
+	stop: function(){
+		// summary:
+		//      Stop an ongoing timed, repeating callback sequence.
+		if(this._timer){
+			clearTimeout(this._timer);
+			this._timer = null;
+		}
+		if(this._obj){
+			this._callback(-1, this._node, this._evt);
+			this._obj = null;
+		}
+	},
+
+	addKeyListener: function(/*DOMNode*/ node, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){
+		// summary: Start listening for a specific typematic key.
+		//	node: the DOM node object to listen on for key events.
+		//	keyObject: an object defining the key to listen for.
+		//		key: (mandatory) the keyCode (number) or character (string) to listen for.
+		//		ctrlKey: desired ctrl key state to initiate the calback sequence:
+		//			pressed (true)
+		//			released (false)
+		//			either (unspecified)
+		//		altKey: same as ctrlKey but for the alt key
+		//		shiftKey: same as ctrlKey but for the shift key
+		//	See the trigger method for other parameters.
+		var ary = [];
+		ary.push(dojo.connect(node, "onkeypress", this, function(evt){
+			if(evt.keyCode == keyObject.keyCode && (!keyObject.charCode || keyObject.charCode == evt.charCode)
+			&& ((typeof keyObject.ctrlKey == "undefined") || keyObject.ctrlKey == evt.ctrlKey)
+			&& ((typeof keyObject.altKey == "undefined") || keyObject.altKey == evt.ctrlKey)
+			&& ((typeof keyObject.shiftKey == "undefined") || keyObject.shiftKey == evt.ctrlKey)){
+				dojo.stopEvent(evt);
+				dijit.util.typematic.trigger(keyObject, _this, node, callback, keyObject, subsequentDelay, initialDelay);
+			}else if (dijit.util.typematic._obj == keyObject){
+				dijit.util.typematic.stop();
+			}
+		}));
+		ary.push(dojo.connect(node, "onkeyup", this, function(evt){
+			if(dijit.util.typematic._obj == keyObject){
+				dijit.util.typematic.stop();
+			}
+		}));
+		return ary;
+	},
+
+	addMouseListener: function(/*DOMNode*/ node, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){
+		// summary: Start listening for a typematic mouse click.
+		//	node: the DOM node object to listen on for mouse events.
+		//	See the trigger method for other parameters.
+		var ary = [];
+		ary.push(dojo.connect(node, "mousedown", this, function(evt){
+			dojo.stopEvent(evt);
+			dijit.util.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay);
+		}));
+		ary.push(dojo.connect(node, "mouseup", this, function(evt){
+			dojo.stopEvent(evt);
+			dijit.util.typematic.stop();
+		}));
+		ary.push(dojo.connect(node, "mouseout", this, function(evt){
+			dojo.stopEvent(evt);
+			dijit.util.typematic.stop();
+		}));
+		ary.push(dojo.connect(node, "mousemove", this, function(evt){
+			dojo.stopEvent(evt);
+		}));
+		ary.push(dojo.connect(node, "dblclick", this, function(evt){
+			dojo.stopEvent(evt);
+			if(dojo.isIE){
+				dijit.util.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay);
+				setTimeout("dijit.util.typematic.stop()",50);
+			}
+		}));
+		return ary;
+	},
+
+	addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){
+		// summary: Start listening for a specific typematic key and mouseclick.
+		//	This is a thin wrapper to addKeyListener and addMouseListener.
+		//	mouseNode: the DOM node object to listen on for mouse events.
+		//	keyNode: the DOM node object to listen on for key events.
+		//	The mouseNode is used as the callback obj parameter.
+		//	See the trigger method for other parameters.
+		return this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay).concat(
+			this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay));
+	}
+};

Added: trunk/examples/typeface/root/static/dojo/dijit/util/wai.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/util/wai.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/util/wai.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,123 @@
+dojo.provide("dijit.util.wai");
+
+dijit.util.waiNames  = ["waiRole", "waiState"];
+
+dijit.util.wai = {
+	// summary: Contains functions to set accessibility roles and states
+	//		onto widget elements
+	waiRole: { 	
+				// name: String:
+				//		information for mapping accessibility role
+				name: "waiRole", 
+				// namespace: String:
+				//		URI of the namespace for the set of roles
+				"namespace": "http://www.w3.org/TR/xhtml2", 
+				// alias: String:
+				//		The alias to assign the namespace
+				alias: "x2",
+				// prefix: String:
+				//		The prefix to assign to the role value
+				prefix: "wairole:"
+	},
+	waiState: { 
+				// name: String:
+				//		information for mapping accessibility state
+				name: "waiState", 
+				// namespace: String:
+				//		URI of the namespace for the set of states
+				"namespace": "http://www.w3.org/2005/07/aaa", 
+				// alias: String:
+				//		The alias to assign the namespace
+				alias: "aaa",
+				// prefix: String:
+				//		empty string - state value does not require prefix
+				prefix: ""
+	},
+	setAttr: function(/*DomNode*/node, /*String*/ ns, /*String*/ attr, /*String|Boolean*/value){
+		// summary: Use appropriate API to set the role or state attribute onto the element.
+		// description: In IE use the generic setAttribute() api.  Append a namespace
+		//   alias to the attribute name and appropriate prefix to the value. 
+		//   Otherwise, use the setAttribueNS api to set the namespaced attribute. Also
+		//   add the appropriate prefix to the attribute value.
+		if(dojo.isIE){
+			node.setAttribute(this[ns].alias+":"+ attr, this[ns].prefix+value);
+		}else{
+			node.setAttributeNS(this[ns]["namespace"], attr, this[ns].prefix+value);
+		}
+	},
+
+	getAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
+		// Summary:  Use the appropriate API to retrieve the role or state value
+		// Description: In IE use the generic getAttribute() api.  An alias value 
+		// 	was added to the attribute name to simulate a namespace when the attribute
+		//  was set.  Otherwise use the getAttributeNS() api to retrieve the state value
+		if(dojo.isIE){
+			return node.getAttribute(this[ns].alias+":"+attr);
+		}else{
+			return node.getAttributeNS(this[ns]["namespace"], attr);
+		}
+	},
+	removeAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
+		// summary:  Use the appropriate API to remove the role or state value
+		// description: In IE use the generic removeAttribute() api.  An alias value 
+		// 	was added to the attribute name to simulate a namespace when the attribute
+		//  was set.  Otherwise use the removeAttributeNS() api to remove the state value
+		var success = true; //only IE returns a value
+		if(dojo.isIE){
+			 success = node.removeAttribute(this[ns].alias+":"+attr);
+		}else{
+			node.removeAttributeNS(this[ns]["namespace"], attr);
+		}
+		return success;
+	},
+	
+	imageBgToSrc : function(/* Node | Node[] */ images) {
+		// summary:  
+		//		Given a single image or array of images
+		//		figure out the background-image style property
+		//		and apply that to the image.src property.
+		// description:  
+		//		For accessibility reasons, all images that are necessary to the
+		//		functioning of a widget should use <image> tags.  Using this method
+		//		allows the image URLs to come from themes (via CSS),
+		//		while still using the image tags.
+		// todo:
+		//		* have this examine background-position and, if set,
+		//			wrap the image in an inline div that allows us to crop
+		//			the image according to width and height specified in CSS.
+		if (!dojo.isArrayLike(images)) { images = [images]; }
+		dojo.forEach(images, 
+			function(image) {
+				var style = image && dojo.getComputedStyle(image);
+				if (!style) return;
+				var href = style.backgroundImage.match(/url\(['"]?(.*?)['"]?\)/);
+				if (!href) return;
+				image.src = href[1];
+				image.style.backgroundImage = "none";
+			}
+		);
+	}
+};
+
+// On page load and at intervals, detect if we are in high-contrast mode or not
+dojo._loaders.unshift(function(){
+	// create div for testing
+	var div = document.createElement("div");
+	div.id = "a11yTestNode";
+	dojo.body().appendChild(div);
+	
+	// test it
+	function check(){
+		var cs = dojo.getComputedStyle(div);
+		var bkImg = cs.backgroundImage; 
+		var needsA11y = (cs.borderTopColor==cs.borderRightColor) || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" ));
+		dojo[needsA11y ? "addClass" : "removeClass"](dojo.body(), "dijit_a11y");
+	}
+	if(dojo.isIE || dojo.isMoz){	// NOTE: checking in Safari messes things up
+		check();
+		if(dojo.isIE){
+			setInterval(check, 4000);
+		}
+	}
+});
+

Added: trunk/examples/typeface/root/static/dojo/dijit/util/window.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dijit/util/window.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dijit/util/window.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,40 @@
+dojo.provide("dijit.util.window");
+
+dijit.util.window.getDocumentWindow = function(doc){
+	//	summary
+	// 	Get window object associated with document doc
+
+	// With Safari, there is not way to retrieve the window from the document, so we must fix it.
+	if(dojo.isSafari && !doc._parentWindow){
+		/*
+			This is a Safari specific function that fix the reference to the parent
+			window from the document object.
+		*/
+		var fix=function(win){
+			win.document._parentWindow=win;
+			for(var i=0; i<win.frames.length; i++){
+				fix(win.frames[i]);
+			}
+		}
+		fix(window.top);
+	}
+
+	//In some IE versions (at least 6.0), document.parentWindow does not return a
+	//reference to the real window object (maybe a copy), so we must fix it as well
+	//We use IE specific execScript to attach the real window reference to
+	//document._parentWindow for later use
+	if(dojo.isIE && window !== document.parentWindow && !doc._parentWindow){
+		/*
+		In IE 6, only the variable "window" can be used to connect events (others
+		may be only copies).
+		*/
+		doc.parentWindow.execScript("document._parentWindow = window;", "Javascript");
+		//to prevent memory leak, unset it after use
+		//another possibility is to add an onUnload handler which seems overkill to me (liucougar)
+		var win = doc._parentWindow;
+		doc._parentWindow = null;
+		return win;	//	Window
+	}
+
+	return doc._parentWindow || doc.parentWindow || doc.defaultView;	//	Window
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/AdapterRegistry.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/AdapterRegistry.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/AdapterRegistry.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,74 @@
+dojo.provide("dojo.AdapterRegistry");
+
+dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){
+	// summary:
+	//		A registry to make contextual calling/searching easier.
+	// description:
+	//		Objects of this class keep list of arrays in the form [name, check,
+	//		wrap, directReturn] that are used to determine what the contextual
+	//		result of a set of checked arguments is. All check/wrap functions
+	//		in this registry should be of the same arity.
+	this.pairs = [];
+	this.returnWrappers = returnWrappers || false;
+}
+
+dojo.extend(dojo.AdapterRegistry, {
+	register: function(name, check, /*Function*/ wrap, directReturn, override){
+		// summary: 
+		//		register a check function to determine if the wrap function or
+		//		object gets selected
+		// name: String
+		//		a way to identify this matcher.
+		// check: Function
+		//		a function that arguments are passed to from the adapter's
+		//		match() function.  The check function should return true if the
+		//		given arguments are appropriate for the wrap function.
+		// directReturn: Boolean?
+		//		If directReturn is true, the value passed in for wrap will be
+		//		returned instead of being called. Alternately, the
+		//		AdapterRegistry can be set globally to "return not call" using
+		//		the returnWrappers property. Either way, this behavior allows
+		//		the registry to act as a "search" function instead of a
+		//		function interception library.
+		// override: Boolean?
+		//		If override is given and true, the check function will be given
+		//		highest priority. Otherwise, it will be the lowest priority
+		//		adapter.
+		this.pairs[((override) ? "unshift" : "push")]([name, check, wrap, directReturn]);
+	},
+
+	match: function(/* ... */){
+    // summary:
+		//		Find an adapter for the given arguments. If no suitable adapter
+		//		is found, throws an exception. match() accepts any number of
+		//		arguments, all of which are passed to all matching functions
+		//		from the registered pairs.
+		for(var i = 0; i < this.pairs.length; i++){
+			var pair = this.pairs[i];
+			if(pair[1].apply(this, arguments)){
+				if((pair[3])||(this.returnWrappers)){
+					return pair[2];
+				}else{
+					return pair[2].apply(this, arguments);
+				}
+			}
+		}
+		throw new Error("No match found");
+	},
+
+	unregister: function(name){
+		// summary: Remove a named adapter from the registry
+
+		// FIXME: this is kind of a dumb way to handle this. On a large
+		// registry this will be slow-ish and we can use the name as a lookup
+		// should we choose to trade memory for speed.
+		for(var i = 0; i < this.pairs.length; i++){
+			var pair = this.pairs[i];
+			if(pair[0] == name){
+				this.pairs.splice(i, 1);
+				return true;
+			}
+		}
+		return false;
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojo/_firebug/LICENSE
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/_firebug/LICENSE	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/_firebug/LICENSE	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+License Disclaimer:
+
+All contents of this directory are Copyright (c) the Dojo Foundation, with the
+following exceptions:
+-------------------------------------------------------------------------------
+
+firebug.html, firebug.js, errIcon.png, infoIcon.png, warningIcon.png:
+	* Copyright (c) 2006-2007, Joe Hewitt, All rights reserved.
+	  Distributed under the terms of the BSD License

Added: trunk/examples/typeface/root/static/dojo/dojo/_firebug/errorIcon.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dojo/_firebug/errorIcon.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dojo/_firebug/firebug.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/_firebug/firebug.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/_firebug/firebug.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,232 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+		 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+	<title>Firebug</title>
+	<style type="text/css">
+		html, body {
+			margin: 0;
+			background: #FFFFFF;
+			font-family: Lucida Grande, Tahoma, sans-serif;
+			font-size: 11px;
+			overflow: hidden;
+		}
+
+		a {
+			text-decoration: none;
+		}
+
+		a:hover {
+			text-decoration: underline;
+		}
+
+		.toolbar {
+			height: 14px;
+			border-top: 1px solid ThreeDHighlight;
+			border-bottom: 1px solid ThreeDShadow;
+			padding: 2px 6px;
+			background: ThreeDFace;
+		}
+
+		.toolbarRight {
+			position: absolute;
+			top: 4px;
+			right: 6px;
+		}
+
+		#log {
+			overflow: auto;
+			position: absolute;
+			left: 0;
+			width: 100%;
+		}
+
+		#commandLine {
+			position: absolute;
+			bottom: 0;
+			left: 0;
+			width: 100%;
+			height: 18px;
+			border: none;
+			border-top: 1px solid ThreeDShadow;
+		}
+
+		/************************************************************************************************/
+
+		.logRow {
+			position: relative;
+			border-bottom: 1px solid #D7D7D7;
+			padding: 2px 4px 1px 6px;
+			background-color: #FFFFFF;
+		}
+
+		.logRow-command {
+			font-family: Monaco, monospace;
+			color: blue;
+		}
+
+		.objectBox-null {
+			padding: 0 2px;
+			border: 1px solid #666666;
+			background-color: #888888;
+			color: #FFFFFF;
+		}
+
+		.objectBox-string {
+			font-family: Monaco, monospace;
+			color: red;
+			white-space: pre;
+		}
+
+		.objectBox-number {
+			color: #000088;
+		}
+
+		.objectBox-function {
+			font-family: Monaco, monospace;
+			color: DarkGreen;
+		}
+
+		.objectBox-object {
+			color: DarkGreen;
+			font-weight: bold;
+		}
+
+		/************************************************************************************************/
+
+		.logRow-info,
+		.logRow-error,
+		.logRow-warning {
+			background: #FFFFFF no-repeat 2px 2px;
+			padding-left: 20px;
+			padding-bottom: 3px;
+		}
+
+		.logRow-info {
+			background-image: url(infoIcon.png);
+		}
+
+		.logRow-warning {
+			background-color: cyan;
+			background-image: url(warningIcon.png);
+		}
+
+		.logRow-error {
+			background-color: LightYellow;
+			background-image: url(errorIcon.png);
+		}
+
+		.errorMessage {
+			vertical-align: top;
+			color: #FF0000;
+		}
+
+		.objectBox-sourceLink {
+			position: absolute;
+			right: 4px;
+			top: 2px;
+			padding-left: 8px;
+			font-family: Lucida Grande, sans-serif;
+			font-weight: bold;
+			color: #0000FF;
+		}
+
+		/************************************************************************************************/
+
+		.logRow-group {
+			background: #EEEEEE;
+			border-bottom: none;
+		}
+
+		.logGroup {
+			background: #EEEEEE;
+		}
+
+		.logGroupBox {
+			margin-left: 24px;
+			border-top: 1px solid #D7D7D7;
+			border-left: 1px solid #D7D7D7;
+		}
+
+		/************************************************************************************************/
+
+		.selectorTag,
+		.selectorId,
+		.selectorClass {
+			font-family: Monaco, monospace;
+			font-weight: normal;
+		}
+
+		.selectorTag {
+			color: #0000FF;
+		}
+
+		.selectorId {
+			color: DarkBlue;
+		}
+
+		.selectorClass {
+			color: red;
+		}
+
+		/************************************************************************************************/
+
+		.objectBox-element {
+			font-family: Monaco, monospace;
+			color: #000088;
+		}
+
+		.nodeChildren {
+			margin-left: 16px;
+		}
+
+		.nodeTag {
+			color: blue;
+		}
+
+		.nodeValue {
+			color: #FF0000;
+			font-weight: normal;
+		}
+
+		.nodeText,
+		.nodeComment {
+			margin: 0 2px;
+			vertical-align: top;
+		}
+
+		.nodeText {
+			color: #333333;
+		}
+
+		.nodeComment {
+			color: DarkGreen;
+		}
+
+		/************************************************************************************************/
+
+		.propertyNameCell {
+			vertical-align: top;
+		}
+
+		.propertyName {
+			font-weight: bold;
+		}
+	</style>
+</head>
+
+<body>
+	<div id="toolbar" class="toolbar">
+		<a href="#" onclick="parent.console.clear()">Clear</a>
+		<span class="toolbarRight">
+			<a href="#" onclick="parent.console.close()">Close</a>
+		</span>
+	</div>
+	<div id="log"></div>
+	<input type="text" id="commandLine">
+	
+	<script>parent.onFirebugReady(document);</script>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojo/_firebug/firebug.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/_firebug/firebug.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/_firebug/firebug.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,602 @@
+dojo.provide("dojo._firebug.firebug");
+if(
+	(
+		(!("console" in window)) || 
+		(!("firebug" in console))
+	)&&
+	(
+		(djConfig["noFirebugLite"] !== true)
+	)
+){
+(function(){
+	// don't build a firebug frame in iframes
+	if(window != window.parent){ return; }
+
+	window.console = {
+		log: function(){
+			logFormatted(arguments, "");
+		},
+		
+		debug: function(){
+			logFormatted(arguments, "debug");
+		},
+		
+		info: function(){
+			logFormatted(arguments, "info");
+		},
+		
+		warn: function(){
+			logFormatted(arguments, "warning");
+		},
+		
+		error: function(){
+			logFormatted(arguments, "error");
+		},
+		
+		assert: function(truth, message){
+			if(!truth){
+				var args = [];
+				for(var i = 1; i < arguments.length; ++i){
+					args.push(arguments[i]);
+				}
+				
+				logFormatted(args.length ? args : ["Assertion Failure"], "error");
+				throw message ? message : "Assertion Failure";
+			}
+		},
+		
+		dir: function(object){
+			var html = [];
+						
+			var pairs = [];
+			for(var name in object){
+				try{
+					pairs.push([name, object[name]]);
+				}catch(e){
+					/* squelch */
+				}
+			}
+			
+			pairs.sort(function(a, b){ 
+				return a[0] < b[0] ? -1 : 1; 
+			});
+			
+			html.push('<table>');
+			for(var i = 0; i < pairs.length; ++i){
+				var name = pairs[i][0], value = pairs[i][1];
+				
+				html.push('<tr>', 
+				'<td class="propertyNameCell"><span class="propertyName">',
+					escapeHTML(name), '</span></td>', '<td><span class="propertyValue">');
+				appendObject(value, html);
+				html.push('</span></td></tr>');
+			}
+			html.push('</table>');
+			
+			logRow(html, "dir");
+		},
+		
+		dirxml: function(node){
+			var html = [];
+			
+			appendNode(node, html);
+			logRow(html, "dirxml");
+		},
+		
+		group: function(){
+			logRow(arguments, "group", pushGroup);
+		},
+		
+		groupEnd: function(){
+			logRow(arguments, "", popGroup);
+		},
+		
+		time: function(name){
+			timeMap[name] = (new Date()).getTime();
+		},
+		
+		timeEnd: function(name){
+			if(name in timeMap){
+				var delta = (new Date()).getTime() - timeMap[name];
+				logFormatted([name+ ":", delta+"ms"]);
+				delete timeMap[name];
+			}
+		},
+		
+		count: function(){
+			this.warn(["count() not supported."]);
+		},
+		
+		trace: function(){
+			this.warn(["trace() not supported."]);
+		},
+		
+		profile: function(){
+			this.warn(["profile() not supported."]);
+		},
+		
+		profileEnd: function(){ },
+		
+		clear: function(){
+			consoleBody.innerHTML = "";
+		},
+
+		open: function(){ toggleConsole(true); },
+		
+		close: function(){
+			if(frameVisible){
+				toggleConsole();
+			}
+		}
+	};
+ 
+	// ***************************************************************************
+	   
+	var consoleFrame = null;
+	var consoleBody = null;
+	var commandLine = null;
+	
+	var frameVisible = false;
+	var messageQueue = [];
+	var groupStack = [];
+	var timeMap = {};
+	
+	var clPrefix = ">>> ";
+
+	// ***************************************************************************
+
+	function toggleConsole(forceOpen){
+		frameVisible = forceOpen || !frameVisible;
+		if(consoleFrame){
+			consoleFrame.style.visibility = frameVisible ? "visible" : "hidden";
+		}else{
+			waitForBody();
+		}
+	}
+
+	function focusCommandLine(){
+		toggleConsole(true);
+		if(commandLine){
+			commandLine.focus();
+		}
+	}
+
+	function waitForBody(){
+		if(document.body){
+			createFrame();
+		}else{
+			setTimeout(waitForBody, 200);
+		}
+	}	 
+
+	function createFrame(){
+		if(consoleFrame){
+			return;
+		}
+		
+		window.onFirebugReady = function(doc){
+			window.onFirebugReady = null;
+
+			var toolbar = doc.getElementById("toolbar");
+			toolbar.onmousedown = onSplitterMouseDown;
+
+			commandLine = doc.getElementById("commandLine");
+			addEvent(commandLine, "keydown", onCommandLineKeyDown);
+
+			addEvent(doc, dojo.isIE || dojo.isSafari ? "keydown" : "keypress", onKeyDown);
+			
+			consoleBody = doc.getElementById("log");
+			layout();
+			flush();
+		}
+
+		consoleFrame = document.createElement("iframe");
+		consoleFrame.setAttribute("src", dojo.moduleUrl("dojo._firebug", "firebug.html"));
+		consoleFrame.setAttribute("frameBorder", "0");
+		with(consoleFrame.style){
+			margin = padding = border = "0px";
+			visibility = (frameVisible ? "visible" : "hidden");	  
+			// zIndex = "2147483647";
+			zIndex = 10000;
+			position = "fixed";
+			width = "100%";
+			left = "0";
+			bottom = "3";
+			height = "200px";
+			khtmlBoxSizing = "border-box";
+			mozBoxSizing = "border-box";
+			boxSizing = "border-box";
+		}
+		document.body.appendChild(consoleFrame);
+	}
+	
+	function evalCommandLine(){
+		var text = commandLine.value;
+		commandLine.value = "";
+
+		logRow([clPrefix, text], "command");
+		
+		var value;
+		try{
+			value = eval(text);
+		}catch(e){
+			/* squelch */
+		}
+
+		console.log(value);
+	}
+	
+	function layout(){
+		var toolbar = consoleBody.ownerDocument.getElementById("toolbar");
+		var height = consoleFrame.offsetHeight - (toolbar.offsetHeight + commandLine.offsetHeight);
+		consoleBody.style.top = toolbar.offsetHeight + "px";
+		consoleBody.style.height = height + "px";
+		
+		commandLine.style.top = (consoleFrame.offsetHeight - commandLine.offsetHeight) + "px";
+	}
+	
+	function logRow(message, className, handler){
+		if(consoleBody){
+			writeMessage(message, className, handler);
+		}else{
+			messageQueue.push([message, className, handler]);
+			waitForBody();
+		}
+	}
+	
+	function flush(){
+		var queue = messageQueue;
+		messageQueue = [];
+		
+		for(var i = 0; i < queue.length; ++i){
+			writeMessage(queue[i][0], queue[i][1], queue[i][2]);
+		}
+	}
+
+	function writeMessage(message, className, handler){
+		var isScrolledToBottom =
+			consoleBody.scrollTop + consoleBody.offsetHeight >= consoleBody.scrollHeight;
+
+		handler = handler||writeRow;
+		
+		handler(message, className);
+		
+		if(isScrolledToBottom){
+			consoleBody.scrollTop = consoleBody.scrollHeight - consoleBody.offsetHeight;
+		}
+	}
+	
+	function appendRow(row){
+		var container = groupStack.length ? groupStack[groupStack.length-1] : consoleBody;
+		container.appendChild(row);
+	}
+
+	function writeRow(message, className){
+		var row = consoleBody.ownerDocument.createElement("div");
+		row.className = "logRow" + (className ? " logRow-"+className : "");
+		row.innerHTML = message.join("");
+		appendRow(row);
+	}
+
+	function pushGroup(message, className){
+		logFormatted(message, className);
+
+		var groupRow = consoleBody.ownerDocument.createElement("div");
+		groupRow.className = "logGroup";
+		var groupRowBox = consoleBody.ownerDocument.createElement("div");
+		groupRowBox.className = "logGroupBox";
+		groupRow.appendChild(groupRowBox);
+		appendRow(groupRowBox);
+		groupStack.push(groupRowBox);
+	}
+
+	function popGroup(){
+		groupStack.pop();
+	}
+	
+	// ***************************************************************************
+
+	function logFormatted(objects, className){
+		var html = [];
+
+		var format = objects[0];
+		var objIndex = 0;
+
+		if(typeof(format) != "string"){
+			format = "";
+			objIndex = -1;
+		}
+
+		var parts = parseFormat(format);
+		for(var i = 0; i < parts.length; ++i){
+			var part = parts[i];
+			if(part && typeof(part) == "object"){
+				var object = objects[++objIndex];
+				part.appender(object, html);
+			}else{
+				appendText(part, html);
+			}
+		}
+
+		for(var i = objIndex+1; i < objects.length; ++i){
+			appendText(" ", html);
+			
+			var object = objects[i];
+			if(typeof(object) == "string"){
+				appendText(object, html);
+			}else{
+				appendObject(object, html);
+			}
+		}
+		
+		logRow(html, className);
+	}
+
+	function parseFormat(format){
+		var parts = [];
+
+		var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;	  
+		var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat};
+
+		for(var m = reg.exec(format); m; m = reg.exec(format)){
+			var type = m[8] ? m[8] : m[5];
+			var appender = type in appenderMap ? appenderMap[type] : appendObject;
+			var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
+
+			parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
+			parts.push({appender: appender, precision: precision});
+
+			format = format.substr(m.index+m[0].length);
+		}
+
+		parts.push(format);
+
+		return parts;
+	}
+
+	function escapeHTML(value){
+		function replaceChars(ch){
+			switch(ch){
+				case "<":
+					return "&lt;";
+				case ">":
+					return "&gt;";
+				case "&":
+					return "&amp;";
+				case "'":
+					return "&#39;";
+				case '"':
+					return "&quot;";
+			}
+			return "?";
+		};
+		return String(value).replace(/[<>&"']/g, replaceChars);
+	}
+
+	function objectToString(object){
+		try{
+			return object+"";
+		}catch(e){
+			return null;
+		}
+	}
+
+	// ***************************************************************************
+
+	function appendText(object, html){
+		html.push(escapeHTML(objectToString(object)));
+	}
+
+	function appendNull(object, html){
+		html.push('<span class="objectBox-null">', escapeHTML(objectToString(object)), '</span>');
+	}
+
+	function appendString(object, html){
+		html.push('<span class="objectBox-string">&quot;', escapeHTML(objectToString(object)),
+			'&quot;</span>');
+	}
+
+	function appendInteger(object, html){
+		html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
+	}
+
+	function appendFloat(object, html){
+		html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
+	}
+
+	function appendFunction(object, html){
+		var reName = /function ?(.*?)\(/;
+		var m = reName.exec(objectToString(object));
+		var name = m ? m[1] : "function";
+		html.push('<span class="objectBox-function">', escapeHTML(name), '()</span>');
+	}
+	
+	function appendObject(object, html){
+		try{
+			if(object == undefined){
+				appendNull("undefined", html);
+			}else if(object == null){
+				appendNull("null", html);
+			}else if(typeof object == "string"){
+				appendString(object, html);
+			}else if(typeof object == "number"){
+				appendInteger(object, html);
+			}else if(typeof object == "function"){
+				appendFunction(object, html);
+			}else if(object.nodeType == 1){
+				appendSelector(object, html);
+			}else if(typeof object == "object"){
+				appendObjectFormatted(object, html);
+			}else{
+				appendText(object, html);
+			}
+		}catch(e){
+			/* squelch */
+		}
+	}
+		
+	function appendObjectFormatted(object, html){
+		var text = objectToString(object);
+		var reObject = /\[object (.*?)\]/;
+
+		var m = reObject.exec(text);
+		html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>')
+	}
+	
+	function appendSelector(object, html){
+		html.push('<span class="objectBox-selector">');
+
+		html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
+		if(object.id){
+			html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
+		}
+		if(object.className){
+			html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');
+		}
+
+		html.push('</span>');
+	}
+
+	function appendNode(node, html){
+		if(node.nodeType == 1){
+			html.push(
+				'<div class="objectBox-element">',
+					'&lt;<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');
+
+			for(var i = 0; i < node.attributes.length; ++i){
+				var attr = node.attributes[i];
+				if(!attr.specified){ continue; }
+				
+				html.push('&nbsp;<span class="nodeName">', attr.nodeName.toLowerCase(),
+					'</span>=&quot;<span class="nodeValue">', escapeHTML(attr.nodeValue),
+					'</span>&quot;')
+			}
+
+			if(node.firstChild){
+				html.push('&gt;</div><div class="nodeChildren">');
+
+				for(var child = node.firstChild; child; child = child.nextSibling){
+					appendNode(child, html);
+				}
+					
+				html.push('</div><div class="objectBox-element">&lt;/<span class="nodeTag">', 
+					node.nodeName.toLowerCase(), '&gt;</span></div>');
+			}else{
+				html.push('/&gt;</div>');
+			}
+		}else if (node.nodeType == 3){
+			html.push('<div class="nodeText">', escapeHTML(node.nodeValue),
+				'</div>');
+		}
+	}
+
+	// ***************************************************************************
+	
+	function addEvent(object, name, handler){
+		if(document.all){
+			object.attachEvent("on"+name, handler);
+		}else{
+			object.addEventListener(name, handler, false);
+		}
+	}
+	
+	function removeEvent(object, name, handler){
+		if(document.all){
+			object.detachEvent("on"+name, handler);
+		}else{
+			object.removeEventListener(name, handler, false);
+		}
+	}
+	
+	function cancelEvent(event){
+		if(document.all){
+			event.cancelBubble = true;
+		}else{
+			event.stopPropagation();		
+		}
+	}
+
+	function onError(msg, href, lineNo){
+		var html = [];
+		
+		var lastSlash = href.lastIndexOf("/");
+		var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);
+		
+		html.push(
+			'<span class="errorMessage">', msg, '</span>', 
+			'<div class="objectBox-sourceLink">', fileName, ' (line ', lineNo, ')</div>'
+		);
+		
+		logRow(html, "error");
+	};
+
+	function onKeyDown(event){
+		if(event.keyCode == 123){
+			toggleConsole();
+		}else if((event.keyCode == 108 || event.keyCode == 76) && event.shiftKey
+				 && (event.metaKey || event.ctrlKey)){
+			focusCommandLine();
+		}else{ return; }
+		
+		cancelEvent(event);
+	}
+
+	function onSplitterMouseDown(event){
+		if(dojo.isSafari || dojo.isOpera){
+			return;
+		}
+		
+		addEvent(document, "mousemove", onSplitterMouseMove);
+		addEvent(document, "mouseup", onSplitterMouseUp);
+
+		for(var i = 0; i < frames.length; ++i){
+			addEvent(frames[i].document, "mousemove", onSplitterMouseMove);
+			addEvent(frames[i].document, "mouseup", onSplitterMouseUp);
+		}
+	}
+	
+	function onSplitterMouseMove(event){
+		var win = document.all
+			? event.srcElement.ownerDocument.parentWindow
+			: event.target.ownerDocument.defaultView;
+
+		var clientY = event.clientY;
+		if(win != win.parent){
+			clientY += win.frameElement ? win.frameElement.offsetTop : 0;
+		}
+		
+		var height = consoleFrame.offsetTop + consoleFrame.clientHeight;
+		var y = height - clientY;
+		
+		consoleFrame.style.height = y + "px";
+		layout();
+	}
+	
+	function onSplitterMouseUp(event){
+		removeEvent(document, "mousemove", onSplitterMouseMove);
+		removeEvent(document, "mouseup", onSplitterMouseUp);
+
+		for(var i = 0; i < frames.length; ++i){
+			removeEvent(frames[i].document, "mousemove", onSplitterMouseMove);
+			removeEvent(frames[i].document, "mouseup", onSplitterMouseUp);
+		}
+	}
+	
+	function onCommandLineKeyDown(event){
+		if(event.keyCode == 13){
+			evalCommandLine();
+		}else if(event.keyCode == 27){
+			commandLine.value = "";
+		}
+	}
+	
+	window.onerror = onError;
+	addEvent(document, dojo.isIE || dojo.isSafari ? "keydown" : "keypress", onKeyDown);
+	
+	if(	(document.documentElement.getAttribute("debug") == "true")||
+		(djConfig.isDebug)
+	){
+		toggleConsole(true);
+	}
+})();
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/_firebug/infoIcon.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dojo/_firebug/infoIcon.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dojo/_firebug/warningIcon.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dojo/_firebug/warningIcon.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dojo/back.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/back.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/back.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,350 @@
+dojo.provide("dojo.back");
+
+(function() { 
+	
+	var back = dojo.back;
+	
+	var initialHref = (typeof(window) !== "undefined") ? window.location.href : "";
+	var initialHash = (typeof(window) !== "undefined") ? window.location.hash : "";
+	var initialState = null;
+
+	var locationTimer = null;
+	var bookmarkAnchor = null;
+	var historyIframe = null;
+	var forwardStack = [];
+	var historyStack = [];
+	var moveForward = false;
+	var changingUrl = false;
+	var historyCounter;
+
+	function handleBackButton(){
+		//summary: private method. Do not call this directly.
+
+		//The "current" page is always at the top of the history stack.
+		console.debug("handlingBackButton");
+		var current = historyStack.pop();
+		if(!current){ return; }
+		var last = historyStack[historyStack.length-1];
+		if(!last && historyStack.length == 0){
+			last = initialState;
+		}
+		if (last){
+			if(last.kwArgs["back"]){
+				last.kwArgs["back"]();
+			}else if(last.kwArgs["backButton"]){
+				last.kwArgs["backButton"]();
+			}else if(last.kwArgs["handle"]){
+				last.kwArgs.handle("back");
+			}
+		}
+		forwardStack.push(current);
+		console.debug("done handling back");
+	}
+
+	back.goBack = handleBackButton;
+
+	function handleForwardButton(){
+		//summary: private method. Do not call this directly.
+		console.debug("handling forward");
+		var last = forwardStack.pop();
+		if(!last){ return; }
+		if(last.kwArgs["forward"]){
+			last.kwArgs.forward();
+		}else if(last.kwArgs["forwardButton"]){
+			last.kwArgs.forwardButton();
+		}else if(last.kwArgs["handle"]){
+			last.kwArgs.handle("forward");
+		}
+		historyStack.push(last);
+		console.debug("done handling forward");
+	}
+
+	back.goForward = handleForwardButton;
+
+	function createState(url, args, hash){
+		//summary: private method. Do not call this directly.
+		return {"url": url, "kwArgs": args, "urlHash": hash};	//Object
+	}
+
+	function getUrlQuery(url){
+		//summary: private method. Do not call this directly.
+		var segments = url.split("?");
+		if (segments.length < 2){
+			return null; //null
+		}
+		else{
+			return segments[1]; //String
+		}
+	}
+
+	var getHash;
+	if(dojo.isOpera){
+		getHash = function(){
+			// work 
+			var href = window.top.location.href;
+			var i = href.indexOf("#");
+			return i >= 0 ? href.substring(i+1) : null;
+		};
+	}else{
+		getHash = function() { return window.location.hash; };
+	}
+
+	function setHash(h) {
+		if(!h) { h = "" };
+		if(h.charAt(0) == "#") { h = h.substring(1); }
+		window.location.hash = h;
+		historyCounter = history.length;
+	}
+	
+	function loadIframeHistory(){
+		//summary: private method. Do not call this directly.
+		var url = (djConfig["dojoIframeHistoryUrl"] || dojo.moduleUrl("dojo", "resources/iframe_history.html")) + "?" + (new Date()).getTime();
+		moveForward = true;
+		(dojo.isSafari) ? historyIframe.location = url : window.frames[historyIframe.name].location = url;
+		return url; //String
+	}
+
+	function checkLocation() {
+		console.debug("checking url");
+		if(!changingUrl){
+			var hsl = historyStack.length;
+
+			if((getHash() == initialHash||window.location.href == initialHref)&&(hsl == 1)){
+				// FIXME: could this ever be a forward button?
+				// we can't clear it because we still need to check for forwards. Ugg.
+				// clearInterval(this.locationTimer);
+				handleBackButton();
+				return;
+			}
+			
+			// first check to see if we could have gone forward. We always halt on
+			// a no-hash item.
+			if(forwardStack.length > 0){
+				if(forwardStack[forwardStack.length-1].urlHash == getHash()){
+					handleForwardButton();
+					return;
+				}
+			}
+	
+			// ok, that didn't work, try someplace back in the history stack
+			if((hsl >= 2)&&(historyStack[hsl-2])){
+				if(historyStack[hsl-2].urlHash==getHash()){
+					handleBackButton();
+					return;
+				}
+			}
+
+			var hisLen = history.length;
+			if(hisLen > historyCounter) handleForwardButton();
+			else if(hisLen < historyCounter) handleBackButton();
+			historyCounter = hisLen;
+		}
+		console.debug("done checking");
+	};
+	
+	back.init = function(){
+		//summary: Initializes the undo stack. This must be called from a <script> 
+		//         block that lives inside the <body> tag to prevent bugs on IE.
+		var src = djConfig["dojoIframeHistoryUrl"] || dojo.moduleUrl("dojo", "resources/iframe_history.html");
+		document.write('<iframe style="border:0;width:1px;height:1px;position:absolute;visibility:hidden;bottom:0;right:0;" name="dj_history" id="dj_history" src="' + src + '"></iframe>');
+	};
+
+	back.setInitialState = function(/*Object*/args){
+		//summary: Sets the state object and back callback for the very first page that is loaded.
+		//description: It is recommended that you call this method as part of an event listener that is registered via
+		//dojo.addOnLoad().
+		//args: Object
+		//		See the addToHistory() function for the list of valid args properties.
+		initialState = createState(initialHref, args, initialHash);
+	};
+
+	//FIXME: Would like to support arbitrary back/forward jumps. Have to rework iframeLoaded among other things.
+	//FIXME: is there a slight race condition in moz using change URL with the timer check and when
+	//       the hash gets set? I think I have seen a back/forward call in quick succession, but not consistent.
+	back.addToHistory = function(/*Object*/ args){
+		//summary: adds a state object (args) to the history list. You must set
+		//djConfig.preventBackButtonFix = false to use dojo.undo.browser.
+
+		//args: Object
+		//		args can have the following properties:
+		//		To support getting back button notifications, the object argument should implement a
+		//		function called either "back", "backButton", or "handle". The string "back" will be
+		//		passed as the first and only argument to this callback.
+		//		- To support getting forward button notifications, the object argument should implement a
+		//		function called either "forward", "forwardButton", or "handle". The string "forward" will be
+		//		passed as the first and only argument to this callback.
+		//		- If you want the browser location string to change, define "changeUrl" on the object. If the
+		//		value of "changeUrl" is true, then a unique number will be appended to the URL as a fragment
+		//		identifier (http://some.domain.com/path#uniquenumber). If it is any other value that does
+		//		not evaluate to false, that value will be used as the fragment identifier. For example,
+		//		if changeUrl: 'page1', then the URL will look like: http://some.domain.com/path#page1
+	 	//		Full example:
+		//		dojo.undo.browser.addToHistory({
+		//		  back: function() { alert('back pressed'); },
+		//		  forward: function() { alert('forward pressed'); },
+		//		  changeUrl: true
+		//		});
+		//
+		//	BROWSER NOTES:
+		//  Safari 1.2: 
+		//	back button "works" fine, however it's not possible to actually
+		//	DETECT that you've moved backwards by inspecting window.location.
+		//	Unless there is some other means of locating.
+		//	FIXME: perhaps we can poll on history.length?
+		//	Safari 2.0.3+ (and probably 1.3.2+):
+		//	works fine, except when changeUrl is used. When changeUrl is used,
+		//	Safari jumps all the way back to whatever page was shown before
+		//	the page that uses dojo.undo.browser support.
+		//	IE 5.5 SP2:
+		//	back button behavior is macro. It does not move back to the
+		//	previous hash value, but to the last full page load. This suggests
+		//	that the iframe is the correct way to capture the back button in
+		//	these cases.
+		//	Don't test this page using local disk for MSIE. MSIE will not create 
+		//	a history list for iframe_history.html if served from a file: URL. 
+		//	The XML served back from the XHR tests will also not be properly 
+		//	created if served from local disk. Serve the test pages from a web 
+		//	server to test in that browser.
+		//	IE 6.0:
+		//	same behavior as IE 5.5 SP2
+		//	Firefox 1.0+:
+		//	the back button will return us to the previous hash on the same
+		//	page, thereby not requiring an iframe hack, although we do then
+		//	need to run a timer to detect inter-page movement.
+
+		//If addToHistory is called, then that means we prune the
+		//forward stack -- the user went back, then wanted to
+		//start a new forward path.
+		forwardStack = []; 
+
+		var hash = null;
+		var url = null;
+		if(!historyIframe){
+			if(djConfig["useXDomain"] && !djConfig["dojoIframeHistoryUrl"]){
+				console.debug("dojo.back: When using cross-domain Dojo builds,"
+					+ " please save iframe_history.html to your domain and set djConfig.dojoIframeHistoryUrl"
+					+ " to the path on your domain to iframe_history.html");
+			}
+			historyIframe = window.frames["dj_history"];
+		}
+		if(!bookmarkAnchor){
+			bookmarkAnchor = document.createElement("a");
+			dojo.body().appendChild(bookmarkAnchor);
+			bookmarkAnchor.style.display = "none";
+		}
+		if(args["changeUrl"]){
+			hash = "#"+ ((args["changeUrl"]!==true) ? args["changeUrl"] : (new Date()).getTime());
+			
+			//If the current hash matches the new one, just replace the history object with
+			//this new one. It doesn't make sense to track different state objects for the same
+			//logical URL. This matches the browser behavior of only putting in one history
+			//item no matter how many times you click on the same #hash link, at least in Firefox
+			//and Safari, and there is no reliable way in those browsers to know if a #hash link
+			//has been clicked on multiple times. So making this the standard behavior in all browsers
+			//so that dojo.back's behavior is the same in all browsers.
+			if(historyStack.length == 0 && initialState.urlHash == hash){
+				initialState = createState(url, args, hash);
+				return;
+			}else if(historyStack.length > 0 && historyStack[historyStack.length - 1].urlHash == hash){
+				historyStack[historyStack.length - 1] = createState(url, args, hash);
+				return;
+			}
+
+			changingUrl = true;
+			setTimeout(function() { 
+					setHash(hash); 
+					changingUrl = false; 					
+				}, 1);
+			bookmarkAnchor.href = hash;
+			
+			if(dojo.isIE){
+				url = loadIframeHistory();
+
+				var oldCB = args["back"]||args["backButton"]||args["handle"];
+
+				//The function takes handleName as a parameter, in case the
+				//callback we are overriding was "handle". In that case,
+				//we will need to pass the handle name to handle.
+				var tcb = function(handleName){
+					if(getHash() != ""){
+						setTimeout(function() { setHash(hash); }, 1);
+					}
+					//Use apply to set "this" to args, and to try to avoid memory leaks.
+					oldCB.apply(this, [handleName]);
+				};
+		
+				//Set interceptor function in the right place.
+				if(args["back"]){
+					args.back = tcb;
+				}else if(args["backButton"]){
+					args.backButton = tcb;
+				}else if(args["handle"]){
+					args.handle = tcb;
+				}
+		
+				var oldFW = args["forward"]||args["forwardButton"]||args["handle"];
+		
+				//The function takes handleName as a parameter, in case the
+				//callback we are overriding was "handle". In that case,
+				//we will need to pass the handle name to handle.
+				var tfw = function(handleName){
+					if(getHash() != ""){
+						setHash(hash);
+					}
+					if(oldFW){ // we might not actually have one
+						//Use apply to set "this" to args, and to try to avoid memory leaks.
+						oldFW.apply(this, [handleName]);
+					}
+				};
+
+				//Set interceptor function in the right place.
+				if(args["forward"]){
+					args.forward = tfw;
+				}else if(args["forwardButton"]){
+					args.forwardButton = tfw;
+				}else if(args["handle"]){
+					args.handle = tfw;
+				}
+
+			}else if(!dojo.isIE){
+				// start the timer
+				if(!locationTimer){
+					locationTimer = setInterval(checkLocation, 5000);
+				}
+				
+			}
+		}else{
+			url = loadIframeHistory();
+		}
+
+		historyStack.push(createState(url, args, hash));
+	};
+
+
+	back.iframeLoaded = function(evt, ifrLoc){
+		//summary: private method. Do not call this directly.
+		var query = getUrlQuery(ifrLoc.href);
+		if(query == null){ 
+			// alert("iframeLoaded");
+			// we hit the end of the history, so we should go back
+			if(historyStack.length == 1){
+				handleBackButton();
+			}
+			return;
+		}
+		if(moveForward){
+			// we were expecting it, so it's not either a forward or backward movement
+			moveForward = false;
+			return;
+		}
+	
+		//Check the back stack first, since it is more likely.
+		//Note that only one step back or forward is supported.
+		if(historyStack.length >= 2 && query == getUrlQuery(historyStack[historyStack.length-2].url)){
+			handleBackButton();
+		}
+		else if(forwardStack.length > 0 && query == getUrlQuery(forwardStack[forwardStack.length-1].url)){
+			handleForwardButton();
+		}
+	};
+ })();

Added: trunk/examples/typeface/root/static/dojo/dojo/behavior.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/behavior.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/behavior.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,181 @@
+dojo.provide("dojo.behavior");
+
+dojo.behavior = new function(){
+	function arrIn(obj, name){
+		if(!obj[name]){ obj[name] = []; }
+		return obj[name];
+	}
+
+	var _inc = 0;
+
+	function forIn(obj, scope, func){
+		var tmpObj = {};
+		for(var x in obj){
+			if(typeof tmpObj[x] == "undefined"){
+				if(!func){
+					scope(obj[x], x);
+				}else{
+					func.call(scope, obj[x], x);
+				}
+			}
+		}
+	}
+
+	// FIXME: need a better test so we don't exclude nightly Safari's!
+	this._behaviors = {};
+	this.add = function(behaviorObj){
+		//	summary:
+		//		add the specified behavior to the list of behaviors which will
+		//		be applied the next time apply() is called. Calls to add() for
+		//		an already existing behavior do not replace the previous rules,
+		//		but are instead additive. New nodes which match the rule will
+		//		have all add()-ed behaviors applied to them when matched.
+		//
+		//	description:
+		//		behavior objects are specified in the following format(s):
+		//		
+		//			{ 
+		//			 	"#id": {
+		//					"found": function(element){
+		//						// ...
+		//					},
+		//			
+		//					"onblah": {targetObj: foo, targetFunc: "bar"},
+		//			
+		//					"onblarg": "/foo/bar/baz/blarg",
+		//			
+		//					"onevent": function(evt){
+		//					},
+		//			
+		//					"onotherevent: function(evt){
+		//						// ...
+		//					}
+		//				},
+		//			
+		//				"#id2": {
+		//					// ...
+		//				},
+		//			
+		//				"#id3": function(element){
+		//					// ...
+		//				},
+		//			
+		//				// publish the match on a topic
+		//				"#id4": "/found/topic/name",
+		//			
+		//				// match all direct descendants
+		//				"#id4 > *": function(element){
+		//					// ...
+		//				},
+		//			
+		//				// match the first child node that's an element
+		//				"#id4 > :first-child": { ... },
+		//			
+		//				// match the last child node that's an element
+		//				"#id4 > :last-child":  { ... },
+		//			
+		//				// all elements of type tagname
+		//				"tagname": {
+		//					// ...
+		//				},
+		//			
+		//				"tagname1 tagname2 tagname3": {
+		//					// ...
+		//				},
+		//			
+		//				".classname": {
+		//					// ...
+		//				},
+		//			
+		//				"tagname.classname": {
+		//					// ...
+		//				},
+		//			}
+		//		
+		//		The "found" method is a generalized handler that's called as soon
+		//		as the node matches the selector. Rules for values that follow also
+		//		apply to the "found" key.
+		//		
+		//		The "on*" handlers are attached with dojo.connect(). 
+		//		
+		//		If the value corresponding to the ID key is a function and not a
+		//		list, it's treated as though it was the value of "found".
+
+		var tmpObj = {};
+		forIn(behaviorObj, this, function(behavior, name){
+			var tBehavior = arrIn(this._behaviors, name);
+			if(typeof tBehavior["id"] != "number"){
+				tBehavior.id = _inc++;
+			}
+			var cversion = [];
+			tBehavior.push(cversion);
+			if((dojo.isString(behavior))||(dojo.isFunction(behavior))){
+				behavior = { found: behavior };
+			}
+			forIn(behavior, function(rule, ruleName){
+				arrIn(cversion, ruleName).push(rule);
+			});
+		});
+	}
+
+	var _applyToNode = function(node, action, ruleSetName){
+		if(dojo.isString(action)){
+			if(ruleSetName == "found"){
+				dojo.publish(action, [ node ]);
+			}else{
+				dojo.connect(node, ruleSetName, function(){
+					dojo.publish(action, arguments);
+				});
+			}
+		}else if(dojo.isFunction(action)){
+			if(ruleSetName == "found"){
+				action(node);
+			}else{
+				dojo.connect(node, ruleSetName, action);
+			}
+		}
+	}
+
+	this.apply = function(){
+		// summary:
+		//		applies all currently registered behaviors to the document,
+		//		taking care to ensure that only incremental updates are made
+		//		since the last time add() or apply() were called. If new
+		//		matching nodes have been added, all rules in a behavior will be
+		//		applied to that node. For previously matched nodes, only
+		//		behaviors which have been added since the last call to apply()
+		//		will be added to the nodes.
+		forIn(this._behaviors, function(tBehavior, id){
+			dojo.query(id).forEach( 
+				function(elem){
+					var runFrom = 0;
+					var bid = "_dj_behavior_"+tBehavior.id;
+					if(typeof elem[bid] == "number"){
+						runFrom = elem[bid];
+						// console.debug(bid, runFrom);
+						if(runFrom == (tBehavior.length)){
+							return;
+						}
+					}
+					// run through the versions, applying newer rules at each step
+
+					for(var x=runFrom, tver; tver = tBehavior[x]; x++){
+						// console.debug(tver);
+						forIn(tver, function(ruleSet, ruleSetName){
+							if(dojo.isArray(ruleSet)){
+								dojo.forEach(ruleSet, function(action){
+									_applyToNode(elem, action, ruleSetName);
+								});
+							}
+						});
+					}
+
+					// ensure that re-application only adds new rules to the node
+					elem[bid] = tBehavior.length;
+				}
+			);
+		});
+	}
+}
+
+dojo.addOnLoad(dojo.behavior, "apply");

Added: trunk/examples/typeface/root/static/dojo/dojo/build.txt
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/build.txt	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/build.txt	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,39 @@
+Files baked into this build:
+
+dojo.js:
+jslib/dojoGuardStart.jsfrag
+../../dojo/_base/_loader/bootstrap.js
+../../dojo/_base/_loader/loader.js
+jslib/dojoGuardEnd.jsfrag
+../../dojo/_base/_loader/hostenv_browser.js
+./../../release/dojo/dojo/_base/lang.js
+./../../release/dojo/dojo/_base/declare.js
+./../../release/dojo/dojo/_base/connect.js
+./../../release/dojo/dojo/_base/Deferred.js
+./../../release/dojo/dojo/_base/json.js
+./../../release/dojo/dojo/_base/array.js
+./../../release/dojo/dojo/_base.js
+./../../release/dojo/dojo/_base/event.js
+./../../release/dojo/dojo/_base/html.js
+./../../release/dojo/dojo/_base/NodeList.js
+./../../release/dojo/dojo/_base/query.js
+./../../release/dojo/dojo/_base/xhr.js
+./../../release/dojo/dojo/_base/fx.js
+
+../dijit/dijit.js:
+./../../release/dojo/dijit/util/manager.js
+./../../release/dojo/dijit/base/Widget.js
+./../../release/dojo/dijit/base/Container.js
+./../../release/dojo/dijit/base/Layout.js
+./../../release/dojo/dijit/base/Showable.js
+./../../release/dojo/dijit/util/sniff.js
+./../../release/dojo/dijit/util/wai.js
+./../../release/dojo/dijit/base/FormElement.js
+./../../release/dojo/dojo/string.js
+./../../release/dojo/dojo/date/stamp.js
+./../../release/dojo/dijit/util/parser.js
+./../../release/dojo/dijit/base/TemplatedWidget.js
+./../../release/dojo/dijit/util/FocusManager.js
+./../../release/dojo/dijit/util/BackgroundIframe.js
+./../../release/dojo/dijit/util/place.js
+./../../release/dojo/dijit/dijit.js

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/README
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/README	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/README	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,18 @@
+All files within this directory were derived from the Common Locale
+Data Repository (see http://unicode.org/cldr)  The CLDR project is
+responsible for the accuracy and maintenance of this data.  A copy
+of this data is checked into the Dojo util project as a zip file.
+The XML data is transformed to the JSON-style Javascript you see
+under the nls/ directory.  These Javascript files include data
+necessary to do things like format and parse dates, numbers, and
+currencies in different locales to consider cultural differences.
+They are used by other modules in core Dojo such as dojo.date,
+dojo.number and dojo.currency.  It usually is not necessary to use
+dojo.cldr directly.
+
+An arbitrary subset of locales have been checked in to dojo/cldr
+under svn.  To support other locales, the full set may be generated
+by using xslt scripts in the util/buildscripts/cldr/ ant script.
+Hundreds of locales are supported by the CLDR project.
+
+See terms of use: http://www.unicode.org/copyright.html#Exhibit1

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/monetary.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/monetary.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/monetary.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,23 @@
+dojo.provide("dojo.cldr.monetary");
+
+dojo.cldr.monetary.getData = function(code){
+// summary: A mapping of currency code to currency-specific formatting information. Returns a unique object with properties: places, round.
+// code: an iso4217 currency code
+
+// from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/currencyData/fractions
+
+	var placesData = {
+		ADP:0,BHD:3,BIF:0,BYR:0,CLF:0,CLP:0,DJF:0,ESP:0,GNF:0,
+		IQD:3,ITL:0,JOD:3,JPY:0,KMF:0,KRW:0,KWD:3,LUF:0,LYD:3,
+		MGA:0,MGF:0,OMR:3,PYG:0,RWF:0,TND:3,TRL:0,VUV:0,XAF:0,
+		XOF:0,XPF:0
+	};
+
+	var roundingData = {CHF:5};
+
+	var places = placesData[code], round = roundingData[code];
+	if(typeof places == "undefined"){ places = 2; }
+	if(typeof round == "undefined"){ round = 0; }
+
+	return {places: places, round: round}; // Object
+};

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,12 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers/currencies
+({
+	EUR_displayName:"EUR",
+	EUR_symbol:"€",
+	GBP_displayName:"GBP",
+	GBP_symbol:"£",
+	JPY_displayName:"JPY",
+	JPY_symbol:"Â¥",
+	USD_displayName:"USD",
+	USD_symbol:"$"
+})
+                 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,13 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers/currencies
+({
+	AUD_displayName:"Australischer Dollar",
+	CAD_displayName:"Kanadischer Dollar",
+	CHF_displayName:"Schweizer Franken",
+	CHF_symbol:"SFr.",
+	EUR_displayName:"Euro",
+	GBP_displayName:"Pfund Sterling",
+	HKD_displayName:"Hongkong Dollar",
+	JPY_displayName:"Yen",
+	USD_displayName:"US Dollar"
+})
+                 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,20 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'months-format-abbr':["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],
+        'months-format-wide':["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],
+        'months-standAlone-narrow':["J","F","M","A","M","J","J","A","S","O","N","D"],
+        'days-format-abbr':["So","Mo","Di","Mi","Do","Fr","Sa"],
+        'days-format-wide':["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"],
+        'days-standAlone-narrow':["S","M","D","M","D","F","S"],
+        'quarters-format-wide':["1. Quartal","2. Quartal","3. Quartal","4. Quartal"],
+        'am':"vorm.",
+        'pm':"nachm.",
+        'eraNames':["v. Chr.","n. Chr."],
+        'eraAbbr':["v. Chr.","n. Chr."],
+        'dateFormat-full': "EEEE, d. MMMM yyyy",
+        'dateFormat-long': "d. MMMM yyyy",
+        'dateFormat-medium': "dd.MM.yyyy",
+        'dateFormat-short': "dd.MM.yy",
+        'timeFormat-full': "H:mm' Uhr 'z"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,6 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'decimal':",",
+        'group':".",
+        'percentFormat':"#,##0 %"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de-de/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de-de/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/de-de/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'currencyFormat':"#,##0.00 ¤"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,17 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers/currencies
+({
+	AUD_displayName:"Australian Dollar",
+	AUD_symbol:"$A",
+	CAD_displayName:"Canadian Dollar",
+	CAD_symbol:"Can$",
+	CHF_displayName:"Swiss Franc",
+	CHF_symbol:"SwF",
+	EUR_displayName:"Euro",
+	GBP_displayName:"British Pound Sterling",
+	HKD_displayName:"Hong Kong Dollar",
+	HKD_symbol:"HK$",
+	JPY_displayName:"Japanese Yen",
+	USD_displayName:"US Dollar",
+	USD_symbol:"US$"
+})
+                 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,22 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'months-format-abbr':["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],
+        'months-format-wide':["January","February","March","April","May","June","July","August","September","October","November","December"],
+        'months-standAlone-narrow':["J","F","M","A","M","J","J","A","S","O","N","D"],
+        'days-format-abbr':["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],
+        'days-format-wide':["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
+        'days-standAlone-narrow':["S","M","T","W","T","F","S"],
+        'quarters-format-wide':["1st quarter","2nd quarter","3rd quarter","4th quarter"],
+        'eraNames':["Before Christ","Anno Domini"],
+        'eraAbbr':["BC","AD"],
+        'dateFormat-full': "EEEE, MMMM d, yyyy",
+        'dateFormat-long': "MMMM d, yyyy",
+        'dateFormat-medium': "MMM d, yyyy",
+        'dateFormat-short': "M/d/yy",
+        'timeFormat-full': "h:mm:ss a v",
+        'timeFormat-long': "h:mm:ss a z",
+        'timeFormat-medium': "h:mm:ss a",
+        'timeFormat-short': "h:mm a",
+        'field-dayperiod':"AM/PM"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'currencyFormat':"¤#,##0.00"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-au/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-au/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-au/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers/currencies
+({
+	AUD_symbol:"$"
+})
+                 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-au/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-au/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-au/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'dateFormat-full': "EEEE, d MMMM yyyy",
+        'dateFormat-long': "d MMMM yyyy",
+        'dateFormat-medium': "dd/MM/yyyy",
+        'dateFormat-short': "d/MM/yy",
+        'timeFormat-long': "h:mm:ss a"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-ca/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-ca/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-ca/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers/currencies
+({
+	CAD_symbol:"$"
+})
+                 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-ca/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-ca/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-ca/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,6 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'dateFormat-medium': "d-MMM-yy",
+        'dateFormat-short': "dd/MM/yy"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-ca/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-ca/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-ca/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'currencyFormat':"¤#,##0.00;(¤#,##0.00)"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-gb/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-gb/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-gb/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,12 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'dateFormat-full': "EEEE, d MMMM yyyy",
+        'dateFormat-long': "d MMMM yyyy",
+        'dateFormat-medium': "d MMM yyyy",
+        'dateFormat-short': "dd/MM/yyyy",
+        'timeFormat-full': "HH:mm:ss z",
+        'timeFormat-long': "HH:mm:ss z",
+        'timeFormat-medium': "HH:mm:ss",
+        'timeFormat-short': "HH:mm"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-us/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-us/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-us/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers/currencies
+({
+	USD_symbol:"$"
+})
+                 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-us/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-us/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/en-us/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'currencyFormat':"¤#,##0.00;(¤#,##0.00)"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,17 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers/currencies
+({
+	AUD_displayName:"dólar australiano",
+	AUD_symbol:"$A",
+	CAD_displayName:"dólar canadiense",
+	CAD_symbol:"Can$",
+	CHF_displayName:"franco suizo",
+	CHF_symbol:"SwF",
+	EUR_displayName:"euro",
+	GBP_displayName:"libra esterlina británica",
+	HKD_displayName:"dólar de Hong Kong",
+	HKD_symbol:"HK$",
+	JPY_displayName:"yen japonés",
+	USD_displayName:"dólar estadounidense",
+	USD_symbol:"US$"
+})
+                 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,31 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'months-format-abbr':["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],
+        'months-format-wide':["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],
+        'months-standAlone-narrow':["E","F","M","A","M","J","J","A","S","O","N","D"],
+        'days-format-abbr':["dom","lun","mar","mié","jue","vie","sáb"],
+        'days-format-wide':["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],
+        'days-standAlone-narrow':["D","L","M","M","J","V","S"],
+        'quarters-format-abbreviated':["T1","T2","T3","T4"],
+        'quarters-format-wide':["1er trimestre","2º trimestre","3er trimestre","4º trimestre"],
+        'am':"a.m.",
+        'pm':"p.m.",
+        'eraAbbr':["a.C.","d.C."],
+        'dateFormat-full': "EEEE d' de 'MMMM' de 'yyyy",
+        'dateFormat-long': "d' de 'MMMM' de 'yyyy",
+        'dateFormat-medium': "dd-MMM-yy",
+        'dateFormat-short': "d/MM/yy",
+        'timeFormat-full': "HH'H'mm''ss\" z",
+        'field-era':"era",
+        'field-year':"año",
+        'field-month':"mes",
+        'field-week':"semana",
+        'field-day':"día",
+        'field-weekday':"día de la semana",
+        'field-dayperiod':"periodo del día",
+        'field-hour':"hora",
+        'field-minute':"minuto",
+        'field-second':"segundo",
+        'field-zone':"zona"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,6 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'decimal':",",
+        'group':".",
+        'currencyFormat':"¤#,##0.00;(¤#,##0.00)"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es-es/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es-es/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es-es/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,8 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'dateFormat-medium': "dd/MM/yyyy",
+        'dateFormat-short': "dd/MM/yy",
+        'timeFormat-medium': "H:mm:ss",
+        'timeFormat-short': "H:mm"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es-es/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es-es/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/es-es/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'currencyFormat':"#,##0.00 ¤"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/fr/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/fr/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/fr/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,13 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers/currencies
+({
+	AUD_displayName:"dollar australien",
+	CAD_displayName:"dollar canadien",
+	CHF_displayName:"franc suisse",
+	CHF_symbol:"sFr.",
+	EUR_displayName:"euro",
+	GBP_displayName:"livre sterling",
+	HKD_displayName:"dollar de Hong Kong",
+	JPY_displayName:"yen",
+	USD_displayName:"dollar des États-Unis"
+})
+                 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/fr/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/fr/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/fr/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,19 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'months-format-abbr':["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc."],
+        'months-format-wide':["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],
+        'months-standAlone-narrow':["J","F","M","A","M","J","J","A","S","O","N","D"],
+        'days-format-abbr':["dim.","lun.","mar.","mer.","jeu.","ven.","sam."],
+        'days-format-wide':["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],
+        'days-standAlone-narrow':["D","L","M","M","J","V","S"],
+        'quarters-format-abbreviated':["T1","T2","T3","T4"],
+        'quarters-format-wide':["1er trimestre","2e trimestre","3e trimestre","4e trimestre"],
+        'eraNames':["av. J.-C.","ap. J.-C."],
+        'eraAbbr':["av. J.-C.","apr. J.-C."],
+        'dateFormat-full': "EEEE d MMMM yyyy",
+        'dateFormat-long': "d MMMM yyyy",
+        'dateFormat-medium': "d MMM yy",
+        'dateFormat-short': "dd/MM/yy",
+        'timeFormat-full': "HH' h 'mm z"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/fr/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/fr/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/fr/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,7 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'decimal':",",
+        'group':" ",
+        'percentFormat':"#,##0 %",
+        'currencyFormat':"#,##0.00 ¤"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,47 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'months-format-abbr':["1","2","3","4","5","6","7","8","9","10","11","12"],
+        'months-format-wide':["1","2","3","4","5","6","7","8","9","10","11","12"],
+        'months-standAlone-narrow':["1","2","3","4","5","6","7","8","9","10","11","12"],
+        'days-format-abbr':["1","2","3","4","5","6","7"],
+        'days-format-wide':["1","2","3","4","5","6","7"],
+        'days-standAlone-narrow':["1","2","3","4","5","6","7"],
+        'quarters-format-abbreviated':["Q1","Q2","Q3","Q4"],
+        'quarters-format-wide':["Q1","Q2","Q3","Q4"],
+        'am':"AM",
+        'pm':"PM",
+        'eraNames':["BCE","CE"],
+        'eraAbbr':["BCE","CE"],
+        'dateFormat-full': "EEEE, yyyy MMMM dd",
+        'dateFormat-long': "yyyy MMMM d",
+        'dateFormat-medium': "yyyy MMM d",
+        'dateFormat-short': "yy/MM/dd",
+        'timeFormat-full': "HH:mm:ss z",
+        'timeFormat-long': "HH:mm:ss z",
+        'timeFormat-medium': "HH:mm:ss",
+        'timeFormat-short': "HH:mm",
+        'dateTimeFormat': "{1} {0}" ,
+        'dateTimeFormats-appendItem-Day':"{0} ({2}: {1})",
+        'dateTimeFormats-appendItem-Day-Of-Week':"{0} {1}",
+        'dateTimeFormats-appendItem-Era':"{0} {1}",
+        'dateTimeFormats-appendItem-Hour':"{0} ({2}: {1})",
+        'dateTimeFormats-appendItem-Minute':"{0} ({2}: {1})",
+        'dateTimeFormats-appendItem-Month':"{0} ({2}: {1})",
+        'dateTimeFormats-appendItem-Quarter':"{0} ({2}: {1})",
+        'dateTimeFormats-appendItem-Second':"{0} ({2}: {1})",
+        'dateTimeFormats-appendItem-Timezone':"{0} {1}",
+        'dateTimeFormats-appendItem-Week':"{0} ({2}: {1})",
+        'dateTimeFormats-appendItem-Year':"{0} {1}",
+        'field-era':"Era",
+        'field-year':"Year",
+        'field-month':"Month",
+        'field-week':"Week",
+        'field-day':"Day",
+        'field-weekday':"Day of the Week",
+        'field-dayperiod':"Dayperiod",
+        'field-hour':"Hour",
+        'field-minute':"Minute",
+        'field-second':"Second",
+        'field-zone':"Zone"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,13 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers/currencies
+({
+	AUD_displayName:"Dollaro Australiano",
+	CAD_displayName:"Dollaro Canadese",
+	CHF_displayName:"Franco Svizzero",
+	CHF_symbol:"SFr.",
+	EUR_displayName:"Euro",
+	GBP_displayName:"Sterlina Inglese",
+	HKD_displayName:"Dollaro di Hong Kong",
+	JPY_displayName:"Yen Giapponese",
+	USD_displayName:"Dollaro Statunitense"
+})
+                 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,30 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'months-format-abbr':["gen","feb","mar","apr","mag","giu","lug","ago","set","ott","nov","dic"],
+        'months-format-wide':["gennaio","febbraio","marzo","aprile","maggio","giugno","luglio","agosto","settembre","ottobre","novembre","dicembre"],
+        'months-standAlone-narrow':["G","F","M","A","M","G","L","A","S","O","N","D"],
+        'days-format-abbr':["dom","lun","mar","mer","gio","ven","sab"],
+        'days-format-wide':["domenica","lunedì","martedì","mercoledì","giovedì","venerdì","sabato"],
+        'days-standAlone-narrow':["D","L","M","M","G","V","S"],
+        'quarters-format-abbreviated':["T1","T2","T3","T4"],
+        'quarters-format-wide':["1o trimestre","2o trimestre","3o trimestre","4o trimestre"],
+        'am':"m.",
+        'pm':"p.",
+        'eraAbbr':["aC","dC"],
+        'dateFormat-full': "EEEE d MMMM yyyy",
+        'dateFormat-long': "dd MMMM yyyy",
+        'dateFormat-medium': "dd/MMM/yy",
+        'dateFormat-short': "dd/MM/yy",
+        'field-era':"era",
+        'field-year':"anno",
+        'field-month':"mese",
+        'field-week':"settimana",
+        'field-day':"giorno",
+        'field-weekday':"giorno della settimana",
+        'field-dayperiod':"periodo del giorno",
+        'field-hour':"ora",
+        'field-minute':"minuto",
+        'field-second':"secondo",
+        'field-zone':"zona"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'decimal':",",
+        'group':"."
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it-it/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it-it/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/it-it/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'timeFormat-long': "H:mm:ss z"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,13 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers/currencies
+({
+	AUD_displayName:"オーストラリア ドル",
+	CAD_displayName:"カナダ ドル",
+	CHF_displayName:"スイス フラン",
+	EUR_displayName:"ユーロ",
+	GBP_displayName:"英国ポンド",
+	HKD_displayName:"香港ドル",
+	JPY_displayName:"日本円",
+	JPY_symbol:"ï¿¥",
+	USD_displayName:"米ドル"
+})
+                 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,21 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'months-format-abbr':["1 月","2 月","3 月","4 月","5 月","6 月","7 月","8 月","9 月","10 月","11 月","12 月"],
+        'months-format-wide':["1 月","2 月","3 月","4 月","5 月","6 月","7 月","8 月","9 月","10 月","11 月","12 月"],
+        'days-format-abbr':["日","月","火","水","木","金","土"],
+        'days-format-wide':["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"],
+        'days-standAlone-narrow':["日","月","火","水","木","金","土"],
+        'quarters-format-wide':["第 1 四半期","第 2 四半期","第 3 四半期","第 4 四半期"],
+        'am':"午前",
+        'pm':"午後",
+        'eraNames':["紀元前","西暦"],
+        'eraAbbr':["紀元前","西暦"],
+        'dateFormat-full': "yyyy'年'M'月'd'日'EEEE",
+        'dateFormat-long': "yyyy'年'M'月'd'日'",
+        'dateFormat-medium': "yyyy/MM/dd",
+        'timeFormat-full': "H'時'mm'分'ss'秒'z",
+        'timeFormat-long': "H:mm:ss:z",
+        'timeFormat-medium': "H:mm:ss",
+        'timeFormat-short': "H:mm"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja-jp/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja-jp/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ja-jp/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'currencyFormat':"¤#,##0.00"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,14 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers/currencies
+({
+	AUD_displayName:"호주 달러",
+	CAD_displayName:"캐나다 달러",
+	CHF_displayName:"스위스 프랑달러",
+	EUR_displayName:"유로화",
+	GBP_displayName:"영국령 파운드 스털링",
+	HKD_displayName:"홍콩 달러",
+	JPY_displayName:"일본 엔화",
+	JPY_symbol:"ï¿¥",
+	USD_displayName:"미국 달러",
+	USD_symbol:"US$"
+})
+                 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,22 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'months-format-abbr':["1ì›”","2ì›”","3ì›”","4ì›”","5ì›”","6ì›”","7ì›”","8ì›”","9ì›”","10ì›”","11ì›”","12ì›”"],
+        'months-format-wide':["1ì›”","2ì›”","3ì›”","4ì›”","5ì›”","6ì›”","7ì›”","8ì›”","9ì›”","10ì›”","11ì›”","12ì›”"],
+        'months-standAlone-narrow':["1ì›”","2ì›”","3ì›”","4ì›”","5ì›”","6ì›”","7ì›”","8ì›”","9ì›”","10ì›”","11ì›”","12ì›”"],
+        'days-format-abbr':["일","월","화","수","목","금","토"],
+        'days-format-wide':["일요일","월요일","화요일","수요일","목요일","금요일","토요일"],
+        'days-standAlone-narrow':["일","월","화","수","목","금","토"],
+        'am':"오전",
+        'pm':"오후",
+        'eraNames':["서력기원전","서력기원"],
+        'eraAbbr':["기원전","서기"],
+        'dateFormat-full': "yyyy'년' M'월' d'일' EEEE",
+        'dateFormat-long': "yyyy'년' M'월' d'일'",
+        'dateFormat-medium': "yyyy. MM. dd",
+        'dateFormat-short': "yy. MM. dd",
+        'timeFormat-full': "a hh'시' mm'분' ss'초' z",
+        'timeFormat-long': "a hh'시' mm'분' ss'초'",
+        'timeFormat-medium': "a hh'시' mm'분'",
+        'timeFormat-short': "a hh'시' mm'분'"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko-kr/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko-kr/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko-kr/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,6 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'timeFormat-medium': "a h:mm:ss",
+        'timeFormat-short': "a h:mm"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko-kr/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko-kr/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/ko-kr/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'currencyFormat':"¤#,##0.00"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,25 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'decimal':".",
+        'group':",",
+        'list':";",
+        'percentSign':"%",
+        'nativeZeroDigit':"0",
+        'patternDigit':"#",
+        'plusSign':"+",
+        'minusSign':"-",
+        'exponential':"E",
+        'perMille':"‰",
+        'infinity':"∞",
+        'nan':"NaN",
+        'decimalFormat':"#,##0.###",
+        'scientificFormat':"#E0",
+        'percentFormat':"#,##0%",
+        'currencySpacing-beforeCurrency-currencyMatch':"[:letter:]",
+        'currencySpacing-beforeCurrency-surroundingMatch':"[:digit:]",
+        'currencySpacing-beforeCurrency-insertBetween':" ",
+        'currencySpacing-afterCurrency-currencyMatch':"[:letter:]",
+        'currencySpacing-afterCurrency-surroundingMatch':"[:digit:]",
+        'currencySpacing-afterCurrency-insertBetween':" ",
+        'currencyFormat':"¤ #,##0.00"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,12 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers/currencies
+({
+	AUD_displayName:"Dólar australiano",
+	CAD_displayName:"Dólar canadense",
+	CHF_displayName:"Franco suíço",
+	EUR_displayName:"Euro",
+	GBP_displayName:"Libra esterlina britânica",
+	HKD_displayName:"Dólar de Hong Kong",
+	JPY_displayName:"Iene japonês",
+	USD_displayName:"Dólar norte-americano"
+})
+                 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,18 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'months-format-abbr':["jan","fev","mar","abr","mai","jun","jul","ago","set","out","nov","dez"],
+        'months-format-wide':["janeiro","fevereiro","março","abril","maio","junho","julho","agosto","setembro","outubro","novembro","dezembro"],
+        'months-standAlone-narrow':["J","F","M","A","M","J","J","A","S","O","N","D"],
+        'days-format-abbr':["dom","seg","ter","qua","qui","sex","sáb"],
+        'days-format-wide':["domingo","segunda-feira","terça-feira","quarta-feira","quinta-feira","sexta-feira","sábado"],
+        'days-standAlone-narrow':["D","S","T","Q","Q","S","S"],
+        'quarters-format-abbreviated':["T1","T2","T3","T4"],
+        'quarters-format-wide':["1º trimestre","2º trimestre","3º trimestre","4º trimestre"],
+        'eraAbbr':["a.C.","d.C."],
+        'dateFormat-full': "EEEE, d' de 'MMMM' de 'yyyy",
+        'dateFormat-long': "d' de 'MMMM' de 'yyyy",
+        'dateFormat-medium': "d/MMM/yyyy",
+        'dateFormat-short': "dd-MM-yyyy",
+        'timeFormat-full': "HH'H'mm'm'ss's' z"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'decimal':",",
+        'group':"."
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt-br/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt-br/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/pt-br/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,18 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'dateFormat-medium': "dd/MM/yyyy",
+        'dateFormat-short': "dd/MM/yy",
+        'timeFormat-full': "HH'h'mm'min'ss's' z",
+        'timeFormat-long': "H'h'm'min's's' z",
+        'field-year':"Ano",
+        'field-month':"Mês",
+        'field-week':"Semana",
+        'field-day':"Dia",
+        'field-weekday':"Dia da semana",
+        'field-dayperiod':"Período do dia",
+        'field-hour':"Hora",
+        'field-minute':"Minuto",
+        'field-second':"Segundo",
+        'field-zone':"Fuso"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,15 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers/currencies
+({
+	AUD_displayName:"澳大利亚元",
+	CAD_displayName:"加拿大元",
+	CHF_displayName:"瑞士法郎",
+	EUR_displayName:"欧元",
+	GBP_displayName:"英磅",
+	HKD_displayName:"港元",
+	HKD_symbol:"HK$",
+	JPY_displayName:"日元",
+	JPY_symbol:"JPÂ¥",
+	USD_displayName:"美元",
+	USD_symbol:"US$"
+})
+                 
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,13 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'months-format-abbr':["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],
+        'months-format-wide':["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],
+        'months-standAlone-narrow':["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],
+        'days-format-abbr':["周日","周一","周二","周三","周四","周五","周六"],
+        'days-format-wide':["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],
+        'days-standAlone-narrow':["日","一","二","三","四","五","六"],
+        'am':"上午",
+        'pm':"下午",
+        'eraAbbr':["公元前","公元"]
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-cn/gregorian.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-cn/gregorian.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-cn/gregorian.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,12 @@
+// generated from ldml/main/*.xml, xpath: ldml/calendars/calendar-gregorian
+({
+        'dateFormat-full': "yyyy'年'M'月'd'日'EEEE",
+        'dateFormat-long': "yyyy'年'M'月'd'日'",
+        'dateFormat-medium': "yyyy-M-d",
+        'dateFormat-short': "yy-M-d",
+        'timeFormat-full': "ahh'时'mm'分'ss'秒' z",
+        'timeFormat-long': "ahh'时'mm'分'ss'秒'",
+        'timeFormat-medium': "ahh:mm:ss",
+        'timeFormat-short': "ah:mm"
+})
+                        
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-cn/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-cn/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-cn/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'currencyFormat':"¤#,##0.00"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-tw/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-tw/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/nls/zh-tw/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+// generated from ldml/main/*.xml, xpath: ldml/numbers
+({
+        'currencyFormat':"¤#,##0.00"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/cldr/supplemental.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cldr/supplemental.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cldr/supplemental.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,70 @@
+dojo.provide("dojo.cldr.supplemental");
+
+dojo.require("dojo.i18n");
+
+dojo.cldr.supplemental.getFirstDayOfWeek = function(/*String?*/locale){
+// summary: Returns a zero-based index for first day of the week
+// description:
+//		Returns a zero-based index for first day of the week, as used by the local (Gregorian) calendar.
+//		e.g. Sunday (returns 0), or Monday (returns 1)
+
+	// from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/firstDay
+	var firstDay = {/*default is 1=Monday*/
+		mv:5,
+		ae:6,af:6,bh:6,dj:6,dz:6,eg:6,er:6,et:6,iq:6,ir:6,jo:6,ke:6,kw:6,lb:6,ly:6,ma:6,om:6,qa:6,sa:6,
+		sd:6,so:6,tn:6,ye:6,
+		as:0,au:0,az:0,bw:0,ca:0,cn:0,fo:0,ge:0,gl:0,gu:0,hk:0,ie:0,il:0,is:0,jm:0,jp:0,kg:0,kr:0,la:0,
+		mh:0,mo:0,mp:0,mt:0,nz:0,ph:0,pk:0,sg:0,th:0,tt:0,tw:0,um:0,us:0,uz:0,vi:0,za:0,zw:0,
+		et:0,mw:0,ng:0,tj:0,
+		gb:0,
+		sy:4
+	};
+
+	var country = dojo.cldr.supplemental._region(locale);
+	var dow = firstDay[country];
+	return (typeof dow == 'undefined') ? 1 : dow; /*Number*/
+};
+
+dojo.cldr.supplemental._region = function(/*String?*/locale){
+	locale = dojo.i18n.normalizeLocale(locale);
+	var tags = locale.split('-');
+	var region = tags[1];
+	if(!region){
+		// IE often gives language only (#2269)
+		// Arbitrary mappings of language-only locales to a country:
+        region = {de:"de", en:"us", es:"es", fi:"fi", fr:"fr", hu:"hu", it:"it",
+        ja:"jp", ko:"kr", nl:"nl", pt:"br", sv:"se", zh:"cn"}[tags[0]];
+	}else if(region.length == 4){
+		// The ISO 3166 country code is usually in the second position, unless a
+		// 4-letter script is given. See http://www.ietf.org/rfc/rfc4646.txt
+		region = tags[2];
+	}
+	return region;
+}
+
+dojo.cldr.supplemental.getWeekend = function(/*String?*/locale){
+// summary: Returns a hash containing the start and end days of the weekend
+// description:
+//		Returns a hash containing the start and end days of the weekend according to local custom using locale,
+//		or by default in the user's locale.
+//		e.g. {start:6, end:0}
+
+	// from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/weekend{Start,End}
+	var weekendStart = {/*default is 6=Saturday*/
+		eg:5,il:5,sy:5,
+		'in':0,
+		ae:4,bh:4,dz:4,iq:4,jo:4,kw:4,lb:4,ly:4,ma:4,om:4,qa:4,sa:4,sd:4,tn:4,ye:4		
+	};
+
+	var weekendEnd = {/*default is 0=Sunday*/
+		ae:5,bh:5,dz:5,iq:5,jo:5,kw:5,lb:5,ly:5,ma:5,om:5,qa:5,sa:5,sd:5,tn:5,ye:5,af:5,ir:5,
+		eg:6,il:6,sy:6
+	};
+
+	var country = dojo.cldr.supplemental._region(locale);
+	var start = weekendStart[country];
+	var end = weekendEnd[country];
+	if(typeof start == 'undefined'){start=6;}
+	if(typeof end == 'undefined'){end=0;}
+	return {start:start, end:end}; /*Object {start,end}*/
+};

Added: trunk/examples/typeface/root/static/dojo/dojo/cookie.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/cookie.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/cookie.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,50 @@
+dojo.provide("dojo.cookie");
+
+dojo.cookie = function(/*String*/name, /*String?*/value, /*Object?*/props){
+	//	summary: 
+	//		Get or set a cookie.
+	//
+	// 		If you pass in one argument, the the value of the cookie is returned
+	//
+	// 		If you pass in two arguments, the cookie value is set to the second
+	// 		argument.
+	//
+	// 		If you pass in three arguments, the cookie value is set to the
+	// 		second argument, and the options on the third argument are used for
+	// 		extended properties on the cookie
+	//
+	//	name: The name of the cookie
+	//	value: Optional. The value for the cookie.
+	//	props: 
+	//		Optional additional properties for the cookie
+	//       expires: Date or Number. Number is seen as days.
+	//                If expires is in the past, the cookie will be deleted
+	//                If expires is left out or is 0, the cookie will expire 
+	//                when the browser closes.
+	//       path: String. The path to use for the cookie.
+	//       domain: String. The domain to use for the cookie.
+	//       secure: Boolean. Whether to only send the cookie on secure connections
+	var c = document.cookie;
+	if(arguments.length == 1){
+		var idx = c.lastIndexOf(name+'=');
+		if(idx == -1){ return null; }
+		var start = idx+name.length+1;
+		var end = c.indexOf(';', idx+name.length+1);
+		if(end == -1){ end = c.length; }
+		return decodeURIComponent(c.substring(start, end)); 
+	}else{
+		props = props || {};
+		value = encodeURIComponent(value);
+		if(typeof(props.expires) == "number"){ 
+			var d = new Date();
+			d.setTime(d.getTime()+(props.expires*24*60*60*1000));
+			props.expires = d;
+		}
+		document.cookie = name + "=" + value 
+			+ (props.expires ? "; expires=" + props.expires.toUTCString() : "")
+			+ (props.path ? "; path=" + props.path : "")
+			+ (props.domain ? "; domain=" + props.domain : "")
+			+ (props.secure ? "; secure" : "");
+		return null;
+	}
+};

Added: trunk/examples/typeface/root/static/dojo/dojo/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,99 @@
+dojo.provide("dojo.currency");
+
+dojo.require("dojo.number");
+dojo.require("dojo.i18n");
+dojo.requireLocalization("dojo.cldr", "currency");
+dojo.require("dojo.cldr.monetary");
+
+dojo.currency._mixInDefaults = function(options){
+	options = options || {};
+	options.type = "currency";
+
+	// Get locale-depenent currency data, like the symbol
+	var bundle = dojo.i18n.getLocalization("dojo.cldr", "currency", options.locale) || {};
+
+	// Mixin locale-independent currency data, like # of places
+	var iso = options.currency;
+	var data = dojo.cldr.monetary.getData(iso);
+
+	dojo.forEach(["displayName","symbol","group","decimal"], function(prop){
+		data[prop] = bundle[iso+"_"+prop];
+	});
+
+	data.fractional = [true, false];
+
+	// Mixin with provided options
+	return dojo.mixin(data, options);
+}
+
+dojo.currency.format = function(/*Number*/value, /*Object?*/options){
+// summary:
+//		Format a Number as a String, using locale-specific settings
+//
+// description:
+//		Create a string from a Number using a known localized pattern.
+//		Formatting patterns appropriate to the locale are chosen from the CLDR http://unicode.org/cldr
+//		as well as the appropriate symbols and delimiters.  See http://www.unicode.org/reports/tr35/#Number_Elements
+//
+// value:
+//		the number to be formatted.
+//
+// options: object {currency: String, pattern: String?, places: Number?, round: Number?, symbol: String?, locale: String?}
+//		currency- the ISO4217 currency code, a three letter sequence like "USD"
+//			See http://en.wikipedia.org/wiki/ISO_4217
+//		symbol- override currency symbol. Normally, will be looked up in table of supported currencies, and ISO currency code will
+//			be used if not found.  See dojo.i18n.cldr.nls->currency.js
+//		pattern- override formatting pattern with this string (see dojo.number.applyPattern)
+//		places- fixed number of decimal places to show.  Default is defined by the currency.
+//	    round- 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1 means don't round.
+//		locale- override the locale used to determine formatting rules
+
+	return dojo.number.format(value, dojo.currency._mixInDefaults(options));
+}
+
+dojo.currency.regexp = function(/*Object?*/options){
+//
+// summary:
+//		Builds the regular needed to parse a number
+//
+// description:
+//		returns regular expression with positive and negative match, group and decimal separators
+//
+// options: object {pattern: String, locale: String, strict: Boolean, places: mixed}
+//		currency- the ISO4217 currency code, a three letter sequence like "USD"
+//			See http://en.wikipedia.org/wiki/ISO_4217
+//		symbol- override currency symbol. Normally, will be looked up in table of supported currencies, and ISO currency code will
+//			be used if not found.  See dojo.i18n.cldr.nls->currency.js
+//		pattern- override pattern with this string
+//		locale- override the locale used to determine formatting rules
+//		strict- strict parsing, false by default
+//		places- number of decimal places to accept.  Default is defined by currency.
+	return dojo.number.regexp(dojo.currency._mixInDefaults(options)); // String
+}
+
+dojo.currency.parse = function(/*String*/expression, /*Object?*/options){
+//
+// summary:
+//		Convert a properly formatted string to a primitive Number,
+//		using locale-specific settings.
+//
+// description:
+//		Create a Number from a string using a known localized pattern.
+//		Formatting patterns are chosen appropriate to the locale.
+//		Formatting patterns are implemented using the syntax described at *URL*
+//
+// expression: A string representation of a Number
+//
+// options: object {pattern: string, locale: string, strict: boolean}
+//		currency- the ISO4217 currency code, a three letter sequence like "USD"
+//			See http://en.wikipedia.org/wiki/ISO_4217
+//		symbol- override currency symbol. Normally, will be looked up in table of supported currencies, and ISO currency code will
+//			be used if not found.  See dojo.i18n.cldr.nls->currency.js
+//		pattern- override pattern with this string
+//		locale- override the locale used to determine formatting rules
+//		strict- strict parsing, false by default
+//		places- number of decimal places to accept.  Default is defined by currency.
+//		fractional- where places are implied by pattern or explicit 'places' parameter, whether to include the fractional portion.
+//			By default for currencies, it the fractional portion is optional.
+	return dojo.number.parse(expression, dojo.currency._mixInDefaults(options));
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/data/JsonItemStore.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/data/JsonItemStore.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/data/JsonItemStore.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,441 @@
+dojo.provide("dojo.data.JsonItemStore");
+
+dojo.require("dojo.data.util.filter");
+dojo.require("dojo.data.util.simpleFetch");
+
+dojo.declare("dojo.data.JsonItemStore",
+	null,
+	function(/* Object */ keywordParameters){
+		// summary: initializer
+		// keywordParameters: {url: String}
+		// keywordParameters: {data: jsonObject}
+		this._arrayOfAllItems = [];
+		this._loadFinished = false;
+		this._jsonFileUrl = keywordParameters.url;
+		this._jsonData = keywordParameters.data;
+		this._features = { 'dojo.data.api.Read': true};
+		this._itemsByIdentity = null;
+		this._itemMap = {}; // Simple associative map for making an O(1) isItem.
+		this._storeRef = "_S";  //Default name for the store reference to attach to every item.
+		this._itemId = "_0"; //Default Item Id for isItem to attach to every item.
+	},{
+	//	summary:
+	//		The JsonItemStore implements the dojo.data.api.Read API and reads
+	//		data from JSON files that have contents in this format --
+	//		{ items: [
+	//			{ name:'Kermit', color:'green', age:12, friends:['Gonzo', {reference:{name:'Fozzie Bear'}}]},
+	//			{ name:'Fozzie Bear', wears:['hat', 'tie']},
+	//			{ name:'Miss Piggy', pets:'Foo-Foo'}
+	//		]}
+	//		Note that it can also contain an 'identifer' property that specified which attribute on the items 
+	//		in the array of items that acts as the unique identifier for that item.
+	//
+
+	url: undefined,
+
+	_assertIsItem: function(/* item */ item){
+		//	summary:
+		//      This function tests whether the item passed in is indeed an item in the store.
+		//	item: 
+		//		The item to test for being contained by the store.
+		if(!this.isItem(item)){ 
+			throw new Error("dojo.data.JsonItemStore: a function was passed an item argument that was not an item");
+		}
+	},
+
+	_assertIsAttribute: function(/* item || String */ attribute){
+		//	summary:
+		//      This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
+		//	attribute: 
+		//		The attribute to test for being contained by the store.
+		if(!this.isItem(attribute)){ 
+			throw new Error("dojo.data.JsonItemStore: a function was passed an attribute argument that was not an attribute object nor an attribute name string");
+		}
+	},
+
+	getValue: function(	/* item */ item, 
+						/* attribute || attribute-name-string */ attribute, 
+						/* value? */ defaultValue){
+		//	summary: 
+		//      See dojo.data.api.Read.getValue()
+		var values = this.getValues(item, attribute);
+		return (values.length > 0)?values[0]:defaultValue; //Object || int || Boolean
+	},
+
+	getValues: function(/* item */ item, 
+						/* attribute || attribute-name-string */ attribute){
+		//	summary: 
+		//		See dojo.data.api.Read.getValues()
+		if(typeof attribute !== "string"){
+			this._assertIsAttribute(attribute);
+			attribute = this.getIdentity(attribute);
+		}
+		this._assertIsItem(item);
+		return item[attribute] || []; //Array
+	},
+
+	getAttributes: function(/* item */ item){
+		//	summary: 
+		//		See dojo.data.api.Read.getAttributes()
+		this._assertIsItem(item);
+		var attributes = [];
+		for(var key in item){
+			//Save off only the real item attributes, not the special id marks for O(1) isItem.
+			if((key !== this._storeRef) && (key !== this._itemId)){
+				attributes.push(key);
+			}
+		}
+		return attributes; //Array
+	},
+
+	hasAttribute: function(	/* item */ item,
+							/* attribute || attribute-name-string */ attribute) {
+		//	summary: 
+		//		See dojo.data.api.Read.hasAttribute()
+		return this.getValues(item, attribute).length > 0;
+	},
+
+	containsValue: function(/* item */ item, 
+							/* attribute || attribute-name-string */ attribute, 
+							/* anything */ value){
+		//	summary: 
+		//		See dojo.data.api.Read.containsValue()
+		return this._containsValue(item,attribute,value,false); //boolean
+	},
+
+	_containsValue: function(	/* item */ item, 
+								/* attribute || attribute-name-string */ attribute, 
+								/* anything */ value,
+								/* boolean */ ignoreCase){
+		//	summary: 
+		//		Internal function for looking at the values contained by the item.
+		//	description: 
+		//		Internal function for looking at the values contained by the item.  This 
+		//		function allows for denoting if the comparison should be case sensitive for
+		//		strings or not (for handling filtering cases where string case should not matter)
+		//	
+		//	item:
+		//		The data item to examine for attribute values.
+		//	attribute:
+		//		The attribute to inspect.
+		//	value:	
+		//		The value to match, strings may contain wildcard items like * and ?.
+		//	ignoreCase:
+		//		Flag to denote that if items are a string type, should case be used for comparison or not.
+
+		var values = this.getValues(item, attribute);
+		for(var i = 0; i < values.length; ++i){
+			var possibleValue = values[i];
+			if(typeof value === "string" && typeof possibleValue === "string"){
+				return (possibleValue.match(dojo.data.util.filter.patternToRegExp(value, ignoreCase)) !== null);
+			}else{
+				//Non-string matching.
+				if(value === possibleValue){
+					return true; // Boolean
+				}
+			}
+		}
+		return false; // Boolean
+	},
+
+	isItem: function(/* anything */ something){
+		//	summary: 
+		//		See dojo.data.api.Read.isItem()
+		if(something && something[this._storeRef] === this){
+			if(this._itemMap[something[this._itemId]] === something){
+				return true;
+			}
+		}
+		return false; // Boolean
+	},
+
+	isItemLoaded: function(/* anything */ something){
+		//	summary: 
+		//		See dojo.data.api.Read.isItemLoaded()
+		return this.isItem(something); //boolean
+	},
+
+	loadItem: function(/* object */ keywordArgs){
+		//	summary: 
+		//		See dojo.data.api.Read.loadItem()
+		this._assertIsItem(keywordArgs.item);
+	},
+
+	getFeatures: function(){
+		//	summary: 
+		//		See dojo.data.api.Read.getFeatures()
+		if (!this._loadFinished){
+			// This has to happen to meet the property that the identity functions are
+			// denoted to work only if the store has been loaded and it had an identifier 
+			// property in the JSON.  So, for the feature to be found, the load had to have 
+			// happened.
+			this._forceLoad();
+		}
+		return this._features; //Object
+	},
+
+	_fetchItems: function(	/* Object */ keywordArgs, 
+							/* Function */ findCallback, 
+							/* Function */ errorCallback){
+		//	summary: 
+		//		See dojo.data.util.simpleFetch.fetch()
+		var self = this;
+		var filter = function(requestArgs, arrayOfAllItems){
+			var items = null;
+			if(requestArgs.query){
+				var ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false; 
+				items = [];
+				for(var i = 0; i < arrayOfAllItems.length; ++i){
+					var match = true;
+					var candidateItem = arrayOfAllItems[i];
+					for(var key in requestArgs.query) {
+						var value = requestArgs.query[key];
+						if (!self._containsValue(candidateItem, key, value, ignoreCase)){
+							match = false;
+						}
+					}
+					if(match){
+						items.push(candidateItem);
+					}
+				}
+				findCallback(items, requestArgs);
+			}else{
+				// We want a copy to pass back in case the parent wishes to sort the array.  We shouldn't allow resort 
+				// of the internal list so that multiple callers can get listsand sort without affecting each other.
+				if(self._arrayOfAllItems.length> 0){
+					items = self._arrayOfAllItems.slice(0,self._arrayOfAllItems.length); 
+				}
+				findCallback(items, requestArgs);
+			}
+		};
+
+		if(this._loadFinished){
+			filter(keywordArgs, this._arrayOfAllItems);
+		}else{
+			if(this._jsonFileUrl){
+				var getArgs = {
+						url: self._jsonFileUrl, 
+						handleAs: "json-comment-optional"
+					};
+				var getHandler = dojo.xhrGet(getArgs);
+				getHandler.addCallback(function(data){
+					// console.debug(dojo.toJson(data));
+					self._loadFinished = true;
+					try{
+						self._arrayOfAllItems = self._getItemsFromLoadedData(data);
+						filter(keywordArgs, self._arrayOfAllItems);
+					}catch(e){
+						errorCallback(e, keywordArgs);
+					}
+
+				});
+				getHandler.addErrback(function(error){
+					errorCallback(error, keywordArgs);
+				});
+			}else if(this._jsonData){
+				try{
+					this._loadFinished = true;
+					this._arrayOfAllItems = this._getItemsFromLoadedData(this._jsonData);
+					this._jsonData = null;
+					filter(keywordArgs, this._arrayOfAllItems);
+				}catch(e){
+					errorCallback(e, keywordArgs);
+				}
+			}else{
+				errorCallback(new Error("dojo.data.JsonItemStore: No JSON source data was provided as either URL or a nested Javascript object."), keywordArgs);
+			}
+		}
+	},
+
+	close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+		 //	summary: 
+		 //		See dojo.data.api.Read.close()
+	},
+
+	_getItemsFromLoadedData: function(/* Object */ dataObject){
+		//	summary:
+		//		Function to parse the loaded data into item format and build the internal items array.
+		//	description:
+		//		Function to parse the loaded data into item format and build the internal items array.
+		//
+		//	dataObject:
+		//		The JS data object containing the raw data to convery into item format.
+		//
+		// 	returns: array
+		//		Array of items in store item format.
+
+		var arrayOfItems = dataObject.items;
+		var i;
+		var item;
+		var attrNames = {};
+
+		// We need to do some transformations to convert the data structure
+		// that we read from the file into a format that will be convenient
+		// to work with in memory.
+
+		// Step 1: We walk through all the attribute values of all the items, 
+		// and replace single values with arrays.  For example, we change this:
+		//		{ name:'Miss Piggy', pets:'Foo-Foo'}
+		// into this:
+		//		{ name:['Miss Piggy'], pets:['Foo-Foo']}
+		// Also store off the keys so we can validate our store reference and item 
+		// id special properties for the O(1) isItem
+		for(i = 0; i < arrayOfItems.length; ++i){
+			item = arrayOfItems[i];
+            for(var key in item){
+				var value = item[key];
+
+				if(value !== null){
+					if(!dojo.isArray(value)){
+						item[key] = [value];
+					}
+				}else{
+					item[key] = [null];
+				}
+				attrNames[key]=key;
+			}
+		}
+
+		//Build unique keys for id and store ref.
+		//This should go really fast, it will generally
+		// never even run the loop..
+		while(attrNames[this._storeRef]){
+			this._storeRef += "_";
+		}
+		while(attrNames[this._itemId]){
+			this._itemId += "_";
+		}
+
+		// Step 2: Some data files specify an optional 'identifier', which is 
+		// the name of an attribute that holds the identity of each item.  If 
+		// this data file specified an identifier attribute, then build an 
+		// hash table of items keyed by the identity of the items.
+		var identifier = dataObject.identifier;
+		var arrayOfValues = null;
+		if(identifier){
+			this._features['dojo.data.api.Identity'] = identifier;
+			this._itemsByIdentity = {};
+			for(var i = 0; i < arrayOfItems.length; ++i){
+				item = arrayOfItems[i];
+				arrayOfValues = item[identifier];
+				identity = arrayOfValues[0];
+				if(!this._itemsByIdentity[identity]){
+					this._itemsByIdentity[identity] = item;
+				}else{
+					if(this._jsonFileUrl){
+						throw new Error("dojo.data.JsonItemStore:  The json data as specified by: [" + this._jsonFileUrl + "] is malformed.  Items within the list have identifier: [" + identifier + "].  Value collided: [" + identity + "]");
+					}else if(this._jsonData){
+						throw new Error("dojo.data.JsonItemStore:  The json data provided by the creation arguments is malformed.  Items within the list have identifier: [" + identifier + "].  Value collided: [" + identity + "]");
+					}
+				}
+
+			}
+		}
+
+		// Step 3: We walk through all the attribute values of all the items,
+		// and replace references with pointers to items.  For example, we change:
+		//		{ name:['Kermit'], friends:[{reference:{name:'Miss Piggy'}}] }
+		// into this:
+		//		{ name:['Kermit'], friends:[miss_piggy] } 
+		// (where miss_piggy is the object representing the 'Miss Piggy' item).
+		// Also generate the associate map for all items for the O(1) isItem function.
+		for(i = 0; i < arrayOfItems.length; ++i){
+            item = arrayOfItems[i]; // example: { name:['Kermit'], friends:[{reference:{name:'Miss Piggy'}}] }
+			item[this._storeRef] = this;
+			item[this._itemId] = i;
+			this._itemMap[i] = item;
+			this._itemMap.lastItem = i;
+			for(key in item){
+				arrayOfValues = item[key]; // example: [{reference:{name:'Miss Piggy'}}]
+				for(var j = 0; j < arrayOfValues.length; ++j) {
+					value = arrayOfValues[j]; // example: {reference:{name:'Miss Piggy'}}
+					if(value !== null && typeof value == "object" && value.reference){
+						var referenceDescription = value.reference; // example: {name:'Miss Piggy'}
+						if(dojo.isString(referenceDescription)){
+							// example: 'Miss Piggy'
+							// from an item like: { name:['Kermit'], friends:[{reference:'Miss Piggy'}]}
+							arrayOfValues[j] = this._itemsByIdentity[referenceDescription];
+						}else{
+							// example: {name:'Miss Piggy'}
+							// from an item like: { name:['Kermit'], friends:[{reference:{name:'Miss Piggy'}}] }
+							for(var k = 0; k < arrayOfItems.length; ++k){
+								var candidateItem = arrayOfItems[k];
+								var found = true;
+								for(var refKey in referenceDescription){
+									if(candidateItem[refKey] != referenceDescription[refKey]){ 
+										found = false; 
+									}
+								}
+								if(found){ 
+									arrayOfValues[j] = candidateItem; 
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		return arrayOfItems; //Array
+	},
+
+	getIdentity: function(/* item */ item){
+		//	summary: 
+		//		See dojo.data.api.Identity.getIdentity()
+		var identifier = this._features['dojo.data.api.Identity'];
+		var arrayOfValues = item[identifier];
+		if(arrayOfValues){
+			return arrayOfValues[0]; //Object || String
+		}
+		return null; //null
+	},
+
+	getItemByIdentity: function(/* String */ identity){
+		//	summary: 
+		//		See dojo.data.api.Identity.getItemByIdentity()
+
+		// Force a sync'ed load if it hasn't occurred yet
+		if(!this._loadFinished){
+			this._forceLoad();
+		}
+		if(this._itemsByIdentity){
+			var item = this._itemsByIdentity[identity];
+			if(item !== undefined){
+				return item; //Object
+			}
+		}
+		return null; //null
+	},
+
+	_forceLoad: function(){
+		//	summary: 
+		//		Internal function to force a load of the store if it hasn't occurred yet.  This is required
+		//		for specific functions to work properly.  See dojo.data.api.Identity.getItemByIdentity()
+		var self = this;
+		if(this._jsonFileUrl){
+			var getArgs = {
+					url: self._jsonFileUrl, 
+					handleAs: "json-comment-optional",
+					sync: true
+				};
+			var getHandler = dojo.xhrGet(getArgs);
+			getHandler.addCallback(function(data){
+				try{
+					self._arrayOfAllItems = self._getItemsFromLoadedData(data);
+					self._loadFinished = true;
+				}catch(e){
+					console.log(e);
+					throw e;
+				}
+			});
+			getHandler.addErrback(function(error){
+				throw error;
+			});
+		}else if(this._jsonData){
+			self._arrayOfAllItems = self._getItemsFromLoadedData(self._jsonData);
+			self._jsonData = null;
+			self._loadFinished = true;
+		} 
+	}
+});
+//Mix in the simple fetch implementation to this class.
+dojo.extend(dojo.data.JsonItemStore,dojo.data.util.simpleFetch);

Added: trunk/examples/typeface/root/static/dojo/dojo/data/api/Identity.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/data/api/Identity.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/data/api/Identity.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,56 @@
+dojo.provide("dojo.data.api.Identity");
+dojo.require("dojo.data.api.Read");
+
+dojo.declare("dojo.data.api.Identity",dojo.data.api.Read,null,{
+	//	summary:
+	//		This is an abstract API that data provider implementations conform to.
+	//		This file defines methods signatures and intentionally leaves all the
+	//		methods unimplemented.
+
+	getFeatures: function(){
+		//	summary: 
+		//		See dojo.data.api.Read.getFeatures()
+		return {
+			 'dojo.data.api.Read': true,
+			 'dojo.data.api.Identity': true
+		};
+	},
+
+	getIdentity: function(/* item */ item){
+		//	summary:
+		//		Returns a unique identifer for an item.  The return value will be
+		//		either a string or something that has a toString() method (such as,
+		//		for example, a dojo.uuid.Uuid object).
+		//	exceptions:
+		//		Conforming implementations may throw an exception or return null if
+		//		item is not an item.
+		//	examples:
+		//		var itemId = store.getIdentity(kermit);
+		//		assert(kermit === store.findByIdentity(store.getIdentity(kermit)));
+		dojo.unimplemented('dojo.data.api.Identity.getIdentity');
+		var itemIdentityString = null;
+		return itemIdentityString; // string
+	},
+
+	getItemByIdentity: function(/* string || object */ identity){
+		//	summary:
+		//		Given the identity of an item, this method returns the item that has 
+		//		that identity.  Conforming implementations should return null if there 
+		//		is no item with the given identity.  Implementations of getItemByIdentity() 
+		//		may sometimes return an item from a local cache and may sometimes 
+		//		fetch an item from a remote server, in which case the call to 
+		//		getItemByIdentity() will block until the getItemByIdentity() implementation 
+		//		has the item to return.	
+		//
+		//	identity:
+		//		The identity of the object to locate.  It should be a string or an 
+		//		object that toString() can be called on (such as a dojo.uuid object).
+		//
+		//	examples:
+		//		var alaska = store.getItemByIdentity("AK");
+		//		assert("AK" == store.getItemByIdentity(store.getItemByIdentity("AK")));
+		dojo.unimplemented('dojo.data.api.Identity.getItemByIdentity');
+		var item = null;
+		return item; // item
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojo/data/api/Notification.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/data/api/Notification.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/data/api/Notification.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,100 @@
+dojo.provide("dojo.data.api.Notification");
+dojo.require("dojo.data.api.Read");
+
+dojo.declare("dojo.data.api.Notification",dojo.data.api.Read,null,{
+	//	summary:
+	//		This is an abstract API that data provider implementations conform to.
+	//		This file defines methods signatures and intentionally leaves all the
+	//		methods unimplemented.
+	//
+	//	description:
+	//		This API defines a set of APIs that all datastores that conform to the
+	//		Notifications API must implement.  In general, most stores will implement 
+	//		these APIs as no-op functions for users who wish to monitor them to be able
+	//		to connect to then via dojo.event.connect().  For non-users of 
+	//		dojo.event.connect, they should be able to just replace the method on the 
+	//		store to obtain notifications.  Both read-only and read-write stores may implement
+	//		this feature.  In the case of a read-only store, this feature makes sense if 
+	//		the store itself does internal polling to a back-end server and periodically updates
+	//		its cache of items (deletes, adds, and updates).
+	//
+	//	examples:
+	//
+	//		function onSet(item, attribute, oldValue, newValue) {
+	//			//Do something with the information...
+	//		};
+	//		var store = new some.newStore();
+	//		dojo.event.connect(store, "onSet", onUpdate);
+
+	getFeatures: function(){
+		//	summary: 
+		//		See dojo.data.api.Read.getFeatures()
+		return {
+			'dojo.data.api.Read': true,
+			'dojo.data.api.Notification': true
+		};
+	},
+
+	onSet: function(/* item */ item, 
+					/*attribute | attribute-name-string*/ attribute, 
+					/*object | array*/ oldValue,
+					/*object | array*/ newValue){
+		//	summary:
+		//		This method is called any time an item is modified via setValue, setValues, unsetAttribute, etc.  
+		//	description:
+		//		This method is called any time an item is modified via setValue, setValues, unsetAttribute, etc.  
+		//		Its purpose is to provide a hook point for those who wish to monitor actions on items in the store 
+		//		in a simple manner.  The general expected usage is to dojo.event.connect() to the store's 
+		//		implementation and be called after the store method is called.
+		//
+		//	item:
+		//		The item being modified.
+		//	attribute:
+		//		The attrubite being changed.  It may be either a string name of the attribute, or an item that represents
+		//		that attribute.
+		//	oldValue:
+		//		The old value of the attribute.  In the case of single value calls, such as setValue, unsetAttribute, etc,
+		//		this value will be generally be an atomic value of some sort (string, int, etc, object).  In the case of 
+		//		multi-valued attributes, it will be an array.
+		//	newValue:
+		//		The new value of the attribute.  In the case of single value calls, such as setValue, this value will be 
+		//		generally be an atomic value of some sort (string, int, etc, object).  In the case of multi-valued attributes, 
+		//		it will be an array.  In the case of unsetAttribute, the new value will be 'undefined'.
+		//
+		//	returns:
+		//		Nothing.
+		dojo.unimplemented('dojo.data.api.Notification.onSet');
+	},
+
+	onNew: function(/* item */ newItem){
+		//	summary:
+		//		This method is called any time a new item is created in the store.
+		//		It is called immediately after the store newItem processing has completed.
+		//	description:
+		//		This method is called any time a new item is created in the store.
+		//		It is called immediately after the store newItem processing has completed.
+		//
+		//	newItem:
+		//		The item created..
+		//
+		//	returns:
+		//		Nothing.
+		dojo.unimplemented('dojo.data.api.Notification.onNew');
+	},
+
+	onDelete: function(/* item */ deletedItem){
+		//	summary:
+		//		This method is called any time an item is deleted from the store.
+		//		It is called immediately after the store deleteItem processing has completed.
+		//	description:
+		//		This method is called any time an item is deleted from the store.
+		//		It is called immediately after the store deleteItem processing has completed.
+		//
+		//	deletedItem:
+		//		The item deleted.
+		//
+		//	returns:
+		//		Nothing.
+		dojo.unimplemented('dojo.data.api.Notification.onDelete');
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojo/data/api/Read.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/data/api/Read.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/data/api/Read.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,417 @@
+dojo.provide("dojo.data.api.Read");
+dojo.require("dojo.data.api.Request");
+
+dojo.declare("dojo.data.api.Read",null,null,{
+	//	summary:
+	//		This is an abstract API that data provider implementations conform to.  
+	//		This file defines methods signatures and intentionally leaves all the
+	//		methods unimplemented.  For more information on the dojo.data APIs, 
+	//		please visit: http://www.dojotoolkit.org/node/98
+
+	getValue: function(	/* item */ item, 
+						/* attribute || attribute-name-string */ attribute, 
+						/* value? */ defaultValue){
+		//	summary:
+		//		Returns a single attribute value.
+		//		Returns defaultValue if and only if *item* does not have a value for *attribute*.
+		//		Returns null if and only if null was explicitly set as the attribute value.
+		//		Returns undefined if and only if the item does not have a value for the given 
+		//		attribute (which is the same as saying the item does not have the attribute). 
+		// description:
+		//		Saying that an "item x does not have a value for an attribute y"
+		//		is identical to saying that an "item x does not have attribute y". 
+		//		It is an oxymoron to say "that attribute is present but has no values" 
+		//		or "the item has that attribute but does not have any attribute values".
+		//		If store.hasAttribute(item, attribute) returns false, then
+		//		store.getValue(item, attribute) will return undefined.
+		//
+		//	exceptions:
+		//		Conforming implementations should throw an exception if *item* is not
+		//		an item, or *attribute* is neither an attribute object or a string.
+		//	examples:
+		//		var darthVader = store.getValue(lukeSkywalker, "father");
+		dojo.unimplemented('dojo.data.api.Read.getValue');
+		var attributeValue = null;
+		return attributeValue; // a literal, an item, null, or undefined (never an array)
+	},
+
+	getValues: function(/* item */ item,
+						/* attribute || attribute-name-string */ attribute){
+		//	summary:
+		// 		This getValues() method works just like the getValue() method, but getValues()
+		//		always returns an array rather than a single attribute value.  The array
+		//		may be empty, may contain a single attribute value, or may contain many
+		//		attribute values.
+		//		If the item does not have a value for the given attribute, then getValues()
+		//		will return an empty array: [].  (So, if store.hasAttribute(item, attribute)
+		//		returns false, then store.getValues(item, attribute) will return [].)
+
+		//	exceptions:
+		//		Throws an exception if *item* is not an item, or *attribute* is neither an 
+		//		attribute object or a string.
+		//	examples:
+		//		var friendsOfLuke = store.getValues(lukeSkywalker, "friends");
+		dojo.unimplemented('dojo.data.api.Read.getValues');
+		var array = [];
+		return array; // an array that may contain literals and items
+	},
+
+	getAttributes: function(/* item */ item){
+		//	summary:
+		//		Returns an array with all the attributes that this item has.  This
+		//		method will always return an array; if the item has no attributes
+		//		at all, getAttributes() will return an empty array: [].
+		//
+		//	exceptions:
+		//		Throws an exception if *item* is not an item. 
+		//	examples:
+		//		var array = store.getAttributes(kermit);
+		dojo.unimplemented('dojo.data.api.Read.getAttributes');
+		var array = [];
+		return array; // array
+	},
+
+	hasAttribute: function(	/* item */ item,
+							/* attribute || attribute-name-string */ attribute){
+		//	summary:
+		//		Returns true if the given *item* has a value for the given *attribute*.
+		//
+		//	exceptions:
+		//		Throws an exception if *item* is not an item, or *attribute* is neither an 
+		//		attribute object or a string.
+		//	examples:
+		//		var trueOrFalse = store.hasAttribute(kermit, "color");
+		dojo.unimplemented('dojo.data.api.Read.hasAttribute');
+		return false; // boolean
+	},
+
+	containsValue: function(/* item */ item,
+							/* attribute || attribute-name-string */ attribute, 
+							/* anything */ value){
+		//	summary:
+		//		Returns true if the given *value* is one of the values that getValues()
+		//		would return.
+		//
+		//	exceptions:
+		//		Throws an exception if *item* is not an item, or *attribute* is neither an 
+		//		attribute object or a string.
+		//	examples:
+		//		var trueOrFalse = store.containsValue(kermit, "color", "green");
+		dojo.unimplemented('dojo.data.api.Read.containsValue');
+		return false; // boolean
+	},
+
+	isItem: function(/* anything */ something){
+		//	summary:
+		//		Returns true if *something* is an item and came from the store instance.  
+		//		Returns false if *something* is a literal, an item from another store instance, 
+		//		or is any object other than an item.
+		//
+		//	examples:
+		//		var yes = store.isItem(store.newItem());
+		//		var no  = store.isItem("green");
+		dojo.unimplemented('dojo.data.api.Read.isItem');
+		return false; // boolean
+	},
+
+	isItemLoaded: function(/* anything */ something) {
+		//	summary:
+		//		Returns false if isItem(something) is false.  Returns false if
+		//		if isItem(something) is true but the the item is not yet loaded
+		//		in local memory (for example, if the item has not yet been read
+		//		from the server).
+		//
+		//	examples:
+		//		var yes = store.isItemLoaded(store.newItem());
+		//		var no  = store.isItemLoaded("green");
+		dojo.unimplemented('dojo.data.api.Read.isItemLoaded');
+		return false; // boolean
+	},
+
+	loadItem: function(/* object */ keywordArgs){
+		//	summary:
+		//		Given an item, this method loads the item so that a subsequent call
+		//		to store.isItemLoaded(item) will return true.  If a call to
+		//		isItemLoaded() returns true before loadItem() is even called,
+		//		then loadItem() need not do any work at all and will not even invoke
+		//		the callback handlers.  So, before invoking this method, check that
+		//		the item has not already been loaded.  
+		// 	keywordArgs:
+		//		An anonymous object that defines the item to load and callbacks to invoke when the 
+		//		load has completed.  The format of the object is as follows:
+		//		{
+		//			item: object,
+		//			onItem: Function,
+		//			onError: Function,
+		//			scope: object
+		//		}
+		//	The *item* parameter.
+		//		The item parameter is an object that represents the item in question that should be
+		//		contained by the store.  This attribute is required.
+		
+		//	The *onItem* parameter.
+		//		Function(item)
+		//		The onItem parameter is the callback to invoke when the item has been loaded.  It takes only one
+		//		parameter, the fully loaded item.
+		//
+		//	The *onError* parameter.
+		//		Function(error)
+		//		The onError parameter is the callback to invoke when the item load encountered an error.  It takes only one
+		//		parameter, the error object
+		//
+		//	The *scope* parameter.
+		//		If a scope object is provided, all of the callback functions (onItem, 
+		//		onError, etc) will be invoked in the context of the scope object.
+		//		In the body of the callback function, the value of the "this"
+		//		keyword will be the scope object.   If no scope object is provided,
+		//		the callback functions will be called in the context of dojo.global().
+		//		For example, onItem.call(scope, item, request) vs. 
+		//		onItem.call(dojo.global(), item, request)
+		if (!this.isItemLoaded(keywordArgs.item)) {
+			dojo.unimplemented('dojo.data.api.Read.loadItem');
+		}
+	},
+
+	fetch: function(/* Object */ keywordArgs){
+		//	summary:
+		//		Given a query and set of defined options, such as a start and count of items to return,
+		//		this method executes the query and makes the results available as data items.
+		//		The format and expectations of stores is that they operate in a generally asynchronous 
+		//		manner, therefore callbacks are always used to return items located by the fetch parameters.
+		//
+		//	description:
+		//		A Request object will always be returned and is returned immediately.
+		//		The basic request is nothing more than the keyword args passed to fetch and 
+		//		an additional function attached, abort().  The returned request object may then be used 
+		//		to cancel a fetch.  All data items returns are passed through the callbacks defined in the 
+		//		fetch parameters and are not present on the 'request' object.
+		//
+		//		This does not mean that custom stores can not add methods and properties to the request object
+		//		returned, only that the API does not require it.  For more info about the Request API, 
+		//		see dojo.data.api.Request
+		//
+		//	keywordArgs:
+		//		The keywordArgs parameter may either be an instance of 
+		//		conforming to dojo.data.api.Request or may be a simple anonymous object
+		//		that may contain any of the following:
+		//		{ 
+		//			query: query-string or query-object,
+		//			queryOptions: object,
+		//			onBegin: Function,
+		//			onItem: Function,
+		//			onComplete: Function,
+		//			onError: Function,
+		//			scope: object,
+		//			start: int
+		//			count: int
+		//			sort: array
+		//		}
+		//		All implementations should accept keywordArgs objects with any of
+		//		the 9 standard properties: query, onBegin, onItem, onComplete, onError 
+		//		scope, sort, start, and count.  Some implementations may accept additional 
+		//		properties in the keywordArgs object as valid parameters, such as 
+		//		{includeOutliers:true}.         
+		//
+		//	The *query* parameter.
+		//		The query may be optional in some data store implementations.
+		//		The dojo.data.api.Read API does not specify the syntax or semantics
+		//		of the query itself -- each different data store implementation
+		//		may have its own notion of what a query should look like.
+		//		In most implementations the query will probably be a string, but
+		//		in some implementations the query might be a Date, or a number,
+		//		or some complex keyword parameter object.  The dojo.data.api.Read
+		//		API is completely agnostic about what the query actually is.  
+		//		In general for query objects that accept strings as attribute value matches, 
+		//		the store should support basic filtering capability, such as * (match any character)
+		//		and ? (match single character). 
+		//
+		//	The *queryOptions* parameter
+		//		The queryOptions parameter is an optional parameter used to specify optiosn that may modify
+		//		the query in some fashion, such as doing a case insensitive search, or doing a deep search
+		//		where all items in a hierarchical representation of data are scanned instead of just the root 
+		//		items.  It currently defines two options that all datastores should attempt to honor if possible:
+		//		{
+		//			ignoreCase: boolean, //Whether or not the query should match case sensitively or not.  Default behaviour is false.
+		//			deep: boolean 	//Whether or not a fetch should do a deep search of items and all child 
+		//							//items instead of just root-level items in a datastore.  Default is false.
+		//		}
+		//
+		//	The *onBegin* parameter.
+		//		function(size, request);
+		//		If an onBegin callback function is provided, the callback function
+		//		will be called just once, before the first onItem callback is called.
+		//		The onBegin callback function will be passed two arguments, the
+		//		the total number of items identified and the Request object.  If the total number is
+		//		unknown, then size will be -1.  Note that size is not necessarily the size of the 
+		//		collection of items returned from the query, as the request may have specified to return only a 
+		//		subset of the total set of items through the use of the start and count parameters.
+		//
+		//	The *onItem* parameter.
+		//		function(item, request);
+		//		If an onItem callback function is provided, the callback function
+		//		will be called as each item in the result is received. The callback 
+		//		function will be passed two arguments: the item itself, and the
+		//		Request object.
+		//
+		//	The *onComplete* parameter.
+		//		function(items, request);
+		//
+		//		If an onComplete callback function is provided, the callback function
+		//		will be called just once, after the last onItem callback is called.
+		//		Note that if the onItem callback is not present, then onComplete will be passed
+		//		an array containing all items which matched the query and the request object.  
+		//		If the onItem callback is present, then onComplete is called as: 
+		//		onComplete(null, request).
+		//
+		//	The *onError* parameter.
+		//		function(errorData, request); 
+		//		If an onError callback function is provided, the callback function
+		//		will be called if there is any sort of error while attempting to
+		//		execute the query.
+		//		The onError callback function will be passed two arguments:
+		//		an Error object and the Request object.
+		//
+		//	The *scope* parameter.
+		//		If a scope object is provided, all of the callback functions (onItem, 
+		//		onComplete, onError, etc) will be invoked in the context of the scope
+		//		object.  In the body of the callback function, the value of the "this"
+		//		keyword will be the scope object.   If no scope object is provided,
+		//		the callback functions will be called in the context of dojo.global().  
+		//		For example, onItem.call(scope, item, request) vs. 
+		//		onItem.call(dojo.global(), item, request)
+		//
+		//	The *start* parameter.
+		//		If a start parameter is specified, this is a indication to the datastore to 
+		//		only start returning items once the start number of items have been located and
+		//		skipped.  When this parameter is paired withh 'count', the store should be able
+		//		to page across queries with millions of hits by only returning subsets of the 
+		//		hits for each query
+		//
+		//	The *count* parameter.
+		//		If a count parameter is specified, this is a indication to the datastore to 
+		//		only return up to that many items.  This allows a fetch call that may have 
+		//		millions of item matches to be paired down to something reasonable.  
+		//
+		//	The *sort* parameter.
+		//		If a sort parameter is specified, this is a indication to the datastore to 
+		//		sort the items in some manner before returning the items.  The array is an array of 
+		//		javascript objects that must conform to the following format to be applied to the
+		//		fetching of items:
+		//		{
+		//			attribute: attribute || attribute-name-string,
+		//			descending: true|false;   // Optional.  Default is false.
+		//		}
+		//		Note that when comparing attributes, if an item contains no value for the attribute
+		//		(undefined), then it the default ascending sort logic should push it to the bottom 
+		//		of the list.  In the descending order case, it such items should appear at the top of the list.
+		// 
+		//	returns:
+		//		The fetch() method will return a javascript object conforming to the API
+		//		defined in dojo.data.api.Request.  In general, it will be the keywordArgs
+		//		object returned with the required functions in Request.js attached.
+		//		Its general purpose is to provide a convenient way for a caller to abort an
+		//		ongoing fetch.  
+		// 
+		//		The Request object may also have additional properties when it is returned
+		//		such as request.store property, which is a pointer to the datastore object that 
+		//		fetch() is a method of.
+		//
+		//	exceptions:
+		//		Throws an exception if the query is not valid, or if the query
+		//		is required but was not supplied.
+		//
+		//	examples:
+		//		// Fetch all books identified by the query and call 'showBooks' when complete
+		//		var request = store.fetch({query:"all books", onComplete: showBooks});
+		//
+		//		// Fetch all items in the story and call 'showEverything' when complete.
+		//		var request = store.fetch(onComplete: showEverything);
+		//
+		//		// Fetch only 10 books that match the query 'all books', starting at the fifth book found during the search.
+		//		// This demonstrates how paging can be done for specific queries.  
+		//		var request = store.fetch({query:"all books", start: 4, count: 10, onComplete: showBooks});
+		//
+		//		// Fetch all items that match the query, calling 'callback' each time an item is located.
+		//		var request = store.fetch({query:"foo/bar", onItem:callback});
+		//
+		//		// Fetch the first 100 books by author King, call showKing when up to 100 items have been located.
+		//		var request = store.fetch({query:{author:"King"}, start: 0, count:100, onComplete: showKing});
+		//
+		//		// Locate the books written by Author King, sort it on title and publisher, then return the first 100 items from the sorted items.
+		//		var request = store.fetch({query:{author:"King"}, sort: [{ attribute: "title", descending: true}, {attribute: "publisher"}], ,start: 0, count:100, onComplete: 'showKing'});
+		//
+		//		// Fetch the first 100 books by authors starting with the name King, then call showKing when up to 100 items have been located.
+		//		var request = store.fetch({query:{author:"King*"}, start: 0, count:100, onComplete: showKing});
+		//
+		//		// Fetch the first 100 books by authors ending with 'ing', but only have one character before it (King, Bing, Ling, Sing, etc.), then call showBooks when up to 100 items have been located.
+		//		var request = store.fetch({query:{author:"?ing"}, start: 0, count:100, onComplete: showBooks});
+		//
+		//		// Fetch the first 100 books by author King, where the name may appear as King, king, KING, kInG, and so on, then call showKing when up to 100 items have been located.
+		//		var request = store.fetch({query:{author:"King"}, queryOptions:(ignoreCase: true}, start: 0, count:100, onComplete: showKing});
+		//
+		//		// Paging:
+		//		var store = new dojo.data.LargeRdbmsStore({url:"jdbc:odbc:foobar"});
+		//		var fetchArgs = {
+		//			query: {type:"employees", name:"Hillary *"}, // string matching
+		//			sort: [{attribute:"department", descending:true}],
+		//			start: 0,
+		//			count: 20,
+		//			scope: displayer,
+		//			onBegin: showThrobber,
+		//			onItem: displayItem,
+		//			onComplete: stopThrobber,
+		//			onError: handleFetchError,
+		//		};
+		//		store.fetch(fetchArgs);
+		//		...
+		//		// and then when the user presses the "Next Page" button...
+		//		fetchArgs.start += 20;
+		//		store.fetch(fetchArgs);  // get the next 20 items
+		dojo.unimplemented('dojo.data.api.Read.fetch');
+		var request = null; 
+		return request; // an object conforming to the dojo.data.api.Request API
+	},
+
+	getFeatures: function(){
+		//	summary:
+		//		The getFeatures() method returns an simple keyword values object 
+		//		that specifies what interface features the datastore implements.  
+		//		A simple CsvStore may be read-only, and the only feature it 
+		//		implements will be the 'dojo.data.api.Read' interface, so the
+		//		getFeatures() method will return an object like this one:
+		//		{'dojo.data.api.Read': true}.
+		//		A more sophisticated datastore might implement a variety of
+		//		interface features, like 'dojo.data.api.Read', 'dojo.data.api.Write', 
+		//		'dojo.data.api.Identity', and 'dojo.data.api.Attribution'.
+		return {
+			'dojo.data.api.Read': true
+		};
+	},
+
+	close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+		//	summary:
+		//		The close() method is intended for instructing the store to 'close' out 
+		//		any information associated with a particular request.
+		//
+		//	description:
+		//		The close() method is intended for instructing the store to 'close' out 
+		//		any information associated with a particular request.  In general, this API
+		//		expects to recieve as a parameter a request object returned from a fetch.  
+		//		It will then close out anything associated with that request, such as 
+		//		clearing any internal datastore caches and closing any 'open' connections.
+		//		For some store implementations, this call may be a no-op.
+		//
+		//	request:
+		//		An instance of a request for the store to use to identify what to close out.
+		//		If no request is passed, then the store should clear all internal caches (if any)
+		//		and close out all 'open' connections.  It does not render the store unusable from
+		//		there on, it merely cleans out any current data and resets the store to initial 
+		//		state.
+		//
+		//	examples:
+		//		var request = store.fetch({onComplete: doSomething});
+		//		...
+		//		store.close(request);
+		dojo.unimplemented('dojo.data.api.Read.close');
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojo/data/api/Request.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/data/api/Request.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/data/api/Request.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,28 @@
+dojo.provide("dojo.data.api.Request");
+
+dojo.declare("dojo.data.api.Request",null,null,{
+	//	summary:
+	//		This class defines out the semantics of what a 'Request' object looks like
+	//		when returned from a fetch() method.  In general, a request object is
+	//		nothing more than the original keywordArgs from fetch with an abort function 
+	//		attached to it to allow users to abort a particular request if they so choose. 
+	//		No other functions are required on a general Request object return.  That does not
+	//		inhibit other store implementations from adding extentions to it, of course.
+	//
+	//		This is an abstract API that data provider implementations conform to.  
+	//		This file defines methods signatures and intentionally leaves all the
+	//		methods unimplemented.
+	//
+	//		For more details on fetch, see dojo.data.api.Read.fetch().
+
+	abort: function(){
+		//	summary:
+		//		This function is a hook point for stores to provide as a way for 
+		//		a fetch to be halted mid-processing.
+		//	description:
+		//		This function is a hook point for stores to provide as a way for 
+		//		a fetch to be halted mid-processing.  For more details on the fetch() api,
+		//		please see dojo.data.api.Read.fetch().
+		dojo.unimplemented('dojo.data.api.Request.abort');
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojo/data/api/Write.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/data/api/Write.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/data/api/Write.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,179 @@
+dojo.provide("dojo.data.api.Write");
+dojo.require("dojo.data.api.Read");
+
+dojo.declare("dojo.data.api.Write", dojo.data.api.Read, {
+	//	summary:
+	//		This is an abstract API that data provider implementations conform to.  
+	//		This file defines methods signatures and intentionally leaves all the
+	//		methods unimplemented.
+
+	getFeatures: function(){
+		//	summary: 
+		//		See dojo.data.api.Read.getFeatures()
+		return {
+			'dojo.data.api.Read': true,
+			'dojo.data.api.Write': true
+		};
+	},
+
+	newItem: function(/* Object? */ keywordArgs){
+		//	summary:
+		//		Returns a newly created item.  Sets the attributes of the new
+		//		item based on the *keywordArgs* provided.  In general, the attribute
+		//		names in the keywords become the attributes in the new item and as for
+		//		the attribute values in keywordArgs, they become the values of the attributes
+		//		in the new item.
+		//
+		//	exceptions:
+		//		Throws an exception if *keywordArgs* is a string or a number or
+		//		anything other than a simple anonymous object.
+		//	examples:
+		//		var kermit = store.newItem({name: "Kermit", color:[blue, green]});
+
+		var newItem;
+		dojo.unimplemented('dojo.data.api.Write.newItem');
+		return newItem; // item
+	},
+
+	deleteItem: function(/* item */ item){
+		//	summary:
+		//		Deletes an item from the store.
+		//
+		//	exceptions:
+		//		Throws an exception if the argument *item* is not an item 
+		//		(if store.isItem(item) returns false).
+		//	examples:
+		//		var success = store.deleteItem(kermit);
+		dojo.unimplemented('dojo.data.api.Write.deleteItem');
+		return false; // boolean
+	},
+
+	setValue: function(	/* item */ item, 
+						/* attribute || string */ attribute,
+						/* almost anything */ value){
+		//	summary:
+		//		Sets the value of an attribute on an item.
+		//		Replaces any previous value or values.
+		//
+		//	exceptions:
+		//		Throws an exception if *item* is not an item, or if *attribute*
+		//		is neither an attribute object or a string.
+		//		Throws an exception if *value* is undefined.
+		//	examples:
+		//		var success = store.set(kermit, "color", "green");
+		dojo.unimplemented('dojo.data.api.Write.setValue');
+		return false; // boolean
+	},
+
+	setValues: function(/* item */ item,
+						/* attribute || string */ attribute, 
+						/* array */ values){
+		//	summary:
+		//		Adds each value in the *values* array as a value of the given
+		//		attribute on the given item.
+		//		Replaces any previous value or values.
+		//		Calling store.setValues(x, y, []) (with *values* as an empty array) has
+		//		the same effect as calling store.clear(x, y).
+		//
+		//	exceptions:
+		//		Throws an exception if *values* is not an array, if *item* is not an
+		//		item, or if *attribute* is neither an attribute object or a string.
+		//	examples:
+		//		var success = store.setValues(kermit, "color", ["green", "aqua"]);
+		//		success = store.setValues(kermit, "color", []);
+		//		if (success) {assert(!store.hasAttribute(kermit, "color"));}
+		dojo.unimplemented('dojo.data.api.Write.setValues');
+		return false; // boolean
+	},
+
+	unsetAttribute: function(	/* item */ item, 
+								/* attribute || string */ attribute){
+		//	summary:
+		//		Deletes all the values of an attribute on an item.
+		//
+		//	exceptions:
+		//		Throws an exception if *item* is not an item, or if *attribute*
+		//		is neither an attribute object or a string.
+		//	examples:
+		//		var success = store.unsetAttribute(kermit, "color");
+		//		if (success) {assert(!store.hasAttribute(kermit, "color"));}
+		dojo.unimplemented('dojo.data.api.Write.clear');
+		return false; // boolean
+	},
+
+	save: function(/* object */ keywordArgs){
+		//	summary:
+		//		Saves to the server all the changes that have been made locally.
+		//		The save operation may take some time and is generally performed
+		//		in an asynchronous fashion.  The outcome of the save action is 
+		//		is passed into the set of supported callbacks for the save.
+		//   
+		//	keywordArgs:
+		//		{
+		//			onComplete: function
+		//			onError: function
+		//			scope: object
+		//		}
+		//
+		//	The *onComplete* parameter.
+		//		function();
+		//
+		//		If an onComplete callback function is provided, the callback function
+		//		will be called just once, after the save has completed.  No parameters
+		//		are generally passed to the onComplete.
+		//
+		//	The *onError* parameter.
+		//		function(errorData); 
+		//
+		//		If an onError callback function is provided, the callback function
+		//		will be called if there is any sort of error while attempting to
+		//		execute the save.  The onError function will be based one parameter, the
+		//		error.
+		//
+		//	The *scope* parameter.
+		//		If a scope object is provided, all of the callback function (
+		//		onComplete, onError, etc) will be invoked in the context of the scope
+		//		object.  In the body of the callback function, the value of the "this"
+		//		keyword will be the scope object.   If no scope object is provided,
+		//		the callback functions will be called in the context of dj_global.  
+		//		For example, onComplete.call(scope) vs. 
+		//		onComplete.call(dj_global)
+		//
+		//	returns:
+		//		Nothing.  Since the saves are generally asynchronous, there is 
+		//		no need to return anything.  All results are passed via callbacks.
+		//	examples:
+		//		store.save({onComplete: onSave});
+		//		store.save({scope: fooObj, onComplete: onSave, onError: saveFailed});
+		dojo.unimplemented('dojo.data.api.Write.save');
+	},
+
+	revert: function(){
+		//	summary:
+		//		Discards any unsaved changes.
+		//	description:
+		//		Discards any unsaved changes.
+		//
+		//	examples:
+		//		var success = store.revert();
+		dojo.unimplemented('dojo.data.api.Write.revert');
+		return false; // boolean
+	},
+
+	isDirty: function(/* item? */ item){
+		//	summary:
+		//		Given an item, isDirty() returns true if the item has been modified 
+		//		since the last save().  If isDirty() is called with no *item* argument,  
+		//		then this method returns true if any item has been modified since
+		//		the last save().
+		//
+		//	exceptions:
+		//		Throws an exception if isDirty() is passed an argument and the
+		//		argument is not an item.
+		//	examples:
+		//		var trueOrFalse = store.isDirty(kermit); // true if kermit is dirty
+		//		var trueOrFalse = store.isDirty();       // true if any item is dirty
+		dojo.unimplemented('dojo.data.api.Write.isDirty');
+		return false; // boolean
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojo/data/util/filter.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/data/util/filter.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/data/util/filter.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,65 @@
+dojo.provide("dojo.data.util.filter");
+
+dojo.data.util.filter.patternToRegExp = function(/*String*/pattern, /*boolean?*/ ignoreCase){
+	//	summary:  
+	//		Helper function to convert a simple pattern to a regular expression for matching.
+	//	description:
+	//		Returns a regular expression object that conforms to the defined conversion rules.
+	//		For example:  
+	//			ca*   -> /^ca.*$/
+	//			*ca*  -> /^.*ca.*$/
+	//			*c\*a*  -> /^.*c\*a.*$/
+	//			*c\*a?*  -> /^.*c\*a..*$/
+	//			and so on.
+	//
+	//	pattern: string
+	//		A simple matching pattern to convert that follows basic rules:
+	//			* Means match anything, so ca* means match anything starting with ca
+	//			? Means match single character.  So, b?b will match to bob and bab, and so on.
+	//      	\ is an escape character.  So for example, \* means do not treat * as a match, but literal character *.
+	//				To use a \ as a character in the string, it must be escaped.  So in the pattern it should be 
+	//				represented by \\ to be treated as an ordinary \ character instead of an escape.
+	//
+	//	ignoreCase:
+	//		An optional flag to indicate if the pattern matching should be treated as case-sensitive or not when comparing
+	//		By default, it is assumed case sensitive.
+
+	var rxp = "^";
+	var c = null;
+	for(var i = 0; i < pattern.length; i++){
+		c = pattern.charAt(i);
+		switch (c) {
+			case '\\':
+				rxp += c;
+				i++;
+				rxp += pattern.charAt(i);
+				break;
+			case '*':
+				rxp += ".*"; break;
+			case '?':
+				rxp += "."; break;
+			case '$':
+			case '^':
+			case '/':
+			case '+':
+			case '.':
+			case '|':
+			case '(':
+			case ')':
+			case '{':
+			case '}':
+			case '[':
+			case ']':
+				rxp += "\\"; //fallthrough
+			default:
+				rxp += c;
+		}
+	}
+	rxp += "$";
+	if(ignoreCase){
+		return new RegExp(rxp,"i"); //RegExp
+	}else{
+		return new RegExp(rxp); //RegExp
+	}
+	
+};

Added: trunk/examples/typeface/root/static/dojo/dojo/data/util/simpleFetch.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/data/util/simpleFetch.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/data/util/simpleFetch.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,86 @@
+dojo.provide("dojo.data.util.simpleFetch");
+dojo.require("dojo.data.util.sorter");
+
+dojo.data.util.simpleFetch.fetch = function(/* Object? */ request){
+	//	summary:
+	//		The simpleFetch mixin is designed to serve as a set of function(s) that can
+	//		be mixed into other datastore implementations to accelerate their development.  
+	//		The simpleFetch mixin should work well for any datastore that can respond to a _fetchItems() 
+	//		call by returning an array of all the found items that matched the query.  The simpleFetch mixin
+	//		is not designed to work for datastores that respond to a fetch() call by incrementally
+	//		loading items, or sequentially loading partial batches of the result
+	//		set.  For datastores that mixin simpleFetch, simpleFetch 
+	//		implements a fetch method that automatically handles eight of the fetch()
+	//		arguments -- onBegin, onItem, onComplete, onError, start, count, sort and scope
+	//		The class mixing in simpleFetch should not implement fetch(),
+	//		but should instead implement a _fetchItems() method.  The _fetchItems() 
+	//		method takes three arguments, the keywordArgs object that was passed 
+	//		to fetch(), a callback function to be called when the result array is
+	//		available, and an error callback to be called if something goes wrong.
+	//		The _fetchItems() method should ignore any keywordArgs parameters for
+	//		start, count, onBegin, onItem, onComplete, onError, sort, and scope.  
+	//		The _fetchItems() method needs to correctly handle any other keywordArgs
+	//		parameters, including the query parameter and any optional parameters 
+	//		(such as includeChildren).  The _fetchItems() method should create an array of 
+	//		result items and pass it to the fetchHandler along with the original request object 
+	//		-- or, the _fetchItems() method may, if it wants to, create an new request object 
+	//		with other specifics about the request that are specific to the datastore and pass 
+	//		that as the request object to the handler.
+	//
+	//		For more information on this specific function, see dojo.data.api.Read.fetch()
+	request = request || {};
+	if(!request.store){
+		request.store = this;
+	}
+	var self = this;
+
+	var _errorHandler = function(errorData, requestObject){
+		if(requestObject.onError){
+			var scope = requestObject.scope || dojo.global;
+			requestObject.onError.call(scope, errorData, requestObject);
+		}
+	};
+
+	var _fetchHandler = function(items, requestObject){
+		var oldAbortFunction = requestObject.abort || null;
+		var aborted = false;
+
+		var startIndex = requestObject.start?requestObject.start:0;
+		var endIndex   = requestObject.count?(startIndex + requestObject.count):items.length;
+
+		requestObject.abort = function(){
+			aborted = true;
+			if(oldAbortFunction){
+				oldAbortFunction.call(requestObject);
+			}
+		};
+
+		var scope = requestObject.scope || dojo.global;
+		if(!requestObject.store){
+			requestObject.store = self;
+		}
+		if(requestObject.onBegin){
+			requestObject.onBegin.call(scope, items.length, requestObject);
+		}
+		if(requestObject.sort){
+			items.sort(dojo.data.util.sorter.createSortFunction(requestObject.sort, self));
+		}
+		if(requestObject.onItem){
+			for(var i = startIndex; (i < items.length) && (i < endIndex); ++i){
+				var item = items[i];
+				if(!aborted){
+					requestObject.onItem.call(scope, item, requestObject);
+				}
+			}
+		}
+		if(requestObject.onComplete && !aborted){
+			var subset = null;
+			if (!requestObject.onItem) {
+				subset = items.slice(startIndex, endIndex);
+			}
+			requestObject.onComplete.call(scope, subset, requestObject);   
+		}
+	};
+	this._fetchItems(request, _fetchHandler, _errorHandler);
+	return request;	// Object
+};

Added: trunk/examples/typeface/root/static/dojo/dojo/data/util/sorter.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/data/util/sorter.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/data/util/sorter.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,77 @@
+dojo.provide("dojo.data.util.sorter");
+
+dojo.data.util.sorter.basicComparator = function(	/*anything*/ a, 
+													/*anything*/ b){
+	//	summary:  
+	//		Basic comparision function that compares if an item is greater or less than another item
+	//	description:  
+	//		returns 1 if a > b, -1 if a < b, 0 if equal.
+	//		undefined values are treated as larger values so that they're pushed to the end of the list.
+
+	var ret = 0;
+	if(a > b || typeof a === "undefined"){
+		ret = 1;
+	}else if(a < b || typeof b === "undefined"){
+		ret = -1;
+	}
+	return ret; //int, {-1,0,1}
+};
+
+dojo.data.util.sorter.createSortFunction = function(	/* attributes array */sortSpec,
+														/*dojo.data.core.Read*/ store){
+	//	summary:  
+	//		Helper function to generate the sorting function based off the list of sort attributes.
+	//	description:  
+	//		The sort function creation will look for a property on the store called 'comparatorMap'.  If it exists
+	//		it will look in the mapping for comparisons function for the attributes.  If one is found, it will
+	//		use it instead of the basic comparator, which is typically used for strings, ints, booleans, and dates.
+	//		Returns the sorting function for this particular list of attributes and sorting directions.
+	//
+	//	sortSpec: array
+	//		A JS object that array that defines out what attribute names to sort on and whether it should be descenting or asending.
+	//		The objects should be formatted as follows:
+	//		{
+	//			attribute: "attributeName-string" || attribute,
+	//			descending: true|false;   // Default is false.
+	//		}
+	//	store: object
+	//		The datastore object to look up item values from.
+	//
+	var sortFunctions=[];   
+
+	function createSortFunction(attr, dir){
+		return function(itemA, itemB){
+			var a = store.getValue(itemA, attr);
+			var b = store.getValue(itemB, attr);
+			//See if we have a override for an attribute comparison.
+			var comparator = null;
+			if(store.comparatorMap){
+				if(typeof attr !== "string"){
+					 attr = store.getIdentity(attr);
+				}
+				comparator = store.comparatorMap[attr]||dojo.data.util.sorter.basicComparator;
+			}
+			comparator = comparator||dojo.data.util.sorter.basicComparator; 
+			return dir * comparator(a,b); //int
+		};
+	}
+
+	for(var i = 0; i < sortSpec.length; i++){
+		sortAttribute = sortSpec[i];
+		if(sortAttribute.attribute){
+			var direction = (sortAttribute.descending) ? -1 : 1;
+			sortFunctions.push(createSortFunction(sortAttribute.attribute, direction));
+		}
+	}
+
+	return function(rowA, rowB){
+		var i=0;
+		while(i < sortFunctions.length){
+			var ret = sortFunctions[i++](rowA, rowB);
+			if(ret !== 0){
+				return ret;//int
+			}
+		}
+		return 0; //int  
+	};  //  Function
+};

Added: trunk/examples/typeface/root/static/dojo/dojo/date/locale.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/date/locale.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/date/locale.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,635 @@
+dojo.provide("dojo.date.locale");
+
+// Localization methods for Date.   Honor local customs using locale-dependent dojo.cldr data.
+
+dojo.require("dojo.date");
+dojo.require("dojo.cldr.supplemental");
+dojo.require("dojo.regexp");
+dojo.require("dojo.string");
+dojo.require("dojo.i18n");
+
+// Load the bundles containing localization information for
+// names and formats
+dojo.requireLocalization("dojo.cldr", "gregorian");
+
+//NOTE: Everything in this module assumes Gregorian calendars.
+// Other calendars will be implemented in separate modules.
+
+(function(){
+	// Format a pattern without literals
+	function formatPattern(dateObject, bundle, pattern){
+		return pattern.replace(/([a-z])\1*/ig, function(match){
+			var s;
+			var c = match.charAt(0);
+			var l = match.length;
+			var pad;
+			var widthList = ["abbr", "wide", "narrow"];
+			switch(c){
+				case 'G':
+//					if(l>3){/*unimplemented*/}
+					s = bundle.eras[dateObject.getFullYear() < 0 ? 1 : 0];
+					break;
+				case 'y':
+					s = dateObject.getFullYear();
+					switch(l){
+						case 1:
+							break;
+						case 2:
+							s = String(s); s = s.substr(s.length - 2);
+							break;
+						default:
+							pad = true;
+					}
+					break;
+				case 'Q':
+				case 'q':
+					s = Math.ceil((dateObject.getMonth()+1)/3);
+//					switch(l){
+//						case 1: case 2:
+							pad = true;
+//							break;
+//						case 3: case 4: // unimplemented
+//					}
+					break;
+				case 'M':
+				case 'L':
+					var m = dateObject.getMonth();
+					var width;
+					switch(l){
+						case 1: case 2:
+							s = m+1; pad = true;
+							break;
+						case 3: case 4: case 5:
+							width = widthList[l-3];
+							break;
+					}
+					if(width){
+						var type = (c == "L") ? "standalone" : "format";
+						var prop = ["months",type,width].join("-");
+						s = bundle[prop][m];
+					}
+					break;
+				case 'w':
+					var firstDay = 0;
+					s = dojo.date.locale._getWeekOfYear(dateObject, firstDay); pad = true;
+					break;
+				case 'd':
+					s = dateObject.getDate(); pad = true;
+					break;
+				case 'D':
+					s = dojo.date.locale._getDayOfYear(dateObject); pad = true;
+					break;
+				case 'E':
+				case 'e':
+				case 'c': // REVIEW: don't see this in the spec?
+					var d = dateObject.getDay();
+					var width;
+					switch(l){
+						case 1: case 2:
+							if(c == 'e'){
+								var first = dojo.cldr.supplemental.getFirstDayOfWeek(options.locale);
+								d = (d-first+7)%7;
+							}
+							if(c != 'c'){
+								s = d+1; pad = true;
+								break;
+							}
+							// else fallthrough...
+						case 3: case 4: case 5:
+							width = widthList[l-3];
+							break;
+					}
+					if(width){
+						var type = (c == "c") ? "standalone" : "format";
+						var prop = ["days",type,width].join("-");
+						s = bundle[prop][d];
+					}
+					break;
+				case 'a':
+					var timePeriod = (dateObject.getHours() < 12) ? 'am' : 'pm';
+					s = bundle[timePeriod];
+					break;
+				case 'h':
+				case 'H':
+				case 'K':
+				case 'k':
+					var h = dateObject.getHours();
+					// strange choices in the date format make it impossible to write this succinctly
+					switch (c) {
+						case 'h': // 1-12
+							s = (h % 12) || 12;
+							break;
+						case 'H': // 0-23
+							s = h;
+							break;
+						case 'K': // 0-11
+							s = (h % 12);
+							break;
+						case 'k': // 1-24
+							s = h || 24;
+							break;
+					}
+					pad = true;
+					break;
+				case 'm':
+					s = dateObject.getMinutes(); pad = true;
+					break;
+				case 's':
+					s = dateObject.getSeconds(); pad = true;
+					break;
+				case 'S':
+					s = Math.round(dateObject.getMilliseconds() * Math.pow(10, l-3));
+					break;
+				case 'v': // FIXME: don't know what this is. seems to be same as z?
+				case 'z':
+					// We only have one timezone to offer; the one from the browser
+					s = dojo.date.getTimezoneName(dateObject);
+					if(s){break;}
+					l=4;
+					// fallthrough... use GMT if tz not available
+				case 'Z':
+					var offset = dateObject.getTimezoneOffset();
+					var tz = [
+						(offset<=0 ? "+" : "-"),
+						dojo.string.pad(Math.floor(Math.abs(offset)/60), 2),
+						dojo.string.pad(Math.abs(offset)% 60, 2)
+					];
+					if(l==4){
+						tz.splice(0, 0, "GMT");
+						tz.splice(3, 0, ":");
+					}
+					s = tz.join("");
+					break;
+//				case 'Y': case 'u': case 'W': case 'F': case 'g': case 'A':
+//					console.debug(match+" modifier unimplemented");
+				default:
+					throw new Error("dojo.date.locale.format: invalid pattern char: "+pattern);
+			}
+			if(pad){ s = dojo.string.pad(s, l); }
+			return s;
+		});
+	}
+
+dojo.date.locale.format = function(/*Date*/dateObject, /*Object?*/options){
+	// summary:
+	//		Format a Date object as a String, using locale-specific settings.
+	//
+	// description:
+	//		Create a string from a Date object using a known localized pattern.
+	//		By default, this method formats both date and time from dateObject.
+	//		Formatting patterns are chosen appropriate to the locale.  Different
+	//		formatting lengths may be chosen, with "full" used by default.
+	//		Custom patterns may be used or registered with translations using
+	//		the addCustomFormats method.
+	//		Formatting patterns are implemented using the syntax described at
+	//		http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns
+	//
+	// dateObject:
+	//		the date and/or time to be formatted.  If a time only is formatted,
+	//		the values in the year, month, and day fields are irrelevant.  The
+	//		opposite is true when formatting only dates.
+	//
+	// options: object {selector: string, formatLength: string, datePattern: string, timePattern: string, locale: string}
+	//		selector- choice of 'time','date' (default: date and time)
+	//		formatLength- choice of long, short, medium or full (plus any custom additions).  Defaults to 'short'
+	//		datePattern,timePattern- override pattern with this string
+	//		am,pm- override strings for am/pm in times
+	//		locale- override the locale used to determine formatting rules
+
+	options = options || {};
+
+	var locale = dojo.i18n.normalizeLocale(options.locale);
+	var formatLength = options.formatLength || 'short';
+	var bundle = dojo.date.locale._getGregorianBundle(locale);
+	var str = [];
+	var sauce = dojo.hitch(this, formatPattern, dateObject, bundle);
+	if(options.selector == "year"){
+		// Special case as this is not yet driven by CLDR data
+		var year = dateObject.getFullYear();
+		if(locale.match(/^zh|^ja/)){
+			year += "\u5E74";
+		}
+		return year;
+	}
+	if(options.selector != "time"){
+		var datePattern = options.datePattern || bundle["dateFormat-"+formatLength];
+		if(datePattern){str.push(_processPattern(datePattern, sauce));}
+	}
+	if(options.selector != "date"){
+		var timePattern = options.timePattern || bundle["timeFormat-"+formatLength];
+		if(timePattern){str.push(_processPattern(timePattern, sauce));}
+	}
+	var result = str.join(" "); //TODO: use locale-specific pattern to assemble date + time
+	return result; // String
+};
+
+dojo.date.locale.regexp = function(/*Object?*/options){
+	// summary:
+	//		Builds the regular needed to parse a localized date
+	//
+	// options: object {selector: string, formatLength: string, datePattern: string, timePattern: string, locale: string, strict: boolean}
+	//		selector- choice of 'time', 'date' (default: date and time)
+	//		formatLength- choice of long, short, medium or full (plus any custom additions).  Defaults to 'short'
+	//		datePattern,timePattern- override pattern with this string
+	//		locale- override the locale used to determine formatting rules
+
+	return dojo.date.locale._parseInfo(options).regexp; // String
+};
+
+dojo.date.locale._parseInfo = function(/*Object?*/options){
+	options = options || {};
+	var locale = dojo.i18n.normalizeLocale(options.locale);
+	var bundle = dojo.date.locale._getGregorianBundle(locale);
+	var formatLength = options.formatLength || 'short';
+	var datePattern = options.datePattern || bundle["dateFormat-" + formatLength];
+	var timePattern = options.timePattern || bundle["timeFormat-" + formatLength];
+	var pattern;
+	if(options.selector == 'date'){
+		pattern = datePattern;
+	}else if(options.selector == 'time'){
+		pattern = timePattern;
+	}else{
+		pattern = datePattern + ' ' + timePattern; //TODO: use locale-specific pattern to assemble date + time
+	}
+
+	var tokens = [];
+	var re = _processPattern(pattern, dojo.hitch(this, _buildDateTimeRE, tokens, bundle, options));
+	return {regexp: re, tokens: tokens, bundle: bundle};
+}
+
+dojo.date.locale.parse = function(/*String*/value, /*Object?*/options){
+	// summary:
+	//		Convert a properly formatted string to a primitive Date object,
+	//		using locale-specific settings.
+	//
+	// description:
+	//		Create a Date object from a string using a known localized pattern.
+	//		By default, this method parses looking for both date and time in the string.
+	//		Formatting patterns are chosen appropriate to the locale.  Different
+	//		formatting lengths may be chosen, with "full" used by default.
+	//		Custom patterns may be used or registered with translations using
+	//		the addCustomFormats method.
+	//		Formatting patterns are implemented using the syntax described at
+	//		http://www.unicode.org/reports/tr35/#Date_Format_Patterns
+	//
+	// value:
+	//		A string representation of a date
+	//
+	// options: object {selector: string, formatLength: string, datePattern: string, timePattern: string, locale: string, strict: boolean}
+	//		selector- choice of 'time', 'date' (default: date and time)
+	//		formatLength- choice of long, short, medium or full (plus any custom additions).  Defaults to 'short'
+	//		datePattern,timePattern- override pattern with this string
+	//		am,pm- override strings for am/pm in times
+	//		locale- override the locale used to determine formatting rules
+	//		strict- strict parsing, off by default
+
+	var info = dojo.date.locale._parseInfo(options);
+	var tokens = info.tokens, bundle = info.bundle;
+	var re = new RegExp("^" + info.regexp + "$");
+	var match = re.exec(value);
+	if(!match){ return null; } // null
+
+	var widthList = ['abbr', 'wide', 'narrow'];
+	//1972 is a leap year.  We want to avoid Feb 29 rolling over into Mar 1,
+	//in the cases where the year is parsed after the month and day.
+	var result = new Date(1972, 0);
+	var expected = {};
+	dojo.forEach(match, function(v, i){
+		if(!i){return;}
+		var token=tokens[i-1];
+		var l=token.length;
+		switch(token.charAt(0)){
+			case 'y':
+				if(l != 2){
+					//interpret year literally, so '5' would be 5 A.D.
+					result.setFullYear(v);
+					expected.year = v;
+				}else{
+					if(v<100){
+						v = Number(v);
+						//choose century to apply, according to a sliding window
+						//of 80 years before and 20 years after present year
+						var year = '' + new Date().getFullYear();
+						var century = year.substring(0, 2) * 100;
+						var yearPart = Number(year.substring(2, 4));
+						var cutoff = Math.min(yearPart + 20, 99);
+						var num = (v < cutoff) ? century + v : century - 100 + v;
+						result.setFullYear(num);
+						expected.year = num;
+					}else{
+						//we expected 2 digits and got more...
+						if(options.strict){
+							return null;
+						}
+						//interpret literally, so '150' would be 150 A.D.
+						//also tolerate '1950', if 'yyyy' input passed to 'yy' format
+						result.setFullYear(v);
+						expected.year = v;
+					}
+				}
+				break;
+			case 'M':
+				if(l>2){
+					var months = bundle['months-format-' + widthList[l-3]].concat();
+					if(!options.strict){
+						//Tolerate abbreviating period in month part
+						//Case-insensitive comparison
+						v = v.replace(".","").toLowerCase();
+						months = dojo.map(months, function(s){ return s.replace(".","").toLowerCase(); } );
+					}
+					v = dojo.indexOf(months, v);
+					if(v == -1){
+//						console.debug("dojo.date.locale.parse: Could not parse month name: '" + v + "'.");
+						return null;
+					}
+				}else{
+					v--;
+				}
+				result.setMonth(v);
+				expected.month = v;
+				break;
+			case 'E':
+			case 'e':
+				var days = bundle['days-format-' + widthList[l-3]].concat();
+				if(!options.strict){
+					//Case-insensitive comparison
+					v = v.toLowerCase();
+					days = dojo.map(days, "".toLowerCase);
+				}
+				v = dojo.indexOf(days, v);
+				if(v == -1){
+//					console.debug("dojo.date.locale.parse: Could not parse weekday name: '" + v + "'.");
+					return null;
+				}
+
+				//TODO: not sure what to actually do with this input,
+				//in terms of setting something on the Date obj...?
+				//without more context, can't affect the actual date
+				//TODO: just validate?
+				break;
+			case 'd':
+				result.setDate(v);
+				expected.date = v;
+				break;
+			case 'D':
+				//FIXME: need to defer this until after the year is set for leap-year?
+				result.setMonth(0);
+				result.setDate(v);
+				break;
+			case 'a': //am/pm
+				var am = options.am || bundle.am;
+				var pm = options.pm || bundle.pm;
+				if(!options.strict){
+					var period = /\./g;
+					v = v.replace(period,'').toLowerCase();
+					am = am.replace(period,'').toLowerCase();
+					pm = pm.replace(period,'').toLowerCase();
+				}
+				if(options.strict && v != am && v != pm){
+//					console.debug("dojo.date.locale.parse: Could not parse am/pm part.");
+					return null;
+				}
+				var hours = result.getHours();
+				if(v == pm && hours < 12){
+					result.setHours(hours + 12); //e.g., 3pm -> 15
+				} else if(v == am && hours == 12){
+					result.setHours(0); //12am -> 0
+				}
+				break;
+			case 'K': //hour (1-24)
+				if(v==24){v=0;}
+				// fallthrough...
+			case 'h': //hour (1-12)
+			case 'H': //hour (0-23)
+			case 'k': //hour (0-11)
+				//TODO: strict bounds checking, padding
+				if(v>23){
+//					console.debug("dojo.date.locale.parse: Illegal hours value");
+					return null;
+				}
+
+				//in the 12-hour case, adjusting for am/pm requires the 'a' part
+				//which for now we will assume always comes after the 'h' part
+				result.setHours(v);
+				break;
+			case 'm': //minutes
+				result.setMinutes(v);
+				break;
+			case 's': //seconds
+				result.setSeconds(v);
+				break;
+			case 'S': //milliseconds
+				result.setMilliseconds(v);
+				break;
+			case 'w':
+//				var firstDay = 0;
+			default:
+//TODO: throw?
+//				console.debug("dojo.date.locale.parse: unsupported pattern char=" + token.charAt(0));
+		}
+	});
+
+	//validate parse date fields versus input date fields
+	if(expected.year && result.getFullYear() != expected.year){
+//		console.debug("dojo.date.locale.parse: Parsed year: '" + result.getFullYear() + "' did not match input year: '" + expected.year + "'.");
+		return null;
+	}
+	if(expected.month && result.getMonth() != expected.month){
+//		console.debug("dojo.date.locale.parse: Parsed month: '" + result.getMonth() + "' did not match input month: '" + expected.month + "'.");
+		return null;
+	}
+	if(expected.date && result.getDate() != expected.date){
+//		console.debug("dojo.date.locale.parse: Parsed day of month: '" + result.getDate() + "' did not match input day of month: '" + expected.date + "'.");
+		return null;
+	}
+
+	//TODO: implement a getWeekday() method in order to test 
+	//validity of input strings containing 'EEE' or 'EEEE'...
+	return result; // Date
+};
+
+function _processPattern(pattern, applyPattern, applyLiteral, applyAll){
+	//summary: Process a pattern with literals in it
+
+	// Break up on single quotes, treat every other one as a literal, except '' which becomes '
+	var identity = function(x){return x;};
+	applyPattern = applyPattern || identity;
+	applyLiteral = applyLiteral || identity;
+	applyAll = applyAll || identity;
+
+	//split on single quotes (which escape literals in date format strings) 
+	//but preserve escaped single quotes (e.g., o''clock)
+	var chunks = pattern.match(/(''|[^'])+/g); 
+	var literal = false;
+
+	dojo.forEach(chunks, function(chunk, i){
+		if(!chunk){
+			chunks[i]='';
+		}else{
+			chunks[i]=(literal ? applyLiteral : applyPattern)(chunk);
+			literal = !literal;
+		}
+	});
+	return applyAll(chunks.join(''));
+}
+
+function _buildDateTimeRE(tokens, bundle, options, pattern){
+	return dojo.regexp.escapeString(pattern).replace(/([a-z])\1*/ig, function(match){
+		// Build a simple regexp.  Avoid captures, which would ruin the tokens list
+		var s;
+		var c = match.charAt(0);
+		var l = match.length;
+		var p2 = '', p3 = '';
+		if(options.strict){
+			if(l > 1){ p2 = '0' + '{'+(l-1)+'}'; }
+			if(l > 2){ p3 = '0' + '{'+(l-2)+'}'; }
+		}else{
+			p2 = '0?'; p3 = '0{0,2}';
+		}
+		switch(c){
+			case 'y':
+				s = '\\d{2,4}';
+				break;
+			case 'M':
+				s = (l>2) ? '\\S+' : p2+'[1-9]|1[0-2]';
+				break;
+			case 'D':
+				s = p2+'[1-9]|'+p3+'[1-9][0-9]|[12][0-9][0-9]|3[0-5][0-9]|36[0-6]';
+				break;
+			case 'd':
+				s = p2+'[1-9]|[12]\\d|3[01]';
+				break;
+			case 'w':
+				s = p2+'[1-9]|[1-4][0-9]|5[0-3]';
+				break;
+		    case 'E':
+				s = '\\S+';
+				break;
+			case 'h': //hour (1-12)
+				s = p2+'[1-9]|1[0-2]';
+				break;
+			case 'k': //hour (0-11)
+				s = p2+'\\d|1[01]';
+				break;
+			case 'H': //hour (0-23)
+				s = p2+'\\d|1\\d|2[0-3]';
+				break;
+			case 'K': //hour (1-24)
+				s = p2+'[1-9]|1\\d|2[0-4]';
+				break;
+			case 'm':
+			case 's':
+				s = '[0-5]\\d';
+				break;
+			case 'S':
+				s = '\\d{'+l+'}';
+				break;
+			case 'a':
+				var am = options.am || bundle.am || 'AM';
+				var pm = options.pm || bundle.pm || 'PM';
+				if(options.strict){
+					s = am + '|' + pm;
+				}else{
+					s = am + '|' + pm;
+					if(am != am.toLowerCase()){ s += '|' + am.toLowerCase(); }
+					if(pm != pm.toLowerCase()){ s += '|' + pm.toLowerCase(); }
+				}
+				break;
+//			default:
+//				console.debug("parse of date format, pattern=" + pattern);
+		}
+
+		if(tokens){ tokens.push(match); }
+
+//FIXME: replace whitespace within final regexp with more flexible whitespace match instead?
+		//tolerate whitespace
+		return '\\s*(' + s + ')\\s*';
+	});
+}
+})();
+
+(function(){
+var _customFormats = [];
+dojo.date.locale.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){
+	// summary:
+	//		Add a reference to a bundle containing localized custom formats to be
+	//		used by date/time formatting and parsing routines.
+	//
+	// description:
+	//		The user may add custom localized formats where the bundle has properties following the
+	//		same naming convention used by dojo for the CLDR data: dateFormat-xxxx / timeFormat-xxxx
+	//		The pattern string should match the format used by the CLDR.
+	//		See dojo.date.format for details.
+	//		The resources must be loaded by dojo.requireLocalization() prior to use
+
+	_customFormats.push({pkg:packageName,name:bundleName});
+};
+
+dojo.date.locale._getGregorianBundle = function(/*String*/locale){
+	var gregorian = {};
+	dojo.forEach(_customFormats, function(desc){
+		var bundle = dojo.i18n.getLocalization(desc.pkg, desc.name, locale);
+		gregorian = dojo.mixin(gregorian, bundle);
+	}, this);
+	return gregorian; /*Object*/
+};
+})();
+
+dojo.date.locale.addCustomFormats("dojo.cldr","gregorian");
+
+dojo.date.locale.getNames = function(/*String*/item, /*String*/type, /*String?*/use, /*String?*/locale){
+	// summary:
+	//		Used to get localized strings from dojo.cldr for day or month names.
+	//
+	// item: 'months' || 'days'
+	// type: 'wide' || 'narrow' || 'abbr' (e.g. "Monday", "Mon", or "M" respectively, in English)
+	// use: 'standAlone' || 'format' (default)
+	// locale: override locale used to find the names
+
+	var label;
+	var lookup = dojo.date.locale._getGregorianBundle(locale);
+	var props = [item, use, type];
+	if(use == 'standAlone'){
+		label = lookup[props.join('-')];
+	}
+	props[1] = 'format';
+
+	// return by copy so changes won't be made accidentally to the in-memory model
+	return (label || lookup[props.join('-')]).concat(); /*Array*/
+};
+
+dojo.date.locale.isWeekend = function(/*Date?*/dateObject, /*String?*/locale){
+	// summary:
+	//	Determines if the date falls on a weekend, according to local custom.
+
+	var weekend = dojo.cldr.supplemental.getWeekend(locale);
+	var day = (dateObject || new Date()).getDay();
+	if(weekend.end<weekend.start){
+		weekend.end+=7;
+		if(day<weekend.start){ day+=7; }
+	}
+	return day >= weekend.start && day <= weekend.end; // Boolean
+};
+
+// These are used only by format and strftime.  Do they need to be public?  Which module should they go in?
+
+dojo.date.locale._getDayOfYear = function(/*Date*/dateObject){
+	// summary: gets the day of the year as represented by dateObject
+	var fullYear = dateObject.getFullYear();
+	var lastDayOfPrevYear = new Date(fullYear-1, 11, 31);
+	return Math.floor((dateObject.getTime() -
+		lastDayOfPrevYear.getTime()) / (24*60*60*1000)); // Number
+}
+
+dojo.date.locale._getWeekOfYear = function(/*Date*/dateObject, /*Number*/firstDay){
+	if(arguments.length == 1){ firstDay = 0; } // Sunday
+
+	// work out the first day of the year corresponding to the week
+	var firstDayOfYear = new Date(dateObject.getFullYear(), 0, 1);
+	var day = firstDayOfYear.getDay();
+	firstDayOfYear.setDate(firstDayOfYear.getDate() -
+			day + firstDay - (day > firstDay ? 7 : 0));
+
+	return Math.floor((dateObject.getTime() -
+		firstDayOfYear.getTime()) / (7*24*60*60*1000)); // Number
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/date/stamp.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/date/stamp.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/date/stamp.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,160 @@
+dojo.provide("dojo.date.stamp");
+
+// Methods to convert dates to or from a wire (string) format using well-known conventions
+
+dojo.require("dojo.string");
+
+/* ISO 8601 Functions
+ *********************/
+
+dojo.date.stamp.setIso8601 = function(/*Date*/dateObject, /*String*/formattedString){
+	// summary: sets a Date object based on an ISO 8601 formatted string (uses date and time)
+	var comps = (formattedString.indexOf("T") == -1) ? formattedString.split(" ") : formattedString.split("T");
+	dateObject = dojo.date.stamp.setIso8601Date(dateObject, comps[0]);
+	if(comps.length == 2){ dateObject = dojo.date.stamp.setIso8601Time(dateObject, comps[1]); }
+	return dateObject; /* Date or null */
+};
+
+dojo.date.stamp.fromIso8601 = function(/*String*/formattedString){
+	// summary: returns a Date object based on an ISO 8601 formatted string (uses date and time)
+	return dojo.date.stamp.setIso8601(new Date(0, 0), formattedString);
+};
+
+dojo.date.stamp.setIso8601Date = function(/*String*/dateObject, /*String*/formattedString){
+	// summary: sets a Date object based on an ISO 8601 formatted string (date only)
+	var regexp = "^([0-9]{4})((-?([0-9]{2})(-?([0-9]{2}))?)|" +
+			"(-?([0-9]{3}))|(-?W([0-9]{2})(-?([1-7]))?))?$";
+	var d = formattedString.match(new RegExp(regexp));
+	if(!d){
+		console.debug("invalid date string: " + formattedString);
+		return null; // null
+	}
+	var year = d[1];
+	var month = d[4];
+	var date = d[6];
+	var dayofyear = d[8];
+	var week = d[10];
+	var dayofweek = d[12] || 1;
+
+	dateObject.setFullYear(year);
+
+	if(dayofyear){
+		dateObject.setMonth(0);
+		dateObject.setDate(Number(dayofyear));
+	}
+	else if(week){
+		dateObject.setMonth(0);
+		dateObject.setDate(1);
+		var day = dateObject.getDay() || 7;
+		var offset = Number(dayofweek) + (7 * Number(week));
+	
+		if(day <= 4){ dateObject.setDate(offset + 1 - day); }
+		else{ dateObject.setDate(offset + 8 - day); }
+	} else{
+		if(month){
+			dateObject.setDate(1);
+			dateObject.setMonth(month - 1); 
+		}
+		if(date){ dateObject.setDate(date); }
+	}
+
+	return dateObject; // Date
+};
+
+dojo.date.stamp.fromIso8601Date = function(/*String*/formattedString){
+	// summary: returns a Date object based on an ISO 8601 formatted string (date only)
+	return dojo.date.stamp.setIso8601Date(new Date(0, 0), formattedString);
+};
+
+dojo.date.stamp.setIso8601Time = function(/*Date*/dateObject, /*String*/formattedString){
+	// summary: sets a Date object based on an ISO 8601 formatted string (time only)
+
+	// first strip timezone info from the end
+	var timezone = "Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$";
+	var d = formattedString.match(new RegExp(timezone));
+
+	var offset = 0; // local time if no tz info
+	if(d){
+		if(d[0] != 'Z'){
+			offset = (Number(d[3]) * 60) + Number(d[5] || 0);
+			if(d[2] != '-'){ offset *= -1; }
+		}
+		offset -= dateObject.getTimezoneOffset();
+		formattedString = formattedString.substr(0, formattedString.length - d[0].length);
+	}
+
+	// then work out the time
+	var regexp = "^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(\.([0-9]+))?)?)?$";
+	d = formattedString.match(new RegExp(regexp));
+	if(!d){
+		console.debug("invalid time string: " + formattedString);
+		return null; // null
+	}
+	var hours = d[1];
+	var mins = Number(d[3] || 0);
+	var secs = d[5] || 0;
+	var ms = d[7] ? (Number("0." + d[7]) * 1000) : 0;
+
+	dateObject.setHours(hours);
+	dateObject.setMinutes(mins);
+	dateObject.setSeconds(secs);
+	dateObject.setMilliseconds(ms);
+
+	if(offset !== 0){
+		dateObject.setTime(dateObject.getTime() + offset * 60000);
+	}	
+	return dateObject; // Date
+};
+
+dojo.date.stamp.fromIso8601Time = function(/*String*/formattedString){
+	// summary: returns a Date object based on an ISO 8601 formatted string (time only)
+	return dojo.date.stamp.setIso8601Time(new Date(0, 0), formattedString);
+};
+
+
+/* RFC-3339 Date Functions
+ *************************/
+
+dojo.date.stamp.toRfc3339 = function(/*Date?*/dateObject, /*String?*/selector){
+//	summary:
+//		Format a JavaScript Date object as a string according to RFC 3339
+//
+//	dateObject:
+//		A JavaScript date, or the current date and time, by default
+//
+//	selector:
+//		"date" or "time" to format selected portions of the Date object.
+//		Date and time will be formatted by default.
+
+	dateObject = dateObject || new Date();
+
+	var _ = dojo.string.pad;
+	var formattedDate = [];
+	if(selector != "time"){
+		var date = [_(dateObject.getFullYear(),4), _(dateObject.getMonth()+1,2), _(dateObject.getDate(),2)].join('-');
+		formattedDate.push(date);
+	}
+	if(selector != "date"){
+		var time = [_(dateObject.getHours(),2), _(dateObject.getMinutes(),2), _(dateObject.getSeconds(),2)].join(':');
+		var timezoneOffset = dateObject.getTimezoneOffset();
+		time += (timezoneOffset > 0 ? "-" : "+") + 
+					_(Math.floor(Math.abs(timezoneOffset)/60),2) + ":" +
+					_(Math.abs(timezoneOffset)%60,2);
+		formattedDate.push(time);
+	}
+	return formattedDate.join('T'); // String
+};
+
+dojo.date.stamp.fromRfc3339 = function(/*String*/rfcDate){
+//	summary:
+//		Create a JavaScript Date object from a string formatted according to RFC 3339
+//
+//	rfcDate:
+//		A string such as 2005-06-30T08:05:00-07:00
+//		"any" is also supported in place of a time.
+
+	// backwards compatible support for use of "any" instead of just not 
+	// including the time
+	rfcDate = rfcDate.replace("Tany","");
+	return dojo.date.stamp.setIso8601(new Date(), rfcDate); // Date or null
+};

Added: trunk/examples/typeface/root/static/dojo/dojo/date.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/date.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/date.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,350 @@
+dojo.provide("dojo.date");
+
+dojo.date.getDaysInMonth = function(/*Date*/dateObject){
+	// summary: returns the number of days in the month used by dateObject
+	var month = dateObject.getMonth();
+	var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+	if (month == 1 && dojo.date.isLeapYear(dateObject)){ return 29; } // Number
+	return days[month]; // Number
+}
+
+dojo.date.isLeapYear = function(/*Date*/dateObject){
+	// summary:
+	//	Determines if the year of the dateObject is a leap year
+	//
+	// description:
+	//	Leap years are years with an additional day YYYY-02-29, where the year
+	//	number is a multiple of four with the following exception: If a year
+	//	is a multiple of 100, then it is only a leap year if it is also a
+	//	multiple of 400. For example, 1900 was not a leap year, but 2000 is one.
+
+	var year = dateObject.getFullYear();
+	return !(year%400) || (!(year%4) && !!(year%100)); // Boolean
+}
+
+// FIXME: This is not localized
+dojo.date.getTimezoneName = function(/*Date*/dateObject){
+	// summary:
+	//	Get the user's time zone as provided by the browser
+	//
+	// dateObject: needed because the timezone may vary with time (daylight savings)
+	//
+	// description:
+	//	Try to get time zone info from toString or toLocaleString
+	//	method of the Date object -- UTC offset is not a time zone.
+	//	See http://www.twinsun.com/tz/tz-link.htm
+	//	Note: results may be inconsistent across browsers.
+
+	var str = dateObject.toString(); // Start looking in toString
+	var tz = ''; // The result -- return empty string if nothing found
+	var match;
+
+	// First look for something in parentheses -- fast lookup, no regex
+	var pos = str.indexOf('(');
+	if(pos > -1){
+		tz = str.substring(++pos, str.indexOf(')'));
+	}else{
+		// If at first you don't succeed ...
+		// If IE knows about the TZ, it appears before the year
+		// Capital letters or slash before a 4-digit year 
+		// at the end of string
+		var pat = /([A-Z\/]+) \d{4}$/;
+		if((match = str.match(pat))){
+			tz = match[1];
+		}else{
+		// Some browsers (e.g. Safari) glue the TZ on the end
+		// of toLocaleString instead of putting it in toString
+			str = dateObject.toLocaleString();
+			// Capital letters or slash -- end of string, 
+			// after space
+			pat = / ([A-Z\/]+)$/;
+			if((match = str.match(pat))){
+				tz = match[1];
+			}
+		}
+	}
+
+	// Make sure it doesn't somehow end up return AM or PM
+	return (tz == 'AM' || tz == 'PM') ? '' : tz; // String
+}
+
+// Utility methods to do arithmetic calculations with Dates
+
+dojo.date.compare = function(/*Date*/date1, /*Date?*/date2, /*String?*/portion){
+	//	summary
+	//		Compare two date objects by date, time, or both.
+	//
+	//  description
+	//  	Returns 0 if equal, positive if a > b, else negative.
+	//
+	//	date1
+	//		Date object
+	//
+	//	date2
+	//		Date object.  If not specified, the current Date is used.
+	//
+	//	portion
+	//		A string indicating the "date" or "time" portion of a Date object.  Compares both "date" and "time" by default.
+	//		One of the following: "date", "time", "datetime"
+
+	// Extra step required in copy for IE - see #3112
+	date1 = new Date(Number(date1));
+	date2 = new Date(Number(date2 || new Date()));
+
+	if(typeof portion !== "undefined"){
+		if(portion == "date"){
+			// Ignore times and compare dates.
+			date1.setHours(0, 0, 0, 0);
+			date2.setHours(0, 0, 0, 0);
+		}else if(portion == "time"){
+			// Ignore dates and compare times.
+			date1.setFullYear(0, 0, 0);
+			date2.setFullYear(0, 0, 0);
+		}
+	}
+	
+	if(date1 > date2){ return 1; } // int
+	if(date1 < date2){ return -1; } // int
+	return 0; // int
+};
+
+dojo.date.add = function(/*Date*/date, /*String*/interval, /*int*/amount){
+	//	summary
+	//		Add to a Date in intervals of different size, from milliseconds to years
+	//
+	//	date
+	//		Date object to start with
+	//
+	//	interval
+	//		A string representing the interval.  One of the following:
+	//			"year", "month", "day", "hour", "minute", "second", "millisecond", "quarter", "week", "weekday"
+	//
+	//	amount
+	//		How much to add to the date.
+
+	var sum = new Date(Number(date)); // convert to Number before copying to accomodate IE (#3112)
+	var fixOvershoot = false;
+	var property = "Date";
+
+	switch(interval){
+		case "day":
+			break;
+		case "weekday":
+			//i18n FIXME: assumes Saturday/Sunday weekend, but even this is not standard.  There are CLDR entries to localize this.
+			var dayOfMonth = date.getDate();
+			var weeks = 0;
+			var days = 0;
+			var strt = 0;
+			var trgt = 0;
+			var adj = 0;
+			// Divide the increment time span into weekspans plus leftover days
+			// e.g., 8 days is one 5-day weekspan / and two leftover days
+			// Can't have zero leftover days, so numbers divisible by 5 get
+			// a days value of 5, and the remaining days make up the number of weeks
+			var mod = amount % 5;
+			if(!mod){
+				days = (amount > 0) ? 5 : -5;
+				weeks = (amount > 0) ? ((amount-5)/5) : ((amount+5)/5);
+			}else{
+				days = mod;
+				weeks = parseInt(amount/5);
+			}
+			// Get weekday value for orig date param
+			strt = date.getDay();
+			// Orig date is Sat / positive incrementer
+			// Jump over Sun
+			if(strt == 6 && amount > 0){
+				adj = 1;
+			}else if(strt == 0 && amount < 0){
+			// Orig date is Sun / negative incrementer
+			// Jump back over Sat
+				adj = -1;
+			}
+			// Get weekday val for the new date
+			trgt = strt + days;
+			// New date is on Sat or Sun
+			if(trgt == 0 || trgt == 6){
+				adj = (amount > 0) ? 2 : -2;
+			}
+			// Increment by number of weeks plus leftover days plus
+			// weekend adjustments
+			amount = dayOfMonth + 7*weeks + days + adj;
+			break;
+		case "year":
+			property = "FullYear";
+			// Keep increment/decrement from 2/29 out of March
+			fixOvershoot = true;
+			break;
+		case "week":
+			amount *= 7;
+			break;
+		case "quarter":
+			// Naive quarter is just three months
+			amount *= 3;
+			// fallthrough...
+		case "month":
+			// Reset to last day of month if you overshoot
+			fixOvershoot = true;
+			property = "Month";
+			break;
+		case "hour":
+		case "minute":
+		case "second":
+		case "millisecond":
+			property = interval.charAt(0).toUpperCase() + interval.substring(1) + "s";
+	}
+
+	if(property){
+		sum["set"+property](sum["get"+property]()+amount);
+	}
+
+	if(fixOvershoot && (sum.getDate() < date.getDate())){
+		sum.setDate(0);
+	}
+
+	return sum; // Date
+};
+
+dojo.date.difference = function(/*Date*/date1, /*Date?*/date2, /*String?*/interval){
+	//	summary
+	//		Get the difference in a specific unit of time (e.g., number of months, weeks,
+	//		days, etc.) between two dates, rounded to the nearest integer.
+	//
+	//	date1
+	//		Date object
+	//
+	//	date2
+	//		Date object.  If not specified, the current Date is used.
+	//
+	//	interval
+	//		A string representing the interval.  One of the following:
+	//			"year", "month", "day", "hour", "minute", "second", "millisecond", "quarter", "week", "weekday"
+	//		Defaults to "day".
+
+	date2 = date2 || new Date();
+	interval = interval || "day";
+	var yearDiff = date2.getFullYear() - date1.getFullYear();
+	var delta = 1; // Integer return value
+
+	switch(interval){
+		case "quarter":
+			var m1 = date1.getMonth();
+			var m2 = date2.getMonth();
+			// Figure out which quarter the months are in
+			var q1 = Math.floor(m1/3) + 1;
+			var q2 = Math.floor(m2/3) + 1;
+			// Add quarters for any year difference between the dates
+			q2 += (yearDiff * 4);
+			delta = q2 - q1;
+			break;
+		case "weekday":
+			var days = Math.round(dojo.date.difference(date1, date2, "day"));
+			var weeks = parseInt(dojo.date.difference(date1, date2, "week"));
+			var mod = days % 7;
+
+			// Even number of weeks
+			if(mod == 0){
+				days = weeks*5;
+			}else{
+				// Weeks plus spare change (< 7 days)
+				var adj = 0;
+				var aDay = date1.getDay();
+				var bDay = date2.getDay();
+
+				weeks = parseInt(days/7);
+				mod = days % 7;
+				// Mark the date advanced by the number of
+				// round weeks (may be zero)
+				var dtMark = new Date(date1);
+				dtMark.setDate(dtMark.getDate()+(weeks*7));
+				var dayMark = dtMark.getDay();
+
+				// Spare change days -- 6 or less
+				if(days > 0){
+					switch(true){
+						// Range starts on Sat
+						case aDay == 6:
+							adj = -1;
+							break;
+						// Range starts on Sun
+						case aDay == 0:
+							adj = 0;
+							break;
+						// Range ends on Sat
+						case bDay == 6:
+							adj = -1;
+							break;
+						// Range ends on Sun
+						case bDay == 0:
+							adj = -2;
+							break;
+						// Range contains weekend
+						case (dayMark + mod) > 5:
+							adj = -2;
+							break;
+						default:
+							// Do nothing
+							break;
+					}
+				}else if(days < 0){
+					switch (true){
+						// Range starts on Sat
+						case aDay == 6:
+							adj = 0;
+							break;
+						// Range starts on Sun
+						case aDay == 0:
+							adj = 1;
+							break;
+						// Range ends on Sat
+						case bDay == 6:
+							adj = 2;
+							break;
+						// Range ends on Sun
+						case bDay == 0:
+							adj = 1;
+							break;
+						// Range contains weekend
+						case (dayMark + mod) < 0:
+							adj = 2;
+							break;
+						default:
+							// Do nothing
+							break;
+					}
+				}
+				days += adj;
+				days -= (weeks*2);
+			}
+			delta = days;
+			break;
+		case "year":
+			delta = yearDiff;
+			break;
+		case "month":
+			delta = (date2.getMonth() - date1.getMonth()) + (yearDiff * 12);
+			break;
+		case "week":
+			// Truncate instead of rounding
+			// Don't use Math.floor -- value may be negative
+			delta = parseInt(dojo.date.difference(date1, date2, "day")/7);
+			break;
+		case "day":
+			delta /= 24;
+			// fallthrough
+		case "hour":
+			delta /= 60;
+			// fallthrough
+		case "minute":
+			delta /= 60;
+			// fallthrough
+		case "second":
+			delta /= 1000;
+			// fallthrough
+		case "millisecond":
+			delta *= date2.getTime() - date1.getTime();
+	}
+
+	// Round for fractional values and DST leaps
+	return Math.round(delta); // Number (integer)
+};

Added: trunk/examples/typeface/root/static/dojo/dojo/dnd/avatar.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/dnd/avatar.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/dnd/avatar.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,73 @@
+dojo.provide("dojo.dnd.avatar");
+
+dojo.require("dojo.dnd.common");
+
+dojo.dnd.Avatar = function(manager){
+	// summary: an object, which represents transferred DnD items visually
+	// manager: Object: a DnD manager object
+	this.manager = manager;
+	this.construct();
+	// calculate various offsets
+	this.offX = dojo.dnd._getOffset(this.node, "Left");
+	this.offY = dojo.dnd._getOffset(this.node, "Top");
+};
+
+dojo.extend(dojo.dnd.Avatar, {
+	construct: function(){
+		// summary: a constructor function;
+		//	it is separate so it can be (dynamically) overwritten in case of need
+		var a = dojo.doc.createElement("table");
+		a.className = "dojoDndAvatar";
+		a.style.position = "absolute";
+		a.style.zIndex = 999;
+		var b = dojo.doc.createElement("tbody");
+		var tr = dojo.doc.createElement("tr");
+		tr.className = "dojoDndAvatarHeader";
+		var td = dojo.doc.createElement("td");
+		td.innerHTML = this._generateText();
+		tr.appendChild(td);
+		dojo.style(tr, "opacity", 0.9);
+		b.appendChild(tr);
+		var k = Math.min(5, this.manager.nodes.length);
+		for(var i = 0; i < k; ++i){
+			tr = dojo.doc.createElement("tr");
+			tr.className = "dojoDndAvatarItem";
+			td = dojo.doc.createElement("td");
+			var t = this.manager.source.nodeCreator(this.manager.source.map[this.manager.nodes[i].id].data, "avatar");
+			td.appendChild(t.node);
+			tr.appendChild(td);
+			dojo.style(tr, "opacity", (6 - i) / 10);
+			b.appendChild(tr);
+		}
+		a.appendChild(b);
+		this.node = a;
+	},
+	destroy: function(){
+		// summary: a desctructor for the avatar, called to remove all references so it can be garbage-collected
+		this.node.parentNode.removeChild(this.node);
+		this.node = false;
+	},
+	update: function(){
+		// summary: updates the avatar to reflect the current DnD state
+		//dojo.html[(this.manager.canDropFlag ? "add" : "remove") + "Class"](this.node, "dojoDndAvatarCanDrop");
+		if(this.manager.canDropFlag){
+		  dojo.addClass(this.node, "dojoDndAvatarCanDrop");
+		}else{
+		  dojo.removeClass(this.node, "dojoDndAvatarCanDrop");
+		}
+		// replace text
+		var t = this.node.getElementsByTagName("td");
+		for(var i = 0; i < t.length; ++i){
+			var n = t[i];
+			//if(dojo.html.hasClass(n.parentNode, "dojoDndAvatarHeader")){
+			if(dojo.hasClass(n.parentNode, "dojoDndAvatarHeader")){
+				n.innerHTML = this._generateText();
+				break;
+			}
+		}
+	},
+	_generateText: function(){
+		// summary: generates a proper text to reflect copying or moving of items
+		return (this.manager.copy ? "copy" : "mov") + "ing " + this.manager.nodes.length + " item" + (this.manager.nodes.length != 1 ? "s" : "");	
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojo/dnd/common.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/dnd/common.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/dnd/common.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,36 @@
+dojo.provide("dojo.dnd.common");
+
+if(navigator.appVersion.indexOf("Macintosh") < 0){
+	dojo.dnd.multiSelectKey = function(e) {
+		// summary: abstracts away the difference between selection on Mac and PC
+		// e: Event: mouse event
+		return e.ctrlKey;	// Boolean
+	};
+}else{
+	dojo.dnd.multiSelectKey = function(e) {
+		// summary: abstracts away the difference between selection on Mac and PC
+		// e: Event: mouse event
+		return e.metaKey;	// Boolean
+	};
+}
+
+dojo.dnd._getOffset = function(node, side){
+	// summary: calculates an offset for a content box
+	// node: Node: a node
+	// side: String: a side of a box ("Left", "Right", "Top", or "Bottom")
+	var t = dojo.style(node, "margin" + side) + dojo.style(node, "padding" + side);
+	// FIXME: border is not processed properly
+	var b = dojo.style(node, "border" + side);
+	if(b == ""){ b = 0; }
+	return t + b;
+};
+
+dojo.dnd._uniqueId = 0;
+dojo.dnd.getUniqueId = function(){
+	// summary: returns a unique string for use with any DOM element
+	var id;
+	do{
+		id = "dojoUnique" + (++dojo.dnd._uniqueId);
+	}while(dojo.byId(id));
+	return id;
+};

Added: trunk/examples/typeface/root/static/dojo/dojo/dnd/container.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/dnd/container.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/dnd/container.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,254 @@
+dojo.provide("dojo.dnd.container");
+
+dojo.require("dojo.dnd.common");
+
+/*
+	Container states:
+		""		- normal state
+		"Over"	- mouse over a container
+	Container item states:
+		""		- normal state
+		"Over"	- mouse over a container item
+*/
+
+dojo.declare("dojo.dnd.Container", null, 
+	// summary: a Container object, which knows when mouse hovers over it, 
+	//	and know over which element it hovers
+function(node, params){
+	// summary: a constructor of the Container
+	// node: Node: node or node's id to build the container on
+	// params: Object: a dict of parameters, recognized parameters are:
+	//	filter: Function: a filter function, which is used to filter out children of the container
+	//	creator: Function: a creator function, which takes a data item, and returns an object like that:
+	//		{node: newNode, data: usedData, types: arrayOfStrings}
+	//	selector: Function: a selector function, which selects all relevant nodes of a container; 
+	//		should be used in pair with the filter function; returns an object like that:
+	//		{parent: parentNode, nodes: arrayOf childNodes}
+	this.node = dojo.byId(node);
+	var me = this;
+	this.nodeFilter = (params && params.filter) ?
+		params.filter :
+		function(n){ return n.parentNode == me.parent && n.nodeType == 1; };
+	this.nodeCreator  = (params && params.creator) ?
+		params.creator :
+		dojo.dnd._defaultCreator(this.node);
+	this.nodeSelector = (params && params.selector) ?
+		params.selector :
+		dojo.dnd._defaultSelector;
+	// class-specific variables
+	this.map = {};
+	this.current = null;
+	// states
+	this.containerState = "";
+	dojo.addClass(this.node, "dojoDndContainer");
+	
+	// mark up children
+	var c = this.nodeSelector(this.node);
+	this.parent = c.parent;
+	c = c.nodes;
+	for(var i = 0; i < c.length; ++i){
+		var n = c[i];
+		if(this.nodeFilter(n) && !n.id){
+			n.id = dojo.dnd.getUniqueId();
+		}
+	}
+	// set up events
+	this.events = [
+		dojo.connect(this.node, "onmouseover", this, "onMouseOver"),
+		dojo.connect(this.node, "onmouseout",  this, "onMouseOut"),
+		// cancel text selection and text dragging
+		dojo.connect(this.node, "ondragstart",   dojo, "stopEvent"),
+		dojo.connect(this.node, "onselectstart", dojo, "stopEvent")
+	];
+},
+{
+	// mouse events
+	onMouseOver: function(e){
+		// summary: event processor for onmouseover
+		// e: Event: mouse event
+		var n = e.relatedTarget;
+		for(; n; n = n.parentNode){
+			if(n == this.node){ break; }
+		}
+		if(!n){
+			this._changeState("Container", "Over");
+			this.onOverEvent();
+		}
+		n = this._getChildByEvent(e);
+		if(this.current == n){ return; }
+		if(this.current){ this._removeItemClass(this.current, "Over"); }
+		if(n){ this._addItemClass(n, "Over"); }
+		this.current = n;
+	},
+	onMouseOut: function(e){
+		// summary: event processor for onmouseout
+		// e: Event: mouse event
+		for(var n = e.relatedTarget; n; n = n.parentNode){
+			if(n == this.node){ return; }
+		}
+		if(this.current){
+			this._removeItemClass(this.current, "Over");
+			this.current = null;
+		}
+		this._changeState("Container", "");
+		this.onOutEvent();
+	},
+	// methods
+	destroy: function(){
+		// summary: prepares the object to be garbage-collected
+		dojo.forEach(this.events, dojo.disconnect);
+		this.node = this.parent = this.current = this.map = null;
+	},
+	getAllNodes: function(){
+		// summary: returns a list (an array) of all valid child nodes
+		var t = [];
+		var c = this.nodeSelector(this.node).nodes;
+		for(var i = 0; i < c.length; ++i){
+			var n = c[i];
+			if(this.nodeFilter(n)){
+				t.push(n);
+			}
+		}
+		return t;	// Array
+	},
+	insertNodes: function(data, before, anchor){
+		// summary: inserts an array of new nodes before/after an anchor node
+		// data: Array: a list of data items, which should be processed by the creator function
+		// before: Boolean: insert before the anchor, if true, and after the anchor otherwise
+		// anchor: Node: the anchor node to be used as a point of insertion
+		if(!this.parent.firstChild){
+			anchor = null;
+		}else if(before){
+			if(!anchor){
+				anchor = this.parent.firstChild;
+			}
+		}else{
+			if(anchor){
+				anchor = anchor.nextSibling;
+			}
+		}
+		if(anchor){
+			for(var i = 0; i < data.length; ++i){
+				var t = this.nodeCreator(data[i]);
+				this.map[t.node.id] = {data: t.data, types: t.types};
+				this.parent.insertBefore(t.node, anchor);
+			}
+		}else{
+			for(var i = 0; i < data.length; ++i){
+				var t = this.nodeCreator(data[i]);
+				this.map[t.node.id] = {data: t.data, types: t.types};
+				this.parent.appendChild(t.node);
+			}
+		}
+		return this;	// self
+	},
+	// utilities
+	onOverEvent: function(){
+		// summary: this function is called once, when mouse is over our container
+	},
+	onOutEvent: function(){
+		// summary: this function is called once, when mouse is out of our container
+	},
+	_changeState: function(type, newState){
+		// summary: changes a named state to new state value
+		// type: String: a name of the state to change
+		// newState: String: new state
+		var prefix = "dojoDnd" + type;
+		var state  = type.toLowerCase() + "State";
+		//dojo.html.replaceClass(this.node, prefix + newState, prefix + this[state]);
+		dojo.removeClass(this.node, prefix + this[state]);
+		dojo.addClass(this.node, prefix + newState);
+		this[state] = newState;
+	},
+	_addItemClass: function(node, type){
+		// summary: adds a class with prefix "dojoDndItem"
+		// node: Node: a node
+		// type: String: a variable suffix for a class name
+		//dojo.html.addClass(node, "dojoDndItem" + type);
+		dojo.addClass(node, "dojoDndItem" + type);
+	},
+	_removeItemClass: function(node, type){
+		// summary: removes a class with prefix "dojoDndItem"
+		// node: Node: a node
+		// type: String: a variable suffix for a class name
+		//dojo.html.removeClass(node, "dojoDndItem" + type);
+		dojo.removeClass(node, "dojoDndItem" + type);
+	},
+	_getChildByEvent: function(e){
+		// summary: gets a child, which is under the mouse at the moment, or null
+		// e: Event: a mouse event
+		var node = e.target;
+		if(node == this.node){ return null; }
+		if(this.nodeFilter(node)) return node;
+		var parent = node.parentNode;
+		while(parent && parent != this.parent && node != this.node){
+			node = parent;
+			parent = node.parentNode;
+			if(this.nodeFilter(node)) return node;
+		}
+		return (parent && this.nodeFilter(node)) ? node : null;	// Node
+	}
+});
+
+dojo.dnd._createNode = function(tag){
+	// summary: returns a function, which creates an element of given tag 
+	//	(SPAN by default) and sets its innerHTML to given text
+	// tag: String: a tag name or empty for SPAN
+	if(!tag){ return dojo.dnd._createSpan; }
+	return function(text){	// Function
+		var n = dojo.doc.createElement(tag);
+		n.innerHTML = text;
+		return n;
+	};
+};
+
+dojo.dnd._createTrTd = function(text){
+	// summary: creates a TR/TD structure with given text as an innerHTML of TD
+	// text: String: a text for TD
+	var tr = dojo.doc.createElement("tr");
+	var td = dojo.doc.createElement("td");
+	td.innerHTML = text;
+	tr.appendChild(td);
+	return tr;	// Node
+};
+
+dojo.dnd._createSpan = function(text){
+	// summary: creates a SPAN element with given text as its innerHTML
+	// text: String: a text for SPAN
+	var n = dojo.doc.createElement("span");
+	n.innerHTML = text;
+	return n;	// Node
+};
+
+// dojo.dnd._defaultCreatorNodes: Object: a dicitionary, which maps container tag names to child tag names
+dojo.dnd._defaultCreatorNodes = {ul: "li", ol: "li", div: "div", p: "div"};
+
+dojo.dnd._defaultCreator = function(node){
+	// summary: takes a container node, and returns an appropriate creator function
+	// node: Node: a container node
+	var tag = node.tagName.toLowerCase();
+	var c = tag == "table" ? dojo.dnd._createTrTd : dojo.dnd._createNode(dojo.dnd._defaultCreatorNodes[tag]);
+	var r = (dojo.lang && dojo.lang.repr) ? dojo.lang.repr : function(o){ return o + ""; };
+	return function(data, hint){	// Function
+		var t = r(data);
+		var n = (hint == "avatar" ? dojo.dnd._createSpan : c)(t);
+		n.id = dojo.dnd.getUniqueId();
+		return {node: n, data: data, types: ["text"]};
+	};
+};
+
+dojo.dnd._defaultSelector = function(node) {
+	// summary: takes a container node, and returns a parent, and a list of children
+	// node: Node: a container node
+	var ret = {parent: node, nodes: []};
+	if(node.tagName.toLowerCase() == "table"){
+		var c = node.getElementsByTagName("tbody");
+		if(c && c.length){
+			ret.parent = c[0];
+		}
+		ret.nodes = ret.parent.getElementsByTagName("tr");
+	}else{
+		ret.nodes = node.childNodes;
+	}
+	return ret;	// Object
+};

Added: trunk/examples/typeface/root/static/dojo/dojo/dnd/manager.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/dnd/manager.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/dnd/manager.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,147 @@
+dojo.provide("dojo.dnd.manager");
+
+dojo.require("dojo.dnd.common");
+dojo.require("dojo.dnd.avatar");
+
+dojo.dnd.Manager = function(){
+	// summary: the manager of DnD operations (usually a singleton)
+	this.avatar  = null;
+	this.source = null;
+	this.nodes = [];
+	this.copy  = true;
+	this.target = null;
+	this.canDropFlag = false;
+	this.events = [];
+};
+
+dojo.extend(dojo.dnd.Manager, {
+	// methods
+	overSource: function(source){
+		// summary: called when a source detected a mouse-over conditiion
+		// source: Object: the reporter
+		if(this.avatar){
+			this.target = (source && source.targetState != "Disabled") ? source : null;
+			this.avatar.update();
+		}
+		dojo.publish("dndSourceOver", [source]);
+	},
+	outSource: function(source){
+		// summary: called when a source detected a mouse-out conditiion
+		// source: Object: the reporter
+		if(this.avatar){
+			if(this.target == source){
+				this.target = null;
+				this.canDropFlag = false;
+				this.avatar.update();
+				dojo.publish("dndSourceOver", [null]);
+			}
+		}else{
+			dojo.publish("dndSourceOver", [null]);
+		}
+	},
+	startDrag: function(source, nodes, copy){
+		// summary: called to initiate the DnD operation
+		// source: Object: the source which provides items
+		// nodes: Array: the list of transferred items
+		// copy: Boolean: copy items, if true, move items otherwise
+		this.source = source;
+		this.nodes  = nodes;
+		this.copy   = copy;
+		this.avatar = this.makeAvatar();
+		dojo.body().appendChild(this.avatar.node);
+		dojo.publish("dndStart", [source, nodes, copy]);
+		this.events = [
+			dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"),
+			dojo.connect(dojo.doc, "onmouseup",   this, "onMouseUp"),
+			dojo.connect(dojo.doc, "onkeydown",   this, "onKeyDown"),
+			dojo.connect(dojo.doc, "onkeyup",     this, "onKeyUp")
+		];
+		var c = "dojoDnd" + (copy ? "Copy" : "Move");
+		dojo.addClass(dojo.body(), c); 
+	},
+	canDrop: function(flag){
+		// summary: called to notify if the current target can accept items
+		var canDropFlag = this.target && flag;
+		if(this.canDropFlag != canDropFlag){
+			this.canDropFlag = canDropFlag;
+			this.avatar.update();
+		}
+	},
+	stopDrag: function(){
+		// summary: stop the DnD in progress
+		dojo.removeClass(dojo.body(), "dojoDndCopy");
+		dojo.removeClass(dojo.body(), "dojoDndMove");
+		dojo.forEach(this.events, dojo.disconnect);
+		this.events = [];
+		this.avatar.destroy();
+		this.avatar = null;
+		this.source = null;
+		this.nodes = [];
+	},
+	makeAvatar: function(){
+		// summary: makes the avatar, it is separate to be overwritten dynamically, if needed
+		return new dojo.dnd.Avatar(this);
+	},
+	updateAvatar: function(){
+		// summary: updates the avatar, it is separate to be overwritten dynamically, if needed
+		this.avatar.update();
+	},
+	// mouse event processors
+	onMouseMove: function(e){
+		// summary: event processor for onmousemove
+		// e: Event: mouse event
+		var a = this.avatar;
+		if(a){
+			var s = a.node.style;
+			s.left = (e.pageX + 10 + (isNaN(a.offX) ? 0 : a.offX)) + "px";
+			s.top  = (e.pageY + 10 +  (isNaN(a.offY) ? 0 : a.offY)) + "px";
+			if(this.copy != dojo.dnd.multiSelectKey(e)){ 
+				this._setCopyStatus(dojo.dnd.multiSelectKey(e));
+			}
+		}
+	},
+	onMouseUp: function(e){
+		// summary: event processor for onmouseup
+		// e: Event: mouse event
+		if(this.avatar){
+			if(this.target && this.canDropFlag){
+				dojo.publish("dndDrop", [this.source, this.nodes, dojo.dnd.multiSelectKey(e)]);
+			}else{
+				dojo.publish("dndCancel");
+			}
+			this.stopDrag();
+		}
+	},
+	// keyboard event processors
+	onKeyDown: function(e){
+		// summary: event processor for onkeydown, watching for CTRL for copy/move status
+		// e: Event: keyboard event
+		if(this.avatar && e.keyCode == dojo.keys.CTRL && !this.copy){ this._setCopyStatus(true); }
+	},
+	onKeyUp: function(e){
+		// summary: event processor for onkeyup, watching for CTRL for copy/move status
+		// e: Event: keyboard event
+		if(this.avatar && e.keyCode == dojo.keys.CTRL && this.copy){ this._setCopyStatus(false); }
+	},
+	// utilities
+	_setCopyStatus: function(copy){
+		// summary: changes the copy status
+		// copy: Boolean: the copy status
+		this.copy = copy;
+		this.source._markDndStatus(this.copy);
+		this.updateAvatar();
+		dojo.removeClass(dojo.body(), "dojoDnd" + (this.copy ? "Move" : "Copy"));
+		dojo.addClass(dojo.body(), "dojoDnd" + (this.copy ? "Copy" : "Move"));
+	}
+});
+
+// summary: the manager singleton variable, can be overwritten, if needed
+dojo.dnd._manager = null;
+
+dojo.dnd.manager = function(){
+	// summary: returns the current DnD manager, creates one if it is not created yet
+	if(!dojo.dnd._manager){
+		dojo.dnd._manager = new dojo.dnd.Manager();
+	}
+	return dojo.dnd._manager;	// Object
+};

Added: trunk/examples/typeface/root/static/dojo/dojo/dnd/move.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/dnd/move.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/dnd/move.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,81 @@
+dojo.provide("dojo.dnd.move");
+
+dojo.require("dojo.dnd.common");
+
+dojo.dnd.Mover = function(node, e){
+	// summary: an object, which makes a node follow the mouse
+	// node: Node: a node (or node's id) to be moved
+	// e: Event: a mouse event, which started the move;
+	//	only pageX and pageY properties are used
+	this.node = dojo.byId(node);
+	var np = dojo.coords(this.node, true);
+	this.posX = np.x - dojo.dnd._getOffset(this.node, "Left") - e.pageX;
+	this.posY = np.y - dojo.dnd._getOffset(this.node, "Top")  - e.pageY;
+	this.firstEvent = dojo.connect(dojo.doc, "onmousemove", this, "_makeAbsolute");
+	this.events = [
+		dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"),
+		dojo.connect(dojo.doc, "onmouseup",   this, "destroy"),
+		// cancel text selection and text dragging
+		dojo.connect(dojo.doc, "ondragstart",   dojo, "stopEvent"),
+		dojo.connect(dojo.doc, "onselectstart", dojo, "stopEvent")
+	];
+};
+
+dojo.extend(dojo.dnd.Mover, {
+	// mouse event processors
+	onMouseMove: function(e){
+		// summary: event processor for onmousemove
+		// e: Event: mouse event
+		var s = this.node.style;
+		s.left = (e.pageX + this.posX) + "px";
+		s.top  = (e.pageY + this.posY) + "px";
+	},
+	// utilities
+	_makeAbsolute: function(){
+		// summary: makes the node absolute; it is meant to be called only once
+		this.node.style.position = "absolute";	// enforcing the absolute mode
+		dojo.disconnect(this.firstEvent);
+		delete this.firstEvent;
+	},
+	destroy: function(){
+		// summary: stops the move, deletes all references, so the object can be garbage-collected
+		dojo.forEach(this.events, dojo.disconnect);
+		if(this.firstEvent){
+			dojo.disconnect(this.firstEvent);
+		}
+		this.node = null;
+	}
+});
+
+dojo.dnd.Moveable = function(node, handle){
+	// summary: an object, which makes a node moveable
+	// node: Node: a node (or node's id) to be moved
+	// handle: Node: a node (or node's id), which is used as a mouse handle;
+	//	if omitted, the node itself is used as a handle
+	if(!handle){ handle = node; }
+	this.node = dojo.byId(node);
+	this.handle = dojo.byId(handle);
+	if(!this.handle){ this.handle = this.node; }
+	this.events = [
+		dojo.connect(this.handle, "onmousedown", this, "onMouseDown"),
+		// cancel text selection and text dragging
+		dojo.connect(this.handle, "ondragstart",   dojo, "stopEvent"),
+		dojo.connect(this.handle, "onselectstart", dojo, "stopEvent")
+	];
+};
+
+dojo.extend(dojo.dnd.Moveable, {
+	// mouse event processors
+	onMouseDown: function(e){
+		// summary: event processor for onmousedown, creates a Mover for the node
+		// e: Event: mouse event
+		new dojo.dnd.Mover(this.node, e);
+		dojo.stopEvent(e);
+	},
+	// utilities
+	destroy: function(){
+		// summary: stops watching for possible move, deletes all references, so the object can be garbage-collected
+		dojo.forEach(this.events, dojo.disconnect);
+		this.node = this.handle = null;
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojo/dnd/selector.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/dnd/selector.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/dnd/selector.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,247 @@
+dojo.provide("dojo.dnd.selector");
+
+dojo.require("dojo.dnd.common");
+dojo.require("dojo.dnd.container");
+
+/*
+	Container item states:
+		""			- an item is not selected
+		"Selected"	- an item is selected
+		"Anchor"	- an item is selected, and is an anchor for a "shift" selection
+*/
+
+dojo.declare("dojo.dnd.Selector", dojo.dnd.Container,
+	// summary: a Selector object, which knows how to select its children
+function(node, params){
+	// summary: a constructor of the Selector
+	// node: Node: node or node's id to build the selector on
+	// params: Object: a dict of parameters, recognized parameters are:
+	//	singular: Boolean: allows selection of only one element, if true
+	//	the rest of parameters are passed to the container
+	this.singular = params && params.singular;
+	// class-specific variables
+	this.selection = {};
+	this.anchor = null;
+	this.simpleSelection = false;
+	// set up events
+	this.events.push(
+		dojo.connect(this.node, "onmousedown", this, "onMouseDown"),
+		dojo.connect(this.node, "onmouseup",   this, "onMouseUp"));
+},
+{
+	// mouse events
+	onMouseDown: function(e){
+		// summary: event processor for onmousedown
+		// e: Event: mouse event
+		if(!this.current){ return; }
+		if(!this.singular && !dojo.dnd.multiSelectKey(e) && !e.shiftKey && (this.current.id in this.selection)){
+			this.simpleSelection = true;
+			dojo.stopEvent(e);
+			return;
+		}
+		if(!this.singular && e.shiftKey){
+			if(!dojo.dnd.multiSelectKey(e)){
+				var empty = {};
+				for(var i in this.selection){
+					if(!(i in empty)){
+						var n = dojo.byId(i);
+						this._removeItemClass(n, "Selected");
+					}
+				}
+				this.selection = {};
+			}
+			var c = this.node.tagName.toLowerCase() == "table" ? this.parent.getElementsByTagName("tr") : this.node.childNodes;
+			if(!this.anchor){
+				var i = 0;
+				for(; i < c.length; ++i){
+					var n = c[i];
+					if(this.nodeFilter(n)){ break; }
+				}
+				this.anchor = c[i];
+				this._addItemClass(this.anchor, "Anchor");
+			}
+			this.selection[this.anchor.id] = 1;
+			if(this.anchor != this.current){
+				var i = 0;
+				for(; i < c.length; ++i){
+					var n = c[i];
+					if(!this.nodeFilter(n)){ continue; }
+					if(n == this.anchor || n == this.current){ break; }
+				}
+				for(++i; i < c.length; ++i){
+					var n = c[i];
+					if(!this.nodeFilter(n)){ continue; }
+					if(n == this.anchor || n == this.current){ break; }
+					this._addItemClass(n, "Selected");
+					this.selection[n.id] = 1;
+				}
+				this._addItemClass(this.current, "Selected");
+				this.selection[this.current.id] = 1;
+			}
+		}else{
+			if(this.singular){
+				if(this.anchor == this.current){
+					if(dojo.dnd.multiSelectKey(e)){
+						this._removeItemClass(this.anchor, "Anchor");
+						this.anchor = null;
+						this.selection = {};
+					}
+				}else{
+					if(this.anchor){
+						this._removeItemClass(this.anchor, "Anchor");
+					}
+					this.anchor = this.current;
+					this._addItemClass(this.anchor, "Anchor");
+					this.selection = {};
+					this.selection[this.current.id] = 1;
+				}
+			}else{
+				if(dojo.dnd.multiSelectKey(e)){
+					if(this.anchor == this.current){
+						this._removeItemClass(this.anchor, "Anchor");
+						delete this.selection[this.anchor.id];
+						this.anchor = null;
+					}else{
+						if(this.current.id in this.selection){
+							this._removeItemClass(this.current, "Selected");
+							delete this.selection[this.current.id];
+						}else{
+							if(this.anchor){
+								dojo.removeClass(this.anchor, "dojoDndItemAnchor");
+								dojo.addClass(this.anchor, "dojoDndItemSelected");
+							}
+							this.anchor = this.current;
+							this._addItemClass(this.current, "Anchor");
+							this.selection[this.current.id] = 1;
+						}
+					}
+				}else{
+					var empty = {};
+					for(var i in this.selection){
+						if(!(i in empty)){
+							var n = dojo.byId(i);
+							this._removeItemClass(n, "Selected");
+						}
+					}
+					if(this.anchor){
+						this._removeItemClass(this.anchor, "Anchor");
+					}
+					this.selection = {};
+					this.anchor = this.current;
+					this._addItemClass(this.current, "Anchor");
+					this.selection[this.current.id] = 1;
+				}
+			}
+		}
+		dojo.stopEvent(e);
+	},
+	onMouseUp: function(e){
+		// summary: event processor for onmouseup
+		// e: Event: mouse event
+		if(!this.simpleSelection){ return; }
+		this.simpleSelection = false;
+		this.selectNone();
+		if(this.current){
+			this.anchor = this.current;
+			this._addItemClass(this.anchor, "Anchor");
+			this.selection[this.current.id] = 1;
+		}
+	},
+	onMouseMove: function(e){
+		// summary: event processor for onmousemove
+		// e: Event: mouse event
+		this.simpleSelection = false;
+	},
+	// utilities
+	onOverEvent: function(){
+		// summary: this function is called once, when mouse is over our container
+		this.onmousemoveEvent = dojo.connect(this.node, "onmousemove", this, "onMouseMove");
+	},
+	onOutEvent: function(){
+		// summary: this function is called once, when mouse is out of our container
+		dojo.disconnect(this.onmousemoveEvent);
+		delete this.onmousemoveEvent;
+	},
+	// methods
+	destroy: function(){
+		// summary: prepares the object to be garbage-collected
+		dojo.dnd.Selector.superclass.destroy.call(this);
+		this.selection = this.anchor = null;
+	},
+	getSelectedNodes: function(){
+		// summary: returns a list (an array) of selected nodes
+		var t = [];
+		var empty = {};
+		for(var i in this.selection){
+			if(!(i in empty)){
+				t.push(dojo.byId(i));
+			}
+		}
+		return t;	// Array
+	},
+	selectNone: function(){
+		// summary: unselects all items
+		var empty = {};
+		for(var i in this.selection){
+			if(!(i in empty)){
+				this._removeItemClass(dojo.byId(i), "Selected");
+			}
+		}
+		if(this.anchor){
+			this._removeItemClass(this.anchor, "Anchor");
+			this.anchor = null;
+		}
+		this.selection = {};
+		return this;	// self
+	},
+	selectAll: function(){
+		// summary: selects all items
+		if(this.anchor){
+			this._removeItemClass(this.anchor, "Anchor");
+			this.anchor = null;
+		}
+		var c = this.node.tagName.toLowerCase() == "table" ? this.parent.getElementsByTagName("tr") : this.node.childNodes;
+		for(var i = 0; i < c.length; ++i){
+			var n = c[i];
+			if(this.nodeFilter(n)){
+				this._addItemClass(n, "Selected");
+				this.selection[n.id] = 1;
+			}
+		}
+		return this;	// self
+	},
+	deleteSelectedNodes: function(){
+		// summary: deletes all selected items
+		var empty = {};
+		for(var i in this.selection){
+			if(!(i in empty)){
+				var n = dojo.byId(i);
+				delete this.map[i];
+				n.parentNode.removeChild(n);
+			}
+		}
+		this.anchor = null;
+		this.selection = {};
+		return this;	// self
+	},
+	insertNodes: function(addSelected, data, before, anchor){
+		// summary: inserts new data items (see Container's insertNodes method for details)
+		// addSelected: Boolean: all new nodes will be added to selected items, if true, no selection change otherwise
+		// data: Array: a list of data items, which should be processed by the creator function
+		// before: Boolean: insert before the anchor, if true, and after the anchot otherwise
+		// anchor: Node: the anchor node to be used as a point of insertion
+		var oldCreator = this.nodeCreator;
+		if(addSelected){
+			var me = this;
+			this.nodeCreator = function(d){
+				var t = oldCreator(d);
+				me._addItemClass(t.node, "Selected");
+				me.selection[t.node.id] = 1;
+				return t;
+			};
+		}
+		dojo.dnd.Selector.superclass.insertNodes.call(this, data, before, anchor);
+		this.nodeCreator = oldCreator;
+		return this;	// self
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojo/dnd/source.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/dnd/source.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/dnd/source.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,259 @@
+dojo.provide("dojo.dnd.source");
+
+dojo.require("dojo.dnd.selector");
+dojo.require("dojo.dnd.manager");
+
+/*
+	Container property:
+		"Horizontal"- if this is the horizontal container
+	Source states:
+		""			- normal state
+		"Moved"		- this source is being moved
+		"Copied"	- this source is being copied
+	Target states:
+		""			- normal state
+		"Disabled"	- the target cannot accept an avatar
+	Target anchor state:
+		""			- item is not selected
+		"Before"	- insert point is before the anchor
+		"After"		- insert point is after the anchor
+*/
+
+dojo.declare("dojo.dnd.Source", dojo.dnd.Selector,
+	// summary: a Source object, which can be used as a DnD source, or a DnD target
+function(node, params){
+	// summary: a constructor of the Selector
+	// node: Node: node or node's id to build the source on
+	// params: Object: a dict of parameters, recognized parameters are:
+	//	isSource: Boolean: can be used as a DnD source, if true; assumed to be "true" if omitted
+	//	accept: Array: list of accepted types (text strings) for a target; assumed to be ["text"] if omitted
+	//	horizontal: Boolean: a horizontal container, if true, vertical otherwise or when omitted
+	//	the rest of parameters are passed to the selector
+	if(!params){ params = {}; }
+	this.isSource = typeof params.isSource == "undefined" ? true : params.isSource;
+	var types = params.accept instanceof Array ? params.accept : ["text"];
+	this.accept = null;
+	if(types.length){
+		this.accept = {};
+		for(var i = 0; i < types.length; ++i){
+			this.accept[types[i]] = 1;
+		}
+	}
+	this.horizontal = params.horizontal;
+	// class-specific variables
+	this.isDragging = false;
+	this.mouseDown = false;
+	this.targetAnchor = null;
+	this.targetBox = null;
+	this.before = true;
+	// states
+	this.sourceState  = "";
+	if(this.isSource){
+		dojo.addClass(this.node, "dojoDndSource");
+	}
+	this.targetState  = "";
+	if(this.accept){
+		dojo.addClass(this.node, "dojoDndTarget");
+	}
+	if(this.horizontal){
+		dojo.addClass(this.node, "dojoDndHorizontal");
+	}
+	// set up events
+	this.topics = {
+		dndSourceOver:	dojo.subscribe("dndSourceOver", this, "onDndSourceOver"),
+		dndStart:		dojo.subscribe("dndStart",  this, "onDndStart"),
+		dndDrop:		dojo.subscribe("dndDrop",   this, "onDndDrop"),
+		dndCnacel:		dojo.subscribe("dndCancel", this, "onDndCancel")
+	};
+},
+{
+	// mouse event processors
+	onMouseMove: function(e){
+		// summary: event processor for onmousemove
+		// e: Event: mouse event
+		if(this.isDragging && this.targetState == "Disabled"){ return; }
+		dojo.dnd.Source.superclass.onMouseMove.call(this, e);
+		var m = dojo.dnd.manager();
+		if(this.isDragging){
+			// calculate before/after
+			var before = false;
+			if(this.current){
+				if(!this.targetBox || this.targetAnchor != this.current){
+					this.targetBox = {
+						xy: dojo.coords(this.current, true),
+						w: this.current.offsetWidth,
+						h: this.current.offsetHeight
+					};
+				}
+				if(this.horizontal){
+					before = (e.pageX - this.targetBox.xy.x) < (this.targetBox.w / 2);
+				}else{
+					before = (e.pageY - this.targetBox.xy.y) < (this.targetBox.h / 2);
+				}
+			}
+			if(this.current != this.targetAnchor || before != this.before){
+				this._markTargetAnchor(before);
+				m.canDrop(!this.current || m.source != this || !(this.current.id in this.selection));
+			}
+		}else{
+			if(this.mouseDown && this.isSource){
+				m.startDrag(this, this.getSelectedNodes(), dojo.dnd.multiSelectKey(e));
+			}
+		}
+	},
+	onMouseDown: function(e){
+		// summary: event processor for onmousedown
+		// e: Event: mouse event
+		this.mouseDown = true;
+		dojo.dnd.Source.superclass.onMouseDown.call(this, e);
+	},
+	onMouseUp: function(e){
+		// summary: event processor for onmouseup
+		// e: Event: mouse event
+		this.mouseDown = false;
+		dojo.dnd.Source.superclass.onMouseUp.call(this, e);
+	},
+	// topic event processors
+	onDndSourceOver: function(source){
+		// summary: topic event processor for ondndsourceover, called when detected a current source
+		// source: Object: the source which has the mouse over it
+		if(this != source){
+			this.mouseDown = false;
+			if(this.targetAnchor){
+				this._unmarkTargetAnchor();
+			}
+		}else if(this.isDragging){
+			var m = dojo.dnd.manager();
+			m.canDrop(this.targetState != "Disabled" && (!this.current || m.source != this || !(this.current.id in this.selection)));
+		}
+	},
+	onDndStart: function(source, nodes, copy){
+		// summary: topic event processor for ondndstart, called to initiate the DnD operation
+		// source: Object: the source which provides items
+		// nodes: Array: the list of transferred items
+		// copy: Boolean: copy items, if true, move items otherwise
+		if(this.isSource){
+			this._changeState("Source", this == source ? (copy ? "Copied" : "Moved") : "");
+		}
+		var accepted = this.accept && this.checkAcceptance(source, nodes);
+		this._changeState("Target", accepted ? "" : "Disabled");
+		if(accepted){
+			dojo.dnd.manager().overSource(this);
+		}
+		this.isDragging = true;
+	},
+	onDndDrop: function(source, nodes, copy){
+		// summary: topic event processor for ondnddrop, called to finish the DnD operation
+		// source: Object: the source which provides items
+		// nodes: Array: the list of transferred items
+		// copy: Boolean: copy items, if true, move items otherwise
+		do{ //break box
+			if(this.containerState != "Over"){ break; }
+			var oldCreator = this.nodeCreator;
+			if(this != source || copy){
+				this.selectNone();
+				this.nodeCreator = function(n){
+					return oldCreator(source.map[n.id].data);
+				};
+			}else{
+				if(this.current.id in this.selection){ break; }
+				this.nodeCreator = function(n){
+					var t = source.map[n.id]; return {node: n, data: t.data, types: t.types};
+				};
+			}
+			this.insertNodes(true, nodes, this.before, this.current);
+			this.nodeCreator = oldCreator;
+			if(this != source && !copy){
+				source.deleteSelectedNodes();
+			}
+		}while(false);
+		this.onDndCancel();
+	},
+	onDndCancel: function(){
+		// summary: topic event processor for ondndcancel, called to cancel the DnD operation
+		if(this.targetAnchor){
+			this._unmarkTargetAnchor();
+			this.targetAnchor = null;
+		}
+		this.before = true;
+		this.isDragging = false;
+		this._changeState("Source", "");
+		this._changeState("Target", "");
+	},
+	// utilities
+	onOverEvent: function(){
+		// summary: this function is called once, when mouse is over our container
+		dojo.dnd.Source.superclass.onOverEvent.call(this);
+		dojo.dnd.manager().overSource(this);
+	},
+	onOutEvent: function(){
+		// summary: this function is called once, when mouse is out of our container
+		dojo.dnd.Source.superclass.onOutEvent.call(this);
+		dojo.dnd.manager().outSource(this);
+	},
+	// methods
+	destroy: function(){
+		// summary: prepares the object to be garbage-collected
+		dojo.dnd.Source.superclass.destroy.call(this);
+		var t = {};
+		for(var i in this.topics){
+			if(!(i in t)){
+				dojo.unsubscribe(i, this.topics[i]);
+			}
+		}
+		this.targetAnchor = null;
+	},
+	checkAcceptance: function(source, nodes){
+		// summary: checks, if the target can accept nodes from this source
+		// source: Object: the source which provides items
+		// nodes: Array: the list of transferred items
+		if(this == source){ return true; }
+		var accepted = true;
+		for(var i = 0; i < nodes.length; ++i){
+			var types = source.map[nodes[i].id].types;
+			if(types instanceof Array){
+				var flag = false;
+				for(var j = 0; j < types.length; ++j){
+					if(types[j] in this.accept){
+						flag = true;
+						break;
+					}
+				}
+				if(!flag){
+					accepted = false;
+					break;
+				}
+			}else{
+				accepted = false;
+			}
+			if(!accepted){ break; }
+		}
+		return accepted;	// Boolean
+	},
+	_markTargetAnchor: function(before){
+		// summary: assigns a class to the current target anchor based on "before" status
+		// before: Boolean: insert before, if true, after otherwise
+		if(this.current == this.targetAnchor && this.before == before){ return; }
+		if(this.targetAnchor){
+			this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");
+		}
+		this.targetAnchor = this.current;
+		this.targetBox = null;
+		this.before = before;
+		if(this.targetAnchor){
+			this._addItemClass(this.targetAnchor, this.before ? "Before" : "After");
+		}
+	},
+	_unmarkTargetAnchor: function(){
+		// summary: removes a class of the current target anchor based on "before" status
+		if(!this.targetAnchor){ return; }
+		this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");
+		this.targetAnchor = null;
+		this.targetBox = null;
+		this.before = true;
+	},
+	_markDndStatus: function(copy){
+		// summary: changes source's state based on "copy" status
+		this._changeState("Source", copy ? "Copied" : "Moved");
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojo/dojo.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/dojo.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/dojo.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,3205 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+/*
+	This is a compiled version of Dojo, built for deployment and not for
+	development. To get an editable version, please visit:
+
+		http://dojotoolkit.org
+
+	for documentation and information on getting the source.
+*/
+
+if(typeof dojo=="undefined"){
+(function(){
+if(typeof this["djConfig"]=="undefined"){
+this.djConfig={};
+}
+if((!this["console"])||(!console["firebug"])){
+this.console={};
+}
+var cn=["assert","count","debug","dir","dirxml","error","group","groupEnd","info","log","profile","profileEnd","time","timeEnd","trace","warn"];
+var i=0,tn;
+while(tn=cn[i++]){
+if(!console[tn]){
+console[tn]=function(){
+};
+}
+}
+if(typeof this["dojo"]=="undefined"){
+this.dojo={};
+}
+dojo.global=this;
+var _4={isDebug:false,allowQueryConfig:false,baseScriptUri:"",baseRelativePath:"",libraryScriptUri:"",preventBackButtonFix:true,delayMozLoadingFix:false};
+for(var _5 in _4){
+if(typeof djConfig[_5]=="undefined"){
+djConfig[_5]=_4[_5];
+}
+}
+var _6=["Browser","Rhino","Spidermonkey","Mobile"];
+var t;
+while(t=_6.shift()){
+dojo["is"+t]=false;
+}
+})();
+dojo.locale=djConfig.locale;
+dojo.version={major:0,minor:0,patch:0,flag:"dev",revision:Number("$Rev: 8123 $".match(/[0-9]+/)[0]),toString:function(){
+with(dojo.version){
+return major+"."+minor+"."+patch+flag+" ("+revision+")";
+}
+}};
+dojo._getProp=function(_8,_9,_a){
+var _b=_a||dojo.global;
+for(var i=0,p;_b&&(p=_8[i]);i++){
+_b=(p in _b?_b[p]:(_9?_b[p]={}:undefined));
+}
+return _b;
+};
+dojo.setObject=function(_e,_f,_10){
+var _11=_e.split("."),p=_11.pop(),obj=dojo._getProp(_11,true,_10);
+return (obj&&p?(obj[p]=_f):undefined);
+};
+dojo.getObject=function(_14,_15,_16){
+return dojo._getProp(_14.split("."),_15,_16);
+};
+dojo.exists=function(_17,obj){
+return Boolean(dojo.getObject(_17,false,obj));
+};
+dojo["eval"]=function(_19){
+return dojo.global.eval?dojo.global.eval(_19):eval(_19);
+};
+dojo.deprecated=function(_1a,_1b,_1c){
+var _1d="DEPRECATED: "+_1a;
+if(_1b){
+_1d+=" "+_1b;
+}
+if(_1c){
+_1d+=" -- will be removed in version: "+_1c;
+}
+console.debug(_1d);
+};
+dojo.experimental=function(_1e,_1f){
+var _20="EXPERIMENTAL: "+_1e;
+_20+=" -- Not yet ready for use.  APIs subject to change without notice.";
+if(_1f){
+_20+=" "+_1f;
+}
+console.debug(_20);
+};
+dojo._getText=function(uri){
+};
+(function(){
+var _22={_pkgFileName:"__package__",_loadedModules:{},_inFlightCount:0,_modulePrefixes:{dojo:{name:"dojo",value:"."},doh:{name:"doh",value:"../util/doh"},tests:{name:"tests",value:"tests"}},_moduleHasPrefix:function(_23){
+var mp=this._modulePrefixes;
+return Boolean(mp[_23]&&mp[_23].value);
+},_getModulePrefix:function(_25){
+var mp=this._modulePrefixes;
+if(this._moduleHasPrefix(_25)){
+return mp[_25].value;
+}
+return _25;
+},_loadedUrls:[],_postLoad:false,_loaders:[],_unloaders:[],_loadNotifying:false};
+for(var _27 in _22){
+dojo[_27]=_22[_27];
+}
+})();
+dojo._loadPath=function(_28,_29,cb){
+var uri=(((_28.charAt(0)=="/"||_28.match(/^\w+:/)))?"":this.baseUrl)+_28;
+if(djConfig.cacheBust&&dojo.isBrowser){
+uri+="?"+String(djConfig.cacheBust).replace(/\W+/g,"");
+}
+try{
+return !_29?this._loadUri(uri,cb):this._loadUriAndCheck(uri,_29,cb);
+}
+catch(e){
+console.debug(e);
+return false;
+}
+};
+dojo._loadUri=function(uri,cb){
+if(this._loadedUrls[uri]){
+return true;
+}
+var _2e=this._getText(uri,true);
+if(!_2e){
+return false;
+}
+this._loadedUrls[uri]=true;
+if(cb){
+_2e="("+_2e+")";
+}
+var _2f=dojo["eval"]("//@ sourceURL="+uri+"\r\n"+_2e);
+if(cb){
+cb(_2f);
+}
+return true;
+};
+dojo._loadUriAndCheck=function(uri,_31,cb){
+var ok=false;
+try{
+ok=this._loadUri(uri,cb);
+}
+catch(e){
+console.debug("failed loading ",uri," with error: ",e);
+}
+return Boolean(ok&&this._loadedModules[_31]);
+};
+dojo.loaded=function(){
+this._loadNotifying=true;
+this._postLoad=true;
+var mll=this._loaders;
+for(var x=0;x<mll.length;x++){
+mll[x]();
+}
+this._loaders=[];
+this._loadNotifying=false;
+};
+dojo.unloaded=function(){
+var mll=this._unloaders;
+while(mll.length){
+(mll.pop())();
+}
+};
+dojo.addOnLoad=function(obj,_38){
+var d=dojo;
+if(arguments.length==1){
+d._loaders.push(obj);
+}else{
+if(arguments.length>1){
+d._loaders.push(function(){
+obj[_38]();
+});
+}
+}
+if(d._postLoad&&d._inFlightCount==0&&!d._loadNotifying){
+d._callLoaded();
+}
+};
+dojo.addOnUnload=function(obj,_3b){
+var d=dojo;
+if(arguments.length==1){
+d._unloaders.push(obj);
+}else{
+if(arguments.length>1){
+d._unloaders.push(function(){
+obj[_3b]();
+});
+}
+}
+};
+dojo._modulesLoaded=function(){
+if(this._postLoad){
+return;
+}
+if(this._inFlightCount>0){
+console.debug("files still in flight!");
+return;
+}
+dojo._callLoaded();
+};
+dojo._callLoaded=function(){
+if(typeof setTimeout=="object"||(djConfig["useXDomain"]&&dojo.isOpera)){
+setTimeout("dojo.loaded();",0);
+}else{
+dojo.loaded();
+}
+};
+dojo._getModuleSymbols=function(_3d){
+var _3e=_3d.split(".");
+for(var i=_3e.length;i>0;i--){
+var _40=_3e.slice(0,i).join(".");
+if((i==1)&&!this._moduleHasPrefix(_40)){
+_3e[0]="../"+_3e[0];
+}else{
+var _41=this._getModulePrefix(_40);
+if(_41!=_40){
+_3e.splice(0,i,_41);
+break;
+}
+}
+}
+return _3e;
+};
+dojo._global_omit_module_check=false;
+dojo._loadModule=function(_42,_43,_44){
+_44=this._global_omit_module_check||_44;
+var _45=this._loadedModules[_42];
+if(_45){
+return _45;
+}
+var _46=_42.split(".");
+var _47=this._getModuleSymbols(_42);
+var _48=((_47[0].charAt(0)!="/")&&!_47[0].match(/^\w+:/));
+var _49=_47[_47.length-1];
+var _4a;
+if(_49=="*"){
+_42=_46.slice(0,-1).join(".");
+_47.pop();
+_4a=_47.join("/")+"/"+this._pkgFileName+".js";
+if(_48&&_4a.charAt(0)=="/"){
+_4a=_4a.slice(1);
+}
+}else{
+_4a=_47.join("/")+".js";
+_42=_46.join(".");
+}
+var _4b=(!_44)?_42:null;
+var ok=this._loadPath(_4a,_4b);
+if((!ok)&&(!_44)){
+throw new Error("Could not load '"+_42+"'; last tried '"+_4a+"'");
+}
+if((!_44)&&(!this["isXDomain"])){
+_45=this._loadedModules[_42];
+if(!_45){
+throw new Error("symbol '"+_42+"' is not defined after loading '"+_4a+"'");
+}
+}
+return _45;
+};
+dojo.require=dojo._loadModule;
+dojo.provide=function(_4d){
+var _4e=String(_4d);
+var _4f=_4e;
+var _50=_4d.split(/\./);
+if(_50[_50.length-1]=="*"){
+_50.pop();
+_4f=_50.join(".");
+}
+var _51=dojo.getObject(_4f,true);
+this._loadedModules[_4e]=_51;
+this._loadedModules[_4f]=_51;
+return _51;
+};
+dojo.platformRequire=function(_52){
+var _53=_52["common"]||[];
+var _54=_53.concat(_52[dojo._name]||_52["default"]||[]);
+for(var x=0;x<_54.length;x++){
+var _56=_54[x];
+if(_56.constructor==Array){
+dojo._loadModule.apply(dojo,_56);
+}else{
+dojo._loadModule(_56);
+}
+}
+};
+dojo.requireIf=function(_57,_58){
+if(_57===true){
+var _59=[];
+for(var i=1;i<arguments.length;i++){
+_59.push(arguments[i]);
+}
+dojo.require.apply(dojo,_59);
+}
+};
+dojo.requireAfterIf=dojo.requireIf;
+dojo.registerModulePath=function(_5b,_5c){
+this._modulePrefixes[_5b]={name:_5b,value:_5c};
+};
+if(djConfig["modulePaths"]){
+for(var param in djConfig["modulePaths"]){
+dojo.registerModulePath(param,djConfig["modulePaths"][param]);
+}
+}
+dojo.requireLocalization=function(_5d,_5e,_5f,_60){
+dojo.require("dojo.i18n");
+dojo.i18n._requireLocalization.apply(dojo.hostenv,arguments);
+};
+(function(){
+var ore=new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$");
+var ire=new RegExp("^((([^:]+:)?([^@]+))@)?([^:]*)(:([0-9]+))?$");
+dojo._Url=function(){
+var n=null;
+var _a=arguments;
+var uri=_a[0];
+for(var i=1;i<_a.length;i++){
+if(!_a[i]){
+continue;
+}
+var _67=new dojo._Url(_a[i]+"");
+var _68=new dojo._Url(uri+"");
+if((_67.path=="")&&(!_67.scheme)&&(!_67.authority)&&(!_67.query)){
+if(_67.fragment!=null){
+_68.fragment=_67.fragment;
+}
+_67=_68;
+}else{
+if(_67.scheme==null){
+_67.scheme=_68.scheme;
+if(_67.authority==null){
+_67.authority=_68.authority;
+if(_67.path.charAt(0)!="/"){
+var _69=_68.path.substring(0,_68.path.lastIndexOf("/")+1)+_67.path;
+var _6a=_69.split("/");
+for(var j=0;j<_6a.length;j++){
+if(_6a[j]=="."){
+if(j==_6a.length-1){
+_6a[j]="";
+}else{
+_6a.splice(j,1);
+j--;
+}
+}else{
+if(j>0&&!(j==1&&_6a[0]=="")&&_6a[j]==".."&&_6a[j-1]!=".."){
+if(j==(_6a.length-1)){
+_6a.splice(j,1);
+_6a[j-1]="";
+}else{
+_6a.splice(j-1,2);
+j-=2;
+}
+}
+}
+}
+_67.path=_6a.join("/");
+}
+}
+}
+}
+uri="";
+if(_67.scheme!=null){
+uri+=_67.scheme+":";
+}
+if(_67.authority!=null){
+uri+="//"+_67.authority;
+}
+uri+=_67.path;
+if(_67.query!=null){
+uri+="?"+_67.query;
+}
+if(_67.fragment!=null){
+uri+="#"+_67.fragment;
+}
+}
+this.uri=uri.toString();
+var r=this.uri.match(ore);
+this.scheme=r[2]||(r[1]?"":null);
+this.authority=r[4]||(r[3]?"":null);
+this.path=r[5];
+this.query=r[7]||(r[6]?"":null);
+this.fragment=r[9]||(r[8]?"":null);
+if(this.authority!=null){
+r=this.authority.match(ire);
+this.user=r[3]||null;
+this.password=r[4]||null;
+this.host=r[5];
+this.port=r[7]||null;
+}
+};
+dojo._Url.prototype.toString=function(){
+return this.uri;
+};
+})();
+dojo.moduleUrl=function(_6d,url){
+var loc=dojo._getModuleSymbols(_6d).join("/");
+if(!loc){
+return null;
+}
+if(loc.lastIndexOf("/")!=loc.length-1){
+loc+="/";
+}
+var _70=loc.indexOf(":");
+if(loc.charAt(0)!="/"&&(_70==-1||_70>loc.indexOf("/"))){
+loc=dojo.baseUrl+loc;
+}
+return new dojo._Url(loc,url);
+};
+}
+if(typeof window!="undefined"){
+dojo.isBrowser=true;
+dojo._name="browser";
+(function(){
+var d=dojo;
+if(document&&document.getElementsByTagName){
+var _72=document.getElementsByTagName("script");
+var _73=/dojo\.js([\?\.]|$)/i;
+for(var i=0;i<_72.length;i++){
+var src=_72[i].getAttribute("src");
+if(!src){
+continue;
+}
+var m=src.match(_73);
+if(m){
+if(!djConfig["baseUrl"]){
+djConfig["baseUrl"]=src.substring(0,m.index);
+}
+var cfg=_72[i].getAttribute("djConfig");
+if(cfg){
+var _78=eval("({ "+cfg+" })");
+for(var x in _78){
+djConfig[x]=_78[x];
+}
+}
+break;
+}
+}
+}
+d.baseUrl=djConfig["baseUrl"];
+var n=navigator;
+var dua=n.userAgent;
+var dav=n.appVersion;
+var tv=parseFloat(dav);
+d.isOpera=(dua.indexOf("Opera")>=0)?tv:0;
+d.isKhtml=(dav.indexOf("Konqueror")>=0)||(dav.indexOf("Safari")>=0)?tv:0;
+d.isSafari=(dav.indexOf("Safari")>=0)?tv:0;
+var _7e=dua.indexOf("Gecko");
+d.isMozilla=d.isMoz=((_7e>=0)&&(!d.isKhtml))?tv:0;
+d.isFF=0;
+d.isIE=0;
+try{
+if(d.isMoz){
+d.isFF=parseFloat(dua.split("Firefox/")[1].split(" ")[0]);
+}
+if((document.all)&&(!d.isOpera)){
+d.isIE=parseFloat(dav.split("MSIE ")[1].split(";")[0]);
+}
+}
+catch(e){
+}
+var cm=document["compatMode"];
+d.isQuirks=(cm=="BackCompat")||(cm=="QuirksMode")||(d.isIE<6);
+d.locale=djConfig.locale||(d.isIE?n.userLanguage:n.language).toLowerCase();
+d._println=console.debug;
+d._XMLHTTP_PROGIDS=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"];
+d._xhrObj=function(){
+var _80=null;
+var _81=null;
+try{
+_80=new XMLHttpRequest();
+}
+catch(e){
+}
+if(!_80){
+for(var i=0;i<3;++i){
+var _83=dojo._XMLHTTP_PROGIDS[i];
+try{
+_80=new ActiveXObject(_83);
+}
+catch(e){
+_81=e;
+}
+if(_80){
+dojo._XMLHTTP_PROGIDS=[_83];
+break;
+}
+}
+}
+if(!_80){
+throw new Error("XMLHTTP not available: "+_81);
+}
+return _80;
+};
+d._isDocumentOk=function(_84){
+var _85=_84.status||0;
+return ((_85>=200)&&(_85<300))||(_85==304)||(_85==1223)||(!_85&&(location.protocol=="file:"||location.protocol=="chrome:"));
+};
+d._getText=function(uri,_87){
+var _88=this._xhrObj();
+if(dojo._Url){
+uri=(new dojo._Url(window.location,uri)).toString();
+}
+_88.open("GET",uri,false);
+try{
+_88.send(null);
+if(!d._isDocumentOk(_88)){
+var err=Error("Unable to load "+uri+" status:"+_88.status);
+err.status=_88.status;
+err.responseText=_88.responseText;
+throw err;
+}
+}
+catch(e){
+if(_87){
+return null;
+}
+throw e;
+}
+return _88.responseText;
+};
+})();
+dojo._handleNodeEvent=function(_8a,_8b,fp){
+var _8d=_8a["on"+_8b]||function(){
+};
+_8a["on"+_8b]=function(){
+fp.apply(_8a,arguments);
+_8d.apply(_8a,arguments);
+};
+return true;
+};
+dojo._initFired=false;
+dojo._loadInit=function(e){
+dojo._initFired=true;
+var _8f=(e&&e.type)?e.type.toLowerCase():"load";
+if(arguments.callee.initialized||(_8f!="domcontentloaded"&&_8f!="load")){
+return;
+}
+arguments.callee.initialized=true;
+if(typeof dojo["_khtmlTimer"]!="undefined"){
+clearInterval(dojo._khtmlTimer);
+delete dojo._khtmlTimer;
+}
+if(dojo._inFlightCount==0){
+dojo._modulesLoaded();
+}
+};
+if(document.addEventListener){
+if(dojo.isOpera||(dojo.isMoz&&(djConfig["enableMozDomContentLoaded"]===true))){
+document.addEventListener("DOMContentLoaded",dojo._loadInit,null);
+}
+window.addEventListener("load",dojo._loadInit,null);
+}
+if(dojo.isIE){
+document.write("<scr"+"ipt defer src=\"//:\" "+"onreadystatechange=\"if(this.readyState=='complete'){dojo._loadInit();}\">"+"</scr"+"ipt>");
+}
+if(/(WebKit|khtml)/i.test(navigator.userAgent)){
+dojo._khtmlTimer=setInterval(function(){
+if(/loaded|complete/.test(document.readyState)){
+dojo._loadInit();
+}
+},10);
+}
+if(dojo.isIE){
+dojo._handleNodeEvent(window,"beforeunload",function(){
+dojo._unloading=true;
+window.setTimeout(function(){
+dojo._unloading=false;
+},0);
+});
+}
+dojo._handleNodeEvent(window,"unload",function(){
+if((!dojo.isIE)||(dojo.isIE&&dojo._unloading)){
+dojo.unloaded();
+}
+});
+try{
+if(dojo.isIE){
+document.namespaces.add("v","urn:schemas-microsoft-com:vml");
+document.createStyleSheet().addRule("v\\:*","behavior:url(#default#VML)");
+}
+}
+catch(e){
+}
+dojo._writeIncludes=function(){
+};
+dojo.doc=window["document"]||null;
+dojo.body=function(){
+return dojo.doc.body||dojo.doc.getElementsByTagName("body")[0];
+};
+dojo.setContext=function(_90,_91){
+dojo.global=_90;
+dojo.doc=_91;
+};
+dojo._fireCallback=function(_92,_93,_94){
+if((_93)&&((typeof _92=="string")||(_92 instanceof String))){
+_92=_93[_92];
+}
+return (_93?_92.apply(_93,_94||[]):_92());
+};
+dojo.withGlobal=function(_95,_96,_97,_98){
+var _99;
+var _9a=dojo.global;
+var _9b=dojo.doc;
+try{
+dojo.setContext(_95,_95.document);
+_99=dojo._fireCallback(_96,_97,_98);
+}
+finally{
+dojo.setContext(_9a,_9b);
+}
+return _99;
+};
+dojo.withDoc=function(_9c,_9d,_9e,_9f){
+var _a0;
+var _a1=dojo.doc;
+try{
+dojo.doc=_9c;
+_a0=dojo._fireCallback(_9d,_9e,_9f);
+}
+finally{
+dojo.doc=_a1;
+}
+return _a0;
+};
+}
+if(djConfig.isDebug){
+if(!console.firebug){
+dojo.require("dojo._firebug.firebug");
+}
+}
+dojo.provide("dojo._base.lang");
+dojo.isString=function(it){
+return (typeof it=="string"||it instanceof String);
+};
+dojo.isArray=function(it){
+return (it&&it instanceof Array||typeof it=="array"||((typeof dojo["NodeList"]!="undefined")&&(it instanceof dojo.NodeList)));
+};
+if(dojo.isBrowser&&dojo.isSafari){
+dojo.isFunction=function(it){
+if((typeof (it)=="function")&&(it=="[object NodeList]")){
+return false;
+}
+return (typeof it=="function"||it instanceof Function);
+};
+}else{
+dojo.isFunction=function(it){
+return (typeof it=="function"||it instanceof Function);
+};
+}
+dojo.isObject=function(it){
+if(typeof it=="undefined"){
+return false;
+}
+return (it===null||typeof it=="object"||dojo.isArray(it)||dojo.isFunction(it));
+};
+dojo.isArrayLike=function(it){
+var d=dojo;
+if((!it)||(typeof it=="undefined")){
+return false;
+}
+if(d.isString(it)){
+return false;
+}
+if(d.isFunction(it)){
+return false;
+}
+if(d.isArray(it)){
+return true;
+}
+if((it.tagName)&&(it.tagName.toLowerCase()=="form")){
+return false;
+}
+if(isFinite(it.length)){
+return true;
+}
+return false;
+};
+dojo.isAlien=function(it){
+if(!it){
+return false;
+}
+return !dojo.isFunction(it)&&/\{\s*\[native code\]\s*\}/.test(String(it));
+};
+dojo._mixin=function(obj,_ab){
+var _ac={};
+for(var x in _ab){
+if((typeof _ac[x]=="undefined")||(_ac[x]!=_ab[x])){
+obj[x]=_ab[x];
+}
+}
+if(dojo.isIE&&(typeof (_ab["toString"])=="function")&&(_ab["toString"]!=obj["toString"])&&(_ab["toString"]!=_ac["toString"])){
+obj.toString=_ab.toString;
+}
+return obj;
+};
+dojo.mixin=function(obj,_af){
+for(var i=1,l=arguments.length;i<l;i++){
+dojo._mixin(obj,arguments[i]);
+}
+return obj;
+};
+dojo.extend=function(_b2,_b3){
+for(var i=1,l=arguments.length;i<l;i++){
+dojo._mixin(_b2.prototype,arguments[i]);
+}
+return _b2;
+};
+dojo._hitchArgs=function(_b6,_b7){
+var pre=dojo._toArray(arguments,2);
+var _b9=dojo.isString(_b7);
+return function(){
+var _ba=dojo._toArray(arguments);
+var f=(_b9?(_b6||dojo.global)[_b7]:_b7);
+return (f)&&(f.apply(_b6||this,pre.concat(_ba)));
+};
+};
+dojo.hitch=function(_bc,_bd){
+if(arguments.length>2){
+return dojo._hitchArgs.apply(dojo,arguments);
+}
+if(!_bd){
+_bd=_bc;
+_bc=null;
+}
+if(dojo.isString(_bd)){
+_bc=_bc||dojo.global;
+if(!_bc[_bd]){
+throw (["dojo.hitch: scope[\"",_bd,"\"] is null (scope=\"",_bc,"\")"].join(""));
+}
+return function(){
+return _bc[_bd].apply(_bc,arguments||[]);
+};
+}else{
+return (!_bc?_bd:function(){
+return _bd.apply(_bc,arguments||[]);
+});
+}
+};
+dojo._delegate=function(obj,_bf){
+function TMP(){
+};
+TMP.prototype=obj;
+var tmp=new TMP();
+if(_bf){
+dojo.mixin(tmp,_bf);
+}
+return tmp;
+};
+dojo.partial=function(_c1){
+var arr=[null];
+return dojo.hitch.apply(dojo,arr.concat(dojo._toArray(arguments)));
+};
+dojo._toArray=function(obj,_c4){
+var arr=[];
+for(var x=_c4||0;x<obj.length;x++){
+arr.push(obj[x]);
+}
+return arr;
+};
+dojo.provide("dojo._base.declare");
+dojo.declare=function(_c7,_c8,_c9,_ca){
+if(dojo.isFunction(_ca)||(!_ca&&!dojo.isFunction(_c9))){
+var t=_ca;
+_ca=_c9;
+_c9=t;
+}
+var _cc=function(){
+this._construct(arguments);
+};
+var dd=dojo.declare,p=_ca||{},_cf=[],pc;
+if(dojo.isArray(_c8)){
+_cf=_c8;
+_c8=_cf.shift();
+}
+var scp=_c8?_c8.prototype:null;
+if(scp){
+_cc.prototype=dojo._delegate(scp);
+}
+dojo.mixin(_cc,{superclass:scp,mixins:_cf,extend:dd._extend});
+for(var i=0,m;(m=_cf[i]);i++){
+dojo.extend(_cc,m.prototype);
+}
+_c9=_c9||(pc=p.constructor)&&(pc!=Object)&&pc||null;
+dojo.extend(_cc,{declaredClass:_c7,_initializer:_c9,preamble:null},p,dd._core);
+_cc.prototype.constructor=_cc;
+return dojo.setObject(_c7,_cc);
+};
+dojo.mixin(dojo.declare,{_extend:function(_d4,_d5){
+dojo.extend(this,_d4);
+this.mixins.push(!_d5?_d4:function(){
+_d4.apply(this,_d5.apply(this,arguments)||arguments);
+});
+},_core:{_construct:function(_d6){
+var c=_d6.callee,s=c.superclass,ct=s&&s.constructor,a=_d6,ii;
+if(fn=c.prototype.preamble){
+a=fn.apply(this,a)||a;
+}
+if(ct&&ct.apply){
+ct.apply(this,a);
+}
+for(var i=0,m;(m=c.mixins[i]);i++){
+if(m.apply){
+m.apply(this,a);
+}
+}
+var ii=c.prototype._initializer;
+if(ii){
+ii.apply(this,_d6);
+}
+},inherited:function(_de,_df,_e0){
+var c=_df.callee,p=this.constructor.prototype,a=_e0||_df,fn;
+if(this[_de]!=c||p[_de]==c){
+while(p&&(p[_de]!==c)){
+p=p.constructor.superclass;
+}
+if(!p){
+throw (this.toString()+": name argument (\""+_de+"\") to inherited must match callee (declare.js)");
+}
+while(p&&(p[_de]==c)){
+p=p.constructor.superclass;
+}
+}
+return (fn=p&&p[_de])&&(fn.apply(this,a));
+}}});
+dojo.provide("dojo._base.connect");
+dojo._listener={getDispatcher:function(){
+return function(){
+var ls=arguments.callee.listeners;
+for(var i in ls){
+if(!(i in Array.prototype)){
+ls[i].apply(this,arguments);
+}
+}
+};
+},add:function(_e7,_e8,_e9){
+_e7=_e7||dojo.global;
+var f=_e7[_e8];
+if(!f||!f.listeners){
+var d=dojo._listener.getDispatcher();
+d.listeners=(f?[f]:[]);
+f=_e7[_e8]=d;
+}
+return f.listeners.push(_e9);
+},remove:function(_ec,_ed,_ee){
+var f=(_ec||dojo.global)[_ed];
+if(f&&f.listeners&&_ee--){
+delete f.listeners[_ee];
+}
+}};
+dojo.connect=function(obj,_f1,_f2,_f3,_f4){
+var a=arguments,_f6=[],i=0;
+_f6.push(dojo.isString(a[0])?null:a[i++],a[i++]);
+var a1=a[i+1];
+_f6.push(dojo.isString(a1)||dojo.isFunction(a1)?a[i++]:null,a[i++]);
+for(var l=a.length;i<l;i++){
+_f6.push(a[i]);
+}
+return dojo._connect.apply(this,_f6);
+};
+dojo._connect=function(obj,_fb,_fc,_fd){
+var h=dojo._listener.add(obj,_fb,dojo.hitch(_fc,_fd));
+return [obj,_fb,h];
+};
+dojo.disconnect=function(_ff){
+dojo._disconnect.apply(this,_ff);
+if(_ff&&_ff[0]!=undefined){
+dojo._disconnect.apply(this,_ff);
+delete _ff[0];
+}
+};
+dojo._disconnect=function(obj,_101,_102){
+dojo._listener.remove(obj,_101,_102);
+};
+dojo._topics={};
+dojo.subscribe=function(_103,_104,_105){
+return dojo._listener.add(dojo._topics,_103,dojo.hitch(_104,_105));
+};
+dojo.unsubscribe=function(_106,_107){
+dojo._listener.remove(dojo._topics,_106,_107);
+};
+dojo.publish=function(_108,args){
+var f=dojo._topics[_108];
+(f)&&(f.apply(this,args||[]));
+};
+dojo.provide("dojo._base.Deferred");
+dojo.Deferred=function(_10b){
+this.chain=[];
+this.id=this._nextId();
+this.fired=-1;
+this.paused=0;
+this.results=[null,null];
+this.canceller=_10b;
+this.silentlyCancelled=false;
+};
+dojo.extend(dojo.Deferred,{_getFunctionFromArgs:function(){
+var a=arguments;
+if((a[0])&&(!a[1])){
+if(dojo.isFunction(a[0])){
+return a[0];
+}else{
+if(dojo.isString(a[0])){
+return dojo.global[a[0]];
+}
+}
+}else{
+if((a[0])&&(a[1])){
+return dojo.hitch(a[0],a[1]);
+}
+}
+return null;
+},makeCalled:function(){
+var _10d=new dojo.Deferred();
+_10d.callback();
+return _10d;
+},toString:function(){
+var _10e;
+if(this.fired==-1){
+_10e="unfired";
+}else{
+if(this.fired==0){
+_10e="success";
+}else{
+_10e="error";
+}
+}
+return "Deferred("+this.id+", "+_10e+")";
+},_nextId:(function(){
+var n=1;
+return function(){
+return n++;
+};
+})(),cancel:function(){
+if(this.fired==-1){
+if(this.canceller){
+this.canceller(this);
+}else{
+this.silentlyCancelled=true;
+}
+if(this.fired==-1){
+this.errback(new Error(this.toString()));
+}
+}else{
+if((this.fired==0)&&(this.results[0] instanceof dojo.Deferred)){
+this.results[0].cancel();
+}
+}
+},_pause:function(){
+this.paused++;
+},_unpause:function(){
+this.paused--;
+if((this.paused==0)&&(this.fired>=0)){
+this._fire();
+}
+},_continue:function(res){
+this._resback(res);
+this._unpause();
+},_resback:function(res){
+this.fired=((res instanceof Error)?1:0);
+this.results[this.fired]=res;
+this._fire();
+},_check:function(){
+if(this.fired!=-1){
+if(!this.silentlyCancelled){
+throw new Error("already called!");
+}
+this.silentlyCancelled=false;
+return;
+}
+},callback:function(res){
+this._check();
+this._resback(res);
+},errback:function(res){
+this._check();
+if(!(res instanceof Error)){
+res=new Error(res);
+}
+this._resback(res);
+},addBoth:function(cb,cbfn){
+var _116=this._getFunctionFromArgs(cb,cbfn);
+if(arguments.length>2){
+_116=dojo.partial(_116,arguments,2);
+}
+return this.addCallbacks(_116,_116);
+},addCallback:function(cb,cbfn){
+var _119=this._getFunctionFromArgs(cb,cbfn);
+if(arguments.length>2){
+_119=dojo.partial(_119,arguments,2);
+}
+return this.addCallbacks(_119,null);
+},addErrback:function(cb,cbfn){
+var _11c=this._getFunctionFromArgs(cb,cbfn);
+if(arguments.length>2){
+_11c=dojo.partial(_11c,arguments,2);
+}
+return this.addCallbacks(null,_11c);
+return this.addCallbacks(null,cbfn);
+},addCallbacks:function(cb,eb){
+this.chain.push([cb,eb]);
+if(this.fired>=0){
+this._fire();
+}
+return this;
+},_fire:function(){
+var _11f=this.chain;
+var _120=this.fired;
+var res=this.results[_120];
+var self=this;
+var cb=null;
+while((_11f.length>0)&&(this.paused==0)){
+var pair=_11f.shift();
+var f=pair[_120];
+if(f==null){
+continue;
+}
+try{
+res=f(res);
+_120=((res instanceof Error)?1:0);
+if(res instanceof dojo.Deferred){
+cb=function(res){
+self._continue(res);
+};
+this._pause();
+}
+}
+catch(err){
+_120=1;
+res=err;
+}
+}
+this.fired=_120;
+this.results[_120]=res;
+if((cb)&&(this.paused)){
+res.addBoth(cb);
+}
+}});
+dojo.provide("dojo._base.json");
+dojo.fromJson=function(json){
+try{
+return eval("("+json+")");
+}
+catch(e){
+console.debug(e);
+return json;
+}
+};
+dojo._escapeString=function(str){
+return ("\""+str.replace(/(["\\])/g,"\\$1")+"\"").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\r]/g,"\\r");
+};
+dojo.toJsonIndentStr="\t";
+dojo.toJson=function(it,_12a,_12b){
+_12b=_12b||"";
+var _12c=(_12a?_12b+dojo.toJsonIndentStr:"");
+var _12d=(_12a?"\n":"");
+var _12e=typeof (it);
+if(_12e=="undefined"){
+return "undefined";
+}else{
+if((_12e=="number")||(_12e=="boolean")){
+return it+"";
+}else{
+if(it===null){
+return "null";
+}
+}
+}
+if(_12e=="string"){
+return dojo._escapeString(it);
+}
+var _12f=arguments.callee;
+var _130;
+if(typeof it.__json__=="function"){
+_130=it.__json__();
+if(it!==_130){
+return _12f(_130,_12a,_12c);
+}
+}
+if(typeof it.json=="function"){
+_130=it.json();
+if(it!==_130){
+return _12f(_130,_12a,_12c);
+}
+}
+if(dojo.isArray(it)){
+var res=[];
+for(var i=0;i<it.length;i++){
+var val=_12f(it[i],_12a,_12c);
+if(typeof (val)!="string"){
+val="undefined";
+}
+res.push(_12d+_12c+val);
+}
+return "["+res.join(",")+_12d+_12b+"]";
+}
+if(_12e=="function"){
+return null;
+}
+var _134=[];
+for(var key in it){
+var _136;
+if(typeof (key)=="number"){
+_136="\""+key+"\"";
+}else{
+if(typeof (key)=="string"){
+_136=dojo._escapeString(key);
+}else{
+continue;
+}
+}
+val=_12f(it[key],_12a,_12c);
+if(typeof (val)!="string"){
+continue;
+}
+_134.push(_12d+_12c+_136+":"+val);
+}
+return "{"+_134.join(",")+_12d+_12b+"}";
+};
+dojo.provide("dojo._base.array");
+(function(){
+var d=dojo;
+if(Array.forEach){
+var tn=["indexOf","lastIndexOf","every","some","forEach","filter","map"];
+for(var x=0;x<tn.length;x++){
+d[tn[x]]=Array[tn[x]];
+}
+}else{
+var _13a=function(arr,obj){
+return [(d.isString(arr)?arr.split(""):arr),(obj||d.global)];
+};
+d.mixin(d,{indexOf:function(_13d,_13e,_13f,_140){
+if(_140){
+var step=-1,i=(_13f||_13d.length-1),end=-1;
+}else{
+var step=1,i=(_13f||0),end=_13d.length;
+}
+for(;i!=end;i+=step){
+if(_13d[i]==_13e){
+return i;
+}
+}
+return -1;
+},lastIndexOf:function(_144,_145,_146){
+return d.indexOf(_144,_145,_146,true);
+},map:function(arr,func,obj){
+var _p=_13a(arr,obj);
+arr=_p[0];
+obj=_p[1];
+var _14b=[];
+for(var i=0;i<arr.length;++i){
+_14b.push(func.call(obj,arr[i]));
+}
+return _14b;
+},forEach:function(arr,_14e,obj){
+if((!arr)||(!arr.length)){
+return;
+}
+var _p=_13a(arr,obj);
+arr=_p[0];
+obj=_p[1];
+for(var i=0,l=arr.length;i<l;i++){
+_14e.call(obj,arr[i],i,arr);
+}
+},_everyOrSome:function(_153,arr,_155,obj){
+var _p=_13a(arr,obj);
+arr=_p[0];
+obj=_p[1];
+for(var i=0,l=arr.length;i<l;i++){
+var _15a=_155.call(obj,arr[i],i,arr);
+if(_153&&!_15a){
+return false;
+}else{
+if((!_153)&&(_15a)){
+return true;
+}
+}
+}
+return (!!_153);
+},every:function(arr,_15c,_15d){
+return this._everyOrSome(true,arr,_15c,_15d);
+},some:function(arr,_15f,_160){
+return this._everyOrSome(false,arr,_15f,_160);
+},filter:function(arr,_162,obj){
+var _p=_13a(arr,obj);
+arr=_p[0];
+obj=_p[1];
+var _165=[];
+for(var i=0;i<arr.length;i++){
+if(_162.call(obj,arr[i],i,arr)){
+_165.push(arr[i]);
+}
+}
+return _165;
+}});
+}
+})();
+dojo.provide("dojo._base");
+dojo.provide("dojo._base.event");
+(function(){
+var de={addListener:function(node,_169,fp){
+if(!node){
+return;
+}
+_169=de._normalizeEventName(_169);
+fp=de._fixCallback(_169,fp);
+node.addEventListener(_169,fp,false);
+return fp;
+},removeListener:function(node,_16c,_16d){
+(node)&&(node.removeEventListener(de._normalizeEventName(_16c),_16d,false));
+},_normalizeEventName:function(name){
+return (name.slice(0,2)=="on"?name.slice(2):name);
+},_fixCallback:function(name,fp){
+return (name!="keypress"?fp:function(e){
+return fp.call(this,de._fixEvent(e,this));
+});
+},_fixEvent:function(evt,_173){
+switch(evt.type){
+case "keypress":
+de._setKeyChar(evt);
+break;
+}
+return evt;
+},_setKeyChar:function(evt){
+evt.keyChar=(evt.charCode?String.fromCharCode(evt.charCode):"");
+}};
+dojo.addListener=function(node,_176,_177,_178){
+return de.addListener(node,_176,dojo.hitch(_177,_178));
+};
+dojo.removeListener=function(node,_17a,_17b){
+de.removeListener(node,_17a,_17b);
+};
+dojo.fixEvent=function(evt,_17d){
+return de._fixEvent(evt,_17d);
+};
+dojo.stopEvent=function(evt){
+evt.preventDefault();
+evt.stopPropagation();
+};
+var dc=dojo._connect;
+var dd=dojo._disconnect;
+dojo._connect=function(obj,_182,_183,_184,_185){
+_185=Boolean(!obj||!(obj.nodeType||obj.attachEvent||obj.addEventListener)||_185);
+var h=(_185?dc.apply(this,arguments):[obj,_182,dojo.addListener.apply(this,arguments)]);
+h.push(_185);
+return h;
+};
+dojo._disconnect=function(obj,_188,_189,_18a){
+(_18a?dd:dojo.removeListener).apply(this,arguments);
+};
+dojo.keys={BACKSPACE:8,TAB:9,CLEAR:12,ENTER:13,SHIFT:16,CTRL:17,ALT:18,PAUSE:19,CAPS_LOCK:20,ESCAPE:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT_ARROW:37,UP_ARROW:38,RIGHT_ARROW:39,DOWN_ARROW:40,INSERT:45,DELETE:46,HELP:47,LEFT_WINDOW:91,RIGHT_WINDOW:92,SELECT:93,NUMPAD_0:96,NUMPAD_1:97,NUMPAD_2:98,NUMPAD_3:99,NUMPAD_4:100,NUMPAD_5:101,NUMPAD_6:102,NUMPAD_7:103,NUMPAD_8:104,NUMPAD_9:105,NUMPAD_MULTIPLY:106,NUMPAD_PLUS:107,NUMPAD_ENTER:108,NUMPAD_MINUS:109,NUMPAD_PERIOD:110,NUMPAD_DIVIDE:111,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,F13:124,F14:125,F15:126,NUM_LOCK:144,SCROLL_LOCK:145};
+if(dojo.isIE){
+_trySetKeyCode=function(e,code){
+try{
+return e.keyCode=code;
+}
+catch(e){
+return 0;
+}
+};
+var ap=Array.prototype;
+var iel=dojo._listener;
+if((dojo.isIE<7)&&(!djConfig._allow_leaks)){
+iel=dojo._ie_listener={handlers:[],add:function(_18f,_190,_191){
+_18f=_18f||dojo.global;
+var f=d=_18f[_190];
+if(!d||!d.listeners){
+d=_18f[_190]=dojo._getIeDispatcher();
+d.listeners=(f?[ieh.push(f)-1]:[]);
+}
+return d.listeners.push(ieh.push(_191)-1);
+},remove:function(_194,_195,_196){
+var f=(_194||dojo.global)[_195],l=f&&f.listeners;
+if(f&&l&&_196--){
+delete ieh[l[_196]];
+delete l[_196];
+}
+}};
+var ieh=iel.handlers;
+}
+dojo.mixin(de,{addListener:function(node,_19a,fp){
+if(!node){
+return;
+}
+_19a=de._normalizeEventName(_19a);
+if(_19a=="onkeypress"){
+var kd=node.onkeydown;
+if(!kd||!kd.listeners||!kd._stealthKeydown){
+de.addListener(node,"onkeydown",de._stealthKeyDown);
+node.onkeydown._stealthKeydown=true;
+}
+}
+return iel.add(node,_19a,de._fixCallback(fp,node));
+},removeListener:function(node,_19e,_19f){
+iel.remove(node,de._normalizeEventName(_19e),_19f);
+},_normalizeEventName:function(_1a0){
+return (_1a0.slice(0,2)!="on"?"on"+_1a0:_1a0);
+},_nop:function(){
+},_fixCallback:function(fp,_1a2){
+return function(e){
+return fp.call(this,de._fixEvent(e,_1a2));
+};
+},_fixEvent:function(evt,_1a5){
+if(!evt){
+var w=(_1a5)&&((_1a5.ownerDocument||_1a5.document||_1a5).parentWindow)||window;
+evt=w.event;
+}
+evt.target=evt.srcElement;
+evt.currentTarget=(_1a5||evt.srcElement);
+evt.layerX=evt.offsetX;
+evt.layerY=evt.offsetY;
+var se=evt.srcElement,doc=(se&&se.ownerDocument)||document;
+var _1a9=((dojo.isIE<6)||(doc["compatMode"]=="BackCompat"))?doc.body:doc.documentElement;
+evt.pageX=evt.clientX+(_1a9.scrollLeft||0);
+evt.pageY=evt.clientY+(_1a9.scrollTop||0);
+if(evt.type=="mouseover"){
+evt.relatedTarget=evt.fromElement;
+}
+if(evt.type=="mouseout"){
+evt.relatedTarget=evt.toElement;
+}
+evt.stopPropagation=this._stopPropagation;
+evt.preventDefault=this._preventDefault;
+return this._fixKeys(evt);
+},_fixKeys:function(evt){
+switch(evt.type){
+case "keypress":
+var c=("charCode" in evt?evt.charCode:evt.keyCode);
+if(c==10){
+c=0;
+evt.keyCode=13;
+}else{
+if(c==13||c==27){
+c=0;
+}else{
+if(c==3){
+c=99;
+}
+}
+}
+evt.charCode=c;
+de._setKeyChar(evt);
+break;
+}
+return evt;
+},_punctMap:{106:42,111:47,186:59,187:43,188:44,189:45,190:46,191:47,192:96,219:91,220:92,221:93,222:39},_stealthKeyDown:function(evt){
+var kp=evt.currentTarget.onkeypress;
+if(!kp||!kp.listeners){
+return;
+}
+var k=evt.keyCode;
+var _1af=(k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);
+if(_1af||evt.ctrlKey){
+var c=(_1af?0:k);
+if(evt.ctrlKey){
+if(k==3||k==13){
+return;
+}else{
+if(c>95&&c<106){
+c-=48;
+}else{
+if((!evt.shiftKey)&&(c>=65&&c<=90)){
+c+=32;
+}else{
+c=de._punctMap[c]||c;
+}
+}
+}
+}
+var faux=de._synthesizeEvent(evt,{type:"keypress",faux:true,charCode:c});
+kp.call(evt.currentTarget,faux);
+evt.cancelBubble=faux.cancelBubble;
+evt.returnValue=faux.returnValue;
+_trySetKeyCode(evt,faux.keyCode);
+}
+},_stopPropagation:function(){
+this.cancelBubble=true;
+},_preventDefault:function(){
+_trySetKeyCode(this,0);
+this.returnValue=false;
+}});
+dojo.stopEvent=function(evt){
+evt=evt||window.event;
+de._stopPropagation.call(evt);
+de._preventDefault.call(evt);
+};
+}
+de._synthesizeEvent=function(evt,_1b4){
+var faux=dojo.mixin({},evt,_1b4);
+de._setKeyChar(faux);
+faux.preventDefault=function(){
+evt.preventDefault();
+};
+faux.stopPropagation=function(){
+evt.stopPropagation();
+};
+return faux;
+};
+if(dojo.isOpera){
+dojo.mixin(de,{_fixEvent:function(evt,_1b7){
+switch(evt.type){
+case "keypress":
+var c=evt.which;
+if(c==3){
+c=99;
+}
+c=((c<41)&&(!evt.shiftKey)?0:c);
+if((evt.ctrlKey)&&(!evt.shiftKey)&&(c>=65)&&(c<=90)){
+c+=32;
+}
+return de._synthesizeEvent(evt,{charCode:c});
+}
+return evt;
+}});
+}
+if(dojo.isSafari){
+dojo.mixin(de,{_fixEvent:function(evt,_1ba){
+switch(evt.type){
+case "keypress":
+var c=evt.charCode,s=evt.shiftKey;
+if(evt.keyIdentifier=="Enter"){
+c=0;
+}else{
+if((evt.ctrlKey)&&(c>0)&&(c<27)){
+c+=96;
+}else{
+if(c==dojo.keys.SHIFT_TAB){
+c=dojo.keys.TAB;
+s=true;
+}else{
+c=(c>=32&&c<63232?c:0);
+}
+}
+}
+return de._synthesizeEvent(evt,{charCode:c,shiftKey:s});
+}
+return evt;
+}});
+dojo.mixin(dojo.keys,{SHIFT_TAB:25,UP_ARROW:63232,DOWN_ARROW:63233,LEFT_ARROW:63234,RIGHT_ARROW:63235,F1:63236,F2:63237,F3:63238,F4:63239,F5:63240,F6:63241,F7:63242,F8:63243,F9:63244,F10:63245,F11:63246,F12:63247,PAUSE:63250,DELETE:63272,HOME:63273,END:63275,PAGE_UP:63276,PAGE_DOWN:63277,INSERT:63302,PRINT_SCREEN:63248,SCROLL_LOCK:63249,NUM_LOCK:63289});
+}
+})();
+if(dojo.isIE<7){
+dojo._getIeDispatcher=function(){
+return function(){
+var ap=Array.prototype,ls=arguments.callee.listeners,h=dojo._ie_listener.handlers;
+for(var i in ls){
+if(!(i in ap)){
+h[ls[i]].apply(this,arguments);
+}
+}
+};
+};
+}
+dojo.provide("dojo._base.html");
+try{
+document.execCommand("BackgroundImageCache",false,true);
+}
+catch(e){
+}
+dojo.createElement=function(obj,_1c2,_1c3){
+};
+if(dojo.isIE&&(dojo.isIE<7)){
+dojo.byId=function(id,doc){
+if(dojo.isString(id)){
+var _d=(doc||dojo.doc);
+var te=_d.getElementById(id);
+if((te)&&(te.id==id)){
+return te;
+}else{
+var eles=_d.all[id];
+if(!eles){
+return;
+}
+if(!eles.length){
+return eles;
+}
+var i=0;
+while(te=eles[i++]){
+if(te.id==id){
+return te;
+}
+}
+}
+}else{
+return id;
+}
+};
+}else{
+dojo.byId=function(id,doc){
+if(dojo.isString(id)){
+return (doc||dojo.doc).getElementById(id);
+}else{
+return id;
+}
+};
+}
+(function(){
+var _1cc=function(node,ref){
+ref.parentNode.insertBefore(node,ref);
+return true;
+};
+var _1cf=function(node,ref){
+var pn=ref.parentNode;
+if(ref==pn.lastChild){
+pn.appendChild(node);
+}else{
+return _1cc(node,ref.nextSibling);
+}
+return true;
+};
+dojo.place=function(node,_1d4,_1d5){
+if((!node)||(!_1d4)||(typeof _1d5=="undefined")){
+return false;
+}
+if(typeof _1d5=="number"){
+var cn=_1d4.childNodes;
+if(((_1d5==0)&&(cn.length==0))||(cn.length==_1d5)){
+_1d4.appendChild(node);
+return true;
+}
+if(_1d5==0){
+return _1cc(node,_1d4.firstChild);
+}
+return _1cf(node,cn[_1d5-1]);
+}
+switch(_1d5.toLowerCase()){
+case "before":
+return _1cc(node,_1d4);
+case "after":
+return _1cf(node,_1d4);
+case "first":
+if(_1d4.firstChild){
+return _1cc(node,_1d4.firstChild);
+}else{
+_1d4.appendChild(node);
+return true;
+}
+break;
+default:
+_1d4.appendChild(node);
+return true;
+}
+};
+dojo.boxModel="content-box";
+if(dojo.isIE){
+var _dcm=document.compatMode;
+dojo.boxModel=(_dcm=="BackCompat")||(_dcm=="QuirksMode")||(dojo.isIE<6)?"border-box":"content-box";
+}
+if(!dojo.isIE){
+var dv=document.defaultView;
+dojo.getComputedStyle=((dojo.isSafari)?function(node){
+var s=dv.getComputedStyle(node,null);
+if(!s){
+node.style.display="";
+s=dv.getComputedStyle(node,null);
+}
+return s;
+}:function(node){
+return dv.getComputedStyle(node,null);
+});
+dojo._toPixelValue=function(_1dc,_1dd){
+return (parseFloat(_1dd)||0);
+};
+}else{
+dojo.getComputedStyle=function(node){
+return node.currentStyle;
+};
+dojo._toPixelValue=function(_1df,_1e0){
+if(!_1e0){
+return 0;
+}
+if(_1e0.slice&&(_1e0.slice(-2)=="px")){
+return parseFloat(_1e0);
+}
+with(_1df){
+var _1e1=style.left;
+var _1e2=runtimeStyle.left;
+runtimeStyle.left=currentStyle.left;
+try{
+style.left=_1e0;
+_1e0=style.pixelLeft;
+}
+catch(e){
+_1e0=0;
+}
+style.left=_1e1;
+runtimeStyle.left=_1e2;
+}
+return _1e0;
+};
+}
+dojo._getOpacity=((dojo.isIE)?function(node){
+try{
+return (node.filters.alpha.opacity/100);
+}
+catch(e){
+return 1;
+}
+}:function(node){
+return node.style.opacity;
+});
+dojo._setOpacity=((dojo.isIE)?function(node,_1e6){
+var o="Alpha(Opacity="+(_1e6*100)+")";
+node.style.filter=o;
+if(node.nodeName.toLowerCase=="tr"){
+dojo.query("> td",node).forEach(function(i){
+i.style.filter=o;
+});
+}
+return _1e6;
+}:function(node,_1ea){
+node.style.opacity=_1ea;
+});
+var _1eb={width:true,height:true,left:true,top:true};
+var _1ec=function(node,type,_1ef){
+if(_1eb[type]===true){
+return dojo._toPixelValue(node,_1ef);
+}else{
+if(_1eb[type]===false){
+return _1ef;
+}else{
+type=type.toLowerCase();
+if((type.indexOf("margin")>=0)||(type.indexOf("padding")>=0)||(type.indexOf("width")>=0)||(type.indexOf("height")>=0)||(type.indexOf("max")>=0)||(type.indexOf("min")>=0)||(type.indexOf("offset")>=0)){
+_1eb[type]=true;
+return dojo._toPixelValue(node,_1ef);
+}else{
+_1eb[type]=false;
+return _1ef;
+}
+}
+}
+};
+dojo.style=function(){
+var _a=arguments;
+var _a_l=_a.length;
+if(!_a_l){
+return;
+}
+var node=dojo.byId(_a[0]);
+var io=((dojo.isIE)&&(_a[1]=="opacity"));
+if(_a_l==3){
+return (io)?dojo._setOpacity(node,_a[2]):node.style[_a[1]]=_a[2];
+}
+var s=dojo.getComputedStyle(node);
+if(_a_l==1){
+return s;
+}
+if(_a_l==2){
+return (io)?dojo._getOpacity(node):_1ec(node,_a[1],s[_a[1]]);
+}
+};
+dojo._getPadBounds=function(n,_1f6){
+var s=_1f6||dojo.getComputedStyle(n),px=dojo._toPixelValue,l=px(n,s.paddingLeft),t=px(n,s.paddingTop);
+return {l:l,t:t,w:l+px(n,s.paddingRight),h:t+px(n,s.paddingBottom)};
+};
+dojo._getPadBorderExtents=function(n,_1fc){
+var s=_1fc||dojo.getComputedStyle(n),px=dojo._toPixelValue,p=dojo._getPadBounds(n,s),bw=(s.borderLeftStyle!="none"?px(n,s.borderLeftWidth):0)+(s.borderRightStyle!="none"?px(n,s.borderRightWidth):0),bh=(s.borderTopStyle!="none"?px(n,s.borderTopWidth):0)+(s.borderBottomStyle!="none"?px(n,s.borderBottomWidth):0);
+return {w:p.w+bw,h:p.h+bh};
+};
+dojo._getMarginExtents=function(n,_203){
+var s=_203||dojo.getComputedStyle(n),px=dojo._toPixelValue;
+return {w:px(n,s.marginLeft)+px(n,s.marginRight),h:px(n,s.marginTop)+px(n,s.marginBottom)};
+};
+if(dojo.isMoz){
+dojo._getMarginBox=function(node,_207){
+var s=_207||dojo.getComputedStyle(node);
+var mb=dojo._getMarginExtents(node,s);
+return {l:parseFloat(s.left)||0,t:parseFloat(s.top)||0,w:node.offsetWidth+mb.w,h:node.offsetHeight+mb.h};
+};
+}else{
+dojo._getMarginBox=function(node,_20b){
+var mb=dojo._getMarginExtents(node,_20b);
+return {l:node.offsetLeft,t:node.offsetTop,w:node.offsetWidth+mb.w,h:node.offsetHeight+mb.h};
+};
+}
+dojo._getContentBox=function(node,_20e){
+var pb=dojo._getPadBounds(node,_20e);
+return {l:pb.l,t:pb.t,w:node.clientWidth-pb.w,h:node.clientHeight-pb.h};
+};
+dojo._setBox=function(node,l,t,w,h,u){
+u=u||"px";
+with(node.style){
+if(!isNaN(l)){
+left=l+u;
+}
+if(!isNaN(t)){
+top=t+u;
+}
+if(w>=0){
+width=w+u;
+}
+if(h>=0){
+height=h+u;
+}
+}
+};
+dojo._setContentBox=function(node,_217,_218,_219,_21a,_21b){
+if(dojo.boxModel=="border-box"){
+var pb=dojo._getPadBorderExtents(node,_21b);
+if(_219>=0){
+_219+=pb.w;
+}
+if(_21a>=0){
+_21a+=pb.h;
+}
+}
+dojo._setBox(node,_217,_218,_219,_21a);
+};
+dojo._nilExtents={w:0,h:0};
+dojo._setMarginBox=function(node,_21e,_21f,_220,_221,_222){
+var s=_222||dojo.getComputedStyle(node);
+var pb=((dojo.boxModel=="border-box")?dojo._nilExtents:dojo._getPadBorderExtents(node,s));
+var mb=dojo._getMarginExtents(node,s);
+if(_220>=0){
+_220=Math.max(_220-pb.w-mb.w,0);
+}
+if(_221>=0){
+_221=Math.max(_221-pb.h-mb.h,0);
+}
+dojo._setBox(node,_21e,_21f,_220,_221);
+};
+dojo.marginBox=function(node,_227){
+node=dojo.byId(node);
+var s=dojo.getComputedStyle(node),b=_227;
+return !b?dojo._getMarginBox(node,s):dojo._setMarginBox(node,b.l,b.t,b.w,b.h,s);
+};
+dojo.contentBox=function(node,_22b){
+node=dojo.byId(node);
+var s=dojo.getComputedStyle(node),b=_22b;
+return !b?dojo._getContentBox(node,s):dojo._setContentBox(node,b.l,b.t,b.w,b.h,s);
+};
+var _22e=function(node,prop){
+if(!node){
+return 0;
+}
+var _b=dojo.body();
+var _232=0;
+while(node){
+try{
+if(dojo.getComputedStyle(node).position=="fixed"){
+return 0;
+}
+}
+catch(e){
+}
+var val=node[prop];
+if(val){
+_232+=val-0;
+if(node==_b){
+break;
+}
+}
+node=node.parentNode;
+}
+return _232;
+};
+dojo._docScroll=function(){
+var _b=dojo.body();
+var _w=dojo.global;
+var de=dojo.doc.documentElement;
+return {y:(_w.pageYOffset||de.scrollTop||_b.scrollTop||0),x:(_w.pageXOffset||de.scrollLeft||_b.scrollLeft||0)};
+};
+var _237=((dojo.isIE>=7)&&(dojo.boxModel!="border-box"))?2:0;
+dojo._abs=function(node,_239){
+var _23a=dojo.doc;
+var ret={x:0,y:0};
+var db=dojo.body();
+if(dojo.isIE){
+with(node.getBoundingClientRect()){
+ret.x=left-_237;
+ret.y=top-_237;
+}
+}else{
+if(_23a["getBoxObjectFor"]){
+var bo=_23a.getBoxObjectFor(node);
+ret.x=bo.x-_22e(node,"scrollLeft");
+ret.y=bo.y-_22e(node,"scrollTop");
+}else{
+if(node["offsetParent"]){
+var _23e;
+if((dojo.isSafari)&&(node.style.getPropertyValue("position")=="absolute")&&(node.parentNode==db)){
+_23e=db;
+}else{
+_23e=db.parentNode;
+}
+if(node.parentNode!=db){
+var nd=node;
+if(dojo.isOpera){
+nd=db;
+}
+ret.x-=_22e(nd,"scrollLeft");
+ret.y-=_22e(nd,"scrollTop");
+}
+var _240=node;
+do{
+var n=_240["offsetLeft"];
+if(!dojo.isOpera||n>0){
+ret.x+=isNaN(n)?0:n;
+}
+var m=_240["offsetTop"];
+ret.y+=isNaN(m)?0:m;
+_240=_240.offsetParent;
+}while((_240!=_23e)&&(_240!=null));
+}else{
+if(node["x"]&&node["y"]){
+ret.x+=isNaN(node.x)?0:node.x;
+ret.y+=isNaN(node.y)?0:node.y;
+}
+}
+}
+}
+if(_239){
+var _243=dojo._docScroll();
+ret.y+=_243.y;
+ret.x+=_243.x;
+}
+return ret;
+};
+dojo.coords=function(node,_245){
+node=dojo.byId(node);
+var s=dojo.getComputedStyle(node);
+var mb=dojo._getMarginBox(node,s);
+var abs=dojo._abs(node,_245);
+mb.x=abs.x;
+mb.y=abs.y;
+return mb;
+};
+})();
+dojo.hasClass=function(node,_24a){
+return ((" "+node.className+" ").indexOf(" "+_24a+" ")>=0);
+};
+dojo.addClass=function(node,_24c){
+var cls=node.className;
+if((" "+cls+" ").indexOf(" "+_24c+" ")<0){
+node.className=cls+(cls?" ":"")+_24c;
+}
+};
+dojo.removeClass=function(node,_24f){
+var cls=node.className;
+if(cls&&cls.indexOf(_24f)>=0){
+node.className=cls.replace(new RegExp("(^|\\s+)"+_24f+"(\\s+|$)"),"$1$2");
+}
+};
+dojo.toggleClass=function(node,_252,_253){
+if(typeof _253=="undefined"){
+_253=!dojo.hasClass(node,_252);
+}
+dojo[_253?"addClass":"removeClass"](node,_252);
+};
+dojo.provide("dojo._base.NodeList");
+(function(){
+var d=dojo;
+dojo.NodeList=function(){
+if((arguments.length==1)&&(typeof arguments[0]=="number")){
+this.length=parseInt(arguments[0]);
+}else{
+if((arguments.length==1)&&(arguments[0].constructor==dojo.NodeList)){
+}else{
+for(var x=0;x<arguments.length;x++){
+this.push(arguments[x]);
+}
+}
+}
+};
+dojo.NodeList.prototype=new Array;
+dojo.extend(dojo.NodeList,{box:function(){
+return dojo.coords(this[0]);
+},boxes:function(){
+var ret=[];
+this.forEach(function(item){
+ret.push(dojo.coords(item));
+});
+return ret;
+},style:function(prop){
+var aa=dojo._toArray(arguments);
+aa.unshift(this[0]);
+return dojo.style.apply(dojo,aa);
+},styles:function(prop){
+var aa=dojo._toArray(arguments);
+aa.unshift(null);
+return this.map(function(i){
+aa[0]=i;
+return dojo.style.apply(dojo,aa);
+});
+},place:function(_25d,_25e){
+var item=d.query(_25d)[0];
+_25e=_25e||"last";
+for(var x=0;x<this.length;x++){
+d.place(this[x],item,_25e);
+}
+return this;
+},orphan:function(_261){
+var _262=d._filterQueryResult(this,_261);
+_262.forEach(function(item){
+if(item["parentNode"]){
+item.parentNode.removeChild(item);
+}
+});
+return _262;
+},adopt:function(_264,_265){
+var item=this[0];
+_265=_265||"last";
+var _267=d.query(_264);
+for(var x=0;x<_267.length;x++){
+d.place(_267[x],item,_265);
+}
+return _267;
+},query:function(_269){
+_269=_269||"";
+var ret=new d.NodeList();
+this.forEach(function(item){
+d.query(_269,item).forEach(function(_26c){
+if(typeof _26c!="undefined"){
+ret.push(_26c);
+}
+});
+});
+return ret;
+},filter:function(_26d){
+var _26e=this;
+var _a=arguments;
+var r=new d.NodeList();
+var rp=function(t){
+if(typeof t!="undefined"){
+r.push(t);
+}
+};
+if(dojo.isString(_26d)){
+_26e=d._filterQueryResult(this,_a[0]);
+if(_a.length==1){
+return _26e;
+}
+d.forEach(d.filter(_26e,_a[1],_a[2]),rp);
+return r;
+}
+d.forEach(d.filter(_26e,_a[0],_a[1]),rp);
+return r;
+},addContent:function(_273,_274){
+var ta=dojo.doc.createElement("span");
+if(dojo.isString(_273)){
+ta.innerHTML=_273;
+}else{
+ta.appendChild(_273);
+}
+var ct=((_274=="first")||(_274=="after"))?"lastChild":"firstChild";
+this.forEach(function(item){
+var tn=ta.cloneNode(true);
+while(tn[ct]){
+d.place(tn[ct],item,_274);
+}
+});
+return this;
+}});
+if(!Array.forEach){
+dojo.extend(dojo.NodeList,{indexOf:function(_279,_27a){
+return d.indexOf(this,_279,_27a);
+},lastIndexOf:function(_27b,_27c){
+return d.lastIndexOf(this,_27b,_27c);
+},forEach:function(_27d,_27e){
+return d.forEach(this,_27d,_27e);
+},every:function(_27f,_280){
+return d.every(this,_27f,_280);
+},some:function(_281,_282){
+return d.some(this,_281,_282);
+},map:function(_283,obj){
+return d.map(this,_283,obj);
+}});
+}
+if(d.isIE){
+var _285=function(_286){
+return ("var a2 = parent."+_286+"; "+"var ap = Array.prototype; "+"var a2p = a2.prototype; "+"for(var x in a2p){ ap[x] = a2p[x]; } "+"parent."+_286+" = Array; ");
+};
+var scs=_285("dojo.NodeList");
+var _288=window.createPopup();
+_288.document.write("<script>"+scs+"</script>");
+_288.show(1,1,1,1);
+}
+})();
+dojo.provide("dojo._base.query");
+(function(){
+var d=dojo;
+var _28a=function(q){
+return [q.indexOf("#"),q.indexOf("."),q.indexOf("["),q.indexOf(":")];
+};
+var _28c=function(_28d,_28e){
+var ql=_28d.length;
+var i=_28a(_28d);
+var end=ql;
+for(var x=_28e;x<i.length;x++){
+if(i[x]>=0){
+if(i[x]<end){
+end=i[x];
+}
+}
+}
+return (end<0)?ql:end;
+};
+var _293=function(_294){
+return _28c(_294,1);
+};
+var _295=function(_296){
+var i=_28a(_296);
+if(i[0]!=-1){
+return _296.substring(i[0]+1,_293(_296));
+}else{
+return "";
+}
+};
+var _298=function(_299){
+var i=_28a(_299);
+if((i[0]==0)||(i[1]==0)){
+return 0;
+}else{
+return _28c(_299,0);
+}
+};
+var _29b=function(_29c){
+var _29d=_298(_29c);
+return ((_29d>0)?_29c.substr(0,_29d).toLowerCase():"*");
+};
+var _29e=function(arr){
+var ret=-1;
+for(var x=0;x<arr.length;x++){
+var ta=arr[x];
+if(ta>=0){
+if((ta>ret)||(ret==-1)){
+ret=ta;
+}
+}
+}
+return ret;
+};
+var _2a3=function(_2a4){
+var i=_28a(_2a4);
+if(-1==i[1]){
+return "";
+}
+var di=i[1]+1;
+var _2a7=_29e(i.slice(2));
+if(di<_2a7){
+return _2a4.substring(di,_2a7);
+}else{
+if(-1==_2a7){
+return _2a4.substr(di);
+}else{
+return "";
+}
+}
+};
+var _2a8=[{key:"|=",match:function(attr,_2aa){
+return "[contains(concat(' ',@"+attr+",' '), ' "+_2aa+"-')]";
+}},{key:"~=",match:function(attr,_2ac){
+return "[contains(concat(' ',@"+attr+",' '), ' "+_2ac+" ')]";
+}},{key:"^=",match:function(attr,_2ae){
+return "[starts-with(@"+attr+", '"+_2ae+"')]";
+}},{key:"*=",match:function(attr,_2b0){
+return "[contains(@"+attr+", '"+_2b0+"')]";
+}},{key:"$=",match:function(attr,_2b2){
+return "[substring(@"+attr+", string-length(@"+attr+")-"+(_2b2.length-1)+")='"+_2b2+"']";
+}},{key:"!=",match:function(attr,_2b4){
+return "[not(@"+attr+"='"+_2b4+"')]";
+}},{key:"=",match:function(attr,_2b6){
+return "[@"+attr+"='"+_2b6+"']";
+}}];
+var _2b7=function(val){
+var re=/^\s+|\s+$/g;
+return val.replace(re,"");
+};
+var _2ba=function(_2bb,_2bc,_2bd,_2be){
+var _2bf;
+var i=_28a(_2bc);
+if(i[2]>=0){
+var _2c1=_2bc.indexOf("]",i[2]);
+var _2c2=_2bc.substring(i[2]+1,_2c1);
+while(_2c2&&_2c2.length){
+if(_2c2.charAt(0)=="@"){
+_2c2=_2c2.slice(1);
+}
+_2bf=null;
+for(var x=0;x<_2bb.length;x++){
+var ta=_2bb[x];
+var tci=_2c2.indexOf(ta.key);
+if(tci>=0){
+var attr=_2c2.substring(0,tci);
+var _2c7=_2c2.substring(tci+ta.key.length);
+if((_2c7.charAt(0)=="\"")||(_2c7.charAt(0)=="'")){
+_2c7=_2c7.substring(1,_2c7.length-1);
+}
+_2bf=ta.match(_2b7(attr),_2b7(_2c7));
+break;
+}
+}
+if((!_2bf)&&(_2c2.length)){
+_2bf=_2bd(_2c2);
+}
+if(_2bf){
+_2be(_2bf);
+}
+_2c2=null;
+var _2c8=_2bc.indexOf("[",_2c1);
+if(0<=_2c8){
+_2c1=_2bc.indexOf("]",_2c8);
+if(0<=_2c1){
+_2c2=_2bc.substring(_2c8+1,_2c1);
+}
+}
+}
+}
+};
+var _2c9=function(_2ca){
+var _2cb=".";
+var _2cc=_2ca.split(" ");
+while(_2cc.length){
+var tqp=_2cc.shift();
+var _2ce;
+if(tqp==">"){
+_2ce="/";
+tqp=_2cc.shift();
+}else{
+_2ce="//";
+}
+var _2cf=_29b(tqp);
+_2cb+=_2ce+_2cf;
+var id=_295(tqp);
+if(id.length){
+_2cb+="[@id='"+id+"'][1]";
+}
+var cn=_2a3(tqp);
+if(cn.length){
+var _2d2=" ";
+if(cn.charAt(cn.length-1)=="*"){
+_2d2="";
+cn=cn.substr(0,cn.length-1);
+}
+_2cb+="[contains(concat(' ', at class,' '), ' "+cn+_2d2+"')]";
+}
+_2ba(_2a8,tqp,function(_2d3){
+return "[@"+_2d3+"]";
+},function(_2d4){
+_2cb+=_2d4;
+});
+}
+return _2cb;
+};
+var _2d5={};
+var _2d6=function(path){
+if(_2d5[path]){
+return _2d5[path];
+}
+var doc=d.doc;
+var _2d9=_2c9(path);
+var tf=function(_2db){
+var ret=[];
+var _2dd;
+try{
+_2dd=doc.evaluate(_2d9,_2db,null,XPathResult.ANY_TYPE,null);
+}
+catch(e){
+console.debug("failure in exprssion:",_2d9,"under:",_2db);
+console.debug(e);
+}
+var _2de=_2dd.iterateNext();
+while(_2de){
+ret.push(_2de);
+_2de=_2dd.iterateNext();
+}
+return ret;
+};
+return _2d5[path]=tf;
+};
+var _2df={};
+var _2e0={};
+var _2e1=function(_2e2,_2e3){
+if(!_2e2){
+return _2e3;
+}
+if(!_2e3){
+return _2e2;
+}
+return function(){
+return _2e2.apply(window,arguments)&&_2e3.apply(window,arguments);
+};
+};
+var _2e4=function(_2e5,_2e6,_2e7,idx){
+var nidx=idx+1;
+var _2ea=(_2e6.length==nidx);
+var tqp=_2e6[idx];
+if(tqp==">"){
+var ecn=_2e5.childNodes;
+if(!ecn.length){
+return;
+}
+nidx++;
+var _2ea=(_2e6.length==nidx);
+var tf=_2ee(_2e6[idx+1]);
+for(var x=ecn.length-1,te;x>=0,te=ecn[x];x--){
+if(tf(te)){
+if(_2ea){
+_2e7.push(te);
+}else{
+_2e4(te,_2e6,_2e7,nidx);
+}
+}
+if(x==0){
+break;
+}
+}
+}
+var _2f1=_2f2(tqp)(_2e5);
+if(_2ea){
+while(_2f1.length){
+_2e7.push(_2f1.shift());
+}
+}else{
+while(_2f1.length){
+_2e4(_2f1.shift(),_2e6,_2e7,nidx);
+}
+}
+};
+var _2f3=function(_2f4,_2f5){
+ret=[];
+var x=_2f4.length-1,te;
+while(te=_2f4[x--]){
+_2e4(te,_2f5,ret,0);
+}
+return ret;
+};
+var _2ee=function(_2f8){
+if(_2df[_2f8]){
+return _2df[_2f8];
+}
+var ff=null;
+var _2fa=_29b(_2f8);
+if(_2fa!="*"){
+ff=_2e1(ff,function(elem){
+var isTn=((elem.nodeType==1)&&(_2fa==elem.tagName.toLowerCase()));
+return isTn;
+});
+}
+var _2fd=_295(_2f8);
+if(_2fd.length){
+ff=_2e1(ff,function(elem){
+return ((elem.nodeType==1)&&(elem.id==_2fd));
+});
+}
+if(Math.max.apply(this,_28a(_2f8).slice(1))>=0){
+ff=_2e1(ff,_2ff(_2f8));
+}
+return _2df[_2f8]=ff;
+};
+var _300=function(node){
+var pn=node.parentNode;
+var pnc=pn.childNodes;
+var nidx=-1;
+var _305=pn.firstChild;
+if(!_305){
+return nidx;
+}
+var ci=node["__cachedIndex"];
+var cl=pn["__cachedLength"];
+if(((typeof cl=="number")&&(cl!=pnc.length))||(typeof ci!="number")){
+pn["__cachedLength"]=pnc.length;
+var idx=1;
+do{
+if(_305===node){
+nidx=idx;
+}
+if(_305.nodeType==1){
+_305["__cachedIndex"]=idx;
+idx++;
+}
+_305=_305.nextSibling;
+}while(_305);
+}else{
+nidx=ci;
+}
+return nidx;
+};
+var _309=0;
+var _30a=function(elem,attr){
+var _30d="";
+if(attr=="class"){
+return elem.className||_30d;
+}
+if(attr=="for"){
+return elem.htmlFor||_30d;
+}
+return elem.getAttribute(attr,2)||_30d;
+};
+var _30e=[{key:"|=",match:function(attr,_310){
+var _311=" "+_310+"-";
+return function(elem){
+var ea=" "+(elem.getAttribute(attr,2)||"");
+return ((ea==_310)||(ea.indexOf(_311)==0));
+};
+}},{key:"^=",match:function(attr,_315){
+return function(elem){
+return (_30a(elem,attr).indexOf(_315)==0);
+};
+}},{key:"*=",match:function(attr,_318){
+return function(elem){
+return (_30a(elem,attr).indexOf(_318)>=0);
+};
+}},{key:"~=",match:function(attr,_31b){
+var tval=" "+_31b+" ";
+return function(elem){
+var ea=" "+_30a(elem,attr)+" ";
+return (ea.indexOf(tval)>=0);
+};
+}},{key:"$=",match:function(attr,_320){
+var tval=" "+_320;
+return function(elem){
+var ea=" "+_30a(elem,attr);
+return (ea.lastIndexOf(_320)==(ea.length-_320.length));
+};
+}},{key:"!=",match:function(attr,_325){
+return function(elem){
+return (_30a(elem,attr)!=_325);
+};
+}},{key:"=",match:function(attr,_328){
+return function(elem){
+return (_30a(elem,attr)==_328);
+};
+}}];
+var _32a=[{key:"first-child",match:function(name,_32c){
+return function(elem){
+if(elem.nodeType!=1){
+return false;
+}
+var fc=elem.previousSibling;
+while(fc&&(fc.nodeType!=1)){
+fc=fc.previousSibling;
+}
+return (!fc);
+};
+}},{key:"last-child",match:function(name,_330){
+return function(elem){
+if(elem.nodeType!=1){
+return false;
+}
+var nc=elem.nextSibling;
+while(nc&&(nc.nodeType!=1)){
+nc=nc.nextSibling;
+}
+return (!nc);
+};
+}},{key:"empty",match:function(name,_334){
+return function(elem){
+var cn=elem.childNodes;
+var cnl=elem.childNodes.length;
+for(var x=cnl-1;x>=0;x--){
+var nt=cn[x].nodeType;
+if((nt==1)||(nt==3)){
+return false;
+}
+}
+return true;
+};
+}},{key:"contains",match:function(name,_33b){
+return function(elem){
+return (elem.innerHTML.indexOf(_33b)>=0);
+};
+}},{key:"not",match:function(name,_33e){
+var ntf=_2ee(_33e);
+return function(elem){
+return (!ntf(elem));
+};
+}},{key:"nth-child",match:function(name,_342){
+var pi=parseInt;
+if(_342=="odd"){
+return function(elem){
+return (((_300(elem))%2)==1);
+};
+}else{
+if((_342=="2n")||(_342=="even")){
+return function(elem){
+return ((_300(elem)%2)==0);
+};
+}else{
+if(_342.indexOf("0n+")==0){
+var _346=pi(_342.substr(3));
+return function(elem){
+return (elem.parentNode.childNodes[_346-1]===elem);
+};
+}else{
+if((_342.indexOf("n+")>0)&&(_342.length>3)){
+var _348=_342.split("n+",2);
+var pred=pi(_348[0]);
+var idx=pi(_348[1]);
+return function(elem){
+return ((_300(elem)%pred)==idx);
+};
+}else{
+if(_342.indexOf("n")==-1){
+var _346=pi(_342);
+return function(elem){
+return (_300(elem)==_346);
+};
+}
+}
+}
+}
+}
+}}];
+var _2ff=function(_34d){
+var _34e=(_2e0[_34d]||_2df[_34d]);
+if(_34e){
+return _34e;
+}
+var ff=null;
+var i=_28a(_34d);
+if(i[0]>=0){
+var tn=_29b(_34d);
+if(tn!="*"){
+ff=_2e1(ff,function(elem){
+return (elem.tagName.toLowerCase()==tn);
+});
+}
+}
+var _353;
+var _354=_2a3(_34d);
+if(_354.length){
+var _355=_354.charAt(_354.length-1)=="*";
+if(_355){
+_354=_354.substr(0,_354.length-1);
+}
+var re=new RegExp("(?:^|\\s)"+_354+(_355?".*":"")+"(?:\\s|$)");
+ff=_2e1(ff,function(elem){
+return re.test(elem.className);
+});
+}
+if(i[3]>=0){
+var _358=_34d.substr(i[3]+1);
+var _359="";
+var obi=_358.indexOf("(");
+var cbi=_358.lastIndexOf(")");
+if((0<=obi)&&(0<=cbi)&&(cbi>obi)){
+_359=_358.substring(obi+1,cbi);
+_358=_358.substr(0,obi);
+}
+_353=null;
+for(var x=0;x<_32a.length;x++){
+var ta=_32a[x];
+if(ta.key==_358){
+_353=ta.match(_358,_359);
+break;
+}
+}
+if(_353){
+ff=_2e1(ff,_353);
+}
+}
+var _35e=(d.isIE)?function(cond){
+return function(elem){
+return elem[cond];
+};
+}:function(cond){
+return function(elem){
+return elem.hasAttribute(cond);
+};
+};
+_2ba(_30e,_34d,_35e,function(_363){
+ff=_2e1(ff,_363);
+});
+if(!ff){
+ff=function(){
+return true;
+};
+}
+return _2e0[_34d]=ff;
+};
+var _364=function(_365){
+return (Math.max.apply(this,_28a(_365))==-1);
+};
+var _366={};
+var _2f2=function(_367,root){
+var fHit=_366[_367];
+if(fHit){
+return fHit;
+}
+var i=_28a(_367);
+var id=_295(_367);
+if(i[0]==0){
+return _366[_367]=function(root){
+return [d.byId(id)];
+};
+}
+var _36d=_2ff(_367);
+var _36e;
+if(i[0]>=0){
+_36e=function(root){
+var te=d.byId(id);
+if(_36d(te)){
+return [te];
+}
+};
+}else{
+var tret;
+var tn=_29b(_367);
+if(_364(_367)){
+_36e=function(root){
+var ret=[];
+var te,x=0,tret=root.getElementsByTagName(tn);
+while(te=tret[x++]){
+ret.push(te);
+}
+return ret;
+};
+}else{
+_36e=function(root){
+var ret=[];
+var te,x=0,tret=root.getElementsByTagName(tn);
+while(te=tret[x++]){
+if(_36d(te)){
+ret.push(te);
+}
+}
+return ret;
+};
+}
+}
+return _366[_367]=_36e;
+};
+var _37b={};
+var _37c={};
+var _37d=function(_37e){
+if(0>_37e.indexOf(" ")){
+return _2f2(_37e);
+}
+var sqf=function(root){
+var _381=_37e.split(" ");
+var _382;
+if(_381[0]==">"){
+_382=[root];
+root=document;
+}else{
+_382=_2f2(_381.shift())(root);
+}
+return _2f3(_382,_381);
+};
+return sqf;
+};
+var _383=((document["evaluate"]&&!d.isSafari)?function(_384){
+var _385=_384.split(" ");
+if((document["evaluate"])&&(_384.indexOf(":")==-1)&&((true))){
+if(((_385.length>2)&&(_384.indexOf(">")==-1))||(_385.length>3)||(_384.indexOf("[")>=0)||((1==_385.length)&&(0<=_384.indexOf(".")))){
+return _2d6(_384);
+}
+}
+return _37d(_384);
+}:_37d);
+var _386=function(_387){
+if(_37c[_387]){
+return _37c[_387];
+}
+if(0>_387.indexOf(",")){
+return _37c[_387]=_383(_387);
+}else{
+var _388=_387.split(", ");
+var tf=function(root){
+var _38b=0;
+var ret=[];
+var tp;
+while(tp=_388[_38b++]){
+ret=ret.concat(_383(tp,tp.indexOf(" "))(root));
+}
+return ret;
+};
+return _37c[_387]=tf;
+}
+};
+var _38e=0;
+var _zip=function(arr){
+var ret=new d.NodeList();
+if(!arr){
+return ret;
+}
+if(arr[0]){
+ret.push(arr[0]);
+}
+if(arr.length<2){
+return ret;
+}
+_38e++;
+arr[0]["_zipIdx"]=_38e;
+for(var x=1,te;te=arr[x];x++){
+if(arr[x]["_zipIdx"]!=_38e){
+ret.push(te);
+}
+te["_zipIdx"]=_38e;
+}
+return ret;
+};
+d.query=function(_394,root){
+if(typeof _394!="string"){
+return new d.NodeList(_394);
+}
+if(typeof root=="string"){
+root=dojo.byId(root);
+}
+return _zip(_386(_394)(root||dojo.doc));
+};
+d._filterQueryResult=function(_396,_397){
+var tnl=new d.NodeList();
+var ff=(_397)?_2ee(_397):function(){
+return true;
+};
+for(var x=0,te;te=_396[x];x++){
+if(ff(te)){
+tnl.push(te);
+}
+}
+return tnl;
+};
+})();
+dojo.provide("dojo._base.xhr");
+dojo.formToObject=function(_39c){
+var ret={};
+var iq="input[type!=file][type!=submit][type!=image][type!=reset][type!=button], select, textarea";
+dojo.query(iq,_39c).filter(function(node){
+return (!node.disabled);
+}).forEach(function(item){
+var _in=item.name;
+var type=(item.type||"").toLowerCase();
+if((type=="radio")||(type=="checkbox")){
+if(item.checked){
+ret[_in]=item.value;
+}
+}else{
+if(item.multiple){
+var ria=ret[_in]=[];
+dojo.query("option[selected]",item).forEach(function(opt){
+ria.push(opt.value);
+});
+}else{
+ret[_in]=item.value;
+if(type=="image"){
+ret[_in+".x"]=ret[_in+".y"]=ret[_in].x=ret[_in].y=0;
+}
+}
+}
+});
+return ret;
+};
+dojo.objectToQuery=function(map){
+var ec=encodeURIComponent;
+var ret="";
+var _3a8={};
+for(var x in map){
+if(map[x]!=_3a8[x]){
+if(dojo.isArray(map[x])){
+for(var y=0;y<map[x].length;y++){
+ret+=ec(x)+"="+ec(map[x][y])+"&";
+}
+}else{
+ret+=ec(x)+"="+ec(map[x])+"&";
+}
+}
+}
+if((ret.length)&&(ret.charAt(ret.length-1)=="&")){
+ret=ret.substr(0,ret.length-1);
+}
+return ret;
+};
+dojo.formToQuery=function(_3ab){
+return dojo.objectToQuery(dojo.formToObject(_3ab));
+};
+dojo.formToJson=function(_3ac){
+return dojo.toJson(dojo.formToObject(_3ac));
+};
+dojo.queryToObject=function(str){
+var ret={};
+var qp=str.split("&");
+var dc=decodeURIComponent;
+dojo.forEach(qp,function(item){
+if(item.length){
+var _3b2=item.split("=");
+var name=_3b2.shift();
+var val=dc(_3b2.join("="));
+if(dojo.isString(ret[name])){
+ret[name]=[ret[name]];
+}
+if(dojo.isArray(ret[name])){
+ret[name].push(val);
+}else{
+ret[name]=val;
+}
+}
+});
+return ret;
+};
+dojo._blockAsync=false;
+dojo._contentHandlers={"text":function(xhr){
+return xhr.responseText;
+},"json":function(xhr){
+console.debug("please consider using a mimetype of text/json-comment-filtered to avoid potential security issues with JSON endpoints");
+return dojo.fromJson(xhr.responseText);
+},"json-comment-optional":function(xhr){
+var _3b8=xhr.responseText;
+var _3b9=_3b8.indexOf("/*");
+var _3ba=_3b8.lastIndexOf("*/");
+if((_3b9==-1)||(_3ba==-1)){
+return dojo.fromJson(xhr.responseText);
+}
+return dojo.fromJson(_3b8.substring(_3b9+2,_3ba));
+},"json-comment-filtered":function(xhr){
+var _3bc=xhr.responseText;
+var _3bd=_3bc.indexOf("/*");
+var _3be=_3bc.lastIndexOf("*/");
+if((_3bd==-1)||(_3be==-1)){
+console.debug("your JSON wasn't comment filtered!");
+return "";
+}
+return dojo.fromJson(_3bc.substring(_3bd+2,_3be));
+},"javascript":function(xhr){
+return dojo.eval(xhr.responseText);
+},"xml":function(xhr){
+return xhr.responseXML;
+}};
+(function(){
+dojo._ioSetArgs=function(args,_3c2,_3c3,_3c4){
+var _3c5={};
+_3c5.args=args;
+var _3c6=null;
+if(args.form){
+var form=dojo.byId(args.form);
+_3c5.url=args.url||form.getAttribute("action");
+_3c6=dojo.formToQuery(form);
+}else{
+_3c5.url=args.url;
+}
+var qi=_3c5.url.indexOf("?");
+var _3c9=[{}];
+if(qi!=-1){
+_3c9.push(dojo.queryToObject(_3c5.url.substr(qi+1)));
+_3c5.url=_3c5.url.substr(0,qi);
+}
+if(_3c6){
+_3c9.push(dojo.queryToObject(_3c6));
+}
+if(args.content){
+_3c9.push(args.content);
+}
+if(args.preventCache){
+_3c9.push({"dojo.preventCache":new Date().valueOf()});
+}
+_3c5.query=dojo.objectToQuery(dojo.mixin.apply(null,_3c9));
+_3c5.ha=args.handleAs||"text";
+var d=new dojo.Deferred(_3c2);
+d.addCallbacks(_3c3,function(_3cb){
+return _3c4(_3cb,d);
+});
+d.ioArgs=_3c5;
+return d;
+};
+var _3cc=function(dfd){
+dfd.canceled=true;
+dfd.ioArgs.xhr.abort();
+};
+var _3ce=function(dfd){
+return dojo._contentHandlers[dfd.ioArgs.ha](dfd.ioArgs.xhr);
+};
+var _3d0=function(_3d1,dfd){
+console.debug("xhr error in:",dfd.ioArgs.xhr);
+console.debug(_3d1);
+return _3d1;
+};
+var _3d3=function(args){
+var dfd=dojo._ioSetArgs(args,_3cc,_3ce,_3d0);
+dfd.ioArgs.xhr=dojo._xhrObj();
+return dfd;
+};
+var _3d6=null;
+var _3d7=[];
+var _3d8=function(){
+var now=(new Date()).getTime();
+if(!dojo._blockAsync){
+dojo.forEach(_3d7,function(tif,_3db){
+if(!tif){
+return;
+}
+var dfd=tif.dfd;
+try{
+if(!dfd||dfd.canceled||!tif.validCheck(dfd)){
+_3d7.splice(_3db,1);
+return;
+}
+if(tif.ioCheck(dfd)){
+_3d7.splice(_3db,1);
+tif.resHandle(dfd);
+}else{
+if(dfd.startTime){
+if(dfd.startTime+(dfd.ioArgs.args.timeout||0)<now){
+dfd.cancel();
+_3d7.splice(_3db,1);
+var err=new Error("timeout exceeded");
+err.dojoType="timeout";
+dfd.errback(err);
+}
+}
+}
+}
+catch(e){
+console.debug(e);
+dfd.errback(new Error("_watchInFlightError!"));
+}
+});
+}
+if(!_3d7.length){
+clearInterval(_3d6);
+_3d6=null;
+return;
+}
+};
+dojo._ioWatch=function(dfd,_3df,_3e0,_3e1){
+if(dfd.ioArgs.args.timeout){
+dfd.startTime=(new Date()).getTime();
+}
+_3d7.push({dfd:dfd,validCheck:_3df,ioCheck:_3e0,resHandle:_3e1});
+if(!_3d6){
+_3d6=setInterval(_3d8,50);
+}
+_3d8();
+};
+var _3e2="application/x-www-form-urlencoded";
+var _3e3=function(dfd){
+return dfd.ioArgs.xhr.readyState;
+};
+var _3e5=function(dfd){
+return 4==dfd.ioArgs.xhr.readyState;
+};
+var _3e7=function(dfd){
+if(dojo._isDocumentOk(dfd.ioArgs.xhr)){
+dfd.callback(dfd);
+}else{
+dfd.errback(new Error("bad http response code:"+dfd.ioArgs.xhr.status));
+}
+};
+var _3e9=function(type,dfd){
+var _3ec=dfd.ioArgs;
+var args=_3ec.args;
+_3ec.xhr.open(type,_3ec.url,(args.sync!==true),(args.user?args.user:undefined),(args.password?args.password:undefined));
+_3ec.xhr.setRequestHeader("Content-Type",(args.contentType||_3e2));
+try{
+_3ec.xhr.send(_3ec.query);
+}
+catch(e){
+_3ec.cancel();
+}
+dojo._ioWatch(dfd,_3e3,_3e5,_3e7);
+return dfd;
+};
+dojo.xhrGet=function(args){
+var dfd=_3d3(args);
+var _3f0=dfd.ioArgs;
+if(_3f0.query.length){
+_3f0.url+="?"+_3f0.query;
+_3f0.query=null;
+}
+return _3e9("GET",dfd);
+};
+dojo.xhrPost=function(args){
+return _3e9("POST",_3d3(args));
+};
+dojo.rawXhrPost=function(args){
+var dfd=_3d3(args);
+dfd.ioArgs.query=args.postData;
+return _3e9("POST",dfd);
+};
+dojo.wrapForm=function(_3f4){
+throw new Error("dojo.wrapForm not yet implemented");
+};
+})();
+dojo.provide("dojo._base.fx");
+dojo._Line=function(_3f5,end){
+this.start=_3f5;
+this.end=end;
+this.getValue=function(n){
+return ((this.end-this.start)*n)+this.start;
+};
+};
+dojo.Color=function(){
+this.setColor.apply(this,arguments);
+};
+dojo.Color.named={black:[0,0,0],silver:[192,192,192],gray:[128,128,128],white:[255,255,255],maroon:[128,0,0],red:[255,0,0],purple:[128,0,128],fuchsia:[255,0,255],green:[0,128,0],lime:[0,255,0],olive:[128,128,0],yellow:[255,255,0],navy:[0,0,128],blue:[0,0,255],teal:[0,128,128],aqua:[0,255,255]};
+dojo.extend(dojo.Color,{_cache:null,setColor:function(){
+this._cache=[];
+var d=dojo;
+var a=arguments;
+var a0=a[0];
+var pmap=(d.isArray(a0)?a0:(d.isString(a0)?d.extractRgb(a0):d._toArray(a)));
+d.forEach(["r","g","b","a"],function(p,i){
+this._cache[i]=this[p]=parseFloat(pmap[i]);
+},this);
+this._cache[3]=this.a=this.a||1;
+},toRgb:function(_3fe){
+return this._cache.slice(0,((_3fe)?4:3));
+},toRgba:function(){
+return this._cache.slice(0,4);
+},toHex:function(){
+return dojo.rgb2hex(this.toRgb());
+},toCss:function(){
+return "rgb("+this.toRgb().join(", ")+")";
+},toString:function(){
+return this.toHex();
+}});
+dojo.blendColors=function(a,b,_401){
+if(typeof a=="string"){
+a=dojo.extractRgb(a);
+}
+if(typeof b=="string"){
+b=dojo.extractRgb(b);
+}
+if(a["_cache"]){
+a=a._cache;
+}
+if(b["_cache"]){
+b=b._cache;
+}
+_401=Math.min(Math.max(-1,(_401||0)),1);
+_401=((_401+1)/2);
+var c=[];
+for(var x=0;x<3;x++){
+c[x]=parseInt(b[x]+((a[x]-b[x])*_401));
+}
+return c;
+};
+dojo.extractRgb=function(_404){
+_404=_404.toLowerCase();
+if(_404.indexOf("rgb")==0){
+var _405=_404.match(/rgba*\((\d+), *(\d+), *(\d+)/i);
+var ret=dojo.map(_405.splice(1,3),parseFloat);
+return ret;
+}else{
+return dojo.hex2rgb(_404)||dojo.Color.named[_404]||[255,255,255];
+}
+};
+dojo.hex2rgb=function(hex){
+var _408="0123456789abcdef";
+var rgb=new Array(3);
+if(hex.charAt(0)=="#"){
+hex=hex.substr(1);
+}
+hex=hex.toLowerCase();
+if(hex.replace(new RegExp("["+_408+"]","g"),"")!=""){
+return null;
+}
+if(hex.length==3){
+rgb[0]=hex.charAt(0)+hex.charAt(0);
+rgb[1]=hex.charAt(1)+hex.charAt(1);
+rgb[2]=hex.charAt(2)+hex.charAt(2);
+}else{
+rgb[0]=hex.substr(0,2);
+rgb[1]=hex.substr(2,2);
+rgb[2]=hex.substr(4);
+}
+for(var i=0;i<rgb.length;i++){
+rgb[i]=_408.indexOf(rgb[i].charAt(0))*16+_408.indexOf(rgb[i].charAt(1));
+}
+return rgb;
+};
+dojo.rgb2hex=function(r,g,b){
+var ret=dojo.map(((r._cache)||((!g)?r:[r,g,b])),function(x,i){
+var s=(new Number(x)).toString(16);
+while(s.length<2){
+s="0"+s;
+}
+return s;
+});
+ret.unshift("#");
+return ret.join("");
+};
+dojo.declare("dojo._Animation",null,function(args){
+dojo.mixin(this,args);
+if(dojo.isArray(this.curve)){
+this.curve=new dojo._Line(this.curve[0],this.curve[1]);
+}
+},{curve:null,duration:1000,easing:null,repeat:0,rate:10,delay:null,beforeBegin:null,onBegin:null,onAnimate:null,onEnd:null,onPlay:null,onPause:null,onStop:null,_active:false,_paused:false,_startTime:null,_endTime:null,_timer:null,_percent:0,_startRepeatCount:0,fire:function(evt,args){
+if(this[evt]){
+this[evt].apply(this,args||[]);
+}
+return this;
+},chain:function(_415){
+dojo.forEach(_415,function(anim,i){
+var prev=(i==0)?this:_415[i-1];
+dojo.connect(prev,"onEnd",anim,"play");
+},this);
+return this;
+},combine:function(_419){
+dojo.forEach(_419,function(anim){
+dojo.connect(this,"play",anim,"play");
+},this);
+return this;
+},play:function(_41b,_41c){
+if(_41c){
+clearTimeout(this._timer);
+this._active=this._paused=false;
+this._percent=0;
+}else{
+if(this._active&&!this._paused){
+return this;
+}
+}
+this.fire("beforeBegin");
+var d=_41b||this.delay;
+if(d>0){
+setTimeout(dojo.hitch(this,function(){
+this.play(null,_41c);
+}),d);
+return this;
+}
+this._startTime=new Date().valueOf();
+if(this._paused){
+this._startTime-=this.duration*this._percent;
+}
+this._endTime=this._startTime+this.duration;
+this._active=true;
+this._paused=false;
+var _41e=this.curve.getValue(this._percent);
+if(this._percent==0){
+if(!this._startRepeatCount){
+this._startRepeatCount=this.repeat;
+}
+this.fire("onBegin",[_41e]);
+}
+this.fire("onPlay",[_41e]);
+this._cycle();
+return this;
+},pause:function(){
+clearTimeout(this._timer);
+if(!this._active){
+return this;
+}
+this._paused=true;
+this.fire("onPause",[this.curve.getValue(this._percent)]);
+return this;
+},gotoPercent:function(pct,_420){
+clearTimeout(this._timer);
+this._active=this._paused=true;
+this._percent=pct*100;
+if(_420){
+this.play();
+}
+return this;
+},stop:function(_421){
+clearTimeout(this._timer);
+if(_421){
+this._percent=1;
+}
+this.fire("onStop",[this.curve.getValue(this._percent)]);
+this._active=this._paused=false;
+return this;
+},status:function(){
+if(this._active){
+return this._paused?"paused":"playing";
+}
+return "stopped";
+},_cycle:function(){
+clearTimeout(this._timer);
+if(this._active){
+var curr=new Date().valueOf();
+var step=(curr-this._startTime)/(this._endTime-this._startTime);
+if(step>=1){
+step=1;
+}
+this._percent=step;
+if(this.easing){
+step=this.easing(step);
+}
+this.fire("onAnimate",[this.curve.getValue(step)]);
+if(step<1){
+this._timer=setTimeout(dojo.hitch(this,"_cycle"),this.rate);
+}else{
+this._active=false;
+if(this.repeat>0){
+this.repeat--;
+this.play(null,true);
+}else{
+if(this.repeat==-1){
+this.play(null,true);
+}else{
+if(this._startRepeatCount){
+this.repeat=this._startRepeatCount;
+this._startRepeatCount=0;
+}
+}
+}
+this.fire("onEnd");
+}
+}
+return this;
+}});
+(function(){
+var _424=function(node){
+if(dojo.isIE){
+if(node.style.zoom.length==0&&dojo.style(node,"zoom")=="normal"){
+node.style.zoom="1";
+}
+if(node.style.width.length==0&&dojo.style(node,"width")=="auto"){
+node.style.width="auto";
+}
+}
+};
+dojo._fade=function(args){
+if(typeof args.end=="undefined"){
+throw new Error("dojo._fade needs an end value");
+}
+args.node=dojo.byId(args.node);
+var _427=dojo.mixin({properties:{}},args);
+var _428=_427.properties.opacity={};
+_428.start=(typeof _427.start=="undefined")?function(){
+return Number(dojo.style(_427.node,"opacity"));
+}:_427.start;
+_428.end=_427.end;
+var anim=dojo.animateProperty(_427);
+dojo.connect(anim,"beforeBegin",null,function(){
+_424(_427.node);
+});
+return anim;
+};
+dojo.fadeIn=function(args){
+return dojo._fade(dojo.mixin({end:1},args));
+};
+dojo.fadeOut=function(args){
+return dojo._fade(dojo.mixin({end:0},args));
+};
+if(dojo.isKhtml&&!dojo.isSafari){
+dojo._defaultEasing=function(n){
+return parseFloat("0.5")+((Math.sin((n+parseFloat("1.5"))*Math.PI))/2);
+};
+}else{
+dojo._defaultEasing=function(n){
+return 0.5+((Math.sin((n+1.5)*Math.PI))/2);
+};
+}
+dojo.animateProperty=function(args){
+args.node=dojo.byId(args.node);
+if(!args.easing){
+args.easing=dojo._defaultEasing;
+}
+var _42f=function(_430){
+this._properties=_430;
+for(var p in _430){
+var prop=_430[p];
+if(dojo.isFunction(prop.start)){
+prop.start=prop.start(prop);
+}
+if(dojo.isFunction(prop.end)){
+prop.end=prop.end(prop);
+}
+}
+this.getValue=function(n){
+var ret={};
+for(var p in this._properties){
+var prop=this._properties[p];
+var _437=null;
+if(prop.start instanceof dojo.Color){
+_437=dojo.rgb2hex(dojo.blendColors(prop.end,prop.start,n));
+}else{
+if(!dojo.isArray(prop.start)){
+_437=((prop.end-prop.start)*n)+prop.start+(p!="opacity"?prop.units||"px":"");
+}
+}
+ret[p]=_437;
+}
+return ret;
+};
+};
+var anim=new dojo._Animation(args);
+dojo.connect(anim,"beforeBegin",anim,function(){
+var pm=this.properties;
+for(var p in pm){
+var prop=pm[p];
+if(dojo.isFunction(prop.start)){
+prop.start=prop.start();
+}
+if(dojo.isFunction(prop.end)){
+prop.end=prop.end();
+}
+var _43c=(p.toLowerCase().indexOf("color")>=0);
+if(typeof prop.end=="undefined"){
+prop.end=dojo.style(this.node,p);
+}else{
+if(typeof prop.start=="undefined"){
+prop.start=dojo.style(this.node,p);
+}
+}
+if(_43c){
+prop.start=new dojo.Color(prop.start);
+prop.end=new dojo.Color(prop.end);
+}else{
+prop.start=(p=="opacity")?Number(prop.start):parseInt(prop.start);
+}
+}
+this.curve=new _42f(pm);
+});
+dojo.connect(anim,"onAnimate",anim,function(_43d){
+for(var s in _43d){
+dojo.style(this.node,s,_43d[s]);
+}
+});
+return anim;
+};
+})();

Added: trunk/examples/typeface/root/static/dojo/dojo/dojo.js.uncompressed.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/dojo.js.uncompressed.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/dojo.js.uncompressed.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5950 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+/*
+	This is a compiled version of Dojo, built for deployment and not for
+	development. To get an editable version, please visit:
+
+		http://dojotoolkit.org
+
+	for documentation and information on getting the source.
+*/
+
+if(typeof dojo == "undefined"){
+
+// TODOC: HOW TO DOC THE BELOW?
+// @global: djConfig
+// summary:
+//		Application code can set the global 'djConfig' prior to loading
+//		the library to override certain global settings for how dojo works.
+// description:  The variables that can be set are as follows:
+//			- isDebug: false
+//			- baseScriptUri: ""
+//			- baseRelativePath: ""
+//			- libraryScriptUri: ""
+//			- locale: undefined
+//			- extraLocale: undefined
+//			- preventBackButtonFix: true
+// note:
+//		'djConfig' does not exist under 'dojo.*' so that it can be set before the
+//		'dojo' variable exists.
+// note:
+//		Setting any of these variables *after* the library has loaded does
+//		nothing at all.
+
+
+(function(){
+	// make sure djConfig is defined
+	if(typeof this["djConfig"] == "undefined"){
+		this.djConfig = {};
+	}
+
+	// firebug stubs
+	if((!this["console"])||(!console["firebug"])){
+		this.console = {};
+	}
+	var cn = [
+		"assert", "count", "debug", "dir", "dirxml", "error", "group",
+		"groupEnd", "info", "log", "profile", "profileEnd", "time",
+		"timeEnd", "trace", "warn"
+	];
+	var i=0, tn;
+	while(tn=cn[i++]){
+		if(!console[tn]){
+			console[tn] = function(){};
+		}
+	}
+
+	//TODOC:  HOW TO DOC THIS?
+	// dojo is the root variable of (almost all) our public symbols -- make sure it is defined.
+	if(typeof this["dojo"] == "undefined"){
+		this.dojo = {};
+	}
+
+	// summary:
+	//		return the current global context object
+	//		(e.g., the window object in a browser).
+	// description:
+	//		Refer to 'dojo.global' rather than referring to window to ensure your
+	//		code runs correctly in contexts other than web browsers (eg: Rhino on a server).
+	dojo.global = this;
+
+	var _config = {
+		isDebug: false,
+		allowQueryConfig: false,
+		baseScriptUri: "",
+		baseRelativePath: "",
+		libraryScriptUri: "",
+		preventBackButtonFix: true,
+		delayMozLoadingFix: false
+	};
+
+	for(var option in _config){
+		if(typeof djConfig[option] == "undefined"){
+			djConfig[option] = _config[option];
+		}
+	}
+
+	var _platforms = ["Browser", "Rhino", "Spidermonkey", "Mobile"];
+	var t;
+	while(t=_platforms.shift()){
+		dojo["is"+t] = false;
+	}
+})();
+
+
+// Override locale setting, if specified
+dojo.locale = djConfig.locale;
+
+//TODOC:  HOW TO DOC THIS?
+dojo.version = {
+	// summary: version number of this instance of dojo.
+	major: 0, minor: 0, patch: 0, flag: "dev",
+	revision: Number("$Rev: 8123 $".match(/[0-9]+/)[0]),
+	toString: function(){
+		with(dojo.version){
+			return major + "." + minor + "." + patch + flag + " (" + revision + ")";	// String
+		}
+	}
+}
+
+dojo._getProp = function(/*Array*/parts, /*Boolean*/create, /*Object*/context){
+	var obj=context||dojo.global;
+	for(var i=0, p; obj&&(p=parts[i]); i++){
+		obj = (p in obj ? obj[p] : (create ? obj[p]={} : undefined));
+	}
+	return obj; // Any
+}
+
+dojo.setObject = function(/*String*/name, /*Any*/value, /*Object*/context){
+	// summary: 
+	//		Set a property from a dot-separated string, such as "A.B.C"
+	//	description: 
+	//		Useful for longer api chains where you have to test each object in
+	//		the chain, or when you have an object reference in string format.
+	//		Objects are created as needed along 'path'.
+	//	name: 	
+	//		Path to a property, in the form "A.B.C".
+	//	context:
+	//		Optional. Object to use as root of path. Defaults to
+	//		'dojo.global'. Null may be passed.
+	var parts=name.split("."), p=parts.pop(), obj=dojo._getProp(parts, true, context);
+	return (obj && p ? (obj[p]=value) : undefined); // Any
+}
+
+dojo.getObject = function(/*String*/name, /*Boolean*/create, /*Object*/context){
+	// summary: 
+	//		Get a property from a dot-separated string, such as "A.B.C"
+	//	description: 
+	//		Useful for longer api chains where you have to test each object in
+	//		the chain, or when you have an object reference in string format.
+	//	name: 	
+	//		Path to an property, in the form "A.B.C".
+	//	context:
+	//		Optional. Object to use as root of path. Defaults to
+	//		'dojo.global'. Null may be passed.
+	//	create: 
+	//		Optional. If true, Objects will be created at any point along the
+	//		'path' that is undefined.
+	return dojo._getProp(name.split("."), create, context); // Any
+}
+
+dojo.exists = function(/*String*/name, /*Object*/obj){
+	// summary: 
+	//		determine if an object supports a given method
+	// description: 
+	//		useful for longer api chains where you have to test each object in
+	//		the chain
+	// name: 	
+	//		Path to an object, in the form "A.B.C".
+	// obj:
+	//		Optional. Object to use as root of path. Defaults to
+	//		'dojo.global'. Null may be passed.
+	return Boolean(dojo.getObject(name, false, obj)); // Boolean
+}
+
+dojo["eval"] = function(/*String*/ scriptFragment){
+	// summary: 
+	//		Perform an evaluation in the global scope.  Use this rather than
+	//		calling 'eval()' directly.
+	// description: 
+	//		Placed in a separate function to minimize size of trapped
+	//		evaluation context.
+	// note:
+	//	 - JSC eval() takes an optional second argument which can be 'unsafe'.
+	//	 - Mozilla/SpiderMonkey eval() takes an optional second argument which is the
+	//  	 scope object for new symbols.
+
+	// FIXME: investigate Joseph Smarr's technique for IE:
+	//		http://josephsmarr.com/2007/01/31/fixing-eval-to-use-global-scope-in-ie/
+	//	see also:
+	// 		http://trac.dojotoolkit.org/ticket/744
+	return dojo.global.eval ? dojo.global.eval(scriptFragment) : eval(scriptFragment); 	// mixed
+}
+
+dojo.deprecated = function(/*String*/ behaviour, /*String?*/ extra, /*String?*/ removal){
+	// summary: 
+	//		Log a debug message to indicate that a behavior has been
+	//		deprecated.
+	// extra: Text to append to the message.
+	// removal: 
+	//		Text to indicate when in the future the behavior will be removed.
+	var message = "DEPRECATED: " + behaviour;
+	if(extra){ message += " " + extra; }
+	if(removal){ message += " -- will be removed in version: " + removal; }
+	console.debug(message);
+}
+
+dojo.experimental = function(/* String */ moduleName, /* String? */ extra){
+	// summary: Marks code as experimental.
+	// description: 
+	//		This can be used to mark a function, file, or module as
+	//		experimental.  Experimental code is not ready to be used, and the
+	//		APIs are subject to change without notice.  Experimental code may be
+	//		completed deleted without going through the normal deprecation
+	//		process.
+	// moduleName: 
+	//		The name of a module, or the name of a module file or a specific
+	//		function
+	// extra: 
+	//		some additional message for the user
+	// examples:
+	//		dojo.experimental("dojo.data.Result");
+	//		dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA");
+	var message = "EXPERIMENTAL: " + moduleName;
+	message += " -- Not yet ready for use.  APIs subject to change without notice.";
+	if(extra){ message += " " + extra; }
+	console.debug(message);
+}
+
+dojo._getText = function(/*String*/ uri){
+	//	summary:	
+	//		Read the plain/text contents at the specified 'uri'.
+	//	description:
+	//		If 'getText()' is not implemented, then it is necessary to
+	//		override 'loadUri()' with an implementation that doesn't
+	//		rely on it.
+
+	// NOTE: platform specializations need to implement this
+}
+
+// vim:ai:ts=4:noet:textwidth=80
+
+/*
+ * loader.js - A bootstrap module.  Runs before the hostenv_*.js file. Contains
+ * all of the package loading methods.
+ */
+
+//A semi-colon is at the start of the line because after doing a build, this
+//function definition get compressed onto the same line as the last line in
+//bootstrap1.js. That list line is just a curly bracket, and the browser
+//complains about that syntax. The semicolon fixes it. Putting it here instead
+//of at the end of bootstrap1.js, since it is more of an issue for this file,
+//(using the closure), and bootstrap1.js could change in the future.
+;(function(){
+	//Additional properties for dojo
+	var _add = {
+		_pkgFileName: "__package__",
+	
+		// for recursion protection
+		_loadedModules: {},
+		_inFlightCount: 0,
+	
+		// FIXME: it should be possible to pull module prefixes in from djConfig
+		_modulePrefixes: {
+			dojo: {name: "dojo", value: "."},
+			doh: {name: "doh", value: "../util/doh"},
+			tests: {name: "tests", value: "tests"}
+		},
+
+		_moduleHasPrefix: function(/*String*/module){
+			// summary: checks to see if module has been established
+			var mp = this._modulePrefixes;
+			return Boolean(mp[module] && mp[module].value); // Boolean
+		},
+
+		_getModulePrefix: function(/*String*/module){
+			// summary: gets the prefix associated with module
+			var mp = this._modulePrefixes;
+			if(this._moduleHasPrefix(module)){
+				return mp[module].value; // String
+			}
+			return module; // String
+		},
+
+		_loadedUrls: [],
+	
+		//WARNING: 
+		//		This variable is referenced by packages outside of bootstrap:
+		//		FloatingPane.js and undo/browser.js
+		_postLoad: false,
+		
+		//Egad! Lots of test files push on this directly instead of using dojo.addOnLoad.
+		_loaders: [],
+		_unloaders: [],
+		_loadNotifying: false
+	};
+	
+	//Add all of these properties to dojo
+	for(var param in _add){
+		dojo[param] = _add[param];
+	}
+})();
+
+dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){
+	// 	summary:
+	//		Load a Javascript module given a relative path
+	//
+	//	description:
+	//		Loads and interprets the script located at relpath, which is
+	//		relative to the script root directory.  If the script is found but
+	//		its interpretation causes a runtime exception, that exception is
+	//		not caught by us, so the caller will see it.  We return a true
+	//		value if and only if the script is found.
+	//
+	// relpath: 
+	//		A relative path to a script (no leading '/', and typically ending
+	//		in '.js').
+	// module: 
+	//		A module whose existance to check for after loading a path.  Can be
+	//		used to determine success or failure of the load.
+	// cb: 
+	//		a callback function to pass the result of evaluating the script
+
+	var uri = (((relpath.charAt(0) == '/' || relpath.match(/^\w+:/))) ? "" : this.baseUrl) + relpath;
+	if(djConfig.cacheBust && dojo.isBrowser){
+		uri += "?" + String(djConfig.cacheBust).replace(/\W+/g,"");
+	}
+	try{
+		return !module ? this._loadUri(uri, cb) : this._loadUriAndCheck(uri, module, cb); // Boolean
+	}catch(e){
+		console.debug(e);
+		return false; // Boolean
+	}
+}
+
+dojo._loadUri = function(/*String (URL)*/uri, /*Function?*/cb){
+	//	summary:
+	//		Loads JavaScript from a URI
+	//	description:
+	//		Reads the contents of the URI, and evaluates the contents.  This is
+	//		used to load modules as well as resource bundles. Returns true if
+	//		it succeeded. Returns false if the URI reading failed.  Throws if
+	//		the evaluation throws.
+	//	uri: a uri which points at the script to be loaded
+	//	cb: 
+	//		a callback function to process the result of evaluating the script
+	//		as an expression, typically used by the resource bundle loader to
+	//		load JSON-style resources
+
+	if(this._loadedUrls[uri]){
+		return true; // Boolean
+	}
+	var contents = this._getText(uri, true);
+	if(!contents){ return false; } // Boolean
+	this._loadedUrls[uri] = true;
+	if(cb){ contents = '('+contents+')'; }
+	// var value = dojo["eval"](contents);
+	var value = dojo["eval"]("//@ sourceURL="+uri+"\r\n"+contents);
+	if(cb){ cb(value); }
+	return true; // Boolean
+}
+
+// FIXME: probably need to add logging to this method
+dojo._loadUriAndCheck = function(/*String (URL)*/uri, /*String*/moduleName, /*Function?*/cb){
+	// summary: calls loadUri then findModule and returns true if both succeed
+	var ok = false;
+	try{
+		ok = this._loadUri(uri, cb);
+	}catch(e){
+		console.debug("failed loading ", uri, " with error: ", e);
+	}
+	return Boolean(ok && this._loadedModules[moduleName]); // Boolean
+}
+
+dojo.loaded = function(){
+	this._loadNotifying = true;
+	this._postLoad = true;
+	var mll = this._loaders;
+	for(var x=0; x<mll.length; x++){
+		mll[x]();
+	}
+
+	//Clear listeners so new ones can be added
+	//For other xdomain package loads after the initial load.
+	this._loaders = [];
+	this._loadNotifying = false;
+}
+
+dojo.unloaded = function(){
+	var mll = this._unloaders;
+	while(mll.length){
+		(mll.pop())();
+	}
+}
+
+dojo.addOnLoad = function(/*Object?*/obj, /*String|Function*/functionName){
+	// summary:
+	//		Registers a function to be triggered after the DOM has finished
+	//		loading and widgets declared in markup have been instantiated.
+	//		Images and CSS files may or may not have finished downloading when
+	//		the specified function is called.  (Note that widgets' CSS and HTML
+	//		code is guaranteed to be downloaded before said widgets are
+	//		instantiated.)
+	//
+	// usage:
+	//		dojo.addOnLoad(functionPointer);
+	//		dojo.addOnLoad(object, "functionName");
+	var d = dojo;
+	if(arguments.length == 1){
+		d._loaders.push(obj);
+	}else if(arguments.length > 1){
+		d._loaders.push(function(){
+			obj[functionName]();
+		});
+	}
+
+	//Added for xdomain loading. dojo.addOnLoad is used to
+	//indicate callbacks after doing some dojo.require() statements.
+	//In the xdomain case, if all the requires are loaded (after initial
+	//page load), then immediately call any listeners.
+	if(d._postLoad && d._inFlightCount == 0 && !d._loadNotifying){
+		d._callLoaded();
+	}
+}
+
+dojo.addOnUnload = function(/*Object?*/obj, /*String|Function?*/functionName){
+	// summary: registers a function to be triggered when the page unloads
+	// usage:
+	//		dojo.addOnUnload(functionPointer)
+	//		dojo.addOnUnload(object, "functionName")
+	var d = dojo;
+	if(arguments.length == 1){
+		d._unloaders.push(obj);
+	}else if(arguments.length > 1){
+		d._unloaders.push(function(){
+			obj[functionName]();
+		});
+	}
+}
+
+dojo._modulesLoaded = function(){
+	if(this._postLoad){ return; }
+	if(this._inFlightCount > 0){ 
+		console.debug("files still in flight!");
+		return;
+	}
+	dojo._callLoaded();
+}
+
+dojo._callLoaded = function(){
+	//The "object" check is for IE, and the other opera check fixes an issue
+	//in Opera where it could not find the body element in some widget test cases.
+	//For 0.9, maybe route all browsers through the setTimeout (need protection
+	//still for non-browser environments though). This might also help the issue with
+	//FF 2.0 and freezing issues where we try to do sync xhr while background css images
+	//are being loaded (trac #2572)? Consider for 0.9.
+	if(typeof setTimeout == "object" || (djConfig["useXDomain"] && dojo.isOpera)){
+		setTimeout("dojo.loaded();", 0);
+	}else{
+		dojo.loaded();
+	}
+}
+
+dojo._getModuleSymbols = function(/*String*/modulename){
+	// summary:
+	//		Converts a module name in dotted JS notation to an array
+	//		representing the path in the source tree
+	var syms = modulename.split(".");
+	for(var i = syms.length; i>0; i--){
+		var parentModule = syms.slice(0, i).join(".");
+		if((i==1) && !this._moduleHasPrefix(parentModule)){		
+			// Support default module directory (sibling of dojo) for top-level modules 
+			syms[0] = "../" + syms[0];
+		}else{
+			var parentModulePath = this._getModulePrefix(parentModule);
+			if(parentModulePath != parentModule){
+				syms.splice(0, i, parentModulePath);
+				break;
+			}
+		}
+	}
+	// console.debug(syms);
+	return syms; // Array
+}
+
+dojo._global_omit_module_check = false;
+
+dojo._loadModule = function(	/*String*/moduleName, 
+								/*Boolean?*/exactOnly, 
+								/*Boolean?*/omitModuleCheck){
+	//	summary:
+	//		loads a Javascript module from the appropriate URI
+	//	description:
+	//		_loadModule("A.B") first checks to see if symbol A.B is defined. If
+	//		it is, it is simply returned (nothing to do).
+	//	
+	//		If it is not defined, it will look for "A/B.js" in the script root
+	//		directory, followed by "A.js".
+	//	
+	//		It throws if it cannot find a file to load, or if the symbol A.B is
+	//		not defined after loading.
+	//	
+	//		It returns the object A.B.
+	//	
+	//		This does nothing about importing symbols into the current package.
+	//		It is presumed that the caller will take care of that. For example,
+	//		to import all symbols:
+	//	
+	//			with (dojo._loadModule("A.B")) {
+	//				...
+	//			}
+	//	
+	//		And to import just the leaf symbol:
+	//	
+	//			var B = dojo._loadModule("A.B");
+	//	   		...
+	//	
+	//		dj_load is an alias for dojo._loadModule
+
+	omitModuleCheck = this._global_omit_module_check || omitModuleCheck;
+	var module = this._loadedModules[moduleName];
+	if(module){
+		return module;
+	}
+
+	// convert periods to slashes
+	var nsyms = moduleName.split(".");
+	var syms = this._getModuleSymbols(moduleName);
+	var startedRelative = ((syms[0].charAt(0) != '/') && !syms[0].match(/^\w+:/));
+	var last = syms[syms.length - 1];
+	var relpath;
+	// figure out if we're looking for a full package, if so, we want to do
+	// things slightly diffrently
+	if(last=="*"){
+		moduleName = nsyms.slice(0, -1).join('.');
+		syms.pop();
+		relpath = syms.join("/") + "/" + this._pkgFileName + '.js';
+		if(startedRelative && relpath.charAt(0)=="/"){
+			relpath = relpath.slice(1);
+		}
+	}else{
+		relpath = syms.join("/") + '.js';
+		moduleName = nsyms.join('.');
+	}
+	var modArg = (!omitModuleCheck) ? moduleName : null;
+	var ok = this._loadPath(relpath, modArg);
+
+	if((!ok)&&(!omitModuleCheck)){
+		throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'");
+	}
+
+	// check that the symbol was defined
+	// Don't bother if we're doing xdomain (asynchronous) loading.
+	if((!omitModuleCheck)&&(!this["isXDomain"])){
+		// pass in false so we can give better error
+		module = this._loadedModules[moduleName];
+		if(!module){
+			throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'"); 
+		}
+	}
+
+	return module;
+}
+
+dojo.require = dojo._loadModule;
+
+dojo.provide = function(/*String*/ packageName){
+	//	summary:
+	//		Each javascript source file must have (exactly) one dojo.provide()
+	//		call at the top of the file, corresponding to the file name.  For
+	//		example, dojo/src/foo.js must have dojo.provide("dojo.foo"); at the
+	//		top of the file.
+	//	description:
+	//		Each javascript source file is called a resource.  When a resource
+	//		is loaded by the browser, dojo.provide() registers that it has been
+	//		loaded.
+	//	
+	//		For backwards compatibility reasons, in addition to registering the
+	//		resource, dojo.provide() also ensures that the javascript object
+	//		for the module exists.  For example,
+	//		dojo.provide("dojo.io.cometd"), in addition to registering that
+	//		cometd.js is a resource for the dojo.iomodule, will ensure that
+	//		the dojo.io javascript object exists, so that calls like
+	//		dojo.io.foo = function(){ ... } don't fail.
+	//
+	//		In the case of a build (or in the future, a rollup), where multiple
+	//		javascript source files are combined into one bigger file (similar
+	//		to a .lib or .jar file), that file will contain multiple
+	//		dojo.provide() calls, to note that it includes multiple resources.
+
+	//Make sure we have a string.
+	var fullPkgName = String(packageName);
+	var strippedPkgName = fullPkgName;
+
+	var syms = packageName.split(/\./);
+	if(syms[syms.length-1]=="*"){
+		syms.pop();
+		strippedPkgName = syms.join(".");
+	}
+	var evaledPkg = dojo.getObject(strippedPkgName, true);
+	this._loadedModules[fullPkgName] = evaledPkg;
+	this._loadedModules[strippedPkgName] = evaledPkg;
+	
+	return evaledPkg; // Object
+}
+
+//Start of old bootstrap2:
+
+dojo.platformRequire = function(/*Object containing Arrays*/modMap){
+	//	description:
+	//		This method taks a "map" of arrays which one can use to optionally
+	//		load dojo modules. The map is indexed by the possible
+	//		dojo.name_ values, with two additional values: "default"
+	//		and "common". The items in the "default" array will be loaded if
+	//		none of the other items have been choosen based on the
+	//		hostenv.name_ item. The items in the "common" array will _always_
+	//		be loaded, regardless of which list is chosen.  Here's how it's
+	//		normally called:
+	//	
+	//			dojo.platformRequire({
+	//				// an example that passes multiple args to _loadModule()
+	//				browser: [
+	//					["foo.bar.baz", true, true], 
+	//					"foo.sample.*",
+	//					"foo.test,
+	//				],
+	//				default: [ "foo.sample.*" ],
+	//				common: [ "really.important.module.*" ]
+	//			});
+
+	// FIXME: dojo.name_ no longer works!!
+
+	var common = modMap["common"]||[];
+	var result = common.concat(modMap[dojo._name]||modMap["default"]||[]);
+
+	for(var x=0; x<result.length; x++){
+		var curr = result[x];
+		if(curr.constructor == Array){
+			dojo._loadModule.apply(dojo, curr);
+		}else{
+			dojo._loadModule(curr);
+		}
+	}
+}
+
+
+dojo.requireIf = function(/*Boolean*/ condition, /*String*/ resourceName){
+	// summary:
+	//		If the condition is true then call dojo.require() for the specified
+	//		resource
+	if(condition === true){
+		// FIXME: why do we support chained require()'s here? does the build system?
+		var args = [];
+		for(var i = 1; i < arguments.length; i++){ 
+			args.push(arguments[i]);
+		}
+		dojo.require.apply(dojo, args);
+	}
+}
+
+dojo.requireAfterIf = dojo.requireIf;
+
+dojo.registerModulePath = function(/*String*/module, /*String*/prefix){
+	//	summary: 
+	//		maps a module name to a path
+	//	description: 
+	//		An unregistered module is given the default path of ../<module>,
+	//		relative to Dojo root. For example, module acme is mapped to
+	//		../acme.  If you want to use a different module name, use
+	//		dojo.registerModulePath. 
+	this._modulePrefixes[module] = { name: module, value: prefix };
+}
+
+if(djConfig["modulePaths"]){
+	for(var param in djConfig["modulePaths"]){
+		dojo.registerModulePath(param, djConfig["modulePaths"][param]);
+	}
+}
+
+dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){
+	// summary:
+	//		Declares translated resources and loads them if necessary, in the
+	//		same style as dojo.require.  Contents of the resource bundle are
+	//		typically strings, but may be any name/value pair, represented in
+	//		JSON format.  See also dojo.i18n.getLocalization.
+	// moduleName: 
+	//		name of the package containing the "nls" directory in which the
+	//		bundle is found
+	// bundleName: 
+	//		bundle name, i.e. the filename without the '.js' suffix
+	// locale: 
+	//		the locale to load (optional)  By default, the browser's user
+	//		locale as defined by dojo.locale
+	// availableFlatLocales: 
+	//		A comma-separated list of the available, flattened locales for this
+	//		bundle. This argument should only be set by the build process.
+	// description:
+	//		Load translated resource bundles provided underneath the "nls"
+	//		directory within a package.  Translated resources may be located in
+	//		different packages throughout the source tree.  For example, a
+	//		particular widget may define one or more resource bundles,
+	//		structured in a program as follows, where moduleName is
+	//		mycode.mywidget and bundleNames available include bundleone and
+	//		bundletwo:
+	//
+	//			...
+	//			mycode/
+	//			 mywidget/
+	//			  nls/
+	//			   bundleone.js (the fallback translation, English in this example)
+	//			   bundletwo.js (also a fallback translation)
+	//			   de/
+	//			    bundleone.js
+	//			    bundletwo.js
+	//			   de-at/
+	//			    bundleone.js
+	//			   en/
+	//			    (empty; use the fallback translation)
+	//			   en-us/
+	//			    bundleone.js
+	//			   en-gb/
+	//			    bundleone.js
+	//			   es/
+	//			    bundleone.js
+	//			    bundletwo.js
+	//			  ...etc
+	//			...
+	//
+	//		Each directory is named for a locale as specified by RFC 3066,
+	//		(http://www.ietf.org/rfc/rfc3066.txt), normalized in lowercase.
+	//		Note that the two bundles in the example do not define all the same
+	//		variants.  For a given locale, bundles will be loaded for that
+	//		locale and all more general locales above it, including a fallback
+	//		at the root directory.  For example, a declaration for the "de-at"
+	//		locale will first load nls/de-at/bundleone.js, then
+	//		nls/de/bundleone.js and finally nls/bundleone.js.  The data will be
+	//		flattened into a single Object so that lookups will follow this
+	//		cascading pattern.  An optional build step can preload the bundles
+	//		to avoid data redundancy and the multiple network hits normally
+	//		required to load these resources.
+
+	dojo.require("dojo.i18n");
+	dojo.i18n._requireLocalization.apply(dojo.hostenv, arguments);
+};
+
+(function(){
+
+	var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$");
+	var ire = new RegExp("^((([^:]+:)?([^@]+))@)?([^:]*)(:([0-9]+))?$");
+
+	dojo._Url = function(/*dojo._Url||String...*/){
+		// summary: 
+		//		Constructor to create an object representing a URL.
+		//		It is marked as private, since we might consider removing
+		//		or simplifying it.
+		// description: 
+		//		Each argument is evaluated in order relative to the next until
+		//		a canonical uri is produced. To get an absolute Uri relative to
+		//		the current document use:
+		//      	new dojo._Url(document.baseURI, url)
+
+		// TODO: support for IPv6, see RFC 2732
+
+		// resolve uri components relative to each other
+		var n = null;
+		var _a = arguments;
+		var uri = _a[0];
+		for(var i = 1; i<_a.length; i++){
+			if(!_a[i]){ continue; }
+
+			// Safari doesn't support this.constructor so we have to be explicit
+			var relobj = new dojo._Url(_a[i]+"");
+			var uriobj = new dojo._Url(uri+"");
+
+			if(
+				(relobj.path=="")	&&
+				(!relobj.scheme)	&&
+				(!relobj.authority)	&&
+				(!relobj.query)
+			){
+				if(relobj.fragment != null){
+					uriobj.fragment = relobj.fragment;
+				}
+				relobj = uriobj;
+			}else if(relobj.scheme == null){
+				relobj.scheme = uriobj.scheme;
+
+				if(relobj.authority == null){
+					relobj.authority = uriobj.authority;
+
+					if(relobj.path.charAt(0) != "/"){
+						var path = uriobj.path.substring(0,
+							uriobj.path.lastIndexOf("/") + 1) + relobj.path;
+
+						var segs = path.split("/");
+						for(var j = 0; j < segs.length; j++){
+							if(segs[j] == "."){
+								if (j == segs.length - 1) { segs[j] = ""; }
+								else { segs.splice(j, 1); j--; }
+							}else if(j > 0 && !(j == 1 && segs[0] == "") &&
+								segs[j] == ".." && segs[j-1] != ".."){
+
+								if(j == (segs.length - 1)){
+									segs.splice(j, 1); segs[j - 1] = "";
+								}else{
+									segs.splice(j - 1, 2); j -= 2;
+								}
+							}
+						}
+						relobj.path = segs.join("/");
+					}
+				}
+			}
+
+			uri = "";
+			if(relobj.scheme != null){ 
+				uri += relobj.scheme + ":";
+			}
+			if(relobj.authority != null){
+				uri += "//" + relobj.authority;
+			}
+			uri += relobj.path;
+			if(relobj.query != null){
+				uri += "?" + relobj.query;
+			}
+			if(relobj.fragment != null){
+				uri += "#" + relobj.fragment;
+			}
+		}
+
+		this.uri = uri.toString();
+
+		// break the uri into its main components
+		var r = this.uri.match(ore);
+
+		this.scheme = r[2] || (r[1] ? "" : null);
+		this.authority = r[4] || (r[3] ? "" : null);
+		this.path = r[5]; // can never be undefined
+		this.query = r[7] || (r[6] ? "" : null);
+		this.fragment  = r[9] || (r[8] ? "" : null);
+
+		if(this.authority != null){
+			// server based naming authority
+			r = this.authority.match(ire);
+
+			this.user = r[3] || null;
+			this.password = r[4] || null;
+			this.host = r[5];
+			this.port = r[7] || null;
+		}
+	}
+
+	dojo._Url.prototype.toString = function(){ return this.uri; };
+})();
+
+dojo.moduleUrl = function(/*String*/module, /*dojo._Url||String*/url){
+	// summary: 
+	//		returns a Url object relative to a module
+	// description: 
+	//		Examples: 
+	//			dojo.moduleUrl("dojo.widget","templates/template.html");
+	//			dojo.moduleUrl("acme","images/small.png")
+
+	var loc = dojo._getModuleSymbols(module).join('/');
+	if(!loc){ return null; }
+	if(loc.lastIndexOf("/") != loc.length-1){
+		loc += "/";
+	}
+	
+	//If the path is an absolute path (starts with a / or is on another
+	//domain/xdomain) then don't add the baseUrl.
+	var colonIndex = loc.indexOf(":");
+	if(loc.charAt(0) != "/" && (colonIndex == -1 || colonIndex > loc.indexOf("/"))){
+		loc = dojo.baseUrl + loc;
+	}
+
+	return new dojo._Url(loc, url);
+}
+
+};
+
+if(typeof window != 'undefined'){
+	dojo.isBrowser = true;
+	dojo._name = "browser";
+
+
+	// attempt to figure out the path to dojo if it isn't set in the config
+	(function(){
+		var d = dojo;
+		// this is a scope protection closure. We set browser versions and grab
+		// the URL we were loaded from here.
+
+		// grab the node we were loaded from
+		if(document && document.getElementsByTagName){
+			var scripts = document.getElementsByTagName("script");
+			var rePkg = /dojo\.js([\?\.]|$)/i;
+			for(var i = 0; i < scripts.length; i++){
+				var src = scripts[i].getAttribute("src");
+				if(!src){ continue; }
+				var m = src.match(rePkg);
+				if(m){
+					// find out where we came from
+					if(!djConfig["baseUrl"]){
+						djConfig["baseUrl"] = src.substring(0, m.index);
+					}
+					// and find out if we need to modify our behavior
+					var cfg = scripts[i].getAttribute("djConfig");
+					if(cfg){
+						var cfgo = eval("({ "+cfg+" })");
+						for(var x in cfgo){
+							djConfig[x] = cfgo[x];
+						}
+					}
+					break; // "first Dojo wins"
+				}
+			}
+		}
+		d.baseUrl = djConfig["baseUrl"];
+
+		// fill in the rendering support information in dojo.render.*
+		var n = navigator;
+		var dua = n.userAgent;
+		var dav = n.appVersion;
+		var tv = parseFloat(dav);
+
+		d.isOpera = (dua.indexOf("Opera") >= 0) ? tv : 0;
+		d.isKhtml = (dav.indexOf("Konqueror") >= 0)||(dav.indexOf("Safari") >= 0) ? tv : 0;
+		d.isSafari = (dav.indexOf("Safari") >= 0) ? tv : 0;
+		var geckoPos = dua.indexOf("Gecko");
+		d.isMozilla = d.isMoz = ((geckoPos >= 0)&&(!d.isKhtml)) ? tv : 0;
+		d.isFF = 0;
+		d.isIE = 0;
+		try{
+			if(d.isMoz){
+				d.isFF = parseFloat(dua.split("Firefox/")[1].split(" ")[0]);
+			}
+			if((document.all)&&(!d.isOpera)){
+				d.isIE = parseFloat(dav.split("MSIE ")[1].split(";")[0]);
+			}
+		}catch(e){}
+
+		var cm = document["compatMode"];
+		d.isQuirks = (cm == "BackCompat")||(cm == "QuirksMode")||(d.isIE < 6);
+
+		// TODO: is the HTML LANG attribute relevant?
+		d.locale = djConfig.locale || (d.isIE ? n.userLanguage : n.language).toLowerCase();
+
+		d._println = console.debug;
+
+		// These are in order of decreasing likelihood; this will change in time.
+		d._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
+
+		d._xhrObj= function(){
+			// summary: 
+			//		does the work of portably generating a new XMLHTTPRequest
+			//		object.
+			var http = null;
+			var last_e = null;
+			try{ http = new XMLHttpRequest(); }catch(e){}
+			if(!http){
+				for(var i=0; i<3; ++i){
+					var progid = dojo._XMLHTTP_PROGIDS[i];
+					try{
+						http = new ActiveXObject(progid);
+					}catch(e){
+						last_e = e;
+					}
+
+					if(http){
+						dojo._XMLHTTP_PROGIDS = [progid];  // so faster next time
+						break;
+					}
+				}
+			}
+
+			if(!http){
+				throw new Error("XMLHTTP not available: "+last_e);
+			}
+
+			return http; // XMLHTTPRequest instance
+		}
+
+		d._isDocumentOk = function(http){
+			var stat = http.status || 0;
+			return ( (stat>=200)&&(stat<300))|| 	// allow any 2XX response code
+				(stat==304)|| 						// get it out of the cache
+				(stat==1223)|| 						// Internet Explorer mangled the status code
+				(!stat && (location.protocol=="file:" || location.protocol=="chrome:") ); // Boolean
+		}
+
+		d._getText = function(uri, fail_ok){
+			// summary: Read the contents of the specified uri and return those contents.
+			// uri:
+			//		A relative or absolute uri. If absolute, it still must be in
+			//		the same "domain" as we are.
+			// fail_ok:
+			//		Default false. If fail_ok and loading fails, return null
+			//		instead of throwing.
+
+			// alert("_getText: " + uri);
+
+			// NOTE: must be declared before scope switches ie. this._xhrObj()
+			var http = this._xhrObj();
+
+			if(dojo._Url){
+				uri = (new dojo._Url(window.location, uri)).toString();
+			}
+			/*
+			console.debug("_getText:", uri);
+			console.debug(window.location+"");
+			alert(uri);
+			*/
+
+			http.open('GET', uri, false);
+			try{
+				http.send(null);
+				if(!d._isDocumentOk(http)){
+					var err = Error("Unable to load "+uri+" status:"+ http.status);
+					err.status = http.status;
+					err.responseText = http.responseText;
+					throw err;
+				}
+			}catch(e){
+				// console.debug(e);
+				if(fail_ok){ return null; }
+				throw e;
+			}
+			return http.responseText; // String
+		}
+	})();
+
+	dojo._handleNodeEvent = function(/*DomNode*/node, /*String*/evtName, /*Function*/fp){
+		// summary:
+		//		non-destructively adds the specified function to the node's
+		//		evtName handler.
+		// node: the DomNode to add the handler to
+		// evtName: should be in the form "click" for "onclick" handlers
+		var oldHandler = node["on"+evtName] || function(){};
+		node["on"+evtName] = function(){
+			fp.apply(node, arguments);
+			oldHandler.apply(node, arguments);
+		}
+		return true;
+	}
+
+	dojo._initFired = false;
+	//	BEGIN DOMContentLoaded, from Dean Edwards (http://dean.edwards.name/weblog/2006/06/again/)
+	dojo._loadInit = function(e){
+		dojo._initFired = true;
+		// allow multiple calls, only first one will take effect
+		// A bug in khtml calls events callbacks for document for event which isnt supported
+		// for example a created contextmenu event calls DOMContentLoaded, workaround
+		var type = (e && e.type) ? e.type.toLowerCase() : "load";
+		if(arguments.callee.initialized || (type!="domcontentloaded" && type!="load")){ return; }
+		arguments.callee.initialized = true;
+		if(typeof dojo["_khtmlTimer"] != 'undefined'){
+			clearInterval(dojo._khtmlTimer);
+			delete dojo._khtmlTimer;
+		}
+
+		if(dojo._inFlightCount == 0){
+			dojo._modulesLoaded();
+		}
+	}
+
+	//	START DOMContentLoaded
+	// Mozilla and Opera 9 expose the event we could use
+	if(document.addEventListener){
+		// NOTE: 
+		//		due to a threading issue in Firefox 2.0, we can't enable
+		//		DOMContentLoaded on that platform. For more information, see:
+		//		http://trac.dojotoolkit.org/ticket/1704
+		if(dojo.isOpera|| (dojo.isMoz && (djConfig["enableMozDomContentLoaded"] === true))){
+			document.addEventListener("DOMContentLoaded", dojo._loadInit, null);
+		}
+
+		//	mainly for Opera 8.5, won't be fired if DOMContentLoaded fired already.
+		//  also used for Mozilla because of trac #1640
+		window.addEventListener("load", dojo._loadInit, null);
+	}
+
+	// 	for Internet Explorer. readyState will not be achieved on init call,
+	// 	but dojo doesn't need it however, we'll include it because we don't
+	// 	know if there are other functions added that might.  Note that this has
+	// 	changed because the build process strips all comments -- including
+	// 	conditional ones.
+	if(dojo.isIE){
+		document.write('<scr'+'ipt defer src="//:" '
+			+ 'onreadystatechange="if(this.readyState==\'complete\'){dojo._loadInit();}">'
+			+ '</scr'+'ipt>'
+		);
+	}
+
+	if(/(WebKit|khtml)/i.test(navigator.userAgent)){ // sniff
+		dojo._khtmlTimer = setInterval(function(){
+			if(/loaded|complete/.test(document.readyState)){
+				dojo._loadInit(); // call the onload handler
+			}
+		}, 10);
+	}
+	//	END DOMContentLoaded
+
+	// IE WebControl hosted in an application can fire "beforeunload" and "unload"
+	// events when control visibility changes, causing Dojo to unload too soon. The
+	// following code fixes the problem
+	// Reference: http://support.microsoft.com/default.aspx?scid=kb;en-us;199155
+	if(dojo.isIE){
+		dojo._handleNodeEvent(window, "beforeunload", function(){
+			dojo._unloading = true;
+			window.setTimeout(function() {
+				dojo._unloading = false;
+			}, 0);
+		});
+	}
+
+	dojo._handleNodeEvent(window, "unload", function(){
+		if((!dojo.isIE)||(dojo.isIE && dojo._unloading)){
+			dojo.unloaded();
+		}
+	});
+
+	/*
+	OpenAjax.subscribe("OpenAjax", "onload", function(){
+		if(dojo._inFlightCount == 0){
+			dojo._modulesLoaded();
+		}
+	});
+
+	OpenAjax.subscribe("OpenAjax", "onunload", function(){
+		dojo.unloaded();
+	});
+	*/
+
+	try{
+		if(dojo.isIE){
+			document.namespaces.add("v","urn:schemas-microsoft-com:vml");
+			document.createStyleSheet().addRule("v\\:*", "behavior:url(#default#VML)");
+		}
+	}catch(e){ }
+
+	// stub, over-ridden by debugging code. This will at least keep us from
+	// breaking when it's not included
+	dojo._writeIncludes = function(){}
+
+	// @global: dojo.doc
+	// summary:
+	//		Current document object. 'dojo.doc' can be modified
+	//		for temporary context shifting. Also see dojo.withDoc().
+	// description:
+	//    Refer to dojo.doc rather
+	//    than referring to 'window.document' to ensure your code runs
+	//    correctly in managed contexts.
+	dojo.doc = window["document"] || null;
+
+	dojo.body = function(){
+		// summary:
+		//		return the body object associated with dojo.doc
+
+		// Note: document.body is not defined for a strict xhtml document
+		// Would like to memoize this, but dojo.doc can change vi dojo.withDoc().
+		return dojo.doc.body || dojo.doc.getElementsByTagName("body")[0];
+	}
+
+	dojo.setContext = function(/*Object*/globalObject, /*DocumentElement*/globalDocument){
+		// summary:
+		//		changes the behavior of many core Dojo functions that deal with
+		//		namespace and DOM lookup, changing them to work in a new global
+		//		context. The varibles dojo.global and dojo.doc
+		//		are modified as a result of calling this function.
+		dojo.global = globalObject;
+		dojo.doc = globalDocument;
+	};
+
+	dojo._fireCallback = function(callback, context, cbArguments){
+		if((context)&&((typeof callback == "string")||(callback instanceof String))){
+			callback = context[callback];
+		}
+		return (context ? callback.apply(context, cbArguments || [ ]) : callback());
+	}
+
+	dojo.withGlobal = function(	/*Object*/globalObject, 
+								/*Function*/callback, 
+								/*Object?*/thisObject, 
+								/*Array?*/cbArguments){
+		// summary:
+		//		Call callback with globalObject as dojo.global and
+		//		globalObject.document as dojo.doc. If provided, globalObject
+		//		will be executed in the context of object thisObject
+		// description:
+		//		When callback() returns or throws an error, the dojo.global
+		//		and dojo.doc will be restored to its previous state.
+		var rval;
+		var oldGlob = dojo.global;
+		var oldDoc = dojo.doc;
+		try{
+			dojo.setContext(globalObject, globalObject.document);
+			rval = dojo._fireCallback(callback, thisObject, cbArguments);
+		}finally{
+			dojo.setContext(oldGlob, oldDoc);
+		}
+		return rval;
+	}
+
+	dojo.withDoc = function(	/*Object*/documentObject, 
+								/*Function*/callback, 
+								/*Object?*/thisObject, 
+								/*Array?*/cbArguments){
+		// summary:
+		//		Call callback with documentObject as dojo.doc. If provided,
+		//		callback will be executed in the context of object thisObject
+		// description:
+		//		When callback() returns or throws an error, the dojo.doc will
+		//		be restored to its previous state.
+		var rval;
+		var oldDoc = dojo.doc;
+		try{
+			dojo.doc = documentObject;
+			rval = dojo._fireCallback(callback, thisObject, cbArguments);
+		}finally{
+			dojo.doc = oldDoc;
+		}
+		return rval;
+	}
+
+} //if (typeof window != 'undefined')
+
+//Load debug code if necessary.
+// dojo.requireIf((djConfig["isDebug"] || djConfig["debugAtAllCosts"]), "dojo.debug");
+
+//window.widget is for Dashboard detection
+//The full conditionals are spelled out to avoid issues during builds.
+//Builds may be looking for require/requireIf statements and processing them.
+// dojo.requireIf(djConfig["debugAtAllCosts"] && !window.widget && !djConfig["useXDomain"], "dojo.browser_debug");
+// dojo.requireIf(djConfig["debugAtAllCosts"] && !window.widget && djConfig["useXDomain"], "dojo.browser_debug_xd");
+
+if(djConfig.isDebug){
+	if(!console.firebug){
+		dojo.require("dojo._firebug.firebug");
+	}
+}
+
+dojo.provide("dojo._base.lang");
+
+// Crockford functions (ish)
+
+dojo.isString = function(/*anything*/ it){
+	// summary:	Return true if it is a String.
+	return (typeof it == "string" || it instanceof String); // Boolean
+}
+
+dojo.isArray = function(/*anything*/ it){
+	// summary: Return true of it is an Array
+	return (it && it instanceof Array || typeof it == "array" || ((typeof dojo["NodeList"] != "undefined") && (it instanceof dojo.NodeList))); // Boolean
+}
+
+if(dojo.isBrowser && dojo.isSafari){
+	// only slow this down w/ gratuitious casting in Safari since it's what's b0rken
+	dojo.isFunction = function(/*anything*/ it){
+		if((typeof(it) == "function") && (it == "[object NodeList]")){ return false; }
+		return (typeof it == "function" || it instanceof Function); // Boolean
+	}
+}else{
+	dojo.isFunction = function(/*anything*/ it){
+		return (typeof it == "function" || it instanceof Function); // Boolean
+	}
+}
+
+dojo.isObject = function(/*anything*/ it){
+	if(typeof it == "undefined"){ return false; }
+	// FIXME: why true for null?
+	return (it === null || typeof it == "object" || dojo.isArray(it) || dojo.isFunction(it)); // Boolean
+}
+
+dojo.isArrayLike = function(/*anything*/ it){
+	// return:
+	//		If it walks like a duck and quicks like a duck, return true
+	var d = dojo;
+	if((!it)||(typeof it == "undefined")){ return false; }
+	if(d.isString(it)){ return false; }
+	// keep out built-in constructors (Number, String, ...) which have length
+	// properties
+	if(d.isFunction(it)){ return false; } 
+	if(d.isArray(it)){ return true; }
+	if((it.tagName)&&(it.tagName.toLowerCase()=='form')){ return false; }
+	if(isFinite(it.length)){ return true; }
+	return false; // Boolean
+}
+
+dojo.isAlien = function(/*anything*/ it){
+	// summary: 
+	//		Returns true if it is a built-in function or some other kind of
+	//		oddball that *should* report as a function but doesn't
+	if(!it){ return false; }
+	return !dojo.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
+}
+
+dojo._mixin = function(/*Object*/ obj, /*Object*/ props){
+	// summary:
+	//		Adds all properties and methods of props to obj. This addition is
+	//		"prototype extension safe", so that instances of objects will not
+	//		pass along prototype defaults.
+	var tobj = {};
+	for(var x in props){
+		// the "tobj" condition avoid copying properties in "props"
+		// inherited from Object.prototype.  For example, if obj has a custom
+		// toString() method, don't overwrite it with the toString() method
+		// that props inherited from Object.protoype
+		if((typeof tobj[x] == "undefined") || (tobj[x] != props[x])){
+			obj[x] = props[x];
+		}
+	}
+	// IE doesn't recognize custom toStrings in for..in
+	if(dojo.isIE && 
+		(typeof(props["toString"]) == "function") && 
+		(props["toString"] != obj["toString"]) && 
+		(props["toString"] != tobj["toString"])
+	){
+		obj.toString = props.toString;
+	}
+	return obj; // Object
+}
+
+dojo.mixin = function(/*Object*/obj, /*Object...*/props){
+	// summary:	Adds all properties and methods of props to obj. 
+	for(var i=1, l=arguments.length; i<l; i++){
+		dojo._mixin(obj, arguments[i]);
+	}
+	return obj; // Object
+}
+
+dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){
+	// summary:
+	//		Adds all properties and methods of props to constructor's
+	//		prototype, making them available to all instances created with
+	//		constructor.
+	for(var i=1, l=arguments.length; i<l; i++){
+		dojo._mixin(constructor.prototype, arguments[i]);
+	}
+	return constructor; // Object
+}
+
+dojo._hitchArgs = function(scope, method /*,...*/){
+	var pre = dojo._toArray(arguments, 2);
+	var named = dojo.isString(method);
+	return function(){
+		// arrayify arguments
+		var args = dojo._toArray(arguments);
+		// locate our method
+		var f = (named ? (scope||dojo.global)[method] : method);
+		// invoke with collected args
+		return (f)&&(f.apply(scope||this, pre.concat(args))); // Any
+ 	} // Function
+}
+
+dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){
+	// summary: 
+	//		Returns a function that will only ever execute in the a given scope. 
+	//		This allows for easy use of object member functions
+	//		in callbacks and other places in which the "this" keyword may
+	//		otherwise not reference the expected scope. 
+	//		Any number of default positional arguments may be passed as parameters 
+	//		beyond "method".
+	//		Each of these values will be used to "placehold" (similar to curry)
+	//		for the hitched function. 
+	// scope: 
+	//		The scope to use when method executes. If method is a string, 
+	//		scope is also the object containing method.
+	// method:
+	//		A function to be hitched to scope, or the name of the method in
+	//		scope to be hitched.
+	// usage:
+	//		dojo.hitch(foo, "bar")(); // runs foo.bar() in the scope of foo
+	//		dojo.hitch(foo, myFunction); // returns a function that runs myFunction in the scope of foo
+	if(arguments.length > 2){
+		return dojo._hitchArgs.apply(dojo, arguments);
+	}
+	if(!method){
+		method = scope;
+		scope = null;
+	}
+	if(dojo.isString(method)){
+		scope = scope || dojo.global;
+		if (!scope[method]) throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join(''))
+		return function(){ return scope[method].apply(scope, arguments||[]); }
+	}else{
+		return (!scope ? method : function(){ return method.apply(scope, arguments||[]); });
+	}
+}
+
+dojo._delegate = function(obj, props){
+	// boodman/crockford delegation
+	function TMP(){};
+	TMP.prototype = obj;
+	var tmp = new TMP();
+	if(props){
+		dojo.mixin(tmp, props);
+	}
+	return tmp;
+}
+
+dojo.partial = function(/*Function|String*/method /*, ...*/){
+	// summary:
+	//		similar to hitch() except that the scope object is left to be
+	//		whatever the execution context eventually becomes. This is the
+	//		functional equivalent of calling:
+	//		dojo.hitch(null, funcName, ...);
+	var arr = [ null ];
+	return dojo.hitch.apply(dojo, arr.concat(dojo._toArray(arguments)));
+}
+
+dojo._toArray = function(/*Object*/obj, /*Number?*/offset){
+	// summary:
+	//		Converts an array-like object (i.e. arguments, DOMCollection)
+	//		to an array. Returns a new Array object.
+	var arr = [];
+	for(var x= offset||0; x<obj.length; x++){
+		arr.push(obj[x]);
+	}
+	return arr;
+}
+
+
+dojo.provide("dojo._base.declare");
+
+
+// this file courtesy of the TurboAjax group, licensed under a Dojo CLA
+
+dojo.declare = function(/*String*/ className, 
+						/*Function||Array*/ superclass, 
+						/*Function*/ init, 
+						/*Object*/ props){
+	//	summary: 
+	//		Create a feature-rich constructor from compact notation
+	//	className: String
+	//		the name of the constructor (loosely, a "class")
+	//		stored in the "declaredClass" property in the created prototype
+	// 	superclass: Function||Array
+	//		may be a Function, or an Array of Functions. If "superclass" is an
+	//		array, the first element is used as the prototypical ancestor and
+	//		any following Functions become mixin ancestors.
+	//	init: Function?
+	//    an initializer function called when an object is instantiated
+	//		from this constructor.
+	//	props: Object?||Array?
+	//		an object (or array of objects) whose properties are copied to the
+	//		created prototype
+	//	description:
+	//		Create a constructor using a compact notation for inheritance and
+	//		prototype extension. 
+	//
+	//		All superclasses (including mixins) must be Functions (not simple Objects).
+	//
+	//		Mixin ancestors provide a type of multiple inheritance.
+	//	
+	//		Prototypes of mixin ancestors are copied to the new class.
+	//
+	//		"className" is cached in "declaredClass" property of the new class.
+	//
+	// usage:
+	//		dojo.declare("my.classes.bar", my.classes.foo,
+	//			function(){
+	//				// initialization function
+	//				this.myComplicatedObject = new ReallyComplicatedObject(); 
+	//			},{ 
+	//				// properties to be added to the class prototype
+	//				someValue: 2,
+	//				someMethod: function(){ 
+	//					doStuff(); 
+	//				}
+	//			}
+	//		);
+	
+	// argument juggling
+	if(dojo.isFunction(props)||(!props&&!dojo.isFunction(init))){ 
+		var t=props; props=init; init=t;
+	}	
+	// our constructor boilerplate (this is cloned, so keep it short)
+	var ctor = function(){this._construct(arguments);}
+	// alias declare, ensure props, make mixin array
+	var dd=dojo.declare, p=props || {}, mixins=[], pc;
+	// extract mixins
+	if(dojo.isArray(superclass)){
+		mixins = superclass;
+		superclass = mixins.shift();
+	}
+	// chain prototypes
+	var scp = superclass ? superclass.prototype : null;
+	if(scp){ctor.prototype = dojo._delegate(scp);}
+	// cache ancestry, attach fancy extension mechanism
+	dojo.mixin(ctor, {superclass: scp, mixins: mixins, extend: dd._extend});
+	// extend with mixin classes
+	for(var i=0,m;(m=mixins[i]);i++){dojo.extend(ctor, m.prototype);}
+	// locate initializer
+	init = init || (pc=p.constructor)&&(pc!=Object)&&pc || null;
+	// decorate the prototype
+	dojo.extend(ctor, {declaredClass: className, _initializer: init, preamble: null}, p, dd._core); 
+	// do this last (doesn't work via extend anyway)
+	ctor.prototype.constructor = ctor;
+	// create named reference
+	return dojo.setObject(className, ctor); // Function
+}
+
+dojo.mixin(dojo.declare, {
+	_extend: function(mixin, preamble) {
+		dojo.extend(this, mixin);
+		this.mixins.push(!preamble ? mixin : function() { mixin.apply(this, preamble.apply(this, arguments) || arguments); });
+	},
+	_core: {
+		_construct: function(args) {
+			var c=args.callee, s=c.superclass, ct=s&&s.constructor, a=args, ii;
+			// call any preamble
+			if(fn=c.prototype.preamble){a = fn.apply(this, a) || a;}
+			// initialize superclass
+			if(ct&&ct.apply){ct.apply(this, a)};
+			// initialize mixins
+			for(var i=0, m; (m=c.mixins[i]); i++){if(m.apply){m.apply(this, a);}}
+			// call our own initializer
+			var ii = c.prototype._initializer;
+			if(ii){ii.apply(this, args);}
+		},
+		inherited: function(name, args, newArgs){
+			var c=args.callee, p=this.constructor.prototype, a=newArgs||args, fn;
+			// if not an instance override 
+			if (this[name]!=c || p[name]==c) {
+				// seek the prototype which contains callee
+				while(p && (p[name]!==c)){p=p.constructor.superclass;}
+				// not found means user error
+				if(!p){ throw(this.toString() + ': name argument ("' + name + '") to inherited must match callee (declare.js)');	}
+				// find the eldest prototype which does not contain callee
+				while(p && (p[name]==c)){p=p.constructor.superclass;}
+			}
+			// if the function exists, invoke it in our scope
+			return (fn=p&&p[name])&&(fn.apply(this, a));
+		}
+	}
+});	
+
+dojo.provide("dojo._base.connect");
+
+
+// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
+
+// FIXME: needs in-code docs in the worst way!!
+
+// low-level delegation machinery
+dojo._listener = {
+	// create a dispatcher function
+	getDispatcher: function(){
+		// following comments pulled out-of-line to prevent cloning them 
+		// in the returned function.
+		// - indices (i) that are really in the array of listeners (ls) will 
+		//   not be in Array.prototype. This is the 'sparse array' trick
+		//   that keeps us safe from libs that take liberties with built-in 
+		//   objects
+		// - listener is invoked with current scope (this)
+		return function(){
+			var ls = arguments.callee.listeners;
+			for(var i in ls){
+				if(!(i in Array.prototype)){
+					ls[i].apply(this, arguments);
+				}
+			}
+		}
+	},
+	// add a listener to an object
+	add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
+		// Whenever 'method' is invoked, 'listener' will have the same scope.
+		// Trying to supporting a context object for the listener led to 
+		// complexity. 
+		// Non trivial to provide 'once' functionality here
+		// because listener could be the result of a dojo.hitch call,
+		// in which case two references to the same hitch target would not
+		// be equivalent. 
+		source = source || dojo.global;
+		// The source method is either null, a dispatcher, or some other function
+		var f = source[method];
+		// Ensure a dispatcher
+		if(!f||!f.listeners){
+			var d = dojo._listener.getDispatcher();
+			// dispatcher holds a list of handlers
+			d.listeners = (f ? [f] : []);
+			// put back in source			
+			f = source[method] = d;
+		}
+		// The contract is that a handle is returned that can 
+		// identify this listener for disconnect. 
+		//
+		// The type of the handle is private. Here is it implemented as Integer. 
+		// DOM event code has this same contract but handle is Function 
+		// in non-IE browsers.
+		//
+		// Could implement 'before' with a flag and unshift.
+		return f.listeners.push(listener) ; /*Handle*/
+	},
+	// remove a listener from an object
+	remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
+		var f = (source||dojo.global)[method];
+		// remember that handle is the index+1 (0 is not a valid handle)
+		if(f && f.listeners && handle--){	
+			delete f.listeners[handle]; 
+		}
+	}
+};
+
+// Multiple delegation for arbitrary methods.
+
+// This unit knows nothing about DOM, 
+// but we include DOM aware 
+// documentation and dontFix
+// argument here to help the autodocs.
+// Actual DOM aware code is in event.js.
+
+dojo.connect = function(/*Object|null*/ obj, 
+						/*String*/ event, 
+						/*Object|null*/ context, 
+						/*String|Function*/ method,
+						/*Boolean*/ dontFix){
+	// summary:
+	//		Create a link that calls one function when another executes. 
+	// description:
+	//		Connects method to event, so that after event fires, method
+	//		does too. Connect as many methods to event as needed.
+	//
+	//		event must be a string. If obj is null, dojo.global is used.
+	//
+	//		null arguments may simply be omitted.
+	//
+	//		obj[event] can resolve to a function or undefined (null). 
+	//		If obj[event] is null, it is assigned a function.
+	//
+	//		The return value is a handle that is needed to 
+	//		remove this connection with dojo.disconnect.
+	// obj: 
+	//		The source object for the event function. 
+	//		Defaults to dojo.global if null.
+	//		If obj is a DOM node, the connection is delegated 
+	//		to the DOM event manager (unless dontFix is true).
+	// event:
+	//		String name of the event function in obj. 
+	//		I.e. identifies a property obj[event].
+	// context: 
+	//		The object that method will receive as "this".
+	//
+	//		If context is null and method is a function, then method
+	//		inherits the context of event.
+	//	
+	//		If method is a string then context must be the source 
+	//		object object for method (context[method]). If context is null,
+	//		dojo.global is used.
+	// method:
+	//		A function reference, or name of a function in context. 
+	//		The function identified by method fires after event does. 
+	//		method receives the same arguments as the event.
+	//		See context argument comments for information on method's scope.
+	// dontFix:
+	//		If obj is a DOM node, set dontFix to true to  prevent delegation 
+	//		of this connection to the DOM event manager. 
+	// usage:
+	//		// when obj.onchange(), do ui.update()
+	//		dojo.connect(obj, "onchange", ui, "update");
+	//		dojo.connect(obj, "onchange", ui, ui.update); // same
+	//
+	//		// using return value for disconnect
+	//		var link = dojo.connect(obj, "onchange", ui, "update");
+	//		...
+	//		dojo.disconnect(link);
+	//
+	//		// when onglobalevent executes, watcher.handler is invoked
+	//		dojo.connect(null, "onglobalevent", watcher, "handler");
+	//
+	//		// when ob.onCustomEvent executes, customEventHandler is invoked
+	//		dojo.connect(ob, "onCustomEvent", null, "customEventHandler");
+	//		dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same
+	//
+	//		// when ob.onCustomEvent executes, customEventHandler is invoked
+	//		// with the same scope (this)
+	//		dojo.connect(ob, "onCustomEvent", null, customEventHandler);
+	//		dojo.connect(ob, "onCustomEvent", customEventHandler); // same
+	//
+	//		// when globalEvent executes, globalHandler is invoked
+	//		// with the same scope (this)
+	//		dojo.connect(null, "globalEvent", null, globalHandler);
+	//		dojo.connect("globalEvent", globalHandler); // same
+
+	// normalize arguments
+	var a=arguments, args=[], i=0;
+	// if a[0] is a String, obj was ommited
+	args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]);
+	// if the arg-after-next is a String or Function, context was NOT omitted
+	var a1 = a[i+1];
+	args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]);
+	// absorb any additional arguments
+	for (var l=a.length; i<l; i++){	args.push(a[i]); }
+	// do the actual work
+	return dojo._connect.apply(this, args); /*Handle*/
+}
+
+dojo._connect = function(obj, event, context, method){
+	var h = dojo._listener.add(obj, event, dojo.hitch(context, method)); 
+	return [obj, event, h]; /*Handle*/
+}
+
+dojo.disconnect = function(/*Handle*/ handle){
+	// summary:
+	//		Remove a link created by dojo.connect.
+	// description:
+	//		Removes the connection between event and the method referenced by handle.
+	// handle:
+	//		the return value of the dojo.connect call that created the connection.
+	dojo._disconnect.apply(this, handle);
+	if (handle && handle[0]!=undefined){
+		dojo._disconnect.apply(this, handle);
+		// let's not keep this reference
+		delete handle[0];
+	}
+}
+
+dojo._disconnect = function(obj, event, handle){
+	dojo._listener.remove(obj, event, handle);
+}
+
+// topic publish/subscribe
+
+dojo._topics = {};
+
+dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ method){
+	// support for 3 argument invocation depends on hitch
+	return dojo._listener.add(dojo._topics, topic, dojo.hitch(context, method)); /*Handle*/
+}
+
+dojo.unsubscribe = function(/*String*/ topic, /*Handle*/ handle){
+	dojo._listener.remove(dojo._topics, topic, handle);
+}
+
+dojo.publish = function(/*String*/ topic, /*Array*/ args){
+	// Note that args is an array. This is more efficient vs variable length argument list.
+	// Ideally, by convention, var args are implemented via Array throughout the APIs.
+	var f = dojo._topics[topic];
+	(f)&&(f.apply(this, args||[]));
+}
+
+dojo.provide("dojo._base.Deferred");
+
+
+// FIXME: need to port tests in!!
+
+dojo.Deferred = function(/*Function?*/ canceller){
+	// summary:
+	//		Encapsulates a sequence of callbacks in response to a value that
+	//		may not yet be available.  This is modeled after the Deferred class
+	//		from Twisted <http://twistedmatrix.com>.
+	// description:
+	//		JavaScript has no threads, and even if it did, threads are hard.
+	//		Deferreds are a way of abstracting non-blocking events, such as the
+	//		final response to an XMLHttpRequest. Deferreds create a promise to
+	//		return a response a some point in the future and an easy way to
+	//		register your interest in receiving that response.
+	//
+	//		The most important methods for Deffered users are:
+	//
+	//			addCallback(handler)
+	//			addErrback(handler)
+	//			callback(result)
+	//			errback(result)
+	//
+	//		In general, when a function returns a Deferred, users then "fill
+	//		in" the second half of the contract by registering callbacks and
+	//		error handlers. You may register as many callback and errback
+	//		handlers as you like and they will be executed in the order
+	//		registered when a result is provided. Usually this result is
+	//		provided as the result of an asynchronous operation. The code
+	//		"managing" the Deferred (the code that made the promise to provide
+	//		an answer later) will use the callback() and errback() methods to
+	//		communicate with registered listeners about the result of the
+	//		operation. At this time, all registered result handlers are called
+	//		*with the most recent result value*.
+	//
+	//		Deferred callback handlers are treated as a chain, and each item in
+	//		the chain is required to return a value that will be fed into
+	//		successive handlers. The most minimal callback may be registered
+	//		like this:
+	//
+	//			var d = new dojo.Deferred();
+	//			d.addCallback(function(result){ return result; });
+	//
+	//		Perhaps the most common mistake when first using Deferreds is to
+	//		forget to return a value (in most cases, the value you were
+	//		passed).
+	//
+	//		The sequence of callbacks is internally represented as a list of
+	//		2-tuples containing the callback/errback pair.  For example, the
+	//		following call sequence:
+	//		
+	//			var d = new dojo.Deferred();
+	//			d.addCallback(myCallback);
+	//			d.addErrback(myErrback);
+	//			d.addBoth(myBoth);
+	//			d.addCallbacks(myCallback, myErrback);
+	//
+	//		is translated into a Deferred with the following internal
+	//		representation:
+	//
+	//		[
+	//			[myCallback, null],
+	//			[null, myErrback],
+	//			[myBoth, myBoth],
+	//			[myCallback, myErrback]
+	//		]
+	//
+	//		The Deferred also keeps track of its current status (fired).  Its
+	//		status may be one of three things:
+	//
+	//			-1: no value yet (initial condition)
+	//			0: success
+	//			1: error
+	//	
+	//		A Deferred will be in the error state if one of the following three
+	//		conditions are met:
+	//
+	//			1. The result given to callback or errback is "instanceof" Error
+	//			2. The previous callback or errback raised an exception while
+	//			   executing
+	//			3. The previous callback or errback returned a value
+	//			   "instanceof" Error
+	//
+	//		Otherwise, the Deferred will be in the success state. The state of
+	//		the Deferred determines the next element in the callback sequence
+	//		to run.
+	//
+	//		When a callback or errback occurs with the example deferred chain,
+	//		something equivalent to the following will happen (imagine that
+	//		exceptions are caught and returned):
+	//
+	//			// d.callback(result) or d.errback(result)
+	//			if(!(result instanceof Error)){
+	//				result = myCallback(result);
+	//			}
+	//			if(result instanceof Error){
+	//				result = myErrback(result);
+	//			}
+	//			result = myBoth(result);
+	//			if(result instanceof Error){
+	//				result = myErrback(result);
+	//			}else{
+	//				result = myCallback(result);
+	//			}
+	//
+	//		The result is then stored away in case another step is added to the
+	//		callback sequence.	Since the Deferred already has a value
+	//		available, any new callbacks added will be called immediately.
+	//
+	//		There are two other "advanced" details about this implementation
+	//		that are useful:
+	//
+	//		Callbacks are allowed to return Deferred instances themselves, so
+	//		you can build complicated sequences of events with ease.
+	//
+	//		The creator of the Deferred may specify a canceller.  The canceller
+	//		is a function that will be called if Deferred.cancel is called
+	//		before the Deferred fires. You can use this to implement clean
+	//		aborting of an XMLHttpRequest, etc. Note that cancel will fire the
+	//		deferred with a CancelledError (unless your canceller returns
+	//		another kind of error), so the errbacks should be prepared to
+	//		handle that error for cancellable Deferreds.
+	// usage:
+	//		Deferred objects are often used when making code asynchronous. It
+	//		may be easiest to write functions in a synchronous manner and then
+	//		split code using a deferred to trigger a response to a long-lived
+	//		operation. For example, instead of register a callback function to
+	//		denote when a rendering operation completes, the function can
+	//		simply return a deferred:
+	//
+	//			// callback style:
+	//			function renderLotsOfData(data, callback){
+	//				var success = false
+	//				try{
+	//					for(var x in data){
+	//						renderDataitem(data[x]);
+	//					}
+	//					success = true;
+	//				}catch(e){ }
+	//				if(callback){
+	//					callback(success);
+	//				}
+	//			}
+	//
+	//			// using callback style
+	//			renderLotsOfData(someDataObj, function(success){
+	//				// handles success or failure
+	//				if(!success){
+	//					promptUserToRecover();
+	//				}
+	//			});
+	//			// NOTE: no way to add another callback here!!
+	//
+	//		Using a Deferred doesn't simplify the sending code any, but it
+	//		provides a standard interface for callers and senders alike,
+	//		providing both with a simple way to service multiple callbacks for
+	//		an operation and freeing both sides from worrying about details
+	//		such as "did this get called already?". With Deferreds, new
+	//		callbacks can be added at any time.
+	//
+	//			// Deferred style:
+	//			function renderLotsOfData(data, callback){
+	//				var d = new dojo.Deferred();
+	//				try{
+	//					for(var x in data){
+	//						renderDataitem(data[x]);
+	//					}
+	//					d.callback(true);
+	//				}catch(e){ 
+	//					d.errback(new Error("rendering failed"));
+	//				}
+	//				return d;
+	//			}
+	//
+	//			// using Deferred style
+	//			renderLotsOfData(someDataObj).addErrback(function(){
+	//				promptUserToRecover();
+	//			});
+	//			// NOTE: addErrback and addCallback both return the Deferred
+	//			// again, so we could chain adding callbacks or save the
+	//			// deferred for later should we need to be notified again.
+	//
+	//		In this example, renderLotsOfData is syncrhonous and so both
+	//		versions are pretty artificial. Putting the data display on a
+	//		timeout helps show why Deferreds rock:
+	//
+	//			// Deferred style and async func
+	//			function renderLotsOfData(data, callback){
+	//				var d = new dojo.Deferred();
+	//				setTimeout(function(){
+	//					try{
+	//						for(var x in data){
+	//							renderDataitem(data[x]);
+	//						}
+	//						d.callback(true);
+	//					}catch(e){ 
+	//						d.errback(new Error("rendering failed"));
+	//					}
+	//				}, 100);
+	//				return d;
+	//			}
+	//
+	//			// using Deferred style
+	//			renderLotsOfData(someDataObj).addErrback(function(){
+	//				promptUserToRecover();
+	//			});
+	//
+	//		Note that the caller doesn't have to change his code at all to
+	//		handle the asynchronous case.
+
+	this.chain = [];
+	this.id = this._nextId();
+	this.fired = -1;
+	this.paused = 0;
+	this.results = [null, null];
+	this.canceller = canceller;
+	this.silentlyCancelled = false;
+};
+
+dojo.extend(dojo.Deferred, {
+	_getFunctionFromArgs: function(){
+		// summary:
+		//		takes one or two arguments and does type detection to determine
+		//		if they contain enough information to return a function from
+		//		them. If a scope and function name are provided a version o
+		//		that function hitched to the passed scope will be returned.
+		// usage: FIXME
+		var a = arguments;
+		if((a[0])&&(!a[1])){
+			if(dojo.isFunction(a[0])){
+				return a[0];
+			}else if(dojo.isString(a[0])){
+				return dojo.global[a[0]];
+			}
+		}else if((a[0])&&(a[1])){
+			return dojo.hitch(a[0], a[1]);
+		}
+		return null;
+	},
+
+	makeCalled: function(){
+		// summary:
+		//		returns a new, empty deferred, which is already in the called
+		//		state. Calling callback() or errback() on this deferred will
+		//		yeild an error and adding new handlers to it will result in
+		//		them being called immediately.
+		var deferred = new dojo.Deferred();
+		deferred.callback();
+		return deferred;
+	},
+
+	toString: function(){
+		var state;
+		if(this.fired == -1){
+			state = 'unfired';
+		}else if(this.fired == 0){
+			state = 'success';
+		}else{
+			state = 'error';
+		}
+		return 'Deferred(' + this.id + ', ' + state + ')';
+	},
+
+	_nextId: (function(){
+		var n = 1;
+		return function(){ return n++; };
+	})(),
+
+	cancel: function(){
+		// summary:	
+		//		Cancels a Deferred that has not yet received a value, or is
+		//		waiting on another Deferred as its value.
+		// description:
+		//		If a canceller is defined, the canceller is called. If the
+		//		canceller did not return an error, or there was no canceller,
+		//		then the errback chain is started.
+		if(this.fired == -1){
+			if (this.canceller){
+				this.canceller(this);
+			}else{
+				this.silentlyCancelled = true;
+			}
+			if(this.fired == -1){
+				this.errback(new Error(this.toString()));
+			}
+		}else if(	(this.fired == 0) &&
+					(this.results[0] instanceof dojo.Deferred)
+		){
+			this.results[0].cancel();
+		}
+	},
+			
+
+	_pause: function(){
+		// summary: 
+		//		Used internally to signal that it's waiting on another Deferred
+		this.paused++;
+	},
+
+	_unpause: function(){
+		// summary: 
+		//		Used internally to signal that it's no longer waiting on
+		//		another Deferred.
+		this.paused--;
+		if(
+			(this.paused == 0) && 
+			(this.fired >= 0)
+		){
+			this._fire();
+		}
+	},
+
+	_continue: function(res){
+		// summary: 
+		//		Used internally when a dependent deferred fires.
+		this._resback(res);
+		this._unpause();
+	},
+
+	_resback: function(res){
+		// summary:
+		//		The private primitive that means either callback or errback
+		this.fired = ((res instanceof Error) ? 1 : 0);
+		this.results[this.fired] = res;
+		this._fire();
+	},
+
+	_check: function(){
+		if(this.fired != -1){
+			if(!this.silentlyCancelled){
+				throw new Error("already called!");
+			}
+			this.silentlyCancelled = false;
+			return;
+		}
+	},
+
+	callback: function(res){
+		// summary:	Begin the callback sequence with a non-error value.
+		
+		/*
+		callback or errback should only be called once on a given
+		Deferred.
+		*/
+		this._check();
+		this._resback(res);
+	},
+
+	errback: function(/*Error*/res){
+		// summary: 
+		//		Begin the callback sequence with an error result.
+		this._check();
+		if(!(res instanceof Error)){
+			res = new Error(res);
+		}
+		this._resback(res);
+	},
+
+	addBoth: function(/*Function||Object*/cb, /*Optional, String*/cbfn){
+		// summary:
+		//		Add the same function as both a callback and an errback as the
+		//		next element on the callback sequence.	This is useful for code
+		//		that you want to guarantee to run, e.g. a finalizer.
+		var enclosed = this._getFunctionFromArgs(cb, cbfn);
+		if(arguments.length > 2){
+			enclosed = dojo.partial(enclosed, arguments, 2);
+		}
+		return this.addCallbacks(enclosed, enclosed);
+	},
+
+	addCallback: function(cb, cbfn){
+		// summary: 
+		//		Add a single callback to the end of the callback sequence.
+		var enclosed = this._getFunctionFromArgs(cb, cbfn);
+		if(arguments.length > 2){
+			enclosed = dojo.partial(enclosed, arguments, 2);
+		}
+		return this.addCallbacks(enclosed, null);
+	},
+
+	addErrback: function(cb, cbfn){
+		// summary: 
+		//		Add a single callback to the end of the callback sequence.
+		var enclosed = this._getFunctionFromArgs(cb, cbfn);
+		if(arguments.length > 2){
+			enclosed = dojo.partial(enclosed, arguments, 2);
+		}
+		return this.addCallbacks(null, enclosed);
+		return this.addCallbacks(null, cbfn);
+	},
+
+	addCallbacks: function(cb, eb){
+		// summary: 
+		//		Add separate callback and errback to the end of the callback
+		//		sequence.
+		this.chain.push([cb, eb])
+		if(this.fired >= 0){
+			this._fire();
+		}
+		return this;
+	},
+
+	_fire: function(){
+		// summary: 
+		//		Used internally to exhaust the callback sequence when a result
+		//		is available.
+		var chain = this.chain;
+		var fired = this.fired;
+		var res = this.results[fired];
+		var self = this;
+		var cb = null;
+		while(
+			(chain.length > 0) &&
+			(this.paused == 0)
+		){
+			// Array
+			var pair = chain.shift();
+			var f = pair[fired];
+			if(f == null){
+				continue;
+			}
+			try{
+				res = f(res);
+				fired = ((res instanceof Error) ? 1 : 0);
+				if(res instanceof dojo.Deferred){
+					cb = function(res){
+						self._continue(res);
+					}
+					this._pause();
+				}
+			}catch(err){
+				fired = 1;
+				res = err;
+			}
+		}
+		this.fired = fired;
+		this.results[fired] = res;
+		if((cb)&&(this.paused)){
+			// this is for "tail recursion" in case the dependent
+			// deferred is already fired
+			res.addBoth(cb);
+		}
+	}
+});
+
+dojo.provide("dojo._base.json");
+
+dojo.fromJson = function(/*String*/ json){
+	// summary:
+	// 		evaluates the passed string-form of a JSON object
+	// json: 
+	//		a string literal of a JSON item, for instance:
+	//			'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'
+	// return:
+	//		the result of the evaluation
+
+	// FIXME: should this accept mozilla's optional second arg?
+	try {
+		return eval("(" + json + ")");
+	}catch(e){
+		console.debug(e);
+		return json;
+	}
+}
+
+dojo._escapeString = function(/*String*/str){
+	//summary:
+	//		Adds escape sequences for non-visual characters, double quote and
+	//		backslash and surrounds with double quotes to form a valid string
+	//		literal.
+	return ('"' + str.replace(/(["\\])/g, '\\$1') + '"'
+		).replace(/[\f]/g, "\\f"
+		).replace(/[\b]/g, "\\b"
+		).replace(/[\n]/g, "\\n"
+		).replace(/[\t]/g, "\\t"
+		).replace(/[\r]/g, "\\r"); // string
+}
+
+dojo.toJsonIndentStr = "\t";
+dojo.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*String?*/ _indentStr){
+	// summary:
+	//		Create a JSON serialization of an object. 
+	//		Note that this doesn't check for infinite recursion, so don't do that!
+	//
+	// it:
+	//		an object to be serialized. Objects may define their own
+	//		serialization via a special "__json__" or "json" function
+	//		property. If a specialized serializer has been defined, it will
+	//		be used as a fallback.
+	//
+	// prettyPrint:
+	//		if true, we indent objects and arrays to make the output prettier.
+	//		The variable dojo.toJsonIndentStr is used as the indent string 
+	//		-- to use something other than the default (tab), 
+	//		change that variable before calling dojo.toJson().
+	//
+	// _indentStr:
+	//		private variable for recursive calls when pretty printing, do not use.
+	//		
+	// return:
+	//		a String representing the serialized version of the passed object.
+
+	_indentStr = _indentStr || "";
+	var nextIndent = (prettyPrint ? _indentStr + dojo.toJsonIndentStr : "");
+	var newLine = (prettyPrint ? "\n" : "");
+	var objtype = typeof(it);
+	if(objtype == "undefined"){
+		return "undefined";
+	}else if((objtype == "number")||(objtype == "boolean")){
+		return it + "";
+	}else if(it === null){
+		return "null";
+	}
+	if(objtype == "string"){ return dojo._escapeString(it); }
+	// recurse
+	var recurse = arguments.callee;
+	// short-circuit for objects that support "json" serialization
+	// if they return "self" then just pass-through...
+	var newObj;
+	if(typeof it.__json__ == "function"){
+		newObj = it.__json__();
+		if(it !== newObj){
+			return recurse(newObj, prettyPrint, nextIndent);
+		}
+	}
+	if(typeof it.json == "function"){
+		newObj = it.json();
+		if(it !== newObj){
+			return recurse(newObj, prettyPrint, nextIndent);
+		}
+	}
+	// array
+	if(dojo.isArray(it)){
+		var res = [];
+		for(var i = 0; i < it.length; i++){
+			var val = recurse(it[i], prettyPrint, nextIndent);
+			if(typeof(val) != "string"){
+				val = "undefined";
+			}
+			res.push(newLine + nextIndent + val);
+		}
+		return "[" + res.join(",") + newLine + _indentStr + "]";
+	}
+	/*
+	// look in the registry
+	try {
+		window.o = it;
+		newObj = dojo.json.jsonRegistry.match(it);
+		return recurse(newObj, prettyPrint, nextIndent);
+	}catch(e){
+		// console.debug(e);
+	}
+	// it's a function with no adapter, skip it
+	*/
+	if(objtype == "function"){
+		return null;
+	}
+	// generic object code path
+	var output = [];
+	for(var key in it){
+		var keyStr;
+		if(typeof(key) == "number"){
+			keyStr = '"' + key + '"';
+		}else if(typeof(key) == "string"){
+			keyStr = dojo._escapeString(key);
+		}else{
+			// skip non-string or number keys
+			continue;
+		}
+		val = recurse(it[key], prettyPrint, nextIndent);
+		if(typeof(val) != "string"){
+			// skip non-serializable values
+			continue;
+		}
+		// FIXME: use += on Moz!!
+		//	 MOW NOTE: using += is a pain because you have to account for the dangling comma...
+		output.push(newLine + nextIndent + keyStr + ":" + val);
+	}
+	return "{" + output.join(",") + newLine + _indentStr + "}";
+}
+
+
+dojo.provide("dojo._base.array");
+
+(function(){
+	var d = dojo;
+	if(Array.forEach){
+		// fast, if we can
+		var tn = ["indexOf", "lastIndexOf", "every", "some", "forEach", "filter", "map"];
+		for(var x=0; x<tn.length; x++){
+			d[tn[x]] = Array[tn[x]];
+		}
+	}else{
+		var _getParts = function(arr, obj){
+			return [ (d.isString(arr) ? arr.split("") : arr), (obj||d.global) ];
+		}
+
+		d.mixin(d, {
+			indexOf: function(	/*Array*/		array, 
+								/*Object*/		value,
+								/*Integer*/		fromIndex,
+								/*Boolean?*/	findLast){
+				// summary:
+				//		locates the first index of the provided value in the passed
+				//		array. If the value is not found, -1 is returned.
+				// description:
+				//		For details on this method, see:
+				// 			http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf
+
+				/* // negative indexes
+				if(fromIndex < 0){
+					fromIndex = array.length+fromIndex;
+				}
+				*/
+
+				// FIXME: use built in indexOf and lastIndexOf if available.
+				if(findLast){
+					var step = -1, i = (fromIndex||array.length - 1), end = -1;
+				}else{
+					var step = 1, i = (fromIndex||0), end = array.length;
+				}
+				for(; i!=end; i+=step){
+					if(array[i] == value){ return i; }
+				}
+				return -1;	// number
+			},
+
+			lastIndexOf: function(/*Array*/array, /*Object*/value, /*boolean?*/identity){
+				// summary:
+				//		locates the lat index of the provided value in the passed
+				//		array. If the value is not found, -1 is returned.
+				// description:
+				//		For details on this method, see:
+				// 			http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf
+				return d.indexOf(array, value, identity, true); // number
+			},
+
+			map: function(/*Array*/arr, /*Function*/func, /*Function?*/obj){
+				// summary:
+				//		applies a function to each element of an Array and creates
+				//		an Array with the results
+				// description:
+				//		returns a new array constituted from the return values of
+				//		passing each element of arr into unary_func. The obj parameter
+				//		may be passed to enable the passed function to be called in
+				//		that scope.  In environments that support JavaScript 1.6, this
+				//		function is a passthrough to the built-in map() function
+				//		provided by Array instances. For details on this, see:
+				// 			http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map
+				// usage:
+				//		dojo.map([1, 2, 3, 4], function(item){ return item+1 });
+				//		// returns [2, 3, 4, 5]
+				var _p = _getParts(arr, obj); arr = _p[0]; obj = _p[1];
+				var outArr = [];
+				for(var i=0;i<arr.length;++i){
+					outArr.push(func.call(obj, arr[i]));
+				}
+				return outArr; // Array
+			},
+
+			forEach: function(/*Array*/arr, /*Function*/callback, /*Object?*/obj){
+				// summary:
+				//		for every item in arr, call callback with that item as its
+				//		only parameter.
+				// description:
+				//		Return values are ignored. This function
+				//		corresponds (and wraps) the JavaScript 1.6 forEach method. For
+				//		more details, see:
+				//			http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach
+
+				// match the behavior of the built-in forEach WRT empty arrs
+				if((!arr)||(!arr.length)){ return; }
+
+				// FIXME: there are several ways of handilng thisObject. Is
+				// dojo.global always the default context?
+				var _p = _getParts(arr, obj); arr = _p[0]; obj = _p[1];
+				for(var i=0,l=arr.length; i<l; i++){ 
+					callback.call(obj, arr[i], i, arr);
+				}
+			},
+
+			_everyOrSome: function(/*Boolean*/every, /*Array*/arr, /*Function*/callback, /*Object?*/obj){
+				var _p = _getParts(arr, obj); arr = _p[0]; obj = _p[1];
+				for(var i=0,l=arr.length; i<l; i++){
+					var result = callback.call(obj, arr[i], i, arr);
+					if(every && !result){
+						return false; // Boolean
+					}else if((!every)&&(result)){
+						return true; // Boolean
+					}
+				}
+				return (!!every); // Boolean
+			},
+
+			every: function(/*Array*/arr, /*Function*/callback, /*Object?*/thisObject){
+				// summary:
+				//		determines whether or not every item in the array satisfies the
+				//		condition implemented by callback. thisObject may be used to
+				//		scope the call to callback. The function signature is derived
+				//		from the JavaScript 1.6 Array.every() function. More
+				//		information on this can be found here:
+				//			http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every
+				// usage:
+				//		dojo.every([1, 2, 3, 4], function(item){ return item>1; });
+				//		// returns false
+				//		dojo.every([1, 2, 3, 4], function(item){ return item>0; });
+				//		// returns true 
+				return this._everyOrSome(true, arr, callback, thisObject); // Boolean
+			},
+
+			some: function(/*Array*/arr, /*Function*/callback, /*Object?*/thisObject){
+				// summary:
+				//		determines whether or not any item in the array satisfies the
+				//		condition implemented by callback. thisObject may be used to
+				//		scope the call to callback. The function signature is derived
+				//		from the JavaScript 1.6 Array.some() function. More
+				//		information on this can be found here:
+				//			http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some
+				// examples:
+				//		dojo.some([1, 2, 3, 4], function(item){ return item>1; });
+				//		// returns true
+				//		dojo.some([1, 2, 3, 4], function(item){ return item<1; });
+				//		// returns false
+				return this._everyOrSome(false, arr, callback, thisObject); // Boolean
+			},
+
+			filter: function(/*Array*/arr, /*Function*/callback, /*Object?*/obj){
+				// summary:
+				//		returns a new Array with those items from arr that match the
+				//		condition implemented by callback. ob may be used to
+				//		scope the call to callback. The function signature is derived
+				//		from the JavaScript 1.6 Array.filter() function.
+				//
+				//		More information on the JS 1.6 API can be found here:
+				//			http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter
+				// examples:
+				//		dojo.filter([1, 2, 3, 4], function(item){ return item>1; });
+				//		// returns [2, 3, 4]
+
+				var _p = _getParts(arr, obj); arr = _p[0]; obj = _p[1];
+				var outArr = [];
+				for(var i = 0; i < arr.length; i++){
+					if(callback.call(obj, arr[i], i, arr)){
+						outArr.push(arr[i]);
+					}
+				}
+				return outArr; // Array
+			}
+		});
+	}
+})();
+
+dojo.provide("dojo._base");
+
+
+
+
+
+
+// dojo.requireIf(dojo.isBrowser, "dojo._base.browserConnect");
+
+
+
+
+
+
+
+// dojo.requireIf(dojo.isBrowser, "dojo._base.cookie");
+
+dojo.provide("dojo._base.event");
+
+
+// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
+
+(function(){
+	// DOM event machinery
+	var de = {
+		addListener: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){
+			if(!node){return;} 
+			event = de._normalizeEventName(event)
+			fp = de._fixCallback(event, fp);
+			node.addEventListener(event, fp, false);
+			return fp; /*Handle*/
+		},
+		removeListener: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
+			// summary:
+			//		clobbers the listener from the node
+			// evtName:
+			//		the name of the handler to remove the function from
+			// node:
+			//		DOM node to attach the event to
+			// handle:
+			//		the handle returned from addListener
+			(node)&&(node.removeEventListener(de._normalizeEventName(event), handle, false));
+		},
+		_normalizeEventName: function(/*String*/name){
+			// Generally, name should be lower case, unless it is special
+			// somehow (e.g. a Mozilla DOM event).
+			// Remove 'on'.
+			return (name.slice(0,2)=="on" ? name.slice(2) : name);
+		},
+		_fixCallback: function(/*String*/name, fp){
+			// By default, we only invoke _fixEvent for 'keypress'
+			// If code is added to _fixEvent for other events, we have
+			// to revisit this optimization.
+			// This also applies to _fixEvent overrides for Safari and Opera
+			// below.
+			return (name!="keypress" ? fp : function(e){ return fp.call(this, de._fixEvent(e, this)); });	
+		},
+		_fixEvent: function(evt, sender){
+			// _fixCallback only attaches us to keypress.
+			// Switch on evt.type anyway because we might 
+			// be called directly from dojo.fixEvent.
+			switch(evt.type){
+				case "keypress":
+					de._setKeyChar(evt);
+					break;
+			}
+			return evt;
+		},
+		_setKeyChar: function(evt){
+			evt.keyChar = (evt.charCode ? String.fromCharCode(evt.charCode) : '');
+		}
+	};
+
+	// DOM events
+	
+	// FIXME: no reason to make this public, use connect
+	dojo.addListener = function(node, event, context, method){
+		return de.addListener(node, event, dojo.hitch(context, method)); // Handle
+	}
+
+	// FIXME: no reason to make this public, use disconnect
+	dojo.removeListener = function(node, event, handle){
+		de.removeListener(node, event, handle);
+	}
+
+	dojo.fixEvent = function(/*Event*/evt, /*DOMNode*/sender){
+		// summary:
+		//		normalizes properties on the event object including event
+		//		bubbling methods, keystroke normalization, and x/y positions
+		// evt: native event object
+		// sender: node to treat as "currentTarget"
+		return de._fixEvent(evt, sender);
+	}
+
+	dojo.stopEvent = function(/*Event*/evt){
+		// summary:
+		//		prevents propagation and clobbers the default action of the
+		//		passed event
+		// evt: Optional for IE. The native event object.
+		evt.preventDefault();
+		evt.stopPropagation();
+	}
+
+	// cache baseline implementations
+
+	var dc = dojo._connect;
+	var dd = dojo._disconnect;
+
+	// Unify connect/disconnect and add/removeListener
+	
+	dojo._connect = function(obj, event, context, method, dontFix){
+		// use listener code (event fixing) for nodes that look like objects, unless told not to
+		dontFix = Boolean(!obj || !(obj.nodeType||obj.attachEvent||obj.addEventListener) || dontFix);
+		// grab up the result of baseline disconnect, or construct one using addListener
+		var h = (dontFix ? dc.apply(this, arguments) : [obj, event, dojo.addListener.apply(this, arguments)]);
+		// append flag to the result identifying the kind of listener 
+		h.push(dontFix);
+		return h;
+	}											
+
+	dojo._disconnect = function(obj, event, handle, dontFix){
+		// dispatch this disconnect either to the baseline code or to removeListener
+		(dontFix ? dd : dojo.removeListener).apply(this, arguments);
+	}											
+
+	// Constants
+
+	// Public: client code must test
+	// keyCode against these named constants, as the
+	// actual codes can vary by browser.
+	dojo.keys = {
+		BACKSPACE: 8,
+		TAB: 9,
+		CLEAR: 12,
+		ENTER: 13,
+		SHIFT: 16,
+		CTRL: 17,
+		ALT: 18,
+		PAUSE: 19,
+		CAPS_LOCK: 20,
+		ESCAPE: 27,
+		SPACE: 32,
+		PAGE_UP: 33,
+		PAGE_DOWN: 34,
+		END: 35,
+		HOME: 36,
+		LEFT_ARROW: 37,
+		UP_ARROW: 38,
+		RIGHT_ARROW: 39,
+		DOWN_ARROW: 40,
+		INSERT: 45,
+		DELETE: 46,
+		HELP: 47,
+		LEFT_WINDOW: 91,
+		RIGHT_WINDOW: 92,
+		SELECT: 93,
+		NUMPAD_0: 96,
+		NUMPAD_1: 97,
+		NUMPAD_2: 98,
+		NUMPAD_3: 99,
+		NUMPAD_4: 100,
+		NUMPAD_5: 101,
+		NUMPAD_6: 102,
+		NUMPAD_7: 103,
+		NUMPAD_8: 104,
+		NUMPAD_9: 105,
+		NUMPAD_MULTIPLY: 106,
+		NUMPAD_PLUS: 107,
+		NUMPAD_ENTER: 108,
+		NUMPAD_MINUS: 109,
+		NUMPAD_PERIOD: 110,
+		NUMPAD_DIVIDE: 111,
+		F1: 112,
+		F2: 113,
+		F3: 114,
+		F4: 115,
+		F5: 116,
+		F6: 117,
+		F7: 118,
+		F8: 119,
+		F9: 120,
+		F10: 121,
+		F11: 122,
+		F12: 123,
+		F13: 124,
+		F14: 125,
+		F15: 126,
+		NUM_LOCK: 144,
+		SCROLL_LOCK: 145
+	};
+	
+	// IE event normalization
+	if(dojo.isIE){ 
+		_trySetKeyCode = function(e, code){
+			try{
+				// squelch errors when keyCode is read-only
+				// (e.g. if keyCode is ctrl or shift)
+				return e.keyCode = code;
+			}catch(e){
+				return 0;
+			}
+		}
+
+		var ap = Array.prototype;
+		// by default, use the standard listener
+		var iel = dojo._listener;
+		// dispatcher tracking property
+		if((dojo.isIE<7)&&(!djConfig._allow_leaks)){
+			// custom listener to handle leak protection for DOM events
+			iel = dojo._ie_listener = {
+				// support handler indirection: 
+				// all event handler functions are actually referenced 
+				// here and event dispatchers reference only indices.
+				handlers: [],
+				// add a listener to an object
+				add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
+					source = source || dojo.global;
+					var f = d = source[method];
+					if(!d||!d.listeners){
+						d = source[method] = dojo._getIeDispatcher();
+						// initialize listeners with original event code (or just empty)
+						d.listeners = (f ? [ieh.push(f) - 1] : []);
+					}
+					return d.listeners.push(ieh.push(listener) - 1) ; /*Handle*/
+				},
+				// remove a listener from an object
+				remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
+					var f = (source||dojo.global)[method], l = f&&f.listeners;
+					if(f && l && handle--){	
+						delete ieh[l[handle]];
+						delete l[handle]; 
+					}
+				}
+			};
+			// alias used above
+			var ieh = iel.handlers;
+		}
+
+		dojo.mixin(de, {
+			addListener: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){
+				if(!node){return;} // undefined
+				event = de._normalizeEventName(event);
+				if(event=="onkeypress"){
+					// we need to listen to onkeydown to synthesize 
+					// keypress events that otherwise won't fire
+					// on IE
+					var kd = node.onkeydown;
+					if(!kd||!kd.listeners||!kd._stealthKeydown){
+						// we simply ignore this connection when disconnecting
+						// because it's harmless 
+						de.addListener(node, "onkeydown", de._stealthKeyDown);
+						// we only want one stealth listener per node
+						node.onkeydown._stealthKeydown = true;
+					} 
+				}
+				return iel.add(node, event, de._fixCallback(fp, node));
+			},
+			removeListener: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
+				iel.remove(node, de._normalizeEventName(event), handle); 
+			},
+			_normalizeEventName: function(/*String*/eventName){
+				// Generally, eventName should be lower case, unless it is
+				// special somehow (e.g. a Mozilla event)
+				// ensure 'on'
+				return (eventName.slice(0,2)!="on" ? "on"+eventName : eventName);
+			},
+			_nop: function(){},
+			_fixCallback: function(fp, sender){
+				return function(e){ 
+					return fp.call(this, de._fixEvent(e, sender));
+				};
+			},
+			_fixEvent: function(/*Event*/evt, /*DOMNode*/sender){
+				// summary:
+				//   normalizes properties on the event object including event
+				//   bubbling methods, keystroke normalization, and x/y positions
+				// evt: native event object
+				// sender: node to treat as "currentTarget"
+				if(!evt){
+					var w = (sender)&&((sender.ownerDocument || sender.document || sender).parentWindow)||window;
+					evt = w.event; 
+				}
+				evt.target = evt.srcElement; 
+				evt.currentTarget = (sender || evt.srcElement); 
+				evt.layerX = evt.offsetX;
+				evt.layerY = evt.offsetY;
+				// FIXME: scroll position query is duped from dojo.html to
+				// avoid dependency on that entire module. Now that HTML is in
+				// Base, we should convert back to something similar there.
+				var se = evt.srcElement, doc = (se && se.ownerDocument) || document;
+				// DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used
+				// here rather than document.body
+				var docBody = ((dojo.isIE<6)||(doc["compatMode"]=="BackCompat")) ? doc.body : doc.documentElement;
+				evt.pageX = evt.clientX + (docBody.scrollLeft || 0);
+				evt.pageY = evt.clientY + (docBody.scrollTop || 0);
+				if(evt.type == "mouseover"){ 
+					evt.relatedTarget = evt.fromElement;
+				}
+				if(evt.type == "mouseout"){ 
+					evt.relatedTarget = evt.toElement;
+				}
+				evt.stopPropagation = this._stopPropagation;
+				evt.preventDefault = this._preventDefault;
+				return this._fixKeys(evt);
+			},
+			_fixKeys: function(evt){
+				switch(evt.type){
+					case "keypress":
+						var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
+						if (c==10){
+							// CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
+							c=0;
+							evt.keyCode = 13;
+						}else if(c==13||c==27){
+							c=0; // Mozilla considers ENTER and ESC non-printable
+						}else if(c==3){
+							c=99; // Mozilla maps CTRL-BREAK to CTRL-c
+						}
+						// Mozilla sets keyCode to 0 when there is a charCode
+						// but that stops the event on IE.
+						evt.charCode = c;
+						de._setKeyChar(evt);
+						break;
+				}
+				return evt;
+			},
+			// some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE
+			// we map those virtual key codes to ascii here
+			// not valid for all (non-US) keyboards, so maybe we shouldn't bother
+			_punctMap: { 
+				106:42, 
+				111:47, 
+				186:59, 
+				187:43, 
+				188:44, 
+				189:45, 
+				190:46, 
+				191:47, 
+				192:96, 
+				219:91, 
+				220:92, 
+				221:93, 
+				222:39 
+			},
+			_stealthKeyDown: function(evt){
+				// IE doesn't fire keypress for most non-printable characters.
+				// other browsers do, we simulate it here.
+				var kp=evt.currentTarget.onkeypress;
+				// only works if kp exists and is a dispatcher
+				if(!kp||!kp.listeners)return;
+				// munge key/charCode
+				var k=evt.keyCode;
+				// These are Windows Virtual Key Codes
+				// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
+				var unprintable = (k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);
+				// synthesize keypress for most unprintables and CTRL-keys
+				if(unprintable||evt.ctrlKey){
+					var c = (unprintable ? 0 : k);
+					if(evt.ctrlKey){
+						if(k==3 || k==13){
+							return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively 									
+						}else if(c>95 && c<106){ 
+							c -= 48; // map CTRL-[numpad 0-9] to ASCII
+						}else if((!evt.shiftKey)&&(c>=65&&c<=90)){ 
+							c += 32; // map CTRL-[A-Z] to lowercase
+						}else{ 
+							c = de._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
+						}
+					}
+					// simulate a keypress event
+					var faux = de._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
+					kp.call(evt.currentTarget, faux);
+					evt.cancelBubble = faux.cancelBubble;
+					evt.returnValue = faux.returnValue;
+					_trySetKeyCode(evt, faux.keyCode);
+				}
+			},
+			// Called in Event scope
+			_stopPropagation: function(){
+				this.cancelBubble = true; 
+			},
+			_preventDefault: function(){
+				_trySetKeyCode(this, 0);
+				this.returnValue = false;
+			}
+		});
+				
+		// override stopEvent for IE
+		dojo.stopEvent = function(evt){
+			evt = evt || window.event;
+			de._stopPropagation.call(evt);
+			de._preventDefault.call(evt);
+		}
+	}
+
+	de._synthesizeEvent = function(evt, props) {
+			var faux = dojo.mixin({}, evt, props);
+			de._setKeyChar(faux);
+			// FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault); 
+			// but it throws an error when preventDefault is invoked on Safari
+			// does Event.preventDefault not support "apply" on Safari?
+			faux.preventDefault = function(){ evt.preventDefault(); }; 
+			faux.stopPropagation = function(){ evt.stopPropagation(); }; 
+			return faux;
+	}
+	
+	// Opera event normalization
+	if(dojo.isOpera){
+		dojo.mixin(de, {
+			_fixEvent: function(evt, sender){
+				switch(evt.type){
+					case "keypress":
+						var c = evt.which;
+						if(c==3){
+							c=99; // Mozilla maps CTRL-BREAK to CTRL-c
+						}
+						// can't trap some keys at all, like INSERT and DELETE
+						// there is no differentiating info between DELETE and ".", or INSERT and "-"
+						c = ((c<41)&&(!evt.shiftKey) ? 0 : c);
+						if((evt.ctrlKey)&&(!evt.shiftKey)&&(c>=65)&&(c<=90)){
+							// lowercase CTRL-[A-Z] keys
+							c += 32;
+						}
+						return de._synthesizeEvent(evt, { charCode: c });
+				}
+				return evt;
+			}
+		});
+	}
+
+	// Safari event normalization
+	if(dojo.isSafari){ 
+		dojo.mixin(de, {
+			_fixEvent: function(evt, sender){
+				switch(evt.type){
+					case "keypress":
+						var c = evt.charCode, s = evt.shiftKey;
+						if(evt.keyIdentifier=="Enter"){
+							c = 0; // differentiate Enter from CTRL-m (both code 13)
+						}else if((evt.ctrlKey)&&(c>0)&&(c<27)){
+							c += 96; // map CTRL-[A-Z] codes to ASCII
+						} else if (c==dojo.keys.SHIFT_TAB) {
+							c = dojo.keys.TAB; // morph SHIFT_TAB into TAB + shiftKey: true
+							s = true;
+						} else {
+							c = (c>=32 && c<63232 ? c : 0); // avoid generating keyChar for non-printables
+						}
+						return de._synthesizeEvent(evt, {charCode: c, shiftKey: s});
+				}
+				return evt;
+			}
+		});
+		dojo.mixin(dojo.keys, {
+			SHIFT_TAB: 25,		
+			UP_ARROW: 63232,
+			DOWN_ARROW: 63233,
+			LEFT_ARROW: 63234,
+			RIGHT_ARROW: 63235,
+			F1: 63236,
+			F2: 63237,
+			F3: 63238,
+			F4: 63239,
+			F5: 63240,
+			F6: 63241,
+			F7: 63242,
+			F8: 63243,
+			F9: 63244,
+			F10: 63245,
+			F11: 63246,
+			F12: 63247,
+			PAUSE: 63250,
+			DELETE: 63272,
+			HOME: 63273,
+			END: 63275,
+			PAGE_UP: 63276,
+			PAGE_DOWN: 63277,
+			INSERT: 63302,
+			PRINT_SCREEN: 63248,
+			SCROLL_LOCK: 63249,
+			NUM_LOCK: 63289
+		});
+	}
+})();
+
+if(dojo.isIE<7){
+	// keep this out of the closure
+	// closing over 'iel' or 'ieh' borks leak prevention
+	// ls[i] is an index into the master handler array
+	dojo._getIeDispatcher = function(){
+		return function(){
+			var ap=Array.prototype, ls=arguments.callee.listeners, h=dojo._ie_listener.handlers;
+			for(var i in ls){
+				if(!(i in ap)){
+					h[ls[i]].apply(this, arguments);
+				}
+			}
+		}
+	}
+}
+
+
+dojo.provide("dojo._base.html");
+
+// FIXME: need to add unit tests for all the semi-public methods
+
+try{
+	document.execCommand("BackgroundImageCache", false, true);
+}catch(e){
+	// sane browsers don't have cache "issues"
+}
+
+// =============================
+// DOM Functions
+// =============================
+
+dojo.createElement = function(obj, parent, position){
+	// TODO: need to finish this!
+}
+
+if(dojo.isIE && (dojo.isIE<7)){ // || dojo.isOpera){
+	dojo.byId = function(/*String*/id, /*DocumentElement*/doc){
+		// summary:
+		// 		similar to other library's "$" function, takes a
+		// 		string representing a DOM id or a DomNode and
+		// 		returns the corresponding DomNode. If a Node is
+		// 		passed, this function is a no-op. Returns a
+		// 		single DOM node or null, working around several
+		// 		browser-specific bugs to do so.
+		// id: DOM id or DOM Node
+		// doc:
+		//		optional, defaults to the current value of
+		//		dojo.doc.  Can be used to retreive
+		//		node references from other documents.
+		if(dojo.isString(id)){
+			var _d = (doc||dojo.doc);
+			var te = _d.getElementById(id);
+			if((te) && (te.id == id)){
+				return te;
+			}else{
+				var eles = _d.all[id];
+				if(!eles){ return; }
+				if(!eles.length){ return eles; }
+				// if more than 1, choose first with the correct id
+				var i=0;
+				while(te=eles[i++]){
+					if(te.id == id){ return te; }
+				}
+			}
+		}else{
+			return id; // DomNode
+		}
+	}
+}else{
+	dojo.byId = function(/*String*/id, /*DocumentElement*/doc){
+		// summary:
+		// 		similar to other library's "$" function, takes a
+		// 		string representing a DOM id or a DomNode and
+		// 		returns the corresponding DomNode. If a Node is
+		// 		passed, this function is a no-op. Returns a
+		// 		single DOM node or null, working around several
+		// 		browser-specific bugs to do so.
+		// id: DOM id or DOM Node
+		// doc:
+		//		optional, defaults to the current value of
+		//		dojo.doc.  Can be used to retreive
+		//		node references from other documents.
+		if(dojo.isString(id)){
+			return (doc||dojo.doc).getElementById(id);
+		}else{
+			return id; // DomNode
+		}
+	}
+}
+
+(function(){
+	var _insertBefore = function(/*Node*/node, /*Node*/ref){
+		ref.parentNode.insertBefore(node, ref);
+		return true;	//	boolean
+	}
+
+	var _insertAfter = function(/*Node*/node, /*Node*/ref){
+		//	summary:
+		//		Try to insert node after ref
+		var pn = ref.parentNode;
+		if(ref == pn.lastChild){
+			pn.appendChild(node);
+		}else{
+			return _insertBefore(node, ref.nextSibling);	//	boolean
+		}
+		return true;	//	boolean
+	}
+
+	dojo.place = function(/*DOMNode*/node, /*DOMNode*/refNode, /*String|Number*/position){
+		//	summary:
+		//		attempt to insert node in relation to ref based on position
+
+		// FIXME: need to write tests for this!!!!
+		if((!node)||(!refNode)||(typeof position == "undefined")){ 
+			return false;	//	boolean 
+		}
+		if(typeof position == "number"){
+			var cn = refNode.childNodes;
+			if(((position == 0)&&(cn.length == 0)) ||
+				(cn.length == position)){
+				refNode.appendChild(node); return true;
+			}
+			if(position == 0){
+				return _insertBefore(node, refNode.firstChild);
+			}
+			return _insertAfter(node, cn[position-1]);
+		}
+		switch(position.toLowerCase()){
+			case "before":
+				return _insertBefore(node, refNode);	//	boolean
+			case "after":
+				return _insertAfter(node, refNode);		//	boolean
+			case "first":
+				if(refNode.firstChild){
+					return _insertBefore(node, refNode.firstChild);	//	boolean
+				}else{
+					refNode.appendChild(node);
+					return true;	//	boolean
+				}
+				break;
+			default: // aka: last
+				refNode.appendChild(node);
+				return true;	//	boolean
+		}
+	}
+
+	// Box functions will assume this model.
+	// On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode.
+	// Can be set to change behavior of box setters.
+	
+	// can be either:
+	//	"border-box"
+	//	"content-box" (default)
+	dojo.boxModel = "content-box";
+
+	// We punt per-node box mode testing completely.
+	// If anybody cares, we can provide an additional (optional) unit 
+	// that overrides existing code to include per-node box sensitivity.
+
+	// Opera documentation claims that Opera 9 uses border-box in BackCompat mode.
+	// but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box.
+	// IIRC, earlier versions of Opera did in fact use border-box.
+	// Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault.
+
+	if(dojo.isIE /*|| dojo.isOpera*/){
+		var _dcm = document.compatMode;
+		// client code may have to adjust if compatMode varies across iframes
+		dojo.boxModel = (_dcm=="BackCompat")||(_dcm=="QuirksMode")||(dojo.isIE<6) ? "border-box" : "content-box";
+	}
+
+	// =============================
+	// Style Functions
+	// =============================
+	
+	// getComputedStyle drives most of the style code.
+	// Wherever possible, reuse the returned object.
+	//
+	// API functions below that need to access computed styles accept an 
+	// optional computedStyle parameter.
+	//
+	// If this parameter is omitted, the functions will call getComputedStyle themselves.
+	//
+	// This way, calling code can access computedStyle once, and then pass the reference to 
+	// multiple API functions. 
+	if(!dojo.isIE){
+		// non-IE branch
+		var dv = document.defaultView;
+		dojo.getComputedStyle = ((dojo.isSafari) ? function(node){
+				var s = dv.getComputedStyle(node, null);
+				if(!s){ 
+					node.style.display = ""; 
+					s = dv.getComputedStyle(node, null);
+				}
+				return s;
+			} : function(node){
+				return dv.getComputedStyle(node, null);
+			}
+		)
+
+		dojo._toPixelValue = function(element, value){
+			// style values can be floats, client code may want
+			// to round for integer pixels.
+			return (parseFloat(value) || 0); 
+		}
+	}else{
+		// IE branch
+		dojo.getComputedStyle = function(node){
+			return node.currentStyle;
+		}
+
+		dojo._toPixelValue = function(element, avalue){
+			if(!avalue){return 0;}
+			// style values can be floats, client code may
+			// want to round this value for integer pixels.
+			if(avalue.slice&&(avalue.slice(-2)=='px')){ return parseFloat(avalue); }
+			with(element){
+				var sLeft = style.left;
+				var rsLeft = runtimeStyle.left;
+				runtimeStyle.left = currentStyle.left;
+				try{
+					// 'avalue' may be incompatible with style.left, which can cause IE to throw
+					// this has been observed for border widths using "thin", "medium", "thick" constants
+					// those particular constants could be trapped by a lookup
+					// but perhaps there are more
+					style.left = avalue;
+					avalue = style.pixelLeft;
+				}catch(e){
+					avalue = 0;
+				}
+				style.left = sLeft;
+				runtimeStyle.left = rsLeft;
+			}
+			return avalue;
+		}
+	}
+
+	// FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
+
+	dojo._getOpacity = ((dojo.isIE) ? function(node){
+			try{
+				return (node.filters.alpha.opacity / 100);
+			}catch(e){
+				return 1;
+			}
+		} : function(node){
+			// FIXME: should we get using the computedStyle of the node?
+			return node.style.opacity;
+		}
+	);
+
+	dojo._setOpacity = ((dojo.isIE) ? function(node, opacity){
+			var o = "Alpha(Opacity="+(opacity*100)+")";
+			node.style.filter = o;
+			if(node.nodeName.toLowerCase == "tr"){
+				dojo.query("> td", node).forEach(function(i){
+					i.style.filter = o;
+				});
+			}
+			return opacity;
+		} : function(node, opacity){
+			node.style.opacity = opacity;
+		}
+	);
+
+	var _pixelNamesCache = {
+		width: true, height: true, left: true, top: true
+	};
+	var _toStyleValue = function(node, type, value){
+		if(_pixelNamesCache[type] === true){
+			return dojo._toPixelValue(node, value)
+		}else if(_pixelNamesCache[type] === false){
+			return value;
+		}else{
+			type = type.toLowerCase();
+			if(
+				(type.indexOf("margin") >= 0) ||
+				// (type.indexOf("border") >= 0) ||
+				(type.indexOf("padding") >= 0) ||
+				(type.indexOf("width") >= 0) ||
+				(type.indexOf("height") >= 0) ||
+				(type.indexOf("max") >= 0) ||
+				(type.indexOf("min") >= 0) ||
+				(type.indexOf("offset") >= 0)
+			){
+				_pixelNamesCache[type] = true;
+				return dojo._toPixelValue(node, value)
+			}else{
+				_pixelNamesCache[type] = false;
+				return value;
+			}
+		}
+	}
+
+	// public API
+	
+	dojo.style = function(){
+		var _a = arguments;
+		var _a_l = _a.length;
+		if(!_a_l){ return; }
+		var node = dojo.byId(_a[0]);
+		var io = ((dojo.isIE)&&(_a[1] == "opacity"));
+		if(_a_l == 3){
+			return (io) ? dojo._setOpacity(node, _a[2]) : node.style[_a[1]] = _a[2];
+		}
+		var s = dojo.getComputedStyle(node);
+		if(_a_l == 1){ return s; }
+		if(_a_l == 2){
+			return (io) ? dojo._getOpacity(node) : _toStyleValue(node, _a[1], s[_a[1]]);
+		}
+	}
+
+	// =============================
+	// Box Functions
+	// =============================
+
+	dojo._getPadBounds = function(n, computedStyle){
+		// Returns special values specifically useful 
+		// for node fitting.
+		// l, t = left and top padding
+		// w = the total of the left and right padding 
+		// h = the total of the top and bottom padding
+		// If 'node' has position, l/t forms the origin for child nodes. 
+		// The w/h are used for calculating boxes.
+		// Normally application code will not need to invoke this directly,
+		// and will use the ...box... functions instead.
+		var 
+			s=computedStyle||dojo.getComputedStyle(n), 
+			px=dojo._toPixelValue,
+			l=px(n, s.paddingLeft), 
+			t=px(n, s.paddingTop);
+		return { 
+			l: l,
+			t: t,
+			w: l+px(n, s.paddingRight),
+			h: t+px(n, s.paddingBottom)
+		};
+	}
+	
+	dojo._getPadBorderExtents = function(n, computedStyle){
+		// w = the total of the left/right padding and left/right border
+		// h = the total of the top/bottom padding and top/bottom border
+		// The w/h are used for calculating boxes.
+		// Normally application code will not need to invoke this directly,
+		// and will use the ...box... functions instead.
+		var 
+			s=computedStyle||dojo.getComputedStyle(n), 
+			px=dojo._toPixelValue, 
+			p=dojo._getPadBounds(n, s),
+			bw=(s.borderLeftStyle!='none' ? px(n, s.borderLeftWidth) : 0) + (s.borderRightStyle!='none' ? px(n, s.borderRightWidth) : 0),
+			bh=(s.borderTopStyle!='none' ? px(n, s.borderTopWidth) : 0) + (s.borderBottomStyle!='none' ? px(n, s.borderBottomWidth) : 0);
+		return { 
+			w: p.w + bw,
+			h: p.h + bh
+		};
+	}
+
+	dojo._getMarginExtents = function(n, computedStyle){
+		var 
+			s=computedStyle||dojo.getComputedStyle(n), 
+			px=dojo._toPixelValue;
+		return { 
+			w: px(n, s.marginLeft)+px(n, s.marginRight),
+			h: px(n, s.marginTop)+px(n, s.marginBottom)
+		};
+	}
+
+	// Box getters work in any box context because offsetWidth/clientWidth
+	// are invariant wrt box context
+	//
+	// They do *not* work for display: inline objects that have padding styles
+	// because the user agent ignores padding (it's bogus styling in any case)
+	//
+	// Be careful with IMGs because they are inline or block depending on 
+	// browser and browser mode.
+
+	if (dojo.isMoz) {
+		dojo._getMarginBox = function(node, computedStyle){
+			var s = computedStyle||dojo.getComputedStyle(node);
+			var mb = dojo._getMarginExtents(node, s);
+			return { l:parseFloat(s.left)||0, t:parseFloat(s.top)||0, w: node.offsetWidth + mb.w, h: node.offsetHeight + mb.h };
+		}
+	} else {
+		dojo._getMarginBox = function(node, computedStyle){
+			var mb=dojo._getMarginExtents(node, computedStyle);
+			return { l:node.offsetLeft, t:node.offsetTop, w: node.offsetWidth + mb.w, h: node.offsetHeight + mb.h };
+		}
+	}
+	
+	dojo._getContentBox = function(node, computedStyle){
+		var pb=dojo._getPadBounds(node, computedStyle);
+		return { l: pb.l, t: pb.t, w: node.clientWidth - pb.w, h: node.clientHeight - pb.h };
+	}
+	
+	dojo._setBox = function(node, l, t, w, h, u){
+		u = u || "px";
+		with(node.style){
+			if(!isNaN(l)){ left = l+u; }
+			if(!isNaN(t)){ top = t+u; }
+			if(w>=0){ width = w+u; }
+			if(h>=0){ height = h+u; }
+		}
+	}
+
+	// Box setters depend on box context because interpretation of width/height styles
+	// vary wrt box context.
+	//
+	// The value of dojo.boxModel is used to determine box context.
+	// dojo.boxModel can be set directly to change behavior.
+	//
+	// Beware of display: inline objects that have padding styles
+	// because the user agent ignores padding (it's a bogus setup anyway)
+	//
+	// Be careful with IMGs because they are inline or block depending on 
+	// browser and browser mode.
+	
+	dojo._setContentBox = function(node, leftPx, topPx, widthPx, heightPx, computedStyle){
+		if(dojo.boxModel == "border-box"){
+			var pb = dojo._getPadBorderExtents(node, computedStyle);
+			if(widthPx>=0){ widthPx += pb.w; }
+			if(heightPx>=0){ heightPx += pb.h; }
+		}
+		dojo._setBox(node, leftPx, topPx, widthPx, heightPx);
+	}
+
+	dojo._nilExtents = { w: 0, h: 0 };
+
+	dojo._setMarginBox = function(node, leftPx, topPx, widthPx, heightPx, computedStyle){
+		var s = computedStyle || dojo.getComputedStyle(node);
+		var pb = ((dojo.boxModel == "border-box") ? dojo._nilExtents : dojo._getPadBorderExtents(node, s));
+		var mb = dojo._getMarginExtents(node, s);
+		if(widthPx>=0){
+			widthPx = Math.max(widthPx - pb.w - mb.w, 0);
+		}
+		if(heightPx>=0){
+			heightPx = Math.max(heightPx - pb.h - mb.h, 0);
+		}
+		dojo._setBox(node, leftPx, topPx, widthPx, heightPx);
+	}
+
+	// public API
+	
+	dojo.marginBox = function(node, boxObj){
+		node = dojo.byId(node);
+		var s = dojo.getComputedStyle(node), b=boxObj;
+		return !b ? dojo._getMarginBox(node, s) : dojo._setMarginBox(node, b.l, b.t, b.w, b.h, s);
+	}
+
+	dojo.contentBox = function(node, boxObj){
+		node = dojo.byId(node);
+		var s = dojo.getComputedStyle(node), b=boxObj;
+		return !b ? dojo._getContentBox(node, s) : dojo._setContentBox(node, b.l, b.t, b.w, b.h, s);
+	}
+	
+	// =============================
+	// Positioning 
+	// =============================
+	
+	var _sumAncestorProperties = function(node, prop){
+		if(!node){ return 0; } // FIXME: throw an error?
+		var _b = dojo.body();
+		var retVal = 0;
+		while(node){
+			try{
+				if(dojo.getComputedStyle(node).position == "fixed"){
+					return 0;
+				}
+			}catch(e){}
+			var val = node[prop];
+			if(val){
+				retVal += val - 0;
+				// opera and khtml #body & #html has the same values, we only
+				// need one value
+				if(node == _b){ break; }
+			}
+			node = node.parentNode;
+		}
+		return retVal;	//	integer
+	}
+
+	dojo._docScroll = function(){
+		var _b = dojo.body();
+		var _w = dojo.global;
+		var de = dojo.doc.documentElement;
+		return {
+			y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0),
+			x: (_w.pageXOffset || de.scrollLeft || _b.scrollLeft || 0)
+		};
+	};
+
+	// IE version and quirks dependent. ugg.
+	var _d_off = ((dojo.isIE >= 7)&&(dojo.boxModel != "border-box")) ? 2 : 0; 
+	dojo._abs = function(/*HTMLElement*/node, /*boolean?*/includeScroll){
+		//	summary
+		//		Gets the absolute position of the passed element based on the
+		//		document itself.
+
+		// FIXME: need to decide in the brave-new-world if we're going to be
+		// margin-box or border-box.
+		var ownerDocument = dojo.doc;
+		var ret = {
+			x: 0,
+			y: 0
+		};
+
+		// targetBoxType == "border-box"
+		var db = dojo.body();
+
+		if(dojo.isIE){
+			with(node.getBoundingClientRect()){
+				ret.x = left-_d_off;
+				ret.y = top-_d_off;
+			}
+		}else if(ownerDocument["getBoxObjectFor"]){
+			// mozilla
+			var bo = ownerDocument.getBoxObjectFor(node);
+			ret.x = bo.x - _sumAncestorProperties(node, "scrollLeft");
+			ret.y = bo.y - _sumAncestorProperties(node, "scrollTop");
+		}else{
+			if(node["offsetParent"]){
+				var endNode;
+				// in Safari, if the node is an absolutely positioned child of
+				// the body and the body has a margin the offset of the child
+				// and the body contain the body's margins, so we need to end
+				// at the body
+				if(	(dojo.isSafari) &&
+					(node.style.getPropertyValue("position") == "absolute") &&
+					(node.parentNode == db)){
+					endNode = db;
+				}else{
+					endNode = db.parentNode;
+				}
+
+				if(node.parentNode != db){
+					var nd = node;
+					if(dojo.isOpera){ nd = db; }
+					ret.x -= _sumAncestorProperties(nd, "scrollLeft");
+					ret.y -= _sumAncestorProperties(nd, "scrollTop");
+				}
+				var curnode = node;
+				do{
+					var n = curnode["offsetLeft"];
+					//FIXME: ugly hack to workaround the submenu in 
+					//popupmenu2 does not shown up correctly in opera. 
+					//Someone have a better workaround?
+					if(!dojo.isOpera || n>0){
+						ret.x += isNaN(n) ? 0 : n;
+					}
+					var m = curnode["offsetTop"];
+					ret.y += isNaN(m) ? 0 : m;
+					curnode = curnode.offsetParent;
+				}while((curnode != endNode)&&(curnode != null));
+			}else if(node["x"]&&node["y"]){
+				ret.x += isNaN(node.x) ? 0 : node.x;
+				ret.y += isNaN(node.y) ? 0 : node.y;
+			}
+		}
+
+		// account for document scrolling!
+		if(includeScroll){
+			var scroll = dojo._docScroll();
+			ret.y += scroll.y;
+			ret.x += scroll.x;
+		}
+
+		/*
+		// FIXME
+		var _getMarginExtents = function(node, s){
+			var px = _getPixelizer(node);
+			return { 
+				w: px(s.marginLeft) + px(s.marginRight),
+				h: px(s.marginTop) + px(s.marginBottom)
+			};
+		}
+
+		var _getMarginBox = function(node, computedStyle){
+			var mb = _getMarginExtents(node, computedStyle);
+			return {
+				w: node.offsetWidth + mb.w, 
+				h: node.offsetHeight + mb.h
+			};
+		}
+
+		var extentFuncArray=[dojo.html.getPaddingExtent, dojo.html.getBorderExtent, dojo.html.getMarginExtent];
+		if(nativeBoxType > targetBoxType){
+			for(var i=targetBoxType;i<nativeBoxType;++i){
+				ret.y += extentFuncArray[i](node, 'top');
+				ret.x += extentFuncArray[i](node, 'left');
+			}
+		}else if(nativeBoxType < targetBoxType){
+			for(var i=targetBoxType;i>nativeBoxType;--i){
+				ret.y -= extentFuncArray[i-1](node, 'top');
+				ret.x -= extentFuncArray[i-1](node, 'left');
+			}
+		}
+		*/
+		// ret.t = ret.y;
+		// ret.l = ret.x;
+		return ret;	//	object
+	}
+
+	// FIXME: need a setter for coords or a moveTo!!
+	dojo.coords = function(node, includeScroll){
+		node = dojo.byId(node);
+		var s = dojo.getComputedStyle(node);
+		var mb = dojo._getMarginBox(node, s);
+		var abs = dojo._abs(node, includeScroll);
+		mb.x = abs.x;
+		mb.y = abs.y;
+		return mb;
+	}
+})();
+
+// =============================
+// (CSS) Class Functions
+// =============================
+
+dojo.hasClass = function(/*HTMLElement*/node, /*String*/classStr){
+	//	summary:
+	//		Returns whether or not the specified classes are a portion of the
+	//		class list currently applied to the node. 
+	return ((" "+node.className+" ").indexOf(" "+classStr+" ") >= 0);  // Boolean
+}
+
+dojo.addClass = function(/*HTMLElement*/node, /*String*/classStr){
+	//	summary:
+	//		Adds the specified classes to the end of the class list on the
+	//		passed node.
+	var cls = node.className;
+	if((" "+cls+" ").indexOf(" "+classStr+" ") < 0){
+		node.className = cls + (cls ? ' ' : '') + classStr;
+	}
+}
+
+dojo.removeClass = function(/*HTMLElement*/node, /*String*/classStr){
+	//	summary: Removes classes from node.
+	var cls = node.className;
+	if(cls && cls.indexOf(classStr) >= 0){
+		node.className = cls.replace(new RegExp('(^|\\s+)'+classStr+'(\\s+|$)'), "$1$2");
+	}
+}
+dojo.toggleClass = function(/*HTMLElement*/node, /*String*/classStr, /*Boolean?*/condition){
+	//	summary: 	Adds a class to node if not present, or removes if present.
+	//				Pass a boolean condition if you want to explicitly add or remove.
+	//	condition:	If passed, true means to add the class, false means to remove.
+	if(typeof condition == "undefined"){
+		condition = !dojo.hasClass(node, classStr);
+	}
+	dojo[condition ? "addClass" : "removeClass"](node, classStr);
+}
+
+dojo.provide("dojo._base.NodeList");
+
+
+
+// FIXME: need to provide a location to extend this object!!
+// FIXME: need to write explicit tests for NodeList
+// FIXME: animation?
+// FIXME: what do the builtin's that we deferr to do when you concat? What gets
+// 			returned? Seems (on FF) to be an Array, not a NodeList!
+
+(function(){
+
+	var d = dojo;
+
+	dojo.NodeList = function(){
+		// NodeList constructor...should probably call down to the superclass ctor?
+		// Array.apply(this, arguments);
+
+		// make it behave like the Array constructor
+		if((arguments.length == 1)&&(typeof arguments[0] == "number")){
+			this.length = parseInt(arguments[0]);
+		}else if((arguments.length == 1)&&(arguments[0].constructor == dojo.NodeList)){
+			// FIXME: implement!
+		}else{
+			for(var x=0; x<arguments.length; x++){
+				this.push(arguments[x]);
+			}
+		}
+	}
+	dojo.NodeList.prototype = new Array;
+
+	dojo.extend(dojo.NodeList,
+		{
+			box: function(){
+				// summary:
+				// 		returns a box object for the first element in a node list
+				return dojo.coords(this[0]);
+			},
+
+			boxes: function(){
+				// summary:
+				// 		returns the box objects all elements in a node list as
+				// 		an Array
+				
+				// FIXME: should we just tack a box property onto each element
+				// instead? Also, is this really that useful anyway?
+				var ret = [];
+				this.forEach(function(item){
+					ret.push(dojo.coords(item));
+				});
+				return ret;
+			},
+
+			style: function(prop){
+				// (key, value)
+				// (props, ...)
+				var aa = dojo._toArray(arguments);
+				aa.unshift(this[0]);
+				return dojo.style.apply(dojo, aa);
+			},
+
+			styles: function(prop){
+				// (key, value)
+				// (props, ...)
+				var aa = dojo._toArray(arguments);
+				aa.unshift(null);
+				return this.map(function(i){
+					aa[0] = i;
+					return dojo.style.apply(dojo, aa);
+				});
+			},
+
+			place: function(queryOrNode, /*String*/ position){
+				// summary:
+				//		placement always relative to the first element matched
+				//		by queryOrNode
+				// position:
+				//		can be one of:
+				//			"last"||"end" (default)
+				//			"first||"start"
+				//			"before"
+				//			"after"
+				// 		or an offset in the childNodes property
+				var item = d.query(queryOrNode)[0];
+				position = position||"last";
+
+				for(var x=0; x<this.length; x++){
+					d.place(this[x], item, position);
+				}
+				return this;
+			},
+
+			orphan: function(/*String*/ simpleFilter){
+				// summary:
+				//		removes elements in this list that match the simple
+				//		filter from their parents and returns them as a new
+				//		NodeList.
+				// simpleFilter: single-expression CSS filter
+				var orphans = d._filterQueryResult(this, simpleFilter);
+				orphans.forEach(function(item){
+					if(item["parentNode"]){
+						item.parentNode.removeChild(item);
+					}
+				});
+				return orphans;
+			},
+
+			adopt: function(queryOrListOrNode, /*String*/ position){
+				// summary:
+				//		places any/all elements in queryOrListOrNode at a
+				//		position relative to the first element in this list.
+				// position:
+				//		can be one of:
+				//			"last"||"end" (default)
+				//			"first||"start"
+				//			"before"
+				//			"after"
+				// 		or an offset in the childNodes property
+				var item = this[0];
+				position = position||"last";
+				var adoptees = d.query(queryOrListOrNode);
+
+				for(var x=0; x<adoptees.length; x++){
+					d.place(adoptees[x], item, position);
+				}
+				return adoptees;
+			},
+
+			// may have name changed to "get" if dojo.query becomes dojo.get
+			// FIXME: do we need this?
+			query: function(/*String*/ queryStr){
+				// summary:
+				//		returns a new NodeList. Elements of the new NodeList
+				//		satisfy the passed query but use elements of the
+				//		current NodeList as query roots.
+
+				queryStr = queryStr||"";
+
+				// FIXME: probably slow
+				var ret = new d.NodeList();
+				this.forEach(function(item){
+					d.query(queryStr, item).forEach(function(subItem){
+						if(typeof subItem != "undefined"){
+							ret.push(subItem);
+						}
+					});
+				});
+				return ret;
+			},
+
+			filter: function(/*String*/ simpleQuery){
+				//			(callback, [thisObject])
+				//			(simpleQuery, callback, [thisObject])
+				// "masks" the built-in javascript filter() method to support
+				// passing a simple string filter in addition to supporting
+				// filtering function objects.
+
+				var items = this;
+				var _a = arguments;
+				var r = new d.NodeList();
+				var rp = function(t){ 
+					if(typeof t != "undefined"){
+						r.push(t); 
+					}
+				}
+				if(dojo.isString(simpleQuery)){
+					items = d._filterQueryResult(this, _a[0]);
+					if(_a.length == 1){
+						// if we only got a string query, pass back the filtered results
+						return items;
+					}
+					// if we got a callback, run it over the filtered items
+					d.forEach(d.filter(items, _a[1], _a[2]), rp);
+					return r;
+				}
+				// handle the (callback, [thisObject]) case
+				d.forEach(d.filter(items, _a[0], _a[1]), rp);
+				return r;
+
+			},
+
+			addContent: function(content, position){
+				// position can be one of:
+				//		"last"||"end" (default)
+				//		"first||"start"
+				//		"before"
+				//		"after"
+				// or an offset in the childNodes property
+				var ta = dojo.doc.createElement("span");
+				if(dojo.isString(content)){
+					ta.innerHTML = content;
+				}else{
+					ta.appendChild(content);
+				}
+				var ct = ((position == "first")||(position == "after")) ? "lastChild" : "firstChild";
+				this.forEach(function(item){
+					var tn = ta.cloneNode(true);
+					while(tn[ct]){
+						d.place(tn[ct], item, position);
+					}
+				});
+				// FIXME: what to return!?
+				return this;
+			}
+		}
+	);
+
+	// now, make sure it's an array subclass on IE:
+	// 
+	// huge thanks to Dean Edwards and Hedger Wang for a solution to
+	// subclassing arrays on IE
+	//		http://dean.edwards.name/weblog/2006/11/hooray/?full
+	//		http://www.hedgerwow.com/360/dhtml/js-array2.html
+	if(!Array.forEach){
+		// make sure that it has all the JS 1.6 things we need before we subclass
+		dojo.extend(dojo.NodeList,
+			{
+				// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
+				// must implement the following JS 1.6 methods:
+
+				// FIXME: would it be smaller if we set these w/ iteration?
+				indexOf: function(value, identity){
+					return d.indexOf(this, value, identity);
+				},
+
+				lastIndexOf: function(value, identity){
+					return d.lastIndexOf(this, value, identity);
+				},
+
+				forEach: function(callback, thisObj){
+					return d.forEach(this, callback, thisObj);
+				},
+
+				every: function(callback, thisObj){
+					return d.every(this, callback, thisObj);
+				},
+
+				some: function(callback, thisObj){
+					return d.some(this, callback, thisObj);
+				},
+
+				map: function(unary_func, obj){
+					return d.map(this, unary_func, obj);
+				}
+
+				// NOTE: filter() is handled in NodeList by default
+			}
+		);
+	}
+	if(d.isIE){
+
+		var subClassStr = function(className){
+			return (
+				// "parent.dojo.debug('setting it up...'); " +
+				"var a2 = parent."+className+"; " +
+				"var ap = Array.prototype; " +
+				"var a2p = a2.prototype; " +
+				"for(var x in a2p){ ap[x] = a2p[x]; } " +
+				"parent."+className+" = Array; "
+			);
+		}
+		var scs = subClassStr("dojo.NodeList");
+		// Hedger's excellent invention
+		var popup = window.createPopup()
+		popup.document.write("<script>"+scs+"</script>");
+		// our fix to ensure that we don't hit strange scoping/timing issues
+		// insisde of setTimeout() blocks
+		popup.show(1, 1, 1, 1);
+
+	}
+})();
+
+dojo.provide("dojo._base.query");
+
+
+;(function(){
+	var d = dojo;
+
+	////////////////////////////////////////////////////////////////////////
+	// Utility code
+	////////////////////////////////////////////////////////////////////////
+
+	var _getIndexes = function(q){
+		return [ q.indexOf("#"), q.indexOf("."), q.indexOf("["), q.indexOf(":") ];
+	}
+
+	var _lowestFromIndex = function(query, index){
+		// spammy and verbose, but fast
+		var ql = query.length;
+		var i = _getIndexes(query);
+		var end = ql;
+		for(var x=index; x<i.length; x++){
+			if(i[x] >= 0){
+				if(i[x] < end){
+					end = i[x];
+				}
+			}
+		}
+		return (end < 0) ? ql : end;
+	}
+
+	var getIdEnd = function(query){
+		return _lowestFromIndex(query, 1);
+	}
+
+	var getId = function(query){
+		var i = _getIndexes(query);
+		if(i[0] != -1){
+			return query.substring(i[0]+1, getIdEnd(query));
+		}else{
+			return "";
+		}
+	}
+
+	var getTagNameEnd = function(query){
+		var i = _getIndexes(query);
+		if((i[0] == 0)||(i[1] == 0)){
+			// hash or dot at the front, no tagname
+			return 0;
+		}else{
+			return _lowestFromIndex(query, 0);
+		}
+	}
+
+
+	var getTagName = function(query){
+		var tagNameEnd = getTagNameEnd(query);
+		// FIXME: should this be ">=" to account for tags like <a> ?
+		return ((tagNameEnd > 0) ? query.substr(0, tagNameEnd).toLowerCase() : "*");
+	}
+
+	var smallest = function(arr){
+		var ret = -1;
+		for(var x=0; x<arr.length; x++){
+			var ta = arr[x];
+			if(ta >= 0){
+				if((ta > ret)||(ret == -1)){
+					ret = ta;
+				}
+			}
+		}
+		return ret;
+	}
+
+	var getClassName = function(query){
+		// [ "#", ".", "[", ":" ];
+		var i = _getIndexes(query);
+		if(-1 == i[1]){ return ""; } // no class component
+		var di = i[1]+1;
+
+		var othersStart = smallest(i.slice(2));
+		if(di < othersStart){
+			return query.substring(di, othersStart);
+		}else if(-1 == othersStart){
+			return query.substr(di);
+		}else{
+			return "";
+		}
+	}
+
+	////////////////////////////////////////////////////////////////////////
+	// XPath query code
+	////////////////////////////////////////////////////////////////////////
+
+	var xPathAttrs = [
+		// FIXME: need to re-order in order of likelyness to be used in matches
+		{
+			key: "|=",
+			match: function(attr, value){
+				return "[contains(concat(' ',@"+attr+",' '), ' "+ value +"-')]";
+			}
+		},
+		{
+			key: "~=",
+			match: function(attr, value){
+				return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
+			}
+		},
+		{
+			key: "^=",
+			match: function(attr, value){
+				return "[starts-with(@"+attr+", '"+ value +"')]";
+			}
+		},
+		{
+			key: "*=",
+			match: function(attr, value){
+				return "[contains(@"+attr+", '"+ value +"')]";
+			}
+		},
+		{
+			key: "$=",
+			match: function(attr, value){
+				return "[substring(@"+attr+", string-length(@"+attr+")-"+(value.length-1)+")='"+value+"']";
+			}
+		},
+		{
+			key: "!=",
+			match: function(attr, value){
+				return "[not(@"+attr+"='"+ value +"')]";
+			}
+		},
+		// NOTE: the "=" match MUST come last!
+		{
+			key: "=",
+			match: function(attr, value){
+				return "[@"+attr+"='"+ value +"']";
+			}
+		}
+	];
+
+	var strip = function(val){
+		var re = /^\s+|\s+$/g;
+		return val.replace(re, "");	//	string
+	}
+
+	var handleAttrs = function(	attrList, 
+								query, 
+								getDefault, 
+								handleMatch){
+		var matcher;
+		var i = _getIndexes(query);
+		if(i[2] >= 0){
+			var lBktIdx = query.indexOf("]", i[2]);
+			var condition = query.substring(i[2]+1, lBktIdx);
+			while(condition && condition.length){
+				if(condition.charAt(0) == "@"){
+					condition = condition.slice(1);
+				}
+
+				matcher = null;
+				// http://www.w3.org/TR/css3-selectors/#attribute-selectors
+				for(var x=0; x<attrList.length; x++){
+					var ta = attrList[x];
+					var tci = condition.indexOf(ta.key);
+					if(tci >= 0){
+						var attr = condition.substring(0, tci);
+						var value = condition.substring(tci+ta.key.length);
+						if(	(value.charAt(0) == "\"")||
+							(value.charAt(0) == "\'")){
+							value = value.substring(1, value.length-1);
+						}
+						matcher = ta.match(strip(attr), strip(value));
+						break;
+					}
+				}
+				if((!matcher)&&(condition.length)){
+					matcher = getDefault(condition);
+				}
+				if(matcher){
+					handleMatch(matcher);
+					// ff = agree(ff, matcher);
+				}
+
+				condition = null;
+				var nbktIdx = query.indexOf("[", lBktIdx);
+				if(0 <= nbktIdx){
+					lBktIdx = query.indexOf("]", nbktIdx);
+					if(0 <= lBktIdx){
+						condition = query.substring(nbktIdx+1, lBktIdx);
+					}
+				}
+			}
+		}
+	}
+
+	var buildPath = function(query){
+		var xpath = ".";
+		var qparts = query.split(" "); // FIXME: this break on span[thinger = foo]
+		while(qparts.length){
+			var tqp = qparts.shift();
+			var prefix;
+			// FIXME: need to add support for ~ and +
+			if(tqp == ">"){
+				prefix = "/";
+				// prefix = "/child::node()";
+				tqp = qparts.shift();
+			}else{
+				prefix = "//";
+				// prefix = "/descendant::node()"
+			}
+
+			// get the tag name (if any)
+			var tagName = getTagName(tqp);
+
+			xpath += prefix + tagName;
+			
+			// check to see if it's got an id. Needs to come first in xpath.
+			var id = getId(tqp);
+			if(id.length){
+				xpath += "[@id='"+id+"'][1]";
+			}
+
+			var cn = getClassName(tqp);
+			// check the class name component
+			if(cn.length){
+				var padding = " ";
+				if(cn.charAt(cn.length-1) == "*"){
+					padding = ""; cn = cn.substr(0, cn.length-1);
+				}
+				xpath += 
+					"[contains(concat(' ', at class,' '), ' "+
+					cn + padding + "')]";
+			}
+
+			handleAttrs(xPathAttrs, tqp, 
+				function(condition){
+						return "[@"+condition+"]";
+				},
+				function(matcher){
+					xpath += matcher;
+				}
+			);
+
+			// FIXME: need to implement pseudo-class checks!!
+		};
+		return xpath;
+	};
+
+	var _xpathFuncCache = {};
+	var getXPathFunc = function(path){
+		if(_xpathFuncCache[path]){
+			return _xpathFuncCache[path];
+		}
+
+		var doc = d.doc;
+		// var parent = d.body(); // FIXME
+		// FIXME: don't need to memoize. The closure scope handles it for us.
+		var xpath = buildPath(path);
+		// console.debug(xpath);
+
+		var tf = function(parent){
+			// XPath query strings are memoized.
+			var ret = [];
+			var xpathResult;
+			try{
+				xpathResult = doc.evaluate(xpath, parent, null, 
+												// XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
+												XPathResult.ANY_TYPE, null);
+			}catch(e){
+				console.debug("failure in exprssion:", xpath, "under:", parent);
+				console.debug(e);
+			}
+			var result = xpathResult.iterateNext();
+			while(result){
+				ret.push(result);
+				result = xpathResult.iterateNext();
+			}
+			return ret;
+		}
+		return _xpathFuncCache[path] = tf;
+	};
+
+	/*
+	d.xPathMatch = function(query){
+		// XPath based DOM query system. Handles a small subset of CSS
+		// selectors, subset is identical to the non-XPath version of this
+		// function. 
+
+		// FIXME: need to add support for alternate roots
+		return getXPathFunc(query)();
+	}
+	*/
+
+	////////////////////////////////////////////////////////////////////////
+	// DOM query code
+	////////////////////////////////////////////////////////////////////////
+
+	var _filtersCache = {};
+	var _simpleFiltersCache = {};
+
+	var agree = function(first, second){
+		if(!first){
+			return second;
+		}
+		if(!second){
+			return first;
+		}
+
+		return function(){
+			return first.apply(window, arguments) && second.apply(window, arguments);
+		}
+	}
+
+	var _filterDown = function(element, queryParts, matchArr, idx){
+		var nidx = idx+1;
+		var isFinal = (queryParts.length == nidx);
+		var tqp = queryParts[idx];
+
+		// see if we can constrain our next level to direct children
+		if(tqp == ">"){
+			var ecn = element.childNodes;
+			if(!ecn.length){
+				return;
+			}
+			nidx++;
+			// kinda janky, too much array alloc
+			var isFinal = (queryParts.length == nidx);
+
+			var tf = getFilterFunc(queryParts[idx+1]);
+			for(var x=ecn.length-1, te; x>=0, te=ecn[x]; x--){
+				if(tf(te)){
+					if(isFinal){
+						matchArr.push(te);
+					}else{
+						_filterDown(te, queryParts, matchArr, nidx);
+					}
+				}
+				if(x==0){
+					break;
+				}
+			}
+		}
+
+		// otherwise, keep going down, unless we'er at the end
+		var candidates = getElementsFunc(tqp)(element);
+		if(isFinal){
+			while(candidates.length){
+				matchArr.push(candidates.shift());
+			}
+			/*
+			candidates.unshift(0, matchArr.length-1);
+			matchArr.splice.apply(matchArr, candidates);
+			*/
+		}else{
+			// if we're not yet at the bottom, keep going!
+			while(candidates.length){
+				_filterDown(candidates.shift(), queryParts, matchArr, nidx);
+			}
+		}
+	}
+
+	var filterDown = function(elements, queryParts){
+		ret = [];
+
+		// for every root, get the elements that match the descendant selector
+		// for(var x=elements.length-1, te; x>=0, te=elements[x]; x--){
+		var x=elements.length-1, te;
+		while(te=elements[x--]){
+			_filterDown(te, queryParts, ret, 0);
+		}
+		return ret;
+	}
+
+	var getFilterFunc = function(query){
+		// note: query can't have spaces!
+		if(_filtersCache[query]){
+			return _filtersCache[query];
+		}
+		var ff = null;
+		var tagName = getTagName(query);
+
+		// does it have a tagName component?
+		if(tagName != "*"){
+			// tag name match
+			ff = agree(ff, 
+				function(elem){
+					var isTn = (
+						(elem.nodeType == 1) &&
+						(tagName == elem.tagName.toLowerCase())
+					);
+					return isTn;
+				}
+			);
+		}
+
+		var idComponent = getId(query);
+
+		// does the node have an ID?
+		if(idComponent.length){
+			ff = agree(ff, 
+				function(elem){
+					return (
+						(elem.nodeType == 1) &&
+						(elem.id == idComponent)
+					);
+				}
+			);
+		}
+
+		if(	Math.max.apply(this, _getIndexes(query).slice(1)) >= 0){
+			// if we have other query param parts, make sure we add them to the
+			// filter chain
+			ff = agree(ff, getSimpleFilterFunc(query));
+		}
+
+		return _filtersCache[query] = ff;
+	}
+
+	var getNodeIndex = function(node){
+		// NOTE: we could have a more accurate caching mechanism by
+		// invalidating caches after the query has finished, but I think that'd
+		// lead to significantly more cache churn than the cache would provide
+		// value for in the common case. Generally, we're more conservative
+		// (and therefore, more accurate) than jQuery and DomQuery WRT node
+		// node indexes, but there may be corner cases in which we fall down.
+		// How much we care about them is TBD.
+
+		var pn = node.parentNode;
+		var pnc = pn.childNodes;
+
+		// check to see if we can trust the cache. If not, re-key the whole
+		// thing and return our node match from that.
+
+		var nidx = -1;
+		var child = pn.firstChild;
+		if(!child){
+			return nidx;
+		}
+
+		var ci = node["__cachedIndex"];
+		var cl = pn["__cachedLength"];
+
+		// only handle cache building if we've gone out of sync
+		if(((typeof cl == "number")&&(cl != pnc.length))||(typeof ci != "number")){
+			// rip though the whole set, building cache indexes as we go
+			pn["__cachedLength"] = pnc.length;
+			var idx = 1;
+			do{
+				// we only assign indexes for nodes with nodeType == 1, as per:
+				//		http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
+				// only elements are counted in the search order, and they
+				// begin at 1 for the first child's index
+
+				if(child === node){
+					nidx = idx;
+				}
+				if(child.nodeType == 1){
+					child["__cachedIndex"] = idx;
+					idx++;
+				}
+				child = child.nextSibling;
+			}while(child);
+		}else{
+			// FIXME: could be incorrect in some cases (node swaps involving
+			// the passed node, etc.), but we ignore those for now.
+			nidx = ci;
+		}
+		return nidx;
+	}
+
+	var firedCount = 0;
+
+	var _getAttr = function(elem, attr){
+		var blank = "";
+		if(attr == "class"){
+			return elem.className || blank;
+		}
+		if(attr == "for"){
+			return elem.htmlFor || blank;
+		}
+		return elem.getAttribute(attr, 2) || blank;
+	}
+
+	var attrs = [
+		// FIXME: need to re-order in order of likelyness to be used in matches
+		{
+			key: "|=",
+			match: function(attr, value){
+				// E[hreflang|="en"]
+				//		an E element whose "hreflang" attribute has a
+				//		hyphen-separated list of values beginning (from the
+				//		left) with "en"
+				var valueDash = " "+value+"-";
+				return function(elem){
+					var ea = " "+(elem.getAttribute(attr, 2) || "");
+					return (
+						(ea == value) ||
+						(ea.indexOf(valueDash)==0)
+					);
+				}
+			}
+		},
+		{
+			key: "^=",
+			match: function(attr, value){
+				return function(elem){
+					return (_getAttr(elem, attr).indexOf(value)==0);
+				}
+			}
+		},
+		{
+			key: "*=",
+			match: function(attr, value){
+				return function(elem){
+					return (_getAttr(elem, attr).indexOf(value)>=0);
+				}
+			}
+		},
+		{
+			key: "~=",
+			match: function(attr, value){
+				// return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
+				var tval = " "+value+" ";
+				return function(elem){
+					var ea = " "+_getAttr(elem, attr)+" ";
+					return (ea.indexOf(tval)>=0);
+				}
+			}
+		},
+		{
+			key: "$=",
+			match: function(attr, value){
+				var tval = " "+value;
+				return function(elem){
+					var ea = " "+_getAttr(elem, attr);
+					return (ea.lastIndexOf(value)==(ea.length-value.length));
+				}
+			}
+		},
+		{
+			key: "!=",
+			match: function(attr, value){
+				return function(elem){
+					return (_getAttr(elem, attr) != value);
+				}
+			}
+		},
+		// NOTE: the "=" match MUST come last!
+		{
+			key: "=",
+			match: function(attr, value){
+				return function(elem){
+					return (_getAttr(elem, attr) == value);
+				}
+			}
+		}
+	];
+
+	var pseudos = [
+		{
+			key: "first-child",
+			match: function(name, condition){
+				return function(elem){
+					if(elem.nodeType != 1){ return false; }
+					// check to see if any of the previous siblings are elements
+					var fc = elem.previousSibling;
+					while(fc && (fc.nodeType != 1)){
+						fc = fc.previousSibling;
+					}
+					return (!fc);
+				}
+			}
+		},
+		{
+			key: "last-child",
+			match: function(name, condition){
+				return function(elem){
+					if(elem.nodeType != 1){ return false; }
+					// check to see if any of the next siblings are elements
+					var nc = elem.nextSibling;
+					while(nc && (nc.nodeType != 1)){
+						nc = nc.nextSibling;
+					}
+					return (!nc);
+				}
+			}
+		},
+		{
+			key: "empty",
+			match: function(name, condition){
+				return function(elem){
+					// DomQuery and jQuery get this wrong, oddly enough.
+					// The CSS 3 selectors spec is pretty explicit about
+					// it, too.
+					var cn = elem.childNodes;
+					var cnl = elem.childNodes.length;
+					// if(!cnl){ return true; }
+					for(var x=cnl-1; x >= 0; x--){
+						var nt = cn[x].nodeType;
+						if((nt == 1)||(nt == 3)){ return false; }
+					}
+					return true;
+				}
+			}
+		},
+		{
+			key: "contains",
+			match: function(name, condition){
+				return function(elem){
+					// FIXME: I dislike this version of "contains", as
+					// whimsical attribute could set it off. An inner-text
+					// based version might be more accurate, but since
+					// jQuery and DomQuery also potentially get this wrong,
+					// I'm leaving it for now.
+					return (elem.innerHTML.indexOf(condition) >= 0);
+				}
+			}
+		},
+		{
+			key: "not",
+			match: function(name, condition){
+				var ntf = getFilterFunc(condition);
+				return function(elem){
+					// FIXME: I dislike this version of "contains", as
+					// whimsical attribute could set it off. An inner-text
+					// based version might be more accurate, but since
+					// jQuery and DomQuery also potentially get this wrong,
+					// I'm leaving it for now.
+					return (!ntf(elem));
+				}
+			}
+		},
+		{
+			key: "nth-child",
+			match: function(name, condition){
+				var pi = parseInt;
+				if(condition == "odd"){
+					return function(elem){
+						return (
+							((getNodeIndex(elem)) % 2) == 1
+						);
+					}
+				}else if((condition == "2n")||
+					(condition == "even")){
+					return function(elem){
+						return ((getNodeIndex(elem) % 2) == 0);
+					}
+				}else if(condition.indexOf("0n+") == 0){
+					var ncount = pi(condition.substr(3));
+					return function(elem){
+						return (elem.parentNode.childNodes[ncount-1] === elem);
+					}
+				}else if(	(condition.indexOf("n+") > 0) &&
+							(condition.length > 3) ){
+					var tparts = condition.split("n+", 2);
+					var pred = pi(tparts[0]);
+					var idx = pi(tparts[1]);
+					return function(elem){
+						return ((getNodeIndex(elem) % pred) == idx);
+					}
+				}else if(condition.indexOf("n") == -1){
+					var ncount = pi(condition);
+					return function(elem){
+						return (getNodeIndex(elem) == ncount);
+					}
+				}
+			}
+		}
+	];
+
+	var getSimpleFilterFunc = function(query){
+		// FIXME: this function currently doesn't support chaining of the same
+		// sub-selector. E.g., we can't yet search on 
+		//		span.thinger.thud 
+		// or
+		//		div:nth-child(even):last-child
+
+		var fcHit = (_simpleFiltersCache[query]||_filtersCache[query]);
+		if(fcHit){ return fcHit; }
+
+		var ff = null;
+
+		// [ q.indexOf("#"), q.indexOf("."), q.indexOf("["), q.indexOf(":") ];
+		var i = _getIndexes(query);
+
+		// the only case where we'll need the tag name is if we came from an ID query
+		if(i[0] >= 0){
+			var tn = getTagName(query);
+			if(tn != "*"){
+				ff = agree(ff, function(elem){
+					return (elem.tagName.toLowerCase() == tn);
+				});
+			}
+		}
+
+		var matcher;
+
+		// if there's a class in our query, generate a match function for it
+		var className = getClassName(query);
+		if(className.length){
+			// get the class name
+			var isWildcard = className.charAt(className.length-1) == "*";
+			if(isWildcard){
+				className = className.substr(0, className.length-1);
+			}
+			// I dislike the regex thing, even if memozied in a cache, but it's VERY short
+			var re = new RegExp("(?:^|\\s)" + className + (isWildcard ? ".*" : "") + "(?:\\s|$)");
+			ff = agree(ff, function(elem){
+				return re.test(elem.className);
+			});
+		}
+
+		if(i[3]>= 0){
+			// NOTE: we count on the pseudo name being at the end
+			// FIXME: this is clearly a bug!!!
+			var pseudoName = query.substr(i[3]+1);
+			var condition = "";
+			var obi = pseudoName.indexOf("(");
+			var cbi = pseudoName.lastIndexOf(")");
+			if(	(0 <= obi)&&
+				(0 <= cbi)&&
+				(cbi > obi)){
+				condition = pseudoName.substring(obi+1, cbi);
+				pseudoName = pseudoName.substr(0, obi);
+			}
+
+			// NOTE: NOT extensible on purpose until I figure out
+			// the portable xpath pseudos extensibility plan.
+
+			// http://www.w3.org/TR/css3-selectors/#structural-pseudos
+			matcher = null;
+			for(var x=0; x<pseudos.length; x++){
+				var ta = pseudos[x];
+				if(ta.key == pseudoName){
+					matcher = ta.match(pseudoName, condition);
+					break;
+				}
+			}
+			if(matcher){
+				ff = agree(ff, matcher);
+			}
+		}
+
+		// [ "#", ".", "[", ":" ];
+		var defaultGetter = (d.isIE) ?
+			function(cond){
+				return function(elem){
+					return elem[cond];
+				}
+			} : function(cond){
+				return function(elem){
+					return elem.hasAttribute(cond);
+				}
+			};
+		handleAttrs(attrs, query, defaultGetter,
+			function(tmatcher){
+				ff = agree(ff, tmatcher);
+			}
+		);
+		if(!ff){
+			ff = function(){ return true; };
+		}
+		return _simpleFiltersCache[query] = ff;
+	}
+
+	var isTagOnly = function(query){
+		return (Math.max.apply(this, _getIndexes(query)) == -1);
+	}
+
+	var _getElementsFuncCache = {};
+
+	var getElementsFunc = function(query, root){
+		var fHit = _getElementsFuncCache[query];
+		if(fHit){ return fHit; }
+		// NOTE: this function is in the fast path! not memoized!!!
+
+		// the query doesn't contain any spaces, so there's only so many
+		// things it could be
+		// [ q.indexOf("#"), q.indexOf("."), q.indexOf("["), q.indexOf(":") ];
+		var i = _getIndexes(query);
+		var id = getId(query);
+		if(i[0] == 0){
+			// ID query. Easy.
+			return _getElementsFuncCache[query] = function(root){
+				return [ d.byId(id) ];
+			}
+		}
+
+		var filterFunc = getSimpleFilterFunc(query);
+
+		var retFunc;
+		if(i[0] >= 0){
+			// we got a filtered ID search (e.g., "h4#thinger")
+			retFunc = function(root){
+				var te = d.byId(id);
+				if(filterFunc(te)){
+					return [ te ];
+				}
+			}
+		}else{
+			// var ret = [];
+			var tret;
+			var tn = getTagName(query);
+
+			if(isTagOnly(query)){
+				// it's just a plain-ol elements-by-tag-name query from the root
+				retFunc = function(root){
+					var ret = [];
+					var te, x=0, tret = root.getElementsByTagName(tn);
+					while(te=tret[x++]){
+						ret.push(te);
+					}
+					return ret;
+				}
+			}else{
+				retFunc = function(root){
+					var ret = [];
+					var te, x=0, tret = root.getElementsByTagName(tn);
+					while(te=tret[x++]){
+						if(filterFunc(te)){
+							ret.push(te);
+						}
+					}
+					return ret;
+				}
+			}
+		}
+		return _getElementsFuncCache[query] = retFunc;
+	}
+
+	var _partsCache = {};
+
+	////////////////////////////////////////////////////////////////////////
+	// the query runner
+	////////////////////////////////////////////////////////////////////////
+
+	var _queryFuncCache = {};
+	var getStepQueryFunc = function(query){
+		if(0 > query.indexOf(" ")){
+			return getElementsFunc(query);
+		}
+
+		var sqf = function(root){
+			var qparts = query.split(" "); // FIXME: this is an inaccurate tokenizer!
+
+			/*
+			// FIXME: need to make root popping more explicit and cache it somehow
+
+			// see if we can't pop a root off the front
+			var partIndex = 0;
+			var lastRoot;
+			while((partIndex < qparts.length)&&(0 <= qparts[partIndex].indexOf("#"))){
+				// FIXME: should we try to cache such that the step function
+				// only ever looks for the last ID-based query part, thereby
+				// avoiding re-runs and potential array alloc?
+
+				lastRoot = root;
+				root = getElementsFunc(qparts[partIndex])()[0];
+				if(!root){ root = lastRoot; break; }
+				partIndex++;
+			}
+			// console.debug(qparts[partIndex], root);
+			if(qparts.length == partIndex){
+				return [ root ];
+			}
+			// FIXME: need to handle tight-loop "div div div" style queries
+			// here so as to avoid huge amounts of array alloc in repeated
+			// getElements calls by filterDown
+			var candidates;
+
+			// FIXME: this isn't very generic. It lets us run like a bat outta
+			// hell on queries like:
+			//		div div span
+			// and:
+			//		#thinger span#blah div span span
+			// but we might still fall apart on searches like:
+			//		foo.bar span[blah="thonk"] div div span code.example
+			// in short, we need to move the look-ahead logic into _filterDown()
+			// console.debug(qparts[partIndex]);
+			if( isTagOnly(qparts[partIndex]) && 
+				(qparts[partIndex+1] != ">")
+			){
+				// go as far as we can down the chain without any intermediate
+				// array allocation
+				qparts = qparts.slice(partIndex);
+				var searchParts = [];
+				var idx = 0;
+				while(qparts[idx] && isTagOnly(qparts[idx]) && (qparts[idx+1] != ">" )){
+					searchParts.push(qparts[idx]);
+					idx++;
+				}
+				var curLevelItems = [ root ];
+				var nextLevelItems;
+				for(var x=0; x<searchParts.length; x++){
+					nextLevelItems = [];
+					var tsp = qparts.shift();
+					for(var y=0; y<curLevelItems.length; y++){
+						var tze, z=0, tcol = curLevelItems[y].getElementsByTagName(tsp);
+						while(tze=tcol[z++]){
+							nextLevelItems.push(tze);
+						}
+					}
+					curLevelItems = nextLevelItems;
+				}
+				candidates = curLevelItems;
+				if(!qparts.length){
+					return candidates;
+				}
+			}else{
+				// console.debug(qparts);
+				candidates = getElementsFunc(qparts.shift())(root);
+			}
+			*/
+			var candidates;
+			if(qparts[0] == ">"){
+				candidates = [ root ];
+				root = document;
+			}else{
+				candidates = getElementsFunc(qparts.shift())(root);
+			}
+			return filterDown(candidates, qparts);
+		}
+		return sqf;
+	}
+
+	var _getQueryFunc = (
+		// NOTE: 
+		//		XPath on the Webkit nighlies is slower than it's DOM iteration
+		//		for most test cases
+		// FIXME: 
+		//		we should try to capture some runtime speed data for each query
+		//		function to determine on the fly if we should stick w/ the
+		//		potentially optimized variant or if we should try something
+		//		new.
+		(document["evaluate"] && !d.isSafari) ? 
+		function(query){
+			// has xpath support that's faster than DOM
+			var qparts = query.split(" ");
+			// can we handle it?
+			if(	(document["evaluate"])&&
+				(query.indexOf(":") == -1)&&
+				(
+					(true) // ||
+					// (query.indexOf("[") == -1) ||
+					// (query.indexOf("=") == -1)
+				)
+			){
+				// dojo.debug(query);
+				// should we handle it?
+
+				// var gtIdx = query.indexOf(">")
+
+				// kind of a lame heuristic, but it works
+				if(	
+					// a "div div div" style query
+					((qparts.length > 2)&&(query.indexOf(">") == -1))||
+					// or something else with moderate complexity. kinda janky
+					(qparts.length > 3)||
+					(query.indexOf("[")>=0)||
+					// or if it's a ".thinger" query
+					((1 == qparts.length)&&(0 <= query.indexOf(".")))
+
+				){
+					// use get and cache a xpath runner for this selector
+					return getXPathFunc(query);
+				}
+			}
+
+			// fallthrough
+			return getStepQueryFunc(query);
+		} : getStepQueryFunc
+	);
+	// uncomment to disable XPath for testing and tuning the DOM path
+	// _getQueryFunc = getStepQueryFunc;
+
+	// FIXME: we've got problems w/ the NodeList query()/filter() functions if we go XPath for everything
+
+	// uncomment to disable DOM queries for testing and tuning XPath
+	// _getQueryFunc = getXPathFunc;
+
+	var getQueryFunc = function(query){
+		if(_queryFuncCache[query]){ return _queryFuncCache[query]; }
+		if(0 > query.indexOf(",")){
+			return _queryFuncCache[query] = _getQueryFunc(query);
+		}else{
+			var parts = query.split(", ");
+			var tf = function(root){
+				var pindex = 0; // avoid array alloc for every invocation
+				var ret = [];
+				var tp;
+				while(tp = parts[pindex++]){
+					ret = ret.concat(_getQueryFunc(tp, tp.indexOf(" "))(root));
+				}
+				return ret;
+			}
+			return _queryFuncCache[query] = tf;
+		}
+	}
+
+	/*
+	// experimental implementation of _zip for IE
+	var _zip = function(arr){
+		if(!arr){ return []; }
+		var al = arr.length;
+		if(al < 2){ return arr; }
+		var ret = [arr[0]];
+		var lastIdx = arr[0].sourceIndex;
+		for(var x=1, te; te = arr[x]; x++){
+		// for(var x=1; x<arr.length; x++){
+			var nsi = te.sourceIndex;
+			if(nsi > lastIdx){
+				ret.push(te);
+				lastIdx = nsi;
+			}
+		}
+		return ret;
+	}
+	*/
+
+	// FIXME: 
+	//		Dean's new Base2 uses a system whereby queries themselves note if
+	//		they'll need duplicate filtering. We need to get on that plan!!
+
+	var _zipIdx = 0;
+	var _zip = function(arr){
+		var ret = new d.NodeList();
+		if(!arr){ return ret; }
+		if(arr[0]){
+			ret.push(arr[0]);
+		}
+		if(arr.length < 2){ return ret; }
+		_zipIdx++;
+		arr[0]["_zipIdx"] = _zipIdx;
+		for(var x=1, te; te = arr[x]; x++){
+			if(arr[x]["_zipIdx"] != _zipIdx){ 
+				ret.push(te);
+			}
+			te["_zipIdx"] = _zipIdx;
+		}
+		// FIXME: should we consider stripping these properties?
+		return ret;
+	}
+
+	d.query = function(query, root){
+		// return is always an array
+		// NOTE: elementsById is not currently supported
+		// NOTE: ignores xpath-ish queries for now
+		if(typeof query != "string"){
+			return new d.NodeList(query);
+		}
+		if(typeof root == "string"){
+			root = dojo.byId(root);
+		}
+
+		// FIXME: should support more methods on the return than the stock array.
+		return _zip(getQueryFunc(query)(root||dojo.doc));
+	}
+
+	/*
+	// exposing these was a mistake
+	d.query.attrs = attrs;
+	d.query.pseudos = pseudos;
+	*/
+
+	d._filterQueryResult = function(nodeList, simpleFilter){
+		var tnl = new d.NodeList();
+		var ff = (simpleFilter) ? getFilterFunc(simpleFilter) : function(){ return true; };
+		// dojo.debug(ff);
+		for(var x=0, te; te = nodeList[x]; x++){
+			if(ff(te)){ tnl.push(te); }
+		}
+		return tnl;
+	}
+})();
+
+dojo.provide("dojo._base.xhr");
+
+
+
+
+
+dojo.formToObject = function(/*DOMNode||String*/ formNode){
+	// summary:
+	//		dojo.formToObject returns the values encoded in an HTML form as
+	//		string properties in an object which it then returns. Disabled form
+	//		elements, buttons, and other non-value form elements are skipped.
+	//		Multi-select elements are returned as an array of string values.
+	// description:
+	//		This form:
+	//
+	//			<form id="test_form">
+	//				<input type="text" name="blah" value="blah">
+	//				<input type="text" name="no_value" value="blah" disabled>
+	//				<input type="button" name="no_value2" value="blah">
+	//				<select type="select" multiple name="multi" size="5">
+	//					<option value="blah">blah</option>
+	//					<option value="thud" selected>thud</option>
+	//					<option value="thonk" selected>thonk</option>
+	//				</select>
+	//			</form>
+	//
+	//		yeilds this object structure as the result of a call to
+	//		formToObject():
+	//
+	//			{ 
+	//				blah: "blah",
+	//				multi: [
+	//					"thud",
+	//					"thonk"
+	//				]
+	//			};
+
+	// FIXME: seems that dojo.query needs negation operators!!
+	var ret = {};
+	var iq = "input[type!=file][type!=submit][type!=image][type!=reset][type!=button], select, textarea";
+	dojo.query(iq, formNode).filter(function(node){
+		return (!node.disabled);
+	}).forEach(function(item){
+		var _in = item.name;
+		var type = (item.type||"").toLowerCase();
+		if((type == "radio")||(type == "checkbox")){
+			if(item.checked){ ret[_in] = item.value; }
+		}else if(item.multiple){
+			var ria = ret[_in] = [];
+			dojo.query("option[selected]", item).forEach(function(opt){
+				ria.push(opt.value);
+			});
+		}else{ 
+			ret[_in] = item.value;
+			if(type == "image"){
+				ret[_in+".x"] = ret[_in+".y"] = ret[_in].x = ret[_in].y = 0;
+			}
+		}
+	});
+	return ret;
+}
+
+dojo.objectToQuery = function(/*Object*/ map){
+	// FIXME: need to implement encodeAscii!!
+	var ec = encodeURIComponent;
+	var ret = "";
+	var backstop = {};
+	for(var x in map){
+		if(map[x] != backstop[x]){
+			if(dojo.isArray(map[x])){
+				for(var y=0; y<map[x].length; y++){
+					ret += ec(x) + "=" + ec(map[x][y]) + "&";
+				}
+			}else{
+				ret += ec(x) + "=" + ec(map[x]) + "&";
+			}
+		}
+	}
+	if((ret.length)&&(ret.charAt(ret.length-1)== "&")){
+		ret = ret.substr(0, ret.length-1);
+	}
+	return ret; // string
+}
+
+dojo.formToQuery = function(/*DOMNode||String*/ formNode){
+	// summary:
+	//		return URL-encoded string representing the form passed as either a
+	//		node or string ID identifying the form to serialize
+	return dojo.objectToQuery(dojo.formToObject(formNode)); // string
+}
+
+dojo.formToJson = function(/*DOMNode||String*/ formNode){
+	// summary:
+	//		return a serialized JSON string from a form node or string
+	//		ID identifying the form to serialize
+	return dojo.toJson(dojo.formToObject(formNode)); // string
+}
+
+dojo.queryToObject = function(/*String*/ str){
+	// summary:
+	//		returns an object representing a de-serialized query section of a
+	//		URL. Query keys with multiple values are returned in an array.
+	// description:
+	//		This string:
+	//
+	//			"foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&"
+	//		
+	//		returns this object structure:
+	//
+	//			{
+	//				foo: [ "bar", "baz" ],
+	//				thinger: " spaces =blah",
+	//				zonk: "blarg"
+	//			}
+	//	
+	//		Note that spaces and other urlencoded entities are correctly
+	//		handled.
+
+	// FIXME: should we grab the URL string if we're not passed one?
+	var ret = {};
+	var qp = str.split("&");
+	var dc = decodeURIComponent;
+	dojo.forEach(qp, function(item){
+		if(item.length){
+			var parts = item.split("=");
+			var name = parts.shift();
+			var val = dc(parts.join("="));
+			if(dojo.isString(ret[name])){
+				ret[name] = [ret[name]];
+			}
+			if(dojo.isArray(ret[name])){
+				ret[name].push(val);
+			}else{
+				ret[name] = val;
+			}
+		}
+	});
+	return ret;
+}
+
+/*
+	from refactor.txt:
+
+	all bind() replacement APIs take the following argument structure:
+
+		{
+			url: "blah.html",
+
+			// all below are optional, but must be supported in some form by
+			// every IO API
+			timeout: 1000, // milliseconds
+			handleAs: "text", // replaces the always-wrong "mimetype"
+			content: { 
+				key: "value"
+			},
+
+			// browser-specific, MAY be unsupported
+			sync: true, // defaults to false
+			form: dojo.byId("someForm") 
+		}
+*/
+
+// need to block async callbacks from snatching this thread as the result
+// of an async callback might call another sync XHR, this hangs khtml forever
+// must checked by watchInFlight()
+
+dojo._blockAsync = false;
+
+dojo._contentHandlers = {
+	"text": function(xhr){ return xhr.responseText; },
+	"json": function(xhr){ 
+		console.debug("please consider using a mimetype of text/json-comment-filtered to avoid potential security issues with JSON endpoints");
+		return dojo.fromJson(xhr.responseText);
+	},
+	"json-comment-optional": function(xhr){ 
+		// NOTE: we provide the json-comment-filtered option as one solution to
+		// the "JavaScript Hijacking" issue noted by Fortify and others. It is
+		// not appropriate for all circumstances.
+		var value = xhr.responseText;
+		var cStartIdx = value.indexOf("\/*");
+		var cEndIdx = value.lastIndexOf("*\/");
+		if((cStartIdx == -1)||(cEndIdx == -1)){
+			return dojo.fromJson(xhr.responseText);
+		}
+		return dojo.fromJson(value.substring(cStartIdx+2, cEndIdx));
+	},
+	"json-comment-filtered": function(xhr){ 
+		// NOTE: we provide the json-comment-filtered option as one solution to
+		// the "JavaScript Hijacking" issue noted by Fortify and others. It is
+		// not appropriate for all circumstances.
+		var value = xhr.responseText;
+		var cStartIdx = value.indexOf("\/*");
+		var cEndIdx = value.lastIndexOf("*\/");
+		if((cStartIdx == -1)||(cEndIdx == -1)){
+			// FIXME: throw exception instead?
+			console.debug("your JSON wasn't comment filtered!"); 
+			return "";
+		}
+		return dojo.fromJson(value.substring(cStartIdx+2, cEndIdx));
+	},
+	"javascript": function(xhr){ 
+		// FIXME: try Moz and IE specific eval variants?
+		return dojo.eval(xhr.responseText);
+	},
+	"xml": function(xhr){ 
+		return xhr.responseXML;
+	}
+};
+
+(function(){
+
+	dojo._ioSetArgs = function(/*Object*/args,
+			/*Function*/canceller,
+			/*Function*/okHandler,
+			/*Function*/errHandler){
+		//summary: sets up the Deferred and ioArgs property on the Deferred so it
+		//can be used in an io call.
+		//args:
+		//		The args object passed into the public io call.
+		//canceller:
+		//		The canceller function used for the Deferred object. The function
+		//		will receive one argument, the Deferred object that is related to the
+		//		canceller.
+		//okHandler:
+		//		The first OK callback to be registered with Deferred. It has the opportunity
+		//		to transform the OK response. It will receive one argument -- the Deferred
+		//		object returned from this function.
+		//errHandler:
+		//		The first error callback to be registered with Deferred. It has the opportunity
+		//		to do cleanup on an error. It will receive two arguments: error (the 
+		//		Error object) and dfd, the Deferred object returned from this function.
+
+		var ioArgs = {};
+		ioArgs.args = args;
+
+		//Get values from form if requestd.
+		var formQuery = null;
+		if(args.form){ 
+			var form = dojo.byId(args.form);
+			ioArgs.url = args.url || form.getAttribute("action");
+			formQuery = dojo.formToQuery(form);
+		}else{
+			ioArgs.url = args.url;
+		}
+
+		// set up the query params
+		var qi = ioArgs.url.indexOf("?");
+		var miArgs = [{}];
+		if(qi != -1){ // url-provided params are the baseline
+			miArgs.push(dojo.queryToObject(ioArgs.url.substr(qi+1)));
+			ioArgs.url = ioArgs.url.substr(0, qi);
+		}
+	
+		if(formQuery){
+			// potentially over-ride url-provided params w/ form values
+			miArgs.push(dojo.queryToObject(formQuery));
+		}
+		if(args.content){
+			// stuff in content over-rides what's set by form
+			miArgs.push(args.content);
+		}
+		if(args.preventCache){
+			miArgs.push({"dojo.preventCache": new Date().valueOf()});
+		}
+		ioArgs.query = dojo.objectToQuery(dojo.mixin.apply(null, miArgs));
+	
+		// .. and the real work of getting the deferred in order, etc.
+		ioArgs.ha = args.handleAs || "text";
+		var d = new dojo.Deferred(canceller);
+		d.addCallbacks(okHandler, function(error){
+				return errHandler(error, d);
+		});
+		
+		/*
+		//Support specifying load and error callback functions from the args.
+		//For those callbacks, the "this" object will be the args object.
+		//The load and error callback will get the deferred result value as the
+		//first argument and the ioArgs object as the second argument.
+		var ld = args.load;
+		if(ld && dojo.isFunction(ld)){
+			d.addCallback(function(value){
+				return ld.call(args, value, ioArgs);
+			});
+		}
+		var err = args.error;
+		if(err && dojo.isFunction(err)){
+			d.addErrback(function(value){
+				return err.call(args, value, ioArgs);
+			});
+		}
+		*/
+
+		d.ioArgs = ioArgs;
+	
+		// FIXME: need to wire up the xhr object's abort method to something
+		// analagous in the Deferred
+		return d;
+	
+	}
+
+	var _deferredCancel = function(/*Deferred*/dfd){
+		//summary: canceller function for dojo._ioSetArgs call.
+		
+		dfd.canceled = true;
+		dfd.ioArgs.xhr.abort();
+	}
+	var _deferredOk = function(/*Deferred*/dfd){
+		//summary: okHandler function for dojo._ioSetArgs call.
+		
+		return dojo._contentHandlers[dfd.ioArgs.ha](dfd.ioArgs.xhr);
+	}
+	var _deferError = function(/*Error*/error, /*Deferred*/dfd){
+		//summary: errHandler function for dojo._ioSetArgs call.
+		
+		// dfd.ioArgs.xhr.abort();
+		console.debug("xhr error in:", dfd.ioArgs.xhr);
+		console.debug(error);
+		return error;
+	}
+
+	var _makeXhrDeferred = function(/*Object*/args){
+		//summary: makes the Deferred object for this xhr request.
+		var dfd = dojo._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError);
+		dfd.ioArgs.xhr = dojo._xhrObj();
+		return dfd;
+	}
+
+	// avoid setting a timer per request. It degrades performance on IE
+	// something fierece if we don't use unified loops.
+	var _inFlightIntvl = null;
+	var _inFlight = [];
+	var _watchInFlight = function(){
+		//summary: 
+		//		internal method that checks each inflight XMLHttpRequest to see
+		//		if it has completed or if the timeout situation applies.
+		
+		var now = (new Date()).getTime();
+		// make sure sync calls stay thread safe, if this callback is called
+		// during a sync call and this results in another sync call before the
+		// first sync call ends the browser hangs
+		if(!dojo._blockAsync){
+			dojo.forEach(_inFlight, function(tif, arrIdx){
+				if(!tif){ return; }
+				var dfd = tif.dfd;
+				try{
+					if(!dfd || dfd.canceled || !tif.validCheck(dfd)){
+						_inFlight.splice(arrIdx, 1); return;
+					}
+					if(tif.ioCheck(dfd)){
+						_inFlight.splice(arrIdx, 1); // clean refs
+						tif.resHandle(dfd);
+					}else if(dfd.startTime){
+						//did we timeout?
+						if(dfd.startTime + (dfd.ioArgs.args.timeout||0) < now){
+							//Stop the request.
+							dfd.cancel();
+							_inFlight.splice(arrIdx, 1); // clean refs
+							var err = new Error("timeout exceeded");
+							err.dojoType = "timeout";
+							dfd.errback(err);
+						}
+					}
+				}catch(e){
+					// FIXME: make sure we errback!
+					console.debug(e);
+					dfd.errback(new Error("_watchInFlightError!"));
+				}
+			});
+		}
+
+		if(!_inFlight.length){
+			clearInterval(_inFlightIntvl);
+			_inFlightIntvl = null;
+			return;
+		}
+	}
+
+	dojo._ioWatch = function(/*Deferred*/dfd,
+		/*Function*/validCheck,
+		/*Function*/ioCheck,
+		/*Function*/resHandle){
+		//summary: watches the io request represented by dfd to see if it completes.
+		//dfd:
+		//		The Deferred object to watch.
+		//validCheck:
+		//		Function used to check if the IO request is still valid. Gets the dfd
+		//		object as its only argument.
+		//ioCheck:
+		//		Function used to check if basic IO call worked. Gets the dfd
+		//		object as its only argument.
+		//resHandle:
+		//		Function used to process response. Gets the dfd
+		//		object as its only argument.
+		if(dfd.ioArgs.args.timeout){
+			dfd.startTime = (new Date()).getTime();
+		}
+		_inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle});
+		if(!_inFlightIntvl){
+			_inFlightIntvl = setInterval(_watchInFlight, 50);
+		}
+		_watchInFlight(); // handle sync requests
+	}
+
+	var _defaultContentType = "application/x-www-form-urlencoded";
+
+	var _validCheck = function(/*Deferred*/dfd){
+		return dfd.ioArgs.xhr.readyState; //boolean
+	}
+	var _ioCheck = function(/*Deferred*/dfd){
+		return 4 == dfd.ioArgs.xhr.readyState; //boolean
+	}
+	var _resHandle = function(/*Deferred*/dfd){
+		if(dojo._isDocumentOk(dfd.ioArgs.xhr)){
+			dfd.callback(dfd);
+		}else{
+			dfd.errback(new Error("bad http response code:" + dfd.ioArgs.xhr.status));
+		}
+	}
+
+	var _doIt = function(/*String*/type, /*Deferred*/dfd){
+		// IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open).
+		// workaround for IE6's apply() "issues"
+		var ioArgs = dfd.ioArgs;
+		var args = ioArgs.args;
+		ioArgs.xhr.open(type, ioArgs.url, (args.sync !== true), (args.user ? args.user : undefined), (args.password ? args.password: undefined));
+		// FIXME: is this appropriate for all content types?
+		ioArgs.xhr.setRequestHeader("Content-Type", (args.contentType||_defaultContentType));
+		// FIXME: set other headers here!
+		try{
+			ioArgs.xhr.send(ioArgs.query);
+		}catch(e){
+			// dfd.cancel();
+			ioArgs.cancel();
+		}
+		dojo._ioWatch(dfd, _validCheck, _ioCheck, _resHandle);
+		return dfd; //Deferred
+	}
+
+	// TODOC: FIXME!!!
+
+	dojo.xhrGet = function(/*Object*/ args){
+		var dfd = _makeXhrDeferred(args);
+		var ioArgs = dfd.ioArgs;
+		if(ioArgs.query.length){
+			ioArgs.url += "?" + ioArgs.query;
+			ioArgs.query = null;
+		}
+		return _doIt("GET", dfd); // dojo.Deferred
+	}
+
+	dojo.xhrPost = function(/*Object*/ args){
+		return _doIt("POST", _makeXhrDeferred(args)); // dojo.Deferred
+	}
+
+	dojo.rawXhrPost = function(/*Object*/ args){
+		var dfd = _makeXhrDeferred(args);
+		dfd.ioArgs.query = args.postData;
+		return _doIt("POST", dfd); // dojo.Deferred
+	}
+
+	dojo.wrapForm = function(formNode){
+		// was FormBind
+		// FIXME: waiting on connect
+		// FIXME: need to think harder about what extensions to this we might
+		// want. What should we allow folks to do w/ this? What events to
+		// set/send?
+		throw new Error("dojo.wrapForm not yet implemented");
+	}
+})();
+
+dojo.provide("dojo._base.fx");
+
+
+
+
+
+
+/*
+	Animation losely package based on Dan Pupius' work: 
+		http://pupius.co.uk/js/Toolkit.Drawing.js
+*/
+dojo._Line = function(/*int*/ start, /*int*/ end){
+	// summary: dojo._Line is the object used to generate values
+	//			from a start value to an end value
+	this.start = start;
+	this.end = end;
+	this.getValue = function(/*float*/ n){
+		//	summary: returns the point on the line
+		//	n: a floating point number greater than 0 and less than 1
+		return ((this.end - this.start) * n) + this.start; // Decimal
+	}
+}
+
+dojo.Color = function(/*r, g, b, a*/){
+	this.setColor.apply(this, arguments);
+}
+
+// FIXME: there's got to be a more space-efficient way to encode or discover these!!
+// eugene: let's support at least HTML4 colors (a standard subset of CSS3 color module),
+// we can add the rest later (with compact representation, of course)
+dojo.Color.named = {
+	black:      [0,0,0],
+	silver:     [192,192,192],
+	gray:       [128,128,128],
+	white:      [255,255,255],
+	maroon:		[128,0,0],
+	red:        [255,0,0],
+	purple:		[128,0,128],
+	fuchsia:	[255,0,255],
+	green:	    [0,128,0],
+	lime:	    [0,255,0],
+	olive:		[128,128,0],
+	yellow:		[255,255,0],
+	navy:       [0,0,128],
+	blue:       [0,0,255],
+	teal:		[0,128,128],
+	aqua:		[0,255,255]
+};
+
+dojo.extend(dojo.Color, {
+	// FIXME: implement caching of the RGBA array generation!! It's stupid that we realloc
+	_cache: null,
+	setColor: function(/*r, g, b, a*/){
+		// summary:
+		// 		takes an r, g, b, a(lpha) value, [r, g, b, a] array, "rgb(...)"
+		// 		string, hex string (#aaa, #aaaaaa, aaaaaaa)
+
+		this._cache = [];
+		var d = dojo;
+		var a = arguments;
+		var a0 = a[0];
+		var pmap = (d.isArray(a0) ? a0 : (d.isString(a0) ? d.extractRgb(a0) : d._toArray(a)) );
+		d.forEach(["r", "g", "b", "a"], function(p, i){
+			this._cache[i] = this[p] = parseFloat(pmap[i]);
+		}, this);
+		this._cache[3] = this.a = this.a || 1.0;
+	},
+	toRgb: function(includeAlpha){
+		return this._cache.slice(0, ((includeAlpha) ? 4 : 3));
+	},
+	toRgba: function(){
+		return this._cache.slice(0, 4);
+	},
+	toHex: function(){
+		return dojo.rgb2hex(this.toRgb());
+	},
+	toCss: function(){
+		return "rgb(" + this.toRgb().join(", ") + ")";
+	},
+	toString: function(){
+		return this.toHex(); // decent default?
+	}
+});
+
+dojo.blendColors = function(a, b, weight){
+	// summary: 
+	//		blend colors a and b with weight
+	//		from -1 to +1, 0 being a 50/50 blend
+	if(typeof a == "string"){ a = dojo.extractRgb(a); }
+	if(typeof b == "string"){ b = dojo.extractRgb(b); }
+	if(a["_cache"]){ a = a._cache; }
+	if(b["_cache"]){ b = b._cache; }
+	weight = Math.min(Math.max(-1, (weight||0)), 1);
+
+	// alex: this interface blows.
+	// map -1 to 1 to the range 0 to 1
+	weight = ((weight + 1)/2);
+	
+	var c = [];
+
+	// var stop = (1000*weight);
+	for(var x = 0; x < 3; x++){
+		// console.debug(b[x] + ((a[x] - b[x]) * weight));
+		c[x] = parseInt( b[x] + ( (a[x] - b[x]) * weight) );
+	}
+	return c;
+}
+
+// get RGB array from css-style color declarations
+dojo.extractRgb = function(color){
+	color = color.toLowerCase();
+	if(color.indexOf("rgb") == 0 ){
+		var matches = color.match(/rgba*\((\d+), *(\d+), *(\d+)/i);
+		var ret = dojo.map(matches.splice(1, 3), parseFloat);
+		return ret;
+	}else{
+		return dojo.hex2rgb(color) || dojo.Color.named[color] || [255, 255, 255];
+	}
+}
+
+dojo.hex2rgb = function(hex){
+	var hexNum = "0123456789abcdef";
+	var rgb = new Array(3);
+	if( hex.charAt(0) == "#" ){ hex = hex.substr(1); }
+	hex = hex.toLowerCase();
+	if(hex.replace(new RegExp("["+hexNum+"]", "g"), "") != ""){
+		return null;
+	}
+	if( hex.length == 3 ){
+		rgb[0] = hex.charAt(0) + hex.charAt(0);
+		rgb[1] = hex.charAt(1) + hex.charAt(1);
+		rgb[2] = hex.charAt(2) + hex.charAt(2);
+	}else{
+		rgb[0] = hex.substr(0, 2);
+		rgb[1] = hex.substr(2, 2);
+		rgb[2] = hex.substr(4);
+	}
+	for(var i = 0; i < rgb.length; i++){
+		rgb[i] = hexNum.indexOf(rgb[i].charAt(0)) * 16 + hexNum.indexOf(rgb[i].charAt(1));
+	}
+	return rgb;
+}
+
+dojo.rgb2hex = function(r, g, b){
+	var ret = dojo.map(((r._cache)||((!g) ? r : [r, g, b])), function(x, i){
+		var s = (new Number(x)).toString(16);
+		while(s.length < 2){ s = "0" + s; }
+		return s;
+	});
+	ret.unshift("#");
+	return ret.join("");
+}
+
+//FIXME: _Animation must be a Deferred?
+dojo.declare("dojo._Animation", null,
+	function(/*Object*/ args){
+		//	summary
+		//		a generic animation object that fires callbacks into it's handlers
+		//		object at various states
+		//  FIXME: document args object
+		dojo.mixin(this, args);
+		if(dojo.isArray(this.curve)){
+			/* curve: Array
+			   pId: a */
+			this.curve = new dojo._Line(this.curve[0], this.curve[1]);
+		}
+	},
+	{
+		// public properties
+		curve: null,
+		duration: 1000,
+		easing: null,
+		repeat: 0,
+		rate: 10, // 100 fps
+		delay: null,
+		
+		// events
+		beforeBegin: null,
+		onBegin: null,
+		onAnimate: null,
+		onEnd: null,
+		onPlay: null,
+		onPause: null,
+		onStop: null,
+
+		// private properties
+		_active: false,
+		_paused: false,
+		_startTime: null,
+		_endTime: null,
+		_timer: null,
+		_percent: 0,
+		_startRepeatCount: 0,
+
+		fire: function(/*Event*/ evt, /*Array?*/ args){
+			// summary: Convenience function.  Fire event "evt" and pass it
+			//			the arguments specified in "args".
+			// evt: The event to fire.
+			// args: The arguments to pass to the event.
+			if(this[evt]){
+				this[evt].apply(this, args||[]);
+			}
+			return this; // dojo._Animation
+		},
+		
+		chain: function(/*dojo._Animation[]*/ anims){
+			dojo.forEach(anims, function(anim, i){
+				var prev = (i==0) ? this : anims[i-1];
+				dojo.connect(prev, "onEnd", anim, "play");
+			}, this);
+			return this; // dojo._Animation
+		},
+
+		combine: function(/*dojo._Animation[]*/ anims){
+			dojo.forEach(anims, function(anim){
+				dojo.connect(this, "play", anim, "play");
+			}, this);
+			return this; // dojo._Animation
+		},
+
+		play: function(/*int?*/ delay, /*boolean?*/ gotoStart){
+			// summary: Start the animation.
+			// delay: How many milliseconds to delay before starting.
+			// gotoStart: If true, starts the animation from the beginning; otherwise,
+			//            starts it from its current position.
+			if(gotoStart){
+				clearTimeout(this._timer);
+				this._active = this._paused = false;
+				this._percent = 0;
+			}else if(this._active && !this._paused){
+				return this; // dojo._Animation
+			}
+
+			this.fire("beforeBegin");
+
+			var d = delay||this.delay;
+			if(d > 0){
+				setTimeout(dojo.hitch(this, function(){ this.play(null, gotoStart); }), d);
+				return this; // dojo._Animation
+			}
+		
+			this._startTime = new Date().valueOf();
+			if(this._paused){
+				this._startTime -= this.duration * this._percent;
+			}
+			this._endTime = this._startTime + this.duration;
+
+			this._active = true;
+			this._paused = false;
+		
+			var value = this.curve.getValue(this._percent);
+			if(this._percent == 0){
+				if(!this._startRepeatCount){
+					this._startRepeatCount = this.repeat;
+				}
+				this.fire("onBegin", [value]);
+			}
+
+			this.fire("onPlay", [value]);
+
+			this._cycle();
+			return this; // dojo._Animation
+		},
+
+		pause: function(){
+			// summary: Pauses a running animation.
+			clearTimeout(this._timer);
+			if(!this._active){ return this; /*dojo._Animation*/}
+			this._paused = true;
+			this.fire("onPause", [this.curve.getValue(this._percent)]);
+			return this; // dojo._Animation
+		},
+
+		gotoPercent: function(/*Decimal*/ pct, /*boolean?*/ andPlay){
+			// summary: Sets the progress of the animation.
+			// pct: A percentage in decimal notation (between and including 0.0 and 1.0).
+			// andPlay: If true, play the animation after setting the progress.
+			clearTimeout(this._timer);
+			this._active = this._paused = true;
+			this._percent = pct * 100;
+			if(andPlay){ this.play(); }
+			return this; // dojo._Animation
+		},
+
+		stop: function(/*boolean?*/ gotoEnd){
+			// summary: Stops a running animation.
+			// gotoEnd: If true, the animation will end.
+			clearTimeout(this._timer);
+			if(gotoEnd){
+				this._percent = 1;
+			}
+			this.fire("onStop", [this.curve.getValue(this._percent)]);
+			this._active = this._paused = false;
+			return this; // dojo._Animation
+		},
+
+		status: function(){
+			// summary: Returns a string representation of the status of
+			//			the animation.
+			if(this._active){
+				return this._paused ? "paused" : "playing"; // String
+			}
+			return "stopped"; // String
+		},
+
+		// "private" methods
+		_cycle: function(){
+			clearTimeout(this._timer);
+			if(this._active){
+				var curr = new Date().valueOf();
+				var step = (curr - this._startTime) / (this._endTime - this._startTime);
+
+				if(step >= 1){
+					step = 1;
+				}
+				this._percent = step;
+
+				// Perform easing
+				if(this.easing){
+					step = this.easing(step);
+				}
+
+				this.fire("onAnimate", [this.curve.getValue(step)]);
+
+				if(step < 1){
+					this._timer = setTimeout(dojo.hitch(this, "_cycle"), this.rate);
+				}else{
+					this._active = false;
+
+					if(this.repeat > 0){
+						this.repeat--;
+						this.play(null, true);
+					}else if(this.repeat == -1){
+						this.play(null, true);
+					}else{
+						if(this._startRepeatCount){
+							this.repeat = this._startRepeatCount;
+							this._startRepeatCount = 0;
+						}
+					}
+					this.fire("onEnd");
+				}
+			}
+			return this; // dojo._Animation
+		}
+	}
+);
+
+(function(){
+	var _makeFadeable = function(node){
+		if(dojo.isIE){
+			// only set the zoom if the "tickle" value would be the same as the
+			// default
+			if(node.style.zoom.length == 0 && dojo.style(node, "zoom") == "normal"){
+				// make sure the node "hasLayout"
+				// NOTE: this has been tested with larger and smaller user-set text
+				// sizes and works fine
+				node.style.zoom = "1";
+				// node.style.zoom = "normal";
+			}
+			// don't set the width to auto if it didn't already cascade that way.
+			// We don't want to f anyones designs
+			if(node.style.width.length == 0 && dojo.style(node, "width") == "auto"){
+				node.style.width = "auto";
+			}
+		}
+	}
+
+	dojo._fade = function(/*Object*/ args){
+		// summary:Returns an animation that will fade the "nodes" from the start to end values passed.
+
+		//FIXME: remove arg checking?  Change docs above to show that end is not optional.  Just make sure this blows up in a reliable way?
+		if(typeof args.end == "undefined"){
+			throw new Error("dojo._fade needs an end value");
+		}
+		args.node = dojo.byId(args.node);
+		var fArgs = dojo.mixin({ properties: {} }, args);
+		var props = fArgs.properties.opacity = {};
+		props.start = (typeof fArgs.start == "undefined") ?
+			function(){ return Number(dojo.style(fArgs.node, "opacity")); } : fArgs.start;
+		props.end = fArgs.end;
+
+		var anim = dojo.animateProperty(fArgs);
+		dojo.connect(anim, "beforeBegin", null, function(){
+			_makeFadeable(fArgs.node);
+		});
+
+		return anim; // dojo._Animation
+	}
+
+	dojo.fadeIn = function(/*Object*/ args){
+		// summary: Returns an animation that will fade "nodes" from its current opacity to fully opaque.
+		// nodes: An array of DOMNodes or one DOMNode.
+		// duration: Duration of the animation in milliseconds.
+		// easing: An easing function.
+		return dojo._fade(dojo.mixin({ end: 1 }, args)); // dojo._Animation
+	}
+
+	dojo.fadeOut = function(/*Object*/ args){
+		// summary: Returns an animation that will fade "nodes" from its current opacity to fully transparent.
+		// nodes: An array of DOMNodes or one DOMNode.
+		// duration: Duration of the animation in milliseconds.
+		// easing: An easing function.
+		return dojo._fade(dojo.mixin({ end: 0 }, args)); // dojo._Animation
+	}
+
+	if(dojo.isKhtml && !dojo.isSafari){
+		// the cool kids are obviously not using konqueror...
+		// found a very wierd bug in floats constants, 1.5 evals as 1
+		// seems somebody mixed up ints and floats in 3.5.4 ??
+		// FIXME: investigate more and post a KDE bug (Fredrik)
+		dojo._defaultEasing = function(/*Decimal?*/ n){
+			//	summary: Returns the point for point n on a sin wave.
+			return parseFloat("0.5")+((Math.sin((n+parseFloat("1.5")) * Math.PI))/2); //FIXME: Does this still occur in the supported Safari version?
+		}
+	}else{
+		dojo._defaultEasing = function(/*Decimal?*/ n){
+			return 0.5+((Math.sin((n+1.5) * Math.PI))/2);
+		}
+	}
+
+	dojo.animateProperty = function(/*Object*/ args){
+		// summary: Returns an animation that will transition the properties of "nodes"
+		//			depending how they are defined in "propertyMap".
+		args.node = dojo.byId(args.node);
+		if (!args.easing){ args.easing = dojo._defaultEasing; }
+		
+		var PropLine = function(properties){
+			this._properties = properties;
+			for (var p in properties){
+				var prop = properties[p];
+				// calculate the end - start to optimize a bit
+				if(dojo.isFunction(prop.start)){
+					prop.start = prop.start(prop);
+				}
+				if(dojo.isFunction(prop.end)){
+					prop.end = prop.end(prop);
+				}
+				/*
+				if(prop.start instanceof dojo.Color){
+					// save these so we don't have to call toRgb() every getValue() call
+					prop.startRgb = prop.start.toRgb();
+					prop.endRgb = prop.end.toRgb();
+				}
+				*/
+			}
+			this.getValue = function(n){
+				var ret = {};
+				for(var p in this._properties){
+					var prop = this._properties[p];
+					var value = null;
+					if(prop.start instanceof dojo.Color){
+						value = dojo.rgb2hex(dojo.blendColors(prop.end, prop.start, n));
+						// value = "rbg("+dojo.blendColors(prop.end, prop.start, n).join(",")+")";
+					}else if(!dojo.isArray(prop.start)){
+						value = ((prop.end - prop.start) * n) + prop.start + (p != "opacity" ? prop.units||"px" : "");
+					}
+					ret[p] = value;
+				}
+				return ret;
+			}
+		}
+		
+		var anim = new dojo._Animation(args);
+		dojo.connect(anim, "beforeBegin", anim, function(){
+			var pm = this.properties;
+			for(var p in pm){
+				var prop = pm[p];
+
+				if(dojo.isFunction(prop.start)){
+					prop.start = prop.start();
+				}
+				if(dojo.isFunction(prop.end)){
+					prop.end = prop.end();
+				}
+
+				var isColor = (p.toLowerCase().indexOf("color") >= 0);
+				if(typeof prop.end == "undefined"){
+					prop.end = dojo.style(this.node, p);
+				}else if(typeof prop.start == "undefined"){
+					prop.start = dojo.style(this.node, p);
+				}
+
+				if(isColor){
+					// console.debug("it's a color!");
+					prop.start = new dojo.Color(prop.start);
+					prop.end = new dojo.Color(prop.end);
+				}else{
+					prop.start = (p == "opacity") ? Number(prop.start) : parseInt(prop.start);
+				}
+				// console.debug("start:", prop.start);
+				// console.debug("end:", prop.end);
+			}
+			this.curve = new PropLine(pm);
+		});
+		dojo.connect(anim, "onAnimate", anim, function(propValues){
+			// try{
+			for(var s in propValues){
+				// console.debug(s, propValues[s], this.node.style[s]);
+				dojo.style(this.node, s, propValues[s]);
+				// this.node.style[s] = propValues[s];
+			}
+			// }catch(e){ console.debug(dojo.toJson(e)); }
+		});
+
+		return anim; // dojo._Animation
+	}
+})();
+

Added: trunk/examples/typeface/root/static/dojo/dojo/fx.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/fx.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/fx.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,136 @@
+dojo.provide("dojo.fx");
+
+dojo.fx.chain = function(/*Array*/ anims){
+	var first = anims.shift();
+	return first.chain(anims);
+}
+
+dojo.fx.combine = function(/*Array*/ anims){
+	var first = anims.shift();
+	return first.combine(anims);
+}
+
+dojo.fx.slideIn = function(/*Object*/ args){
+	// summary: Returns an animation that will show and wipe in "nodes".
+	// nodes: An array of DOMNodes or one DOMNode.
+	// duration: Duration of the animation in milliseconds.
+	// easing: An easing function.
+	args.node = dojo.byId(args.node);
+
+	// get node height, either it's natural height or it's height specified via style or class attributes
+	// (for FF, the node has to be (temporarily) rendered to measure height)
+	var anim = dojo.animateProperty(dojo.mixin({
+		properties: {
+			height: {
+				start: 1 // 0 causes IE to display the whole panel
+			}
+		},
+		oprop: {}
+	}, args));
+	dojo.connect(anim, "beforeBegin", anim, function(){
+		var node = this.node;
+		var s = this.node.style;
+		s.visibility="hidden";
+		s.display="";
+
+		//		var nodeHeight = dojo.html.getBorderBox(node).height;
+		//FIXME: ok to use contentbox?
+		var nodeHeight = dojo.contentBox(node).h;
+
+		s.visibility="";
+		s.display="none";
+		this.properties.height.end = nodeHeight;
+
+		var oprop = this.oprop;
+		oprop.overflow = s.overflow;
+		oprop.height = s.height;
+		s.overflow = "hidden";
+		s.height = "1px"; // 0 causes IE to display the whole panel
+		dojo.style(this.node, 'display', '');
+	});
+	
+	dojo.connect(anim, "onEnd", anim, function(){ 
+		var s = this.node.style;
+		var oprop = this.oprop;
+		s.overflow = oprop.overflow;
+		s.height = oprop.height;
+	});
+
+	return anim; // dojo._Animation
+}
+
+dojo.fx.slideOut = function(/*Object*/ args){
+	// summary: Returns an animation that will wipe out and hide "nodes".
+	// nodes: An array of DOMNodes or one DOMNode.
+	// duration: Duration of the animation in milliseconds.
+	// easing: An easing function.
+	var node = args.node = dojo.byId(args.node);
+
+	var oprop = {};	// old properties of node (before we mucked w/them)
+	var anim = dojo.animateProperty(dojo.mixin({
+		properties: {
+			height: {
+				start: function(){ return dojo.contentBox(node).h; }, //FIXME: why a closure here?
+				end: 1 // 0 causes IE to display the whole panel
+			}
+		},
+		oprop: oprop
+	}, args));
+	dojo.connect(anim, "beforeBegin", anim, function(){
+		var s=node.style;
+		oprop.overflow = s.overflow;
+		oprop.height = s.height;
+		s.overflow = "hidden";
+		dojo.style(node, 'display', '');
+	});
+	dojo.connect(anim, "onEnd", anim, function(){
+		dojo.style(this.node, 'display', 'none');
+		var s=this.node.style;
+		s.overflow = oprop.overflow;
+		s.height = oprop.height;
+	});
+
+	return anim; // dojo._Animation
+}
+
+dojo.fx.slideTo = function(/*Object?*/ args){
+	// summary: Returns an animation that will slide "nodes" from its current position to
+	//			the position defined in "coords".
+	// nodes: An array of DOMNodes or one DOMNode.
+	// coords: { top: Decimal?, left: Decimal? }
+	var node = args.node = dojo.byId(args.node);
+	var compute = dojo.getComputedStyle;
+	
+	var top = null;
+	var left = null;
+	
+	var init = (function(){
+		var innerNode = node;
+		return function(){
+			var pos = compute(innerNode).position;
+			top = (pos == 'absolute' ? node.offsetTop : parseInt(compute(node).top) || 0);
+			left = (pos == 'absolute' ? node.offsetLeft : parseInt(compute(node).left) || 0);
+
+			if(pos != 'absolute' && pos != 'relative'){
+				var ret = dojo.coords(innerNode, true);
+				top = ret.y;
+				left = ret.x;
+				innerNode.style.position="absolute";
+				innerNode.style.top=top+"px";
+				innerNode.style.left=left+"px";
+			}
+		}
+	})();
+	init();
+
+	var anim = dojo.animateProperty(dojo.mixin({
+		properties: {
+			top: { start: top, end: args.top||0 },
+			left: { start: left, end: args.left||0 }
+		}
+	}, args));
+	dojo.connect(anim, "beforeBegin", anim, init);
+
+	return anim; // dojo._Animation
+}
+

Added: trunk/examples/typeface/root/static/dojo/dojo/i18n.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/i18n.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/i18n.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,248 @@
+dojo.provide("dojo.i18n");
+
+dojo.i18n.getLocalization = function(/*String*/packageName, /*String*/bundleName, /*String?*/locale){
+//	summary:
+//		Returns an Object containing the localization for a given resource bundle
+//		in a package, matching the specified locale.
+//
+//	description:
+//		Returns a hash containing name/value pairs in its prototypesuch that values can be easily overridden.
+//		Throws an exception if the bundle is not found.
+//		Bundle must have already been loaded by dojo.requireLocalization() or by a build optimization step.
+//
+//	packageName: package which is associated with this resource
+//	bundleName: the base filename of the resource bundle (without the ".js" suffix)
+//	locale: the variant to load (optional).  By default, the locale defined by the
+//		host environment: dojo.locale
+
+	dojo.i18n._preloadLocalizations();
+	locale = dojo.i18n.normalizeLocale(locale);
+
+	// look for nearest locale match
+	var elements = locale.split('-');
+	var module = [packageName,"nls",bundleName].join('.');
+	var bundle = dojo._loadedModules[module];
+	if(bundle){
+		var localization;
+		for(var i = elements.length; i > 0; i--){
+			var loc = elements.slice(0, i).join('_');
+			if(bundle[loc]){
+				localization = bundle[loc];
+				break;
+			}
+		}
+		if(!localization){
+			localization = bundle.ROOT;
+		}
+
+		// make a singleton prototype so that the caller won't accidentally change the values globally
+		if(localization){
+			var clazz = function(){};
+			clazz.prototype = localization;
+			return new clazz(); // Object
+		}
+	}
+
+	throw new Error("Bundle not found: " + bundleName + " in " + packageName+" , locale=" + locale);
+};
+
+dojo.i18n.normalizeLocale = function(/*String?*/locale){
+	//	summary:
+	//		Returns canonical form of locale, as used by Dojo.
+	//
+	//  description:
+	//		All variants are case-insensitive and are separated by '-' as specified in RFC 3066.
+	//		If no locale is specified, the dojo.locale is returned.  dojo.locale is defined by
+	//		the user agent's locale unless overridden by djConfig.
+
+	var result = locale ? locale.toLowerCase() : dojo.locale;
+	if(result == "root"){
+		result = "ROOT";
+	}
+	return result; // String
+};
+
+dojo.i18n._requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){
+	// summary:
+	//	See dojo.requireLocalization()
+	//
+	// description:
+	//  Called by the bootstrap, but factored out so that it is only included in the build when needed.
+
+	dojo.i18n._preloadLocalizations();
+	var targetLocale = dojo.i18n.normalizeLocale(locale);
+ 	var bundlePackage = [moduleName, "nls", bundleName].join(".");
+	// NOTE: 
+	//		When loading these resources, the packaging does not match what is
+	//		on disk.  This is an implementation detail, as this is just a
+	//		private data structure to hold the loaded resources.  e.g.
+	//		tests/hello/nls/en-us/salutations.js is loaded as the object
+	//		tests.hello.nls.salutations.en_us={...} The structure on disk is
+	//		intended to be most convenient for developers and translators, but
+	//		in memory it is more logical and efficient to store in a different
+	//		order.  Locales cannot use dashes, since the resulting path will
+	//		not evaluate as valid JS, so we translate them to underscores.
+	
+	//Find the best-match locale to load if we have available flat locales.
+	var bestLocale = "";
+	if(availableFlatLocales){
+		var flatLocales = availableFlatLocales.split(",");
+		for(var i = 0; i < flatLocales.length; i++){
+			//Locale must match from start of string.
+			if(targetLocale.indexOf(flatLocales[i]) == 0){
+				if(flatLocales[i].length > bestLocale.length){
+					bestLocale = flatLocales[i];
+				}
+			}
+		}
+		if(!bestLocale){
+			bestLocale = "ROOT";
+		}		
+	}
+
+	//See if the desired locale is already loaded.
+	var tempLocale = availableFlatLocales ? bestLocale : targetLocale;
+	var bundle = dojo._loadedModules[bundlePackage];
+	var localizedBundle = null;
+	if(bundle){
+		if(djConfig.localizationComplete && bundle._built){return;}
+		var jsLoc = tempLocale.replace(/-/g, '_');
+		var translationPackage = bundlePackage+"."+jsLoc;
+		localizedBundle = dojo._loadedModules[translationPackage];
+	}
+
+	if(!localizedBundle){
+		bundle = dojo["provide"](bundlePackage);
+		var syms = dojo._getModuleSymbols(moduleName);
+		var modpath = syms.concat("nls").join("/");
+		var parent;
+
+		dojo.i18n._searchLocalePath(tempLocale, availableFlatLocales, function(loc){
+			var jsLoc = loc.replace(/-/g, '_');
+			var translationPackage = bundlePackage + "." + jsLoc;
+			var loaded = false;
+			if(!dojo._loadedModules[translationPackage]){
+				// Mark loaded whether it's found or not, so that further load attempts will not be made
+				dojo["provide"](translationPackage);
+				var module = [modpath];
+				if(loc != "ROOT"){module.push(loc);}
+				module.push(bundleName);
+				var filespec = module.join("/") + '.js';
+				loaded = dojo._loadPath(filespec, null, function(hash){
+					// Use singleton with prototype to point to parent bundle, then mix-in result from loadPath
+					var clazz = function(){};
+					clazz.prototype = parent;
+					bundle[jsLoc] = new clazz();
+					for(var j in hash){ bundle[jsLoc][j] = hash[j]; }
+				});
+			}else{
+				loaded = true;
+			}
+			if(loaded && bundle[jsLoc]){
+				parent = bundle[jsLoc];
+			}else{
+				bundle[jsLoc] = parent;
+			}
+			
+			if(availableFlatLocales){
+				//Stop the locale path searching if we know the availableFlatLocales, since
+				//the first call to this function will load the only bundle that is needed.
+				return true;
+			}
+		});
+	}
+
+	//Save the best locale bundle as the target locale bundle when we know the
+	//the available bundles.
+	if(availableFlatLocales && targetLocale != bestLocale){
+		bundle[targetLocale.replace(/-/g, '_')] = bundle[bestLocale.replace(/-/g, '_')];
+	}
+};
+
+(function(){
+	// If other locales are used, dojo.requireLocalization should load them as
+	// well, by default. 
+	// 
+	// Override dojo.requireLocalization to do load the default bundle, then
+	// iterate through the extraLocale list and load those translations as
+	// well, unless a particular locale was requested.
+
+	var extra = djConfig.extraLocale;
+	if(extra){
+		if(!extra instanceof Array){
+			extra = [extra];
+		}
+
+		var req = dojo.i18n._requireLocalization;
+		dojo.i18n._requireLocalization = function(m, b, locale, availableFlatLocales){
+			req(m,b,locale, availableFlatLocales);
+			if(locale){return;}
+			for(var i=0; i<extra.length; i++){
+				req(m,b,extra[i], availableFlatLocales);
+			}
+		};
+	}
+})();
+
+dojo.i18n._searchLocalePath = function(/*String*/locale, /*Boolean*/down, /*Function*/searchFunc){
+	//	summary:
+	//		A helper method to assist in searching for locale-based resources.
+	//		Will iterate through the variants of a particular locale, either up
+	//		or down, executing a callback function.  For example, "en-us" and
+	//		true will try "en-us" followed by "en" and finally "ROOT".
+
+	locale = dojo.i18n.normalizeLocale(locale);
+
+	var elements = locale.split('-');
+	var searchlist = [];
+	for(var i = elements.length; i > 0; i--){
+		searchlist.push(elements.slice(0, i).join('-'));
+	}
+	searchlist.push(false);
+	if(down){searchlist.reverse();}
+
+	for(var j = searchlist.length - 1; j >= 0; j--){
+		var loc = searchlist[j] || "ROOT";
+		var stop = searchFunc(loc);
+		if(stop){ break; }
+	}
+};
+
+//These properties/functions are placed outside of _preloadLocalizations
+//So that the xd loading can use/override them.
+dojo.i18n._localesGenerated /***BUILD:localesGenerated***/; // value will be inserted here at build time, if necessary
+dojo.i18n.registerNlsPath = function(){
+	//summary; registers nls path. Defined as a function so xd loading
+	//can redefine it.
+	dojo.registerModulePath("nls","nls");		
+}
+
+dojo.i18n._preloadLocalizations = function(){
+	// summary:
+	//		Load built, flattened resource bundles, if available for all
+	//		locales used in the page. Execute only once. Note that this is a
+	//		no-op unless there is a build.
+
+	if(dojo.i18n._localesGenerated){
+		dojo.i18n.registerNlsPath();	
+
+		function preload(locale){
+			locale = dojo.i18n.normalizeLocale(locale);
+			dojo.i18n._searchLocalePath(locale, true, function(loc){
+				for(var i=0; i<dojo.i18n._localesGenerated.length;i++){
+					if(dojo.i18n._localesGenerated[i] == loc){
+						dojo["require"]("nls.dojo_"+loc);
+						return true; // Boolean
+					}
+				}
+				return false; // Boolean
+			});
+		}
+		preload();
+		var extra = djConfig.extraLocale||[];
+		for(var i=0; i<extra.length; i++){
+			preload(extra[i]);
+		}
+	}
+	dojo.i18n._preloadLocalizations = function(){};
+};

Added: trunk/examples/typeface/root/static/dojo/dojo/io/script.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/io/script.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/io/script.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,167 @@
+dojo.provide("dojo.io.script");
+
+dojo.io.script = {
+	get: function(/*Object*/args){
+		//summary: sends a get request using a dynamically created script tag.
+		//TODOC: valid arguments.
+		var dfd = this._makeScriptDeferred(args);
+		var ioArgs = dfd.ioArgs;
+		if(ioArgs.query.length){
+			ioArgs.url += "?" + ioArgs.query;
+		}
+
+		this.attach(ioArgs.id, ioArgs.url);
+		dojo._ioWatch(dfd, this._validCheck, this._ioCheck, this._resHandle);
+		return dfd;
+	},
+
+	attach: function(/*String*/id, /*String*/url){
+		//Attaches the script element to the DOM.
+		//Use this method if you just want to attach a script to the
+		//DOM and do not care when or if it loads.
+		var element = document.createElement("script");
+		element.type = "text/javascript";
+		element.src = url;
+		element.id = id;
+		document.getElementsByTagName("head")[0].appendChild(element);
+	},
+
+	remove: function(/*String*/id){
+		//summary: removes the script element with the given id.
+		//FIXME: Convert to destroyNode function if/when it exists?
+		var node = dojo.byId(id);
+		if(node && node.parentNode){
+			node.parentNode.removeChild(node);
+		}
+		if(dojo.isIE){
+			node.outerHTML=''; //prevent ugly IE mem leak associated with Node.removeChild (ticket #1727)
+		}
+	},
+
+	_makeScriptDeferred: function(/*Object*/args){
+		//summary: sets up the Deferred object for script request.
+		var dfd = dojo._ioSetArgs(args, this._deferredCancel, this._deferredOk, this._deferredError);
+
+		var ioArgs = dfd.ioArgs;
+		ioArgs.id = "dojoIoScript" + (this._counter++);
+		ioArgs.canDelete = false;
+
+		//Special setup for jsonp case
+		if(args.jsonpParam){
+			//Add the jsonp parameter.
+			ioArgs.query = ioArgs.query || "";
+			if(ioArgs.query.length > 0){
+				ioArgs.query += "&";
+			}
+			ioArgs.query += args.jsonpParam + "=dojo.io.script.jsonp_" + ioArgs.id + "._jsonpCallback";
+
+			//Setup the Deferred to have the jsonp callback.
+			ioArgs.canDelete = true;
+			dfd._jsonpCallback = this._jsonpCallback;
+			this["jsonp_" + ioArgs.id] = dfd;
+		}
+		return dfd;
+	},
+	
+	_deferredCancel: function(/*Deferred*/td){
+		//summary: canceller function for dojo._ioSetArgs call.
+
+		//DO NOT use "this" and expect it to be dojo.io.script.
+		td.canceled = true;
+		if(td.ioArgs.canDelete){
+			dojo.io.script._deadScripts.push(td.ioArgs.id);
+		}
+	},
+
+	_deferredOk: function(/*Deferred*/dfd){
+		//summary: okHandler function for dojo._ioSetArgs call.
+
+		//DO NOT use "this" and expect it to be dojo.io.script.
+		if(dfd.ioArgs.json){
+			//Make sure to *not* remove the json property from the
+			//Deferred, so that the Deferred can still function correctly
+			//after the response is received.
+			return dfd.ioArgs.json;
+		}else{
+			//FIXME: cannot return the dfd here, otherwise that stops
+			//the callback chain in Deferred. So return the ioArgs instead.
+			//This doesn't feel right.
+			return dfd.ioArgs;
+		}
+	},
+	
+	_deferredError: function(/*Error*/error, /*Deferred*/dfd){
+		//summary: errHandler function for dojo._ioSetArgs call.
+
+		//DO NOT use "this" and expect it to be dojo.io.script.
+		if(td.ioArgs.canDelete){
+			dojo.io.script._deadScripts.push(td.ioArgs.id);
+		}
+		console.debug("dojo.io.script error", error);
+		return error;
+	},
+
+	_deadScripts: [],
+	_counter: 1,
+
+	_validCheck: function(/*Deferred*/dfd){
+		//summary: inflight check function to see if dfd is still valid.
+
+		//Do script cleanup here. We wait for one inflight pass
+		//to make sure we don't get any weird things by trying to remove a script
+		//tag that is part of the call chain (IE 6 has been known to
+		//crash in that case).
+		var _self = dojo.io.script;
+		var deadScripts = _self._deadScripts;
+		if(deadScripts && deadScripts.length > 0){
+			for(var i = 0; i < deadScripts.length; i++){
+				//Remove the script tag
+				_self.remove(deadScripts[i]);
+				
+				//Remove the jsonp callback on dojo.io.script
+				if(_self["jsonp_" + deadScripts[i]]){
+					delete _self["jsonp_" + deadScripts[i]];
+				}
+			}
+			dojo.io.script._deadScripts = [];
+		}
+
+		return true;
+	},
+
+	_ioCheck: function(/*Deferred*/dfd){
+		//summary: inflight check function to see if IO finished.
+
+		//Check for finished jsonp
+		if(dfd.ioArgs.json){
+			return true;
+		}
+
+		//Check for finished "checkString" case.
+		var checkString = dfd.ioArgs.args.checkString;
+		if(checkString && eval("typeof(" + checkString + ") != 'undefined'")){
+			return true;
+		}
+
+		return false;
+	},
+
+	_resHandle: function(/*Deferred*/dfd){
+		//summary: inflight function to handle a completed response.
+		if(dojo.io.script._ioCheck(dfd)){
+			dfd.callback(dfd);
+		}else{
+			//This path should never happen since the only way we can get
+			//to _resHandle is if _ioCheck is true.
+			dfd.errback(new Error("inconceivable dojo.io.script._resHandle error"));
+		}
+	},
+
+	_jsonpCallback: function(/*JSON Object*/json){
+		//summary: generic handler for jsonp callback. A pointer
+		//to this function is used for all jsonp callbacks.
+		//NOTE: the "this" in this function will be the Deferred
+		//object that represents the script request.
+		this.ioArgs.json = json;
+	}
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,459 @@
+dojo.provide("dojo.number");
+
+dojo.require("dojo.i18n");
+dojo.requireLocalization("dojo.cldr", "number");
+dojo.require("dojo.string");
+dojo.require("dojo.regexp");
+
+dojo.number.format = function(/*Number*/value, /*Object?*/options){
+	// summary:
+	//		Format a Number as a String, using locale-specific settings
+	//
+	// description:
+	//		Create a string from a Number using a known localized pattern.
+	//		Formatting patterns appropriate to the locale are chosen from the CLDR http://unicode.org/cldr
+	//		as well as the appropriate symbols and delimiters.  See http://www.unicode.org/reports/tr35/#Number_Elements
+	//
+	// value:
+	//		the number to be formatted.  If not a valid JavaScript number, return null.
+	//
+	// options: object {pattern: String?, type: String?, places: Number?, round: Number?, currency: String?, symbol: String?, locale: String?}
+	//		pattern- override formatting pattern with this string (see dojo.number._applyPattern)
+	//		type- choose a format type based on the locale from the following: decimal, scientific, percent, currency. decimal by default.
+	//		places- fixed number of decimal places to show.  This overrides any information in the provided pattern.
+	//		round- 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1 means don't round.
+	//		currency- iso4217 currency code
+	//		symbol- localized currency symbol
+	//		locale- override the locale used to determine formatting rules
+
+	options = dojo.mixin({}, options || {});
+	var locale = dojo.i18n.normalizeLocale(options.locale);
+	var bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale);
+	options.customs = bundle;
+	var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];
+	if(isNaN(value)){ return null; } // null
+	return dojo.number._applyPattern(value, pattern, options); // String
+};
+
+//dojo.number._numberPatternRE = /(?:[#0]*,?)*[#0](?:\.0*#*)?/; // not precise, but good enough
+dojo.number._numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/; // not precise, but good enough
+
+dojo.number._applyPattern = function(/*Number*/value, /*String*/pattern, /*Object?*/options){
+	// summary: Apply pattern to format value as a string using options. Gives no consideration to local customs.
+	// value: the number to be formatted.
+	// pattern: a pattern string as described in http://www.unicode.org/reports/tr35/#Number_Format_Patterns
+	// options: object {customs: Object?, places: Number?, currency: String?, round: Number?, symbol: String?}
+	//  customs- a hash containing: decimal, group, ...
+
+//TODO: support escapes
+	options = options || {};
+	var group = options.customs.group;
+	var decimal = options.customs.decimal;
+
+	var patternList = pattern.split(';');
+	var positivePattern = patternList[0];
+	pattern = patternList[(value < 0) ? 1 : 0] || ("-" + positivePattern);
+
+	//TODO: only test against unescaped
+	if(pattern.indexOf('%') != -1){
+		value *= 100;
+	}else if(pattern.indexOf('\u2030') != -1){
+		value *= 1000; // per mille
+	}else if(pattern.indexOf('\u00a4') != -1){
+		group = options.customs.currencyGroup || group;//mixins instead?
+		decimal = options.customs.currencyDecimal || decimal;// Should these be mixins instead?
+		pattern = pattern.replace(/\u00a4{1,3}/, function(match){
+			var prop = ["symbol", "currency", "displayName"][match.length-1];
+			return options[prop] || options.currency || "";
+		});
+	}else if(pattern.indexOf('E') != -1){
+		throw new Error("exponential notation not supported");
+	}
+	
+//TODO: support @ sig figs?
+	var numberPatternRE = dojo.number._numberPatternRE;
+	var numberPattern = positivePattern.match(numberPatternRE);
+	if(!numberPattern){
+		throw new Error("unable to find a number expression in pattern: "+pattern);
+	}
+	return pattern.replace(numberPatternRE,
+		dojo.number._formatAbsolute(value, numberPattern[0], {decimal: decimal, group: group, places: options.places}));
+}
+
+dojo.number.round = function(/*Number*/value, /*Number*/places, /*Number?*/multiple){
+	// summary: Rounds the number at the given number of places
+	// value: the number to round
+	// places: the number of decimal places where rounding takes place
+	// multiple: rounds next place to nearest multiple
+
+	var pieces = String(value).split(".");
+	var length = (pieces[1] && pieces[1].length) || 0;
+	if(length > places){
+		var factor = Math.pow(10, places);
+		if(multiple > 0){factor *= 10/multiple;places++;} //FIXME
+		value = Math.round(value * factor)/factor;
+
+		// truncate to remove any residual floating point values
+		pieces = String(value).split(".");
+		length = (pieces[1] && pieces[1].length) || 0;
+		if(length > places){
+			pieces[1] = pieces[1].substr(0, places);
+			value = Number(pieces.join("."));
+		}
+	}
+	return value; //Number
+}
+
+dojo.number._formatAbsolute = function(/*Number*/value, /*String*/pattern, /*Object?*/options){
+	// summary: 
+	//		Apply numeric pattern to absolute value using options. Gives no
+	//		consideration to local customs.
+	// value:
+	//		the number to be formatted, ignores sign
+	// pattern:
+	//		the number portion of a pattern (e.g. #,##0.00)
+	// options:
+	//		object {decimal: String?, group: String?, places: Number?}
+	//  		decimal: the decimal separator
+	//  		group: the group separator
+	//  		places: number of decimal places
+	//  		round: 5 rounds to nearest .5; 0 rounds to nearest whole (default). -1 means don't round.
+	options = options || {};
+	if(options.places === true){options.places=0;}
+	if(options.places === Infinity){options.places=6;} // avoid a loop; pick a limit
+
+	var patternParts = pattern.split(".");
+	var maxPlaces = (options.places >= 0) ? options.places : (patternParts[1] && patternParts[1].length) || 0;
+	if(!(options.round < 0)){
+		value = dojo.number.round(value, maxPlaces, options.round);
+	}
+
+	var valueParts = String(Math.abs(value)).split(".");
+	var fractional = valueParts[1] || "";
+	if(options.places){
+		valueParts[1] = dojo.string.pad(fractional.substr(0, options.places), options.places, '0', true);
+	}else if(patternParts[1] && options.places !== 0){
+		// Pad fractional with trailing zeros
+		var pad = patternParts[1].lastIndexOf("0") + 1;
+		if(pad > fractional.length){
+			valueParts[1] = dojo.string.pad(fractional, pad, '0', true);
+		}
+
+		// Truncate fractional
+		var places = patternParts[1].length;
+		if(places < fractional.length){
+			valueParts[1] = fractional.substr(0, places);
+		}
+	}else{
+		if(valueParts[1]){ valueParts.pop(); }
+	}
+
+	// Pad whole with leading zeros
+	var patternDigits = patternParts[0].replace(',', '');
+	pad = patternDigits.indexOf("0");
+	if(pad != -1){
+		pad = patternDigits.length - pad;
+		if(pad > valueParts[0].length){
+			valueParts[0] = dojo.string.pad(valueParts[0], pad);
+		}
+
+		// Truncate whole
+		if(patternDigits.indexOf("#") == -1){
+			valueParts[0] = valueParts[0].substr(valueParts[0].length - pad);
+		}
+	}
+
+	// Add group separators
+	var index = patternParts[0].lastIndexOf(',');
+	var groupSize, groupSize2;
+	if(index != -1){
+		groupSize = patternParts[0].length - index - 1;
+		var remainder = patternParts[0].substr(0, index);
+		index = remainder.lastIndexOf(',');
+		if(index != -1){
+			groupSize2 = remainder.length - index - 1;
+		}
+	}
+	var pieces = [];
+	for(var whole = valueParts[0]; whole;){
+		var off = whole.length - groupSize;
+		pieces.push((off > 0) ? whole.substr(off) : whole);
+		whole = (off > 0) ? whole.slice(0, off) : "";
+		if(groupSize2){
+			groupSize = groupSize2;
+			delete groupSize2;
+		}
+	}
+	valueParts[0] = pieces.reverse().join(options.group || ",");
+
+	return valueParts.join(options.decimal || ".");
+};
+
+dojo.number.regexp = function(/*Object?*/options){
+	//
+	// summary:
+	//		Builds the regular needed to parse a number
+	//
+	// description:
+	//		returns regular expression with positive and negative match, group
+	//		and decimal separators
+	//
+	// options: object {pattern: String, type: String locale: String, strict: Boolean, places: mixed}
+	//		pattern- override pattern with this string
+	//		type- choose a format type based on the locale from the following: decimal, scientific, percent, currency. decimal by default.
+	//		locale- override the locale used to determine formatting rules
+	//		strict- strict parsing, false by default
+	//		places- number of decimal places to accept: Infinity, a positive number, or a range "n,m"
+	return dojo.number._parseInfo(options).regexp; // String
+}
+
+dojo.number._parseInfo = function(/*Object?*/options){
+	options = options || {};
+	var locale = dojo.i18n.normalizeLocale(options.locale);
+	var bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale);
+	var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];
+//TODO: memoize?
+	var group = bundle.group;
+	var decimal = bundle.decimal;
+	var factor = 1;
+
+	if(pattern.indexOf('%') != -1){
+		factor /= 100;
+	}else if(pattern.indexOf('\u2030') != -1){
+		factor /= 1000; // per mille
+	}else{
+		var isCurrency = pattern.indexOf('\u00a4') != -1;
+		if(isCurrency){
+			group = bundle.currencyGroup || group;
+			decimal = bundle.currencyDecimal || decimal;
+		}
+	}
+
+	if(group == '\xa0'){ group = ' '; }
+
+	//TODO: handle quoted escapes
+	var patternList = pattern.split(';');
+	if(patternList.length == 1){
+		patternList.push("-" + patternList[0]);
+	}
+
+	var re = dojo.regexp.buildGroupRE(patternList, function(pattern){
+		pattern = "(?:"+dojo.regexp.escapeString(pattern, '.')+")";
+		return pattern.replace(dojo.number._numberPatternRE, function(format){
+			var flags = {
+				signed: false,
+				separator: options.strict ? group : [group,""],
+				fractional: options.fractional,
+				decimal: decimal,
+				exponent: false};
+			var parts = format.split('.');
+			var places = options.places;
+			if(parts.length == 1 || places === 0){flags.fractional = false;}
+			else{
+				if(typeof places == "undefined"){ places = parts[1].lastIndexOf('0')+1; }
+				if(places && options.fractional == undefined){flags.fractional = true;} // required fractional, unless otherwise specified
+				if(!options.places && (places < parts[1].length)){ places += "," + parts[1].length; }
+				flags.places = places;
+			}
+			var groups = parts[0].split(',');
+			if(groups.length>1){
+				flags.groupSize = groups.pop().length;
+				if(groups.length>1){
+					flags.groupSize2 = groups.pop().length;
+				}
+			}
+			return "("+dojo.number._realNumberRegexp(flags)+")";
+		});
+	}, true);
+
+	if(isCurrency){
+		// substitute the currency symbol for the placeholder in the pattern
+		re = re.replace(/(\s*)(\u00a4{1,3})(\s*)/g, function(match, before, target, after){
+			var prop = ["symbol", "currency", "displayName"][target.length-1];
+			var symbol = dojo.regexp.escapeString(options[prop] || options.currency || "");
+			before = before ? "\\s" : "";
+			after = after ? "\\s" : "";
+			if(!options.strict){
+				if(before){before += "*";}
+				if(after){after += "*";}
+				return "(?:"+before+symbol+after+")?";
+			}
+			return before+symbol+after;
+		});
+	}
+
+//TODO: substitute localized sign/percent/permille/etc.?
+
+	return {regexp: re, group: group, decimal: decimal, factor: factor}; // Object
+}
+
+dojo.number.parse = function(/*String*/expression, /*Object?*/options){
+	// summary:
+	//		Convert a properly formatted string to a primitive Number,
+	//		using locale-specific settings.
+	//
+	// description:
+	//		Create a Number from a string using a known localized pattern.
+	//		Formatting patterns are chosen appropriate to the locale.
+	//		Formatting patterns are implemented using the syntax described at
+	//		*URL*
+	//
+	// expression: A string representation of a Number
+	//
+	// options: 
+	//		object {pattern: string, locale: string, strict: boolean}
+	//		pattern:
+	//			override pattern with this string
+	//		type:
+	//			choose a format type based on the locale from the following:
+	//			decimal, scientific, percent, currency. decimal by default.
+	//		locale:
+	//			override the locale used to determine formatting rules
+	//		strict: 
+	//			strict parsing, false by default
+	//		currency:
+	//			object with currency information
+
+	var info = dojo.number._parseInfo(options);
+
+	var results = (new RegExp("^"+info.regexp+"$")).exec(expression);
+		if(!results){
+			return NaN; //NaN
+	}
+	var absoluteMatch = results[1]; // match for the positive expression
+	if(!results[1]){
+		if(!results[2]){
+			return NaN; //NaN
+		}
+		// matched the negative pattern
+		absoluteMatch = results[2];
+		info.factor *= -1;
+	}
+
+	// Transform it to something Javascript can parse as a number
+	while(absoluteMatch.indexOf(info.group) != -1){
+		absoluteMatch = absoluteMatch.replace(info.group, "");
+	}
+	absoluteMatch = absoluteMatch.replace(info.decimal, ".");
+
+	// Adjust for negative sign, percent, etc. as necessary
+	return Number(absoluteMatch) * info.factor; //Number
+};
+
+dojo.number._realNumberRegexp = function(/*Object?*/flags){
+	// summary: Builds a regular expression to match a real number in exponential notation
+	//
+	// flags:An object
+	//		flags.places:
+	//			The integer number of decimal places or a range given as "n,m".
+	//			If not given, the decimal part is optional and the number of
+	//			places is unlimited.
+	//		flags.decimal:
+	//			A string for the character used as the decimal point.  Default
+	//			is ".".
+	//    flags.fractional:
+	//			Whether decimal places are allowed.  Can be true, false, or
+	//			[true, false].  Default is [true, false]
+	//    flags.exponent:
+	//			Express in exponential notation.  Can be true, false, or [true,
+	//			false]. Default is [true, false], (i.e. will match if the
+	//			exponential part is present are not).
+	//    flags.eSigned:
+	//			The leading plus-or-minus sign on the exponent.  Can be true,
+	//			false, or [true, false].  Default is [true, false], (i.e. will
+	//			match if it is signed or unsigned).  flags in regexp.integer
+	//			can be applied.
+
+	// assign default values to missing paramters
+	flags = (typeof flags == "object") ? flags : {};
+	if(typeof flags.places == "undefined"){ flags.places = Infinity; }
+	if(typeof flags.decimal != "string"){ flags.decimal = "."; }
+	if(typeof flags.fractional == "undefined"){ flags.fractional = [true, false]; }
+	if(typeof flags.exponent == "undefined"){ flags.exponent = [true, false]; }
+	if(typeof flags.eSigned == "undefined"){ flags.eSigned = [true, false]; }
+
+	// integer RE
+	var integerRE = dojo.number._integerRegexp(flags);
+
+	// decimal RE
+	var decimalRE = dojo.regexp.buildGroupRE(flags.fractional,
+		function(q){
+			var re = "";
+			if(q && (flags.places!==0)){
+				re = "\\" + flags.decimal;
+				if(flags.places == Infinity){ 
+					re = "(?:" + re + "\\d+)?"; 
+				}else{
+					re += "\\d{" + flags.places + "}"; 
+				}
+			}
+			return re;
+		},
+		true
+	);
+
+	// exponent RE
+	var exponentRE = dojo.regexp.buildGroupRE(flags.exponent,
+		function(q){ 
+			if(q){ return "([eE]" + dojo.number._integerRegexp({ signed: flags.eSigned}) + ")"; }
+			return ""; 
+		}
+	);
+
+	// real number RE
+	var realRE = integerRE + decimalRE;
+	// allow for decimals without integers, e.g. .25
+	if(decimalRE){realRE = "(?:(?:"+ realRE + ")|(?:" + decimalRE + "))";}
+	return realRE + exponentRE; // String
+};
+
+dojo.number._integerRegexp = function(/*Object?*/flags){
+	// summary: 
+	//		Builds a regular expression that matches an integer
+	// flags: 
+	//		An object
+	//		flags.signed :
+	//			The leading plus-or-minus sign. Can be true, false, or [true,
+	//			false]. Default is [true, false], (i.e. will match if it is
+	//			signed or unsigned).
+	//		flags.separator:
+	//			The character used as the thousands separator. Default is no
+	//			separator. For more than one symbol use an array, e.g. [",",
+	//			""], makes ',' optional.
+	//		flags.groupSize: group size between separators
+	//		flags.groupSize2: second grouping (for India)
+
+	// assign default values to missing paramters
+	flags = (typeof flags == "object") ? flags : {};
+	if(typeof flags.signed == "undefined"){ flags.signed = [true, false]; }
+	if(typeof flags.separator == "undefined"){
+		flags.separator = "";
+	}else if(typeof flags.groupSize == "undefined"){
+		flags.groupSize = 3;
+	}
+	// build sign RE
+	var signRE = dojo.regexp.buildGroupRE(flags.signed,
+		function(q) { return q ? "[-+]" : ""; },
+		true
+	);
+
+	// number RE
+	var numberRE = dojo.regexp.buildGroupRE(flags.separator,
+		function(sep){ 
+			if(!sep){ 
+				return "(?:0|[1-9]\\d*)";
+			}
+			sep = dojo.regexp.escapeString(sep);
+			var grp = flags.groupSize, grp2 = flags.groupSize2;
+			if(grp2){
+				var grp2RE = "(?:0|[1-9]\\d{0," + (grp2-1) + "}(?:[" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})";
+				return ((grp-grp2) > 0) ? "(?:" + grp2RE + "|(?:0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE;
+			}
+			return "(?:0|[1-9]\\d{0," + (grp-1) + "}(?:[" + sep + "]\\d{" + grp + "})*)";
+		},
+		true
+	);
+
+	// integer RE
+	return signRE + numberRE; // String
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/regexp.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/regexp.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/regexp.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,49 @@
+dojo.provide("dojo.regexp");
+
+dojo.regexp.escapeString = function(/*String*/str, /*String?*/except){
+//summary:
+//	Adds escape sequences for special characters in regular expressions
+// except: a String with special characters to be left unescaped
+
+//	return str.replace(/([\f\b\n\t\r[\^$|?*+(){}])/gm, "\\$1"); // string
+	return str.replace(/([\.$?*!=:|{}\(\)\[\]\\\/^])/g, function(ch){
+		if(except && except.indexOf(ch) != -1){
+			return ch;
+		}
+		return "\\" + ch;
+	}); // String
+}
+
+dojo.regexp.buildGroupRE = function(/*value or Array of values*/a, /*Function(x) returns a regular expression as a String*/re,
+	/*Boolean?*/nonCapture){
+	// summary: Builds a regular expression that groups subexpressions
+	// description: A utility function used by some of the RE generators.
+	//  The subexpressions are constructed by the function, re, in the second parameter.
+	//  re builds one subexpression for each elem in the array a, in the first parameter.
+	//  Returns a string for a regular expression that groups all the subexpressions.
+	//
+	// a:  A single value or an array of values.
+	// re:  A function.  Takes one parameter and converts it to a regular expression. 
+	// nonCapture: If true, uses non-capturing match, otherwise matches are retained by regular expression. 
+
+	// case 1: a is a single value.
+	if(!(a instanceof Array)){
+		return re(a); // String
+	}
+
+	// case 2: a is an array
+	var b = [];
+	for (var i = 0; i < a.length; i++){
+		// convert each elem to a RE
+		b.push(re(a[i]));
+	}
+
+	 // join the REs as alternatives in a RE group.
+	return dojo.regexp.group(b.join("|"), nonCapture); // String
+}
+
+dojo.regexp.group = function(/*String*/expression, /*Boolean?*/nonCapture){
+	// summary: adds group match to expression
+	// nonCapture: If true, uses non-capturing match, otherwise matches are retained by regular expression. 
+	return "(" + (nonCapture ? "?:":"") + expression + ")"; // String
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/resources/LICENSE
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/resources/LICENSE	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/resources/LICENSE	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+License Disclaimer:
+
+All contents of this directory are Copyright (c) the Dojo Foundation, with the
+following exceptions:
+-------------------------------------------------------------------------------
+
+dojo.css:
+	* parts Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+	  Distributed under the terms of the BSD License

Added: trunk/examples/typeface/root/static/dojo/dojo/resources/dojo.css
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/resources/dojo.css	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/resources/dojo.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,172 @@
+/*
+	This is the baseline page-level CSS file for use with Dojo applications.
+
+	Applications using Dojo will function correctly without including this
+	file, but it should provide sane defaults for many common things that page
+	authors often need to set up manually.
+*/
+
+/*
+	The below are borrowed from YUI's reset style sheets for pages and fonts.
+	We've verified w/ the YUI development team that these are entirely
+	copyright Yahoo, written entirely by Nate Koechley and Matt Sweeney without
+	external contributions.
+
+	Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+	Code licensed under the BSD License:
+	http://developer.yahoo.net/yui/license.txt
+	version: 2.2.1
+*/
+
+body, div, dl, dt, dd, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, input, textarea, p, blockquote, th, td {
+	margin: 0;
+	padding: 0;
+}
+
+fieldset, img {
+	border: 0;
+}
+
+address, caption, cite, code, dfn, th, var /*, em, strong*/ {
+	font-style: normal; 
+	font-weight: normal;
+}
+
+caption, th {
+	text-align: left;
+}
+
+q:before, q:after {
+	content:"";
+}
+
+abbr, acronym {
+	border:0;
+}
+
+select, input, textarea {
+	font-size:99%;
+}
+
+body * {
+	line-height:1.22em;
+}
+
+/* 
+
+	End YUI imported code.
+	Begin Dojo additions.
+
+	Style definitions, based partially on the Tundra theme.
+	Relative unit calculations based on "Compose to a Vertical Rhythm",
+	by Richard Rutter (http://24ways.org/2006/compose-to-a-vertical-rhythm)
+
+	If changing the font size, make sure you do it in both
+	percent and px (% for IE, px for everything else). 
+	% value based on default size of 16px (in most browsers).
+	So if you want the default size to be 14px, set the 
+	% to 87% (14/16 = 0.875).
+
+	Typical values:
+	10px: 62.5%
+	11px: 69% (68.75)
+	12px: 75%
+	13px: 81.25%
+	14px: 87.5%
+	16px: 100%
+
+	Default: 13px, specified by the YUI imports, so we don't need to repeat ourselves
+*/
+body { 
+	font: 13px "Myriad Pro",Myriad,Arial,Helvetica,clean,sans-serif; 
+	*font-size: small;
+	*font: x-small;
+}
+
+/* Headings */
+h1 {
+	font-size: 1.5em; 
+	font-weight: normal;
+	line-height: 1em; 
+	margin-top: 1em;
+	margin-bottom:0;
+}
+
+h2 { 
+	font-size: 1.1667em; 
+	font-weight: bold; 
+	line-height: 1.286em; 
+	margin-top: 1.929em; 
+	margin-bottom:0.643em;
+}
+
+h3, h4, h5, h6 {
+	font-size: 1em; 
+	font-weight: bold; 
+	line-height: 1.5em; 
+	margin-top: 1.5em; 
+	margin-bottom: 0;
+}
+
+/* paragraphs, quotes and lists */
+p { 
+	font-size: 1em; 
+	margin-top: 1.5em; 
+	margin-bottom: 1.5em; 
+	line-height: 1.5em;
+}
+
+blockquote { 
+	font-size: 0.916em; 
+	margin-top: 3.272em; 
+	margin-bottom: 3.272em; 
+	line-height: 1.636em; 
+	padding: 1.636em; 
+	border-top: 1px solid #ccc; 
+	border-bottom: 1px solid #ccc;
+}
+
+ol li, ul li { 
+	font-size: 1em; 
+	line-height: 1.5em; 
+	margin: 0;
+}
+
+/* pre and code */
+pre, code { 
+	font-size:115%;
+	*font-size:100%;
+	font-family: Courier, "Courier New"; 
+	background-color: #efefef; 
+	border: 1px solid #ccc;
+}
+
+pre { 
+	border-width: 1px 0; 
+	padding: 1.5em;
+}
+
+/* TODO: Double-check how these definitions will interfere with Dijits */
+/* tables */
+table { 
+	font-size: 100%;
+	border-collapse: collapse; 
+	border-spacing: 0; 
+	border: 1px solid #ccc; 
+	margin: 0 1.5em;
+}
+
+th { 
+	text-align: center; 
+	font-weight: bold;
+}
+
+table thead, table tfoot { 
+	background-color: #efefef; 
+	border: 1px solid #ccc; 
+	border-width: 1px 0; 
+}
+
+thead tr th, thead tr td, tbody tr td, tfoot tr td { 
+	padding: 0.25em 0.5em;
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/resources/iframe_history.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/resources/iframe_history.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/resources/iframe_history.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,84 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+	<title></title>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
+	<script type="text/javascript">
+	// <!--
+	var noInit = false;
+	var domain = "";
+	// document.domain = "localhost";
+	
+	function defineParams(sparams){
+		if(sparams){
+			var ss = (sparams.indexOf("&amp;") >= 0) ? "&amp;" : "&";
+			sparams = sparams.split(ss);
+			for(var x=0; x<sparams.length; x++){
+				var tp = sparams[x].split("=");
+				if(typeof window[tp[0]] != "undefined"){
+					window[tp[0]] = ((tp[1]=="true")||(tp[1]=="false")) ? eval(tp[1]) : tp[1];
+				}
+			}
+		}
+	}
+	
+	function init(){
+		// parse the query string if there is one to try to get params that
+		// we can act on. Also allow params to be in a fragment identifier.
+		var query = null;
+		var frag = null;
+		var url = document.location.href;
+		var hashIndex = url.indexOf("#");
+		
+		//Extract fragment identifier
+		if(hashIndex != -1){
+			frag = url.substring(hashIndex + 1, url.length);
+			url = url.substring(0, hashIndex);
+		}
+
+		//Extract querystring
+		var parts = url.split("?");
+		if(parts.length == 2){
+			query = parts[1];
+		}
+
+		defineParams(query);
+		defineParams(frag);
+
+		if(noInit){ return; }
+		if(domain.length > 0){
+			document.domain = domain;
+		}
+		var hasParentDojo = false;
+		try{
+			hasParentDojo = window.parent != window && window.parent["dojo"];
+		}catch(e){
+			alert("Initializing iframe_history.html failed. If you are using a cross-domain Dojo build,"
+				+ " please save iframe_history.html to your domain and set djConfig.dojoIframeHistoryUrl"
+				+ " to the path on your domain to iframe_history.html");
+			throw e;
+		}
+
+		if(hasParentDojo){
+			//Set the page title so IE history shows up with a somewhat correct name.
+			document.title = window.parent.document.title;
+			
+			//Notify parent that we are loaded.
+			var pdj = window.parent.dojo;
+			if(pdj["back"]){
+				pdj.back.iframeLoaded(null, window.location);
+			}
+		}
+
+	}
+	// -->
+	</script>
+</head>
+<body onload="try{ init(); }catch(e){ alert(e); }">
+	<h4>The Dojo Toolkit -- iframe_history.html</h4>
+
+	<p>This file is used in Dojo's back/fwd button management.</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojo/rpc/JsonPService.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/rpc/JsonPService.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/rpc/JsonPService.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,39 @@
+dojo.provide("dojo.rpc.JsonPService");
+dojo.require("dojo.rpc.RpcService");
+dojo.require("dojo.io.script");
+
+dojo.declare(
+	"dojo.rpc.JsonPService",
+	dojo.rpc.RpcService,
+	function(args, requiredArgs){
+		if(this.required && requiredArgs){
+			dojo.mixin(this.required, requiredArgs);
+			dojo.forEach(this.required, function(req){
+				if(req=="" || req==undefined){
+					throw new Error("Required Service Argument not found: "+req); 
+				}
+			});
+		}		
+	},
+	{
+		strictArgChecks: false,
+		bind: function(method, parameters, deferredRequestHandler, url){
+			//summary
+			var def = dojo.io.script.get({
+				url: url||this.serviceUrl,
+				jsonpParam: this.jsonParam||"callback",
+				content: this.createRequest(parameters),
+				handleAs: "json",	
+				preventCache: true
+			});
+			def.addCallbacks(this.resultCallback(deferredRequestHandler), this.errorCallback(deferredRequestHandler));
+		},
+		createRequest: function(parameters){
+			if(dojo.isArrayLike(parameters)&&(parameters.length==1)){
+				var params = parameters[0];
+			}
+			dojo.mixin(params,this.required);
+			return params;
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/rpc/JsonService.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/rpc/JsonService.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/rpc/JsonService.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,66 @@
+dojo.provide("dojo.rpc.JsonService");
+dojo.require("dojo.rpc.RpcService");
+
+dojo.declare(
+	"dojo.rpc.JsonService", 
+	dojo.rpc.RpcService,	
+	{
+		bustCache: false,
+	
+		contentType: "application/json-rpc",
+
+		lastSubmissionId: 0,
+
+		callRemote: function(method, params){
+			// summary:
+			// 		call an arbitrary remote method without requiring it to be
+			// 		predefined with SMD
+			var deferred = new dojo.Deferred();
+			this.bind(method, params, deferred);
+			return deferred;
+		},
+
+		bind: function(method, parameters, deferredRequestHandler, url){
+			//summary:
+			//		JSON-RPC bind method. Takes remote method, parameters,
+			//		deferred, and a url, calls createRequest to make a JSON-RPC
+			//		envelope and passes that off with bind.
+			var def = dojo.rawXhrPost({
+				url: url||this.serviceUrl,
+				postData: this.createRequest(method, parameters),
+				contentType: this.contentType,
+				timeout: this.timeout, 
+				handleAs: "json",
+			});
+			def.addCallbacks(this.resultCallback(deferredRequestHandler), this.errorCallback(deferredRequestHandler));
+		},
+
+		createRequest: function(method, params){
+			// summary:
+			//		create a JSON-RPC envelope for the request
+
+			var req = { "params": params, "method": method, "id": ++this.lastSubmissionId };
+			// console.debug("createRequest: Method: " + method + " Parameters: ", params);	
+			// console.debug("createRequest js object:",req);
+			var data = dojo.toJson(req);
+			console.debug("createRequest (json string):", data);
+			return data;
+		},
+
+		parseResults: function(obj){
+			//summary:
+			//		parse the result envelope and pass the results back to to
+			//		the callback function
+			if(obj==null){ return; }
+			if(obj["Result"]!=null){ 
+				return obj["Result"]; 
+			}else if(obj["result"]!=null){ 
+				return obj["result"]; 
+			}else if(obj["ResultSet"]){
+				return obj["ResultSet"];
+			}else{
+				return obj;
+			}
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/rpc/RpcService.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/rpc/RpcService.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/rpc/RpcService.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,135 @@
+dojo.provide("dojo.rpc.RpcService");
+
+dojo.declare(
+	"dojo.rpc.RpcService",
+	null, 
+        function(args){
+		//summary:
+		//Take a string as a url to retrieve an smd or an object that is an smd or partial smd to use
+		//as a definition for the service
+                //      - the text of the SMD to evaluate
+                //      - a raw SMD object
+                //      - the SMD URL
+                if(args){
+			//if the arg is a string, we assume it is a url to retrieve an smd definition from
+			if(dojo.isString(args)){
+				var def = dojo.xhrGet({
+					url: args,
+					handleAs: "json",
+					sync: true
+				});
+
+				def.addCallback(this, "processSmd");
+				def.addErrback(function() {
+					throw new Error("Unable to load SMD from " . args);					
+				});
+
+			}else if(args["smdStr"]){
+				this.processSmd(dj_eval("("+args.smdStr+")"));
+			}else{
+	                        // otherwise we assume it's an arguments object with the following
+				// (optional) properties:
+				//      - serviceUrl
+				//      - strictArgChecks
+				//      - smdStr
+				//      - smdObj
+
+				if(args["serviceUrl"]){
+					this.serviceUrl = args.serviceUrl;
+				}
+
+				if(args["timeout"]){
+					this.timeout = args.timeout;
+				}else{
+					this.timeout=3000;
+				}
+
+	                        if(typeof args["strictArgChecks"] != "undefined"){
+					this.strictArgChecks = args.strictArgChecks;
+				}
+
+				this.processSmd(args);
+			}
+		}
+	},
+	{
+
+		strictArgChecks: true,
+		serviceUrl: "",
+
+		parseResults: function(obj){
+			// summary
+			// 		parse the results coming back from an rpc request.  this
+			// 		base implementation, just returns the full object
+			// 		subclasses should parse and only return the actual results
+			return obj;
+		},
+
+		errorCallback: function(/* dojo.Deferred */ deferredRequestHandler){
+			// summary:
+			//		create callback that calls the Deferres errback method
+			return function(data){
+				deferredRequestHandler.errback(new Error(data.message));
+			}
+		},
+
+		resultCallback: function(/* dojo.Deferred */ deferredRequestHandler){
+			// summary:
+			// 		create callback that calls the Deferred's callback method
+			var tf = dojo.hitch(this, 
+				function(obj){
+					if(obj["error"]!=null){
+						var err = new Error(obj.error);
+						err.id = obj.id;
+						deferredRequestHandler.errback(err);
+					}else{
+						var results = this.parseResults(obj);
+						deferredRequestHandler.callback(results); 
+					}
+				}
+			);
+			return tf;
+		},
+
+		generateMethod: function(/*string*/ method, /*array*/ parameters, /*string*/ url){
+			// summary:
+			// 		generate the local bind methods for the remote object
+			return dojo.hitch(this, function(){
+				var deferredRequestHandler = new dojo.Deferred();
+	
+				// if params weren't specified, then we can assume it's varargs
+				if( (this.strictArgChecks) &&
+					(parameters != null) &&
+					(arguments.length != parameters.length)
+				){
+					// put error stuff here, no enough params
+					throw new Error("Invalid number of parameters for remote method.");
+				}else{
+					this.bind(method, dojo._toArray(arguments), deferredRequestHandler, url);
+				}
+	
+				return deferredRequestHandler;
+			});
+		},
+
+		processSmd: function(/*json*/ object){
+			// summary:
+			// 		callback method for reciept of a smd object.  Parse the smd
+			// 		and generate functions based on the description
+			if(object.methods){
+				dojo.forEach(object.methods, function(m){
+					if(m && m["name"]){
+						this[m.name] = this.generateMethod(	m.name,
+											m.parameters, 
+											m["url"]||m["serviceUrl"]||m["serviceURL"]);
+						if(!dojo.isFunction(this[m.name])){
+							console.debug("RpcService: Failed to create", m.name, "()");
+						}
+					}
+				}, this);
+			}
+
+			this.serviceUrl = object.serviceUrl||object.serviceURL;
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/string.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/string.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/string.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,58 @@
+dojo.provide("dojo.string");
+
+dojo.string.pad = function(/*String*/text, /*int*/size, /*String?*/ch, /*boolean?*/end){
+	// summary:
+	//		Pad a string to guarantee that it is at least 'size' length by
+	//		filling with the character 'c' at either the start or end of the
+	//		string. Pads at the start, by default.
+	// text: the string to pad
+	// size: length to provide padding
+	// ch: character to pad, defaults to '0'
+	// end: adds padding at the end if true, otherwise pads at start
+
+	var out = String(text);
+	if(!ch){
+		ch = '0';
+	}
+	while(out.length < size){
+		if(end){
+			out += ch;
+		}else{
+			out = ch + out;
+		}
+	}
+	return out;	// String
+}
+
+dojo.string.substitute = function(	/*String*/template, 
+									/*Object or Array*/map, 
+									/*Function?*/transform, 
+									/*Object?*/thisObject){
+	// summary:
+	//		Performs parameterized substitutions on a string. Throws an
+	//		exception if any parameter is unmatched.
+	// description:
+	//		For example,
+	//			dojo.string.substitute("File '${0}' is not found in directory '${1}'.",["foo.html","/temp"]);
+	//			dojo.string.substitute("File '${name}' is not found in directory '${info.dir}'.",{name: "foo.html", info: {dir: "/temp"}});
+	//		both return
+	//			"File 'foo.html' is not found in directory '/temp'."
+	// template: 
+	//		a string with expressions in the form ${key} to be replaced or
+	//		${key:format} which specifies a format function.  NOTE syntax has
+	//		changed from %{key}
+	// map: where to look for substitutions
+	// transform: 
+	//		a function to process all parameters before substitution takes
+	//		place, e.g. dojo.string.encodeXML
+	// thisObject: 
+	//		where to look for optional format function; default to the global
+	//		namespace
+
+	return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(match, key, format){
+		var value = dojo.getObject(key,false,map);
+		if(format){ value = dojo.getObject(format,false,thisObject)(value);}
+		if(transform){ value = transform(value); }
+		return value.toString();
+	}); // string
+};

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/AdapterRegistry.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/AdapterRegistry.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/AdapterRegistry.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,71 @@
+dojo.provide("tests.AdapterRegistry");
+dojo.require("dojo.AdapterRegistry");
+
+doh.register("tests.AdapterRegistry", 
+	[
+		function ctor(t){
+			var taa = new dojo.AdapterRegistry();
+			t.is(0, taa.pairs.length);
+			t.f(taa.returnWrappers);
+
+			var taa = new dojo.AdapterRegistry(true);
+			t.t(taa.returnWrappers);
+		},
+
+		function register(t){
+			var taa = new dojo.AdapterRegistry();
+			taa.register("blah", 
+				function(str){ return str == "blah"; },
+				function(){ return "blah"; }
+			);
+			t.is(1, taa.pairs.length);
+			t.is("blah", taa.pairs[0][0]);
+
+			taa.register("thinger");
+			taa.register("prepend", null, null, true, true);
+			t.is("prepend", taa.pairs[0][0]);
+			t.t(taa.pairs[0][3]);
+		},
+
+		/*
+		function match(t){
+		},
+		*/
+
+		function noMatch(t){
+			var taa = new dojo.AdapterRegistry();
+			var threw = false;
+			try{
+				taa.match("blah");
+			}catch(e){
+				threw = true;
+			}
+			t.t(threw);
+		},
+
+		function returnWrappers(t){
+			var taa = new dojo.AdapterRegistry();
+			taa.register("blah", 
+				function(str){ return str == "blah"; },
+				function(){ return "blah"; }
+			);
+			t.is("blah", taa.match("blah"));
+
+			taa.returnWrappers = true;
+			t.is("blah", taa.match("blah")());
+		},
+
+		function unregister(t){
+			var taa = new dojo.AdapterRegistry();
+			taa.register("blah", 
+				function(str){ return str == "blah"; },
+				function(){ return "blah"; }
+			);
+			taa.register("thinger");
+			taa.register("prepend", null, null, true, true);
+			taa.unregister("prepend");
+			t.is(2, taa.pairs.length);
+			t.is("blah", taa.pairs[0][0]);
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/TODO
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/TODO	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/TODO	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,12 @@
+This file lists tests that need to be implemented or expanded. See ticket #3121
+for changes related to thigns listed here.
+
+Tests to add:
+-------------
+	* xhr put/delete tests
+	* html tests need to start exercising the semi-public methods
+
+Tests to improve:
+-----------------
+	* cookie tests don't seem to test expiry or date functions
+	* NodeList isn't testing several of its public methods (place, orphan, adopt, etc.)

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/Deferred.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/Deferred.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/Deferred.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,64 @@
+dojo.provide("tests._base.Deferred");
+
+doh.register("tests._base.Deferred", 
+	[
+
+		function callback(t){
+			var nd = new dojo.Deferred();
+			var cnt = 0;
+			nd.addCallback(function(res){
+				doh.debug("debug from dojo.Deferred callback");
+				return res;
+			});
+			nd.addCallback(function(res){
+				// t.debug("val:", res);
+				cnt+=res;
+				return cnt;
+			});
+			nd.callback(5);
+			// t.debug("cnt:", cnt);
+			t.assertEqual(cnt, 5);
+		},
+
+		function errback(t){
+			var nd = new dojo.Deferred();
+			var cnt = 0;
+			nd.addErrback(function(val){
+				return ++cnt;
+			});
+			nd.errback();
+			t.assertEqual(cnt, 1);
+		},
+
+		function callbackTwice(t){
+			var nd = new dojo.Deferred();
+			var cnt = 0;
+			nd.addCallback(function(res){
+				return ++cnt;
+			});
+			nd.callback();
+			t.assertEqual(cnt, 1);
+			var thrown = false;
+			try{
+				nd.callback();
+			}catch(e){
+				thrown = true;
+			}
+			t.assertTrue(thrown);
+		},
+
+		function addBoth(t){
+			var nd = new dojo.Deferred();
+			var cnt = 0;
+			nd.addBoth(function(res){
+				return ++cnt;
+			});
+			nd.callback();
+			t.assertEqual(cnt, 1);
+
+			// nd.callback();
+			// t.debug(cnt);
+			// t.assertEqual(cnt, 1);
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/NodeList.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/NodeList.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/NodeList.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,200 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+	"http://www.w3.org/TR/html4/strict.dtd">
+<!--
+	we use a strict-mode DTD to ensure that the box model is the same for these
+	basic tests
+-->
+<html>
+	<head>
+		<style type="text/css">
+			@import "../../resources/dojo.css";
+			html, body {
+				padding: 0px;
+				margin: 0px;
+				border: 0px;
+			}
+
+			#sq100 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 100px;
+				top: 100px;
+				width: 100px;
+				height: 100px;
+				border: 0px;
+				padding: 0px;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+		</style>
+		<title>testing dojo.NodeList</title>
+		<script type="text/javascript" src="../../dojo.js" 
+			djConfig="isDebug: true, noFirebugLite: true"></script>
+		<script type="text/javascript">
+			dojo.require("doh.runner");
+			dojo.addOnLoad(function(){
+				var fourElementNL = new dojo.NodeList(
+					dojo.byId("c1"), 
+					dojo.byId("t"),
+					dojo.byId("c1"), 
+					dojo.byId("t")
+				);
+				doh.register("t", 
+					[
+						// constructor tests
+						function ctor(t){
+							var nl = new dojo.NodeList();
+							nl.push(dojo.byId("c1"));
+							t.is(1, nl.length);
+						},
+						function ctorArgs(t){
+							var nl = new dojo.NodeList(4);
+							nl.push(dojo.byId("c1"));
+							t.is(5, nl.length);
+						},
+						function ctorArgs2(t){
+							var nl = new dojo.NodeList(dojo.byId("c1"), dojo.byId("t"));
+							t.is(2, nl.length);
+							t.is(dojo.byId("c1"), nl[0]);
+							t.is(dojo.byId("t"), nl[1]);
+						},
+
+						// iteration and array tests
+						function forEach(t){
+							var lastItem;
+							var nl = new dojo.NodeList(dojo.byId("c1"), dojo.byId("t"));
+							nl.forEach(function(i){ lastItem = i; });
+							t.is(dojo.byId("t"), lastItem);
+
+							nl.forEach(function(i, idx, arr){
+								t.t(arr instanceof dojo.NodeList);
+								t.is(2, arr.length);
+							});
+						},
+						function indexOf(t){
+							t.is(0, fourElementNL.indexOf(dojo.byId("c1")));
+							t.is(1, fourElementNL.indexOf(dojo.byId("t")));
+							t.is(-1, fourElementNL.indexOf(null));
+						},
+						function lastIndexOf(t){
+							t.is(2, fourElementNL.lastIndexOf(dojo.byId("c1")));
+							t.is(3, fourElementNL.lastIndexOf(dojo.byId("t")));
+							t.is(-1, fourElementNL.lastIndexOf(null));
+						},
+						function every(t){
+							var ctr = 0;
+							var ret = fourElementNL.every(function(){
+								ctr++;
+								return true;
+							});
+							t.is(4, ctr);
+							t.t(ret);
+
+							ctr = 0;
+							var ret = fourElementNL.every(function(){
+								ctr++;
+								return false;
+							});
+							t.is(1, ctr);
+							t.f(ret);
+						},
+						function some(t){
+							var ret = fourElementNL.some(function(){
+								return true;
+							});
+							t.t(ret);
+
+							var ret = fourElementNL.some(function(i){
+								return (i.id == "t");
+							});
+							t.t(ret);
+						},
+						function map(t){
+							var ret = fourElementNL.map(function(){
+								return true;
+							});
+							t.is(ret, [true, true, true, true]);
+							var cnt = 0;
+							var ret = fourElementNL.map(function(){
+								return cnt++;
+							});
+							t.is(ret, [0, 1, 2, 3]);
+							// FIXME: need more tests on map!!
+						},
+
+						// sub-search
+						function query(t){
+							var pnl = new dojo.NodeList(dojo.byId("t"));
+							t.is(dojo.byId("c1"), pnl.query("span")[0]);
+							t.is(dojo.byId("t"), dojo.query("body").query(":last-child")[0]);
+							t.is(dojo.byId("c1"), dojo.query("body").query(":last-child")[1]);
+							t.is(1, pnl.query().length);
+						},
+						function filter(t){
+							t.is(dojo.query("body :first-child").filter(":last-child")[0], dojo.byId("c1"));
+							t.is(1, dojo.query("*").filter(function(n){ return (n.nodeName.toLowerCase() == "span"); }).length);
+
+							var filterObj = {
+								filterFunc: function(n){
+									return (n.nodeName.toLowerCase() == "span");
+								}
+							};
+							t.is(1, dojo.query("*").filter(filterObj.filterFunc).length);
+							t.is(1, dojo.query("*").filter(filterObj.filterFunc, filterObj).length);
+						},
+
+						// layout DOM functions
+						function box(t){
+							var tnl = new dojo.NodeList(dojo.byId('sq100'))
+							t.is(100, tnl.box().w);
+							t.is(100, tnl.box().h);
+						},
+						function boxes(t){
+							var tnl = new dojo.NodeList(dojo.byId('sq100'))
+							t.is(100, tnl.boxes()[0].w);
+							t.is(100, tnl.boxes()[0].h);
+							t.is(document.body.getElementsByTagName("*").length, dojo.query("body *").boxes().length);
+						},
+						function style(t){
+							var sq100 = dojo.byId("sq100")
+							var tnl = new dojo.NodeList(sq100)
+							t.is(1, tnl.style("opacity"));
+							tnl.push(dojo.byId("t"));
+							dojo.style(dojo.byId("t"), "opacity", 0.5);
+							t.is(1, tnl.style("opacity"));
+						},
+						function styles(t){
+							var tnl = new dojo.NodeList(dojo.byId("sq100"));
+							t.is(1, tnl.styles("opacity")[0]);
+							tnl.push(dojo.byId("t"));
+							dojo.style(dojo.byId("t"), "opacity", 0.5);
+							t.is(0.5, tnl.styles("opacity")[1]);
+						}/*,
+						function place(t){
+						},
+						function orphan(t){
+						},
+						function adopt(t){
+						},
+						function addContent(t){
+						}
+						*/
+					]
+				);
+				doh.run();
+			});
+		</script>
+	</head>
+	<body>
+		<h1>testing dojo.NodeList</h1>
+		<div id="sq100">
+			100px square, abs
+		</div>
+		<div id="t">
+			<span id="c1">c1</span>
+		</div>
+	</body>
+</html>
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/bootstrap.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/bootstrap.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/bootstrap.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,86 @@
+dojo.provide("tests._base._loader.bootstrap");
+
+tests.register("tests._base._loader.bootstrap", 
+	[
+
+		function hasConsole(t){
+			t.assertTrue("console" in dojo.global);
+			t.assertTrue("assert" in console);
+			t.assertEqual("function", typeof console.assert);
+		},
+
+		function hasDjConfig(t){
+			t.assertTrue("djConfig" in dojo.global);
+		},
+
+		{
+			name: "getObject",
+			setUp: function(){
+				//Set an object in global scope.
+				dojo.global.globalValue = {
+					color: "blue",
+					size: 20
+				};
+				
+				//Set up an object in a specific scope.
+				this.foo = {
+					bar: {
+						color: "red",
+						size: 100
+					}
+				};
+			},
+			runTest: function(t){
+				//Test for existing object using global as root path.
+				var globalVar = dojo.getObject("globalValue");
+				t.is("object", (typeof globalVar));
+				t.assertEqual("blue", globalVar.color);
+				t.assertEqual(20, globalVar.size);
+				t.assertEqual("blue", dojo.getObject("globalValue.color"));
+				
+				//Test for non-existent object using global as root path.
+				//Then create it.
+				t.assertFalse(dojo.getObject("something.thatisNew"));
+				t.assertTrue(typeof(dojo.getObject("something.thatisNew", true)) == "object");
+				
+				//Test for existing object using another object as root path.
+				var scopedVar = dojo.getObject("foo.bar", false, this);
+				t.assertTrue(typeof(scopedVar) == "object");
+				t.assertEqual("red", scopedVar.color);
+				t.assertEqual(100, scopedVar.size);
+				t.assertEqual("red", dojo.getObject("foo.bar.color", true, this));
+				
+				//Test for existing object using another object as root path.
+				//Then create it.
+				t.assertFalse(dojo.getObject("something.thatisNew", false, this));
+				t.assertTrue(typeof(dojo.getObject("something.thatisNew", true, this)) == "object");
+			},
+			tearDown: function(){
+				//Clean up global object that should not exist if
+				//the test is re-run.
+				try{
+					delete dojo.global.something;
+					delete this.something;
+				}catch(e){}
+			}
+		},
+		
+		{
+			name: "exists",
+			setUp: function(){
+				this.foo = {
+					bar: {}
+				};
+			},
+			runTest: function(t){
+				t.assertTrue(dojo.exists("foo.bar", this));
+				t.assertFalse(dojo.exists("foo.bar"));
+			}
+		},
+
+		function evalWorks(t){
+			t.assertTrue(dojo.eval("(true)"));
+			t.assertFalse(dojo.eval("(false)"));
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/getText.txt
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/getText.txt	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/getText.txt	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1 @@
+dojo._getText() test data
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/hostenv_browser.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/hostenv_browser.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/hostenv_browser.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,11 @@
+dojo.provide("tests._base._loader.hostenv_browser");
+
+tests.register("tests._base._loader.hostenv_browser", 
+	[
+		function getText(t){
+			var filePath = dojo.moduleUrl("tests._base._loader", "getText.txt");
+			var text = dojo._getText(filePath);
+			t.assertEqual("dojo._getText() test data", text);
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/hostenv_rhino.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/hostenv_rhino.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/hostenv_rhino.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,13 @@
+dojo.provide("tests._base._loader.hostenv_rhino");
+
+tests.register("tests._base._loader.hostenv_rhino", 
+	[
+		function getText(t){
+			var filePath = dojo.moduleUrl("tests._base._loader", "getText.txt");
+			var text = (new String(readText(filePath)));
+			//The Java file read seems to add a line return.
+			text = text.replace(/[\r\n]+$/, "");
+			t.assertEqual("dojo._getText() test data", text);
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/hostenv_spidermonkey.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/hostenv_spidermonkey.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/hostenv_spidermonkey.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,11 @@
+dojo.provide("tests._base._loader.hostenv_spidermonkey");
+
+tests.register("tests._base._loader.hostenv_spidermonkey", 
+	[
+		function getText(t){
+			var filePath = dojo.moduleUrl("tests._base._loader", "getText.txt");
+			var text = readText(filePath);
+			t.assertEqual("dojo._getText() test data", text);
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/loader.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/loader.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/_loader/loader.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,48 @@
+dojo.provide("tests._base._loader.loader");
+
+tests.register("tests._base._loader.loader", 
+	[
+		function baseUrl(t){
+			var originalBaseUrl = djConfig["baseUrl"] || "./";
+
+			t.assertEqual(originalBaseUrl, dojo.baseUrl);
+		},
+		
+		function modulePaths(t){
+			dojo.registerModulePath("mycoolmod", "../some/path/mycoolpath");
+			dojo.registerModulePath("mycoolmod.widget", "http://some.domain.com/another/path/mycoolpath/widget");
+
+			t.assertEqual("../some/path/mycoolpath/util", dojo._getModuleSymbols("mycoolmod.util").join("/"));
+			t.assertEqual("http://some.domain.com/another/path/mycoolpath/widget", dojo._getModuleSymbols("mycoolmod.widget").join("/"));
+			t.assertEqual("http://some.domain.com/another/path/mycoolpath/widget/thingy", dojo._getModuleSymbols("mycoolmod.widget.thingy").join("/"));
+		},
+		
+		function moduleUrls(t){
+			dojo.registerModulePath("mycoolmod", "some/path/mycoolpath");
+			dojo.registerModulePath("mycoolmod2", "/some/path/mycoolpath2");
+			dojo.registerModulePath("mycoolmod.widget", "http://some.domain.com/another/path/mycoolpath/widget");
+
+
+			var basePrefix = dojo.baseUrl;
+			//dojo._Uri will strip off "./" characters, so do the same here
+			if(basePrefix == "./"){
+				basePrefix = "";
+			}
+			
+			t.assertEqual(basePrefix + "some/path/mycoolpath/my/favorite.html",
+				dojo.moduleUrl("mycoolmod", "my/favorite.html").toString());
+			t.assertEqual(basePrefix + "some/path/mycoolpath/my/favorite.html",
+				dojo.moduleUrl("mycoolmod.my", "favorite.html").toString());
+
+			t.assertEqual("/some/path/mycoolpath2/my/favorite.html",
+				dojo.moduleUrl("mycoolmod2", "my/favorite.html").toString());
+			t.assertEqual("/some/path/mycoolpath2/my/favorite.html",
+				dojo.moduleUrl("mycoolmod2.my", "favorite.html").toString());
+
+			t.assertEqual("http://some.domain.com/another/path/mycoolpath/widget/my/favorite.html",
+				dojo.moduleUrl("mycoolmod.widget", "my/favorite.html").toString());
+			t.assertEqual("http://some.domain.com/another/path/mycoolpath/widget/my/favorite.html",
+				dojo.moduleUrl("mycoolmod.widget.my", "favorite.html").toString());
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/array.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/array.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/array.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,254 @@
+dojo.provide("tests._base.array");
+
+tests.register("tests._base.array", 
+	[
+		function testIndexOf(t){
+			var foo = [128, 256, 512];
+			var bar = ["aaa", "bbb", "ccc"];
+			
+			t.assertTrue(dojo.indexOf([45, 56, 85], 56) == 1);
+			t.assertTrue(dojo.indexOf([Number, String, Date], String) == 1);
+			t.assertTrue(dojo.indexOf(foo, foo[1]) == 1);
+			t.assertTrue(dojo.indexOf(foo, foo[2]) == 2);
+			t.assertTrue(dojo.indexOf(bar, bar[1]) == 1);
+			t.assertTrue(dojo.indexOf(bar, bar[2]) == 2);
+			
+			foo.push(bar);
+			t.assertTrue(dojo.indexOf(foo, bar) == 3);
+		},
+
+		function testIndexOfFromIndex(t){
+			var foo = [128, 256, 512];
+			var bar = ["aaa", "bbb", "ccc"];
+			
+			// FIXME: what happens w/ negative indexes?
+			t.assertEqual(-1, dojo.indexOf([45, 56, 85], 56, 2));
+			t.assertEqual(1, dojo.indexOf([45, 56, 85], 56, 1));
+		},
+
+		function testLastIndexOf(t){
+			var foo = [128, 256, 512];
+			var bar = ["aaa", "bbb", "aaa", "ccc"];
+			
+			t.assertTrue(dojo.indexOf([45, 56, 85], 56) == 1);
+			t.assertTrue(dojo.indexOf([Number, String, Date], String) == 1);
+			t.assertTrue(dojo.lastIndexOf(foo, foo[1]) == 1);
+			t.assertTrue(dojo.lastIndexOf(foo, foo[2]) == 2);
+			t.assertTrue(dojo.lastIndexOf(bar, bar[1]) == 1);
+			t.assertTrue(dojo.lastIndexOf(bar, bar[2]) == 2);
+			t.assertTrue(dojo.lastIndexOf(bar, bar[0]) == 2);
+		},
+
+		function testLastIndexOfFromIndex(t){
+			// FIXME: what happens w/ negative indexes?
+			t.assertEqual(1, dojo.lastIndexOf([45, 56, 85], 56, 1));
+			t.assertEqual(-1, dojo.lastIndexOf([45, 56, 85], 85, 1));
+		},
+
+		function testForEach(t){
+			var foo = [128, "bbb", 512];
+			dojo.forEach(foo, function(elt, idx, array){
+				switch(idx){
+					case 0: t.assertEqual(128, elt); break;
+					case 1: t.assertEqual("bbb", elt); break;
+					case 2: t.assertEqual(512, elt); break;
+					default: t.assertTrue(false);
+				}
+			});
+
+			var noException = true;
+			try{
+				dojo.forEach(undefined, function(){});
+			}catch(e){
+				noException = false;
+			}
+			t.assertTrue(noException);
+		},
+
+		function testForEach_str(t){
+			var bar = 'abc';
+			dojo.forEach(bar, function(elt, idx, array){
+				switch(idx){
+					case 0: t.assertEqual("a", elt); break;
+					case 1: t.assertEqual("b", elt); break;
+					case 2: t.assertEqual("c", elt); break;
+					default: t.assertTrue(false);
+				}
+			});
+		},
+		// FIXME: test forEach w/ a NodeList()?
+
+		function testEvery(t){
+			var foo = [128, "bbb", 512];
+
+			t.assertTrue(
+				dojo.every(foo, function(elt, idx, array){
+					t.assertEqual(Array, array.constructor);
+					t.assertTrue(dojo.isArray(array));
+					t.assertTrue(typeof idx == "number");
+					if(idx == 1){ t.assertEqual("bbb" , elt); }
+					return true;
+				})
+			);
+
+			t.assertTrue(
+				dojo.every(foo, function(elt, idx, array){
+					switch(idx){
+						case 0: t.assertEqual(128, elt); return true;
+						case 1: t.assertEqual("bbb", elt); return true;
+						case 2: t.assertEqual(512, elt); return true;
+						default: return false;
+					}
+				})
+			);
+
+			t.assertFalse(
+				dojo.every(foo, function(elt, idx, array){
+					switch(idx){
+						case 0: t.assertEqual(128, elt); return true;
+						case 1: t.assertEqual("bbb", elt); return true;
+						case 2: t.assertEqual(512, elt); return false;
+						default: return true;
+					}
+				})
+			);
+
+		},
+
+		function testEvery_str(t){
+			var bar = 'abc';
+			t.assertTrue(
+				dojo.every(bar, function(elt, idx, array){
+					switch(idx){
+						case 0: t.assertEqual("a", elt); return true;
+						case 1: t.assertEqual("b", elt); return true;
+						case 2: t.assertEqual("c", elt); return true;
+						default: return false;
+					}
+				})
+			);
+
+			t.assertFalse(
+				dojo.every(bar, function(elt, idx, array){
+					switch(idx){
+						case 0: t.assertEqual("a", elt); return true;
+						case 1: t.assertEqual("b", elt); return true;
+						case 2: t.assertEqual("c", elt); return false;
+						default: return true;
+					}
+				})
+			);
+		},
+		// FIXME: test NodeList for every()?
+
+		function testSome(t){
+			var foo = [128, "bbb", 512];
+			t.assertTrue(
+				dojo.some(foo, function(elt, idx, array){
+					t.assertEqual(3, array.length);
+					return true;
+				})
+			);
+
+			t.assertTrue(
+				dojo.some(foo, function(elt, idx, array){
+					if(idx < 1){ return true; }
+					return false;
+				})
+			);
+
+			t.assertFalse(
+				dojo.some(foo, function(elt, idx, array){
+					return false;
+				})
+			);
+
+			t.assertTrue(
+				dojo.some(foo, function(elt, idx, array){
+					t.assertEqual(Array, array.constructor);
+					t.assertTrue(dojo.isArray(array));
+					t.assertTrue(typeof idx == "number");
+					if(idx == 1){ t.assertEqual("bbb" , elt); }
+					return true;
+				})
+			);
+		},
+
+		function testSome_str(t){
+			var bar = 'abc';
+			t.assertTrue(
+				dojo.some(bar, function(elt, idx, array){
+					t.assertEqual(3, array.length);
+					switch(idx){
+						case 0: t.assertEqual("a", elt); return true;
+						case 1: t.assertEqual("b", elt); return true;
+						case 2: t.assertEqual("c", elt); return true;
+						default: return false;
+					}
+				})
+			);
+
+			t.assertTrue(
+				dojo.some(bar, function(elt, idx, array){
+					switch(idx){
+						case 0: t.assertEqual("a", elt); return true;
+						case 1: t.assertEqual("b", elt); return true;
+						case 2: t.assertEqual("c", elt); return false;
+						default: return true;
+					}
+				})
+			);
+
+			t.assertFalse(
+				dojo.some(bar, function(elt, idx, array){
+					return false;
+				})
+			);
+		},
+		// FIXME: need to add scoping tests for all of these!!!
+
+		function testFilter(t){
+			var foo = ["foo", "bar", 10];
+
+			t.assertEqual(["foo"],
+				dojo.filter(foo, function(elt, idx, array){
+					return idx < 1;
+				})
+			);
+
+			t.assertEqual(["foo"],
+				dojo.filter(foo, function(elt, idx, array){
+					return elt == "foo";
+				})
+			);
+
+			t.assertEqual([],
+				dojo.filter(foo, function(elt, idx, array){
+					return false;
+				})
+			);
+
+			t.assertEqual([10],
+				dojo.filter(foo, function(elt, idx, array){
+					return typeof elt == "number";
+				})
+			);
+		},
+
+		function testFilter_str(t){
+			var foo = "thinger blah blah blah";
+			t.assertEqual(["t", "h", "i"],
+				dojo.filter(foo, function(elt, idx, array){
+					return idx < 3;
+				})
+			);
+
+			t.assertEqual([],
+				dojo.filter(foo, function(elt, idx, array){
+					return false;
+				})
+			);
+		}
+	]
+);
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/connect.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/connect.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/connect.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,202 @@
+dojo.provide("tests._base.connect");
+
+hub = function(){
+}
+
+failures = 0;
+bad = function(){
+	failures++;
+}
+
+good = function(){
+}
+
+// make 'iterations' connections to hub
+// roughly half of which will be to 'good' and 
+// half to 'bad'
+// all connections to 'bad' are disconnected
+// test can then be performed on the values
+// 'failures' and 'successes'
+markAndSweepTest = function(iterations){
+	var marked = [];
+	// connections
+	for(var i=0; i<iterations; i++){
+		if(Math.random() < 0.5){
+			marked.push(dojo.connect('hub', bad));
+		}else{
+			dojo.connect('hub', good);
+		}
+	}
+	// Randomize markers (only if the count isn't very high)
+	if(i < Math.pow(10, 4)){
+		var rm = [ ];
+		while(marked.length){
+			var m = Math.floor(Math.random() * marked.length);
+			rm.push(marked[m]);
+			marked.splice(m, 1);
+		}
+		marked = rm;				
+	} 
+	for(var m=0; m<marked.length; m++){
+		dojo.disconnect(marked[m]);
+	}
+	// test
+	failures = 0;
+	hub();
+	// return number of disconnected functions that fired (should be 0)
+	return failures;
+}
+
+markAndSweepSubscribersTest = function(iterations){
+	var topic = "hubbins";
+	var marked = [];
+	// connections
+	for(var i=0; i<iterations; i++){
+		if(Math.random() < 0.5){
+			marked.push(dojo.subscribe(topic, bad));
+		}else{
+			dojo.subscribe(topic, good);
+		}
+	}
+	// Randomize markers (only if the count isn't very high)
+	if(i < Math.pow(10, 4)){
+		var rm = [ ];
+		while(marked.length){
+			var m = Math.floor(Math.random() * marked.length);
+			rm.push(marked[m]);
+			marked.splice(m, 1);
+		}
+		marked = rm;				
+	} 
+	for(var m=0; m<marked.length; m++){
+		dojo.unsubscribe(topic, marked[m]);
+	}
+	// test
+	failures = 0;
+	dojo.publish(topic);
+	// return number of unsubscribed functions that fired (should be 0)
+	return failures;
+}
+
+tests.register("tests._base.connect",
+	[
+		function smokeTest(t){
+			// foo sets ok to false
+			var ok, foo = { foo: function(){ok=false} };
+			// connected function sets ok to true
+			dojo.connect(foo, "foo", null, function(){ok=true});
+			foo.foo();
+			t.is(true, ok);
+		},
+		function basicTest(t) {
+			var out = '';
+			var obj = {
+				foo: function() {
+					out += 'foo';
+				},
+				bar: function() {
+					out += 'bar';
+				},
+				baz: function() {
+					out += 'baz';
+				}
+			};
+			//
+			var foobar = dojo.connect(obj, "foo", obj, "bar");
+			dojo.connect(obj, "bar", obj, "baz");
+			//
+			out = '';
+			obj.foo();
+			t.is('foobarbaz', out);
+			//
+			out = '';
+			obj.bar();
+			t.is('barbaz', out);
+			//
+			out = '';
+			obj.baz();
+			t.is('baz', out);
+			//
+			dojo.connect(obj, "foo", obj, "baz");
+			dojo.disconnect(foobar);
+			//
+			out = '';
+			obj.foo();
+			t.is('foobaz', out);
+			//
+			out = '';
+			obj.bar();
+			t.is('barbaz', out);
+			//
+			out = '';
+			obj.baz();
+			t.is('baz', out);
+		},
+		function hubConnectDisconnect1000(t){
+			t.is(markAndSweepTest(1000), 0);
+		},
+		function args4Test(t){
+			// standard 4 args test
+			var ok, obj = { foo: function(){ok=false;}, bar: function(){ok=true} };
+			dojo.connect(obj, "foo", obj, "bar");
+			obj.foo();
+			t.is(true, ok);
+		},
+		function args3Test(t){
+			// make some globals
+			var ok;
+			dojo.global["gFoo"] = function(){ok=false;};
+			dojo.global["gOk"] = function(){ok=true;};
+			// 3 arg shorthand for globals (a)
+			var link = dojo.connect("gFoo", null, "gOk");
+			gFoo();
+			dojo.disconnect(link);
+			t.is(true, ok);
+			// 3 arg shorthand for globals (b)
+			link = dojo.connect(null, "gFoo", "gOk");
+			gFoo();
+			dojo.disconnect(link);
+			t.is(true, ok);
+			// verify disconnections 
+			gFoo();
+			t.is(false, ok);
+		},
+		function args2Test(t){
+			// make some globals
+			var ok;
+			dojo.global["gFoo"] = function(){ok=false;};
+			dojo.global["gOk"] = function(){ok=true;};
+			// 2 arg shorthand for globals 
+			var link = dojo.connect("gFoo", "gOk");
+			gFoo();
+			dojo.disconnect(link);
+			t.is(true, ok);
+			// 2 arg shorthand for globals, alternate scoping 
+			link = dojo.connect("gFoo", gOk);
+			gFoo();
+			dojo.disconnect(link);
+			t.is(true, ok);
+		},
+		function scopeTest1(t){
+			var foo = { ok: true, foo: function(){this.ok=false;} };
+			var bar = { ok: false, bar: function(){this.ok=true} };
+			// link foo.foo to bar.bar with natural scope
+			var link = dojo.connect(foo, "foo", bar, "bar");
+			foo.foo();
+			t.is(false, foo.ok);
+			t.is(true, bar.ok);
+		},		
+		function scopeTest2(t){
+			var foo = { ok: true, foo: function(){this.ok=false;} };
+			var bar = { ok: false, bar: function(){this.ok=true} };
+			// link foo.foo to bar.bar such that scope is always 'foo'
+			var link = dojo.connect(foo, "foo", bar.bar);
+			foo.foo();
+			t.is(true, foo.ok);
+			t.is(false, bar.ok);
+		},
+		function publishSubscribe1000(t){
+			t.is(markAndSweepSubscribersTest(1000), 0);
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/declare.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/declare.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/declare.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,181 @@
+dojo.provide("tests._base.declare");
+
+tests.register("tests._base.declare",
+	[
+		function smokeTest(t){
+			dojo.declare("tests._base.declare.tmp");
+			var tmp = new tests._base.declare.tmp();
+			dojo.declare("testsFoo");
+			var tmp = new testsFoo();
+		},
+		function smokeTest2(t){
+			dojo.declare("tests._base.declare.foo", null, null, {
+				foo: "thonk"
+			});
+			var tmp = new tests._base.declare.foo();
+			t.is("thonk", tmp.foo);
+
+			dojo.declare("testsFoo2", null, null, {
+				foo: "thonk"
+			});
+			var tmp2 = new testsFoo2();
+			t.is("thonk", tmp2.foo);
+		},
+		function smokeTestWithCtor(t){
+			dojo.declare("tests._base.declare.fooBar", null, 
+				function(){
+					this.foo = "blah";
+				}, {
+					foo: "thonk"
+				}
+			);
+			var tmp = new tests._base.declare.fooBar();
+			t.is("blah", tmp.foo);
+		},
+		function smokeTestCompactArgs(t){
+			dojo.declare("tests._base.declare.fooBar2", null, {
+					foo: "thonk"
+				}
+			);
+			var tmp = new tests._base.declare.fooBar2();
+			t.is("thonk", tmp.foo);
+		},
+		function smokeTestWithSwappedArgs(t){
+			dojo.declare("tests._base.declare.fooBar3", null, 
+				{
+					foo: "thonk"
+				}, function(){
+					this.foo = "blah";
+				} 
+			);
+			var tmp = new tests._base.declare.fooBar3();
+			t.is("blah", tmp.foo);
+		},
+		function subclass(t){
+			dojo.declare("tests._base.declare.tmp3", null, {
+					foo: "thonk"
+				}
+			);
+			dojo.declare("tests._base.declare.tmp4",
+				tests._base.declare.tmp3);
+			var tmp = new tests._base.declare.tmp4();
+			t.is("thonk", tmp.foo);
+		},
+		function subclassWithCtor(t){
+			dojo.declare("tests._base.declare.tmp5", null, 
+				function(){
+					this.foo = "blah";
+				}, {
+					foo: "thonk"
+				}
+			);
+			dojo.declare("tests._base.declare.tmp6",
+				tests._base.declare.tmp5);
+			var tmp = new tests._base.declare.tmp6();
+			t.is("blah", tmp.foo);
+		},
+		function mixinSubclass(t){
+			dojo.declare("tests._base.declare.tmp7", null, null, {
+					foo: "thonk"
+				}
+			);
+			dojo.declare("tests._base.declare.tmp8", null, function(){
+				this.foo = "blah";
+			});
+			var tmp = new tests._base.declare.tmp8();
+			t.is("blah", tmp.foo);
+			dojo.declare("tests._base.declare.tmp9",
+				[
+					tests._base.declare.tmp7, // prototypal
+					tests._base.declare.tmp8  // mixin
+				]);
+			var tmp2 = new tests._base.declare.tmp9();
+			t.is("blah", tmp2.foo);
+		},
+		function superclassRef(t){
+			dojo.declare("tests._base.declare.tmp10", null, {
+					foo: "thonk"
+				}
+			);
+			dojo.declare("tests._base.declare.tmp11", 
+				tests._base.declare.tmp10, 
+				function(){
+					this.foo = "blah";
+				}
+			);
+			var tmp = new tests._base.declare.tmp11();
+			t.is("blah", tmp.foo);
+			t.is("thonk", tests._base.declare.tmp11.superclass.foo);
+		},
+		function inheritedCall(t){
+			var foo = "xyzzy";
+			dojo.declare("tests._base.declare.tmp12", null, {
+					foo: "thonk",
+					bar: function(arg1, arg2){
+						if(arg1){
+							this.foo = arg1;
+						}
+						if(arg2){
+							foo = arg2;
+						}
+					}
+				}
+			);
+			dojo.declare("tests._base.declare.tmp13", 
+				tests._base.declare.tmp12, 
+				function(){
+					this.foo = "blah";
+				}
+			);
+			var tmp = new tests._base.declare.tmp13();
+			t.is("blah", tmp.foo);
+			t.is("xyzzy", foo);
+			tmp.bar("zot");
+			t.is("zot", tmp.foo);
+			t.is("xyzzy", foo);
+			tmp.bar("trousers", "squiggle");
+			t.is("trousers", tmp.foo);
+			t.is("squiggle", foo);
+		},
+		function inheritedExplicitCall(t){
+			var foo = "xyzzy";
+			dojo.declare("tests._base.declare.tmp14", null, {
+					foo: "thonk",
+					bar: function(arg1, arg2){
+						if(arg1){
+							this.foo = arg1;
+						}
+						if(arg2){
+							foo = arg2;
+						}
+					}
+				}
+			);
+			dojo.declare("tests._base.declare.tmp15", 
+				tests._base.declare.tmp14, 
+				function(){
+					this.foo = "blah";
+				},{
+					bar: function(arg1, arg2){
+						this.inherited("bar", arguments, [arg2, arg1]);
+					},
+					baz: function(arg1, arg2){
+						tests._base.declare.tmp15.superclass.bar.apply(this, arguments);
+					}
+				}
+			);
+			var tmp = new tests._base.declare.tmp15();
+			t.is("blah", tmp.foo);
+			t.is("xyzzy", foo);
+			tmp.baz("zot");
+			t.is("zot", tmp.foo);
+			t.is("xyzzy", foo);
+			tmp.bar("trousers", "squiggle");
+			t.is("squiggle", tmp.foo);
+			t.is("trousers", foo);
+		}
+		// FIXME: there are still some permeutations to test like:
+		//	- ctor arguments
+		//	- multi-level inheritance + L/R conflict checks
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/fx.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/fx.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/fx.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,211 @@
+<html>
+	<head>
+		<title>testing Core FX</title>
+		<style type="text/css">
+			@import "../../resources/dojo.css";
+		</style>
+		<script type="text/javascript" 
+			src="../../dojo.js" 
+			djConfig="isDebug: true"></script>
+		<script type="text/javascript" src="../../_base/fx.js"></script>
+		<script type="text/javascript">
+			var duration = 1000;
+			dojo.require("doh.runner");
+			dojo.addOnLoad(function(){
+				doh.register("t", 
+					[
+						{
+							name: "fadeOut",
+							timeout: 1500,
+							runTest: function(t){
+								var opacity = dojo.style('foo', 'opacity');
+								t.is(1, opacity);
+								var anim = dojo.fadeOut({ node: 'foo', duration: duration });
+								var d = new doh.Deferred();
+								dojo.connect(anim, "onEnd", null, function(){
+									var opacity = dojo.style('foo', 'opacity');
+									// console.debug(anim._start);
+									var elapsed = (new Date()) - anim._start;
+									t.is(0, opacity);
+									t.assertTrue(elapsed >= duration);
+									d.callback(true);
+								});
+								anim._start = new Date();
+								anim.play();
+								return d;
+							}
+						},
+						{
+							name: "fadeIn",
+							timeout: 1500,
+							runTest: function(t){
+								var opacity = dojo.style('foo', 'opacity');
+								t.is(0, opacity);
+								var anim = dojo.fadeIn({ node: 'foo', duration: duration });
+								var d = new doh.Deferred();
+								dojo.connect(anim, "onEnd", null, function(){
+									var opacity = dojo.style('foo', 'opacity');
+									// console.debug(anim._start);
+									var elapsed = (new Date()) - anim._start;
+									t.is(1, opacity);
+									t.assertTrue(elapsed >= duration);
+									d.callback(true);
+								});
+								anim._start = new Date();
+								anim.play();
+								return d;
+							}
+						},
+						{
+							name: "animateColor",
+							timeout: 1500,
+							runTest: function(t){
+								var d = new doh.Deferred();
+								var anim = dojo.animateProperty({ 
+									node: "foo", 
+									duration: duration,
+									properties: { 
+										color: 				{ start: "black", end: "white" },
+										backgroundColor: 	{ start: "white", end: "black" } 
+									} 
+								});
+								dojo.connect(anim, "onEnd", anim, function(){
+									d.callback(true);
+								});
+								anim.play();
+								return d;
+							}
+						},
+						{
+							name: "animateColorBack",
+							timeout: 1500,
+							runTest: function(t){
+								var d = new doh.Deferred();
+								var anim = dojo.animateProperty({ 
+									node: "foo", 
+									duration: duration,
+									properties: { 
+										color: 				{ end: "black" },
+										backgroundColor: 	{ end: "#5d81b4" }, 
+										letterSpacing: 		{ start: 0, end: 10 } 
+									} 
+								});
+								dojo.connect(anim, "onEnd", anim, function(){
+									d.callback(true);
+								});
+								anim.play();
+								return d;
+							}
+						},
+						{
+							name: "animateHeight",
+							timeout: 1500,
+							runTest: function(t){
+								var startHeight = dojo.marginBox("foo").h; 
+								var endHeight = Math.round(startHeight / 2);
+								
+								var anim = dojo.animateProperty({
+									node: "foo",
+									properties: { height: { end: endHeight } },
+									duration: duration
+								});
+
+								var d = new doh.Deferred();
+
+								dojo.connect(anim, "onEnd", anim, function(){
+									var elapsed = (new Date().valueOf()) - anim._startTime;
+									t.assertTrue(elapsed >= duration);
+									var height = dojo.marginBox("foo").h; 
+									t.is(height, endHeight);
+									d.callback(true);
+								});
+								
+								anim.play();
+								return d;
+							}
+						},
+						{
+							name: "extractRgb",
+							runTest: function(t){
+								var white = [255,255,255];
+								function verifyColor(str, expected) {
+									var rgb = dojo.extractRgb(str);
+									t.is(expected, rgb);
+									dojo.forEach(rgb, function(n){ t.is("number", typeof(n)); });
+								}
+								verifyColor("white", white);
+								verifyColor("#fff", white);
+								verifyColor("#ffffff", white);
+								verifyColor("rgb(255,255,255)", white);
+							}
+						}
+					]
+				);
+				doh.run();
+			});
+		</script>
+		<style type="text/css">
+			body {
+				margin: 1em;
+				background-color: #DEDEDE;
+			}
+
+			.box {
+				color: #292929;
+				/* color: #424242; */
+				/* text-align: left; */
+				width: 300px;
+				border: 1px solid #BABABA;
+				background-color: white;
+				padding-left: 10px;
+				padding-right: 10px;
+				margin-left: 10px;
+				-o-border-radius: 10px;
+				-moz-border-radius: 12px;
+				-webkit-border-radius: 10px;
+				/* -opera-border-radius: 10px; */
+				border-radius: 10px;
+				-moz-box-sizing: border-box;
+				-opera-sizing: border-box;
+				-webkit-box-sizing: border-box;
+				-khtml-box-sizing: border-box;
+				box-sizing: border-box;
+				overflow: hidden;
+				/* position: absolute; */
+			}
+		</style>
+	</head>
+	<body>
+		<h1>testing Core FX</h1>
+		<form name="testForm">
+		<input type="button" onClick="dojo.fadeOut({ node: 'foo', duration: 1000 }).play()" value="fade out"></input>
+		<input type="button" onClick="dojo.fadeIn({ node: 'foo', duration: 1000 }).play()" value="fade in"></input>
+		</form>
+		<div id="foo" class="box" style="float: left;">
+			<p>
+			Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
+			semper sagittis velit. Cras in mi. Duis porta mauris ut ligula.
+			Proin porta rutrum lacus. Etiam consequat scelerisque quam. Nulla
+			facilisi.  Maecenas luctus venenatis nulla. In sit amet dui non mi
+			semper iaculis.  Sed molestie tortor at ipsum. Morbi dictum rutrum
+			magna. Sed vitae risus.
+			</p>
+			<p>
+			Aliquam vitae enim. Duis scelerisque metus auctor est venenatis
+			imperdiet. Fusce dignissim porta augue. Nulla vestibulum. Integer
+			lorem nunc, ullamcorper a, commodo ac, malesuada sed, dolor. Aenean
+			id mi in massa bibendum suscipit. Integer eros. Nullam suscipit
+			mauris. In pellentesque. Mauris ipsum est, pharetra semper,
+			pharetra in, viverra quis, tellus. Etiam purus. Quisque egestas,
+			tortor ac cursus lacinia, felis leo adipiscing nisi, et rhoncus
+			elit dolor eget eros. Fusce ut quam. Suspendisse eleifend leo vitae
+			ligula. Nulla facilisi. Nulla rutrum, erat vitae lacinia dictum,
+			pede purus imperdiet lacus, ut semper velit ante id metus. Praesent
+			massa dolor, porttitor sed, pulvinar in, consequat ut, leo. Nullam
+			nec est. Aenean id risus blandit tortor pharetra congue.
+			Suspendisse pulvinar.
+			</p>
+		</div>
+	</body>
+</html>
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/fx.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/fx.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/fx.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+dojo.provide("tests._base.fx");
+if(dojo.isBrowser){
+	doh.registerUrl("tests._base.fx", dojo.moduleUrl("tests", "_base/fx.html"), 15000);
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/html.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/html.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/html.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,286 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+	"http://www.w3.org/TR/html4/strict.dtd">
+<!--
+	we use a strict-mode DTD to ensure that the box model is the same for these
+	basic tests
+-->
+<html>
+	<head>
+		<title>testing Core HTML/DOM/CSS/Style utils</title>
+		<style type="text/css">
+			@import "../../resources/dojo.css";
+		</style>
+		<script type="text/javascript" 
+			src="../../dojo.js" 
+			djConfig="isDebug: true"></script>
+		<script type="text/javascript">
+			dojo.require("doh.runner");
+			dojo.addOnLoad(function(){
+				doh.register("t", 
+					[
+						"t.is(100, dojo.marginBox('sq100').w);",
+						"t.is(100, dojo.marginBox('sq100').h);",
+
+						"t.is(120, dojo.marginBox('sq100margin10').w);",
+						"t.is(120, dojo.marginBox('sq100margin10').h);",
+						"t.is(100, dojo.contentBox('sq100margin10').w);",
+						"t.is(100, dojo.contentBox('sq100margin10').h);",
+
+						"t.is(140, dojo.marginBox('sq100margin10pad10').w);",
+						"t.is(140, dojo.marginBox('sq100margin10pad10').h);",
+
+						"t.is(120, dojo.marginBox('sq100pad10').w);",
+						"t.is(120, dojo.marginBox('sq100pad10').h);",
+
+						"t.is(110, dojo.marginBox('sq100ltpad10').w);",
+						"t.is(110, dojo.marginBox('sq100ltpad10').h);",
+						"t.is(100, dojo.contentBox('sq100ltpad10').w);",
+						"t.is(100, dojo.contentBox('sq100ltpad10').h);",
+
+						"t.is(120, dojo.marginBox('sq100ltpad10rbmargin10').w);",
+						"t.is(120, dojo.marginBox('sq100ltpad10rbmargin10').h);",
+
+						"t.is(120, dojo.marginBox('sq100border10').w);",
+						"t.is(120, dojo.marginBox('sq100border10').h);",
+						"t.is(100, dojo.contentBox('sq100border10').w);",
+						"t.is(100, dojo.contentBox('sq100border10').h);",
+
+						"t.is(140, dojo.marginBox('sq100border10margin10').w);",
+						"t.is(140, dojo.marginBox('sq100border10margin10').h);",
+						"t.is(100, dojo.contentBox('sq100border10margin10').w);",
+						"t.is(100, dojo.contentBox('sq100border10margin10').h);",
+
+						"t.is(160, dojo.marginBox('sq100border10margin10pad10').w);",
+						"t.is(160, dojo.marginBox('sq100border10margin10pad10').h);",
+						"t.is(100, dojo.contentBox('sq100border10margin10pad10').w);",
+						"t.is(100, dojo.contentBox('sq100border10margin10pad10').h);",
+
+						"t.is(100, dojo.marginBox('sq100nopos').w);",
+						"t.is(100, dojo.marginBox('sq100nopos').h);",
+
+						function coordsBasic(t){
+							var pos = dojo.coords("sq100", false);
+							// console.debug(pos);
+							t.is(100, pos.x);
+							t.is(100, pos.y);
+							t.is(100, pos.w);
+							t.is(100, pos.h);
+						},
+						function coordsMargin(t){
+							// coords is getting us the margin-box location, is
+							// this right?
+							var pos = dojo.coords("sq100margin10", false);
+							t.is(260, pos.x);
+							t.is(110, pos.y);
+							t.is(120, pos.w);
+							t.is(120, pos.h);
+						},
+						function sq100nopos(t){
+							var pos = dojo.coords("sq100nopos", false);
+							// console.debug(pos);
+							t.is(0, pos.x);
+							t.t(pos.y > 0);
+							t.is(100, pos.w);
+							t.is(100, pos.h);
+						},
+						"t.is(1, dojo.style('sq100nopos', 'opacity'));",
+						"t.is(0.1, dojo.style('sq100nopos', 'opacity', 0.1));",
+						"t.is(0.8, dojo.style('sq100nopos', 'opacity', 0.8));",
+						"t.is('static', dojo.style('sq100nopos', 'position'));",
+						function getBgcolor(t){
+							var bgc = dojo.style('sq100nopos', 'backgroundColor');
+							t.t((bgc == "rgb(0, 0, 0)")||(bgc == "black")||(bgc == "#000000"));
+						}
+					]
+				);
+				doh.run();
+			});
+		</script>
+		<style type="text/css">
+			html, body {
+				padding: 0px;
+				margin: 0px;
+				border: 0px;
+			}
+
+			#sq100 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 100px;
+				top: 100px;
+				width: 100px;
+				height: 100px;
+				border: 0px;
+				padding: 0px;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#sq100margin10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 250px;
+				top: 100px;
+				width: 100px;
+				height: 100px;
+				border: 0px;
+				padding: 0px;
+				margin: 10px;
+				overflow: hidden;
+			}
+
+			#sq100margin10pad10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 400px;
+				top: 100px;
+				width: 100px;
+				height: 100px;
+				border: 0px;
+				padding: 10px;
+				margin: 10px;
+				overflow: hidden;
+			}
+
+			#sq100pad10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 100px;
+				top: 250px;
+				width: 100px;
+				height: 100px;
+				border: 0px;
+				padding: 10px;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#sq100ltpad10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 250px;
+				top: 250px;
+				width: 100px;
+				height: 100px;
+				border: 0px;
+				padding-left: 10px;
+				padding-top: 10px;
+				padding-right: 0px;
+				padding-bottom: 0px;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#sq100ltpad10rbmargin10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 400px;
+				top: 250px;
+				width: 100px;
+				height: 100px;
+				border: 0px;
+				padding-left: 10px;
+				padding-top: 10px;
+				padding-right: 0px;
+				padding-bottom: 0px;
+				margin-left: 0px;
+				margin-top: 0px;
+				margin-right: 10px;
+				margin-bottom: 10px;
+				overflow: hidden;
+			}
+
+			#sq100border10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 100px;
+				top: 400px;
+				width: 100px;
+				height: 100px;
+				border: 10px solid yellow;
+				padding: 0px;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#sq100border10margin10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 250px;
+				top: 400px;
+				width: 100px;
+				height: 100px;
+				border: 10px solid yellow;
+				padding: 0px;
+				margin: 10px;
+				overflow: hidden;
+			}
+
+			#sq100border10margin10pad10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 400px;
+				top: 400px;
+				width: 100px;
+				height: 100px;
+				border: 10px solid yellow;
+				padding: 10px;
+				margin: 10px;
+				overflow: hidden;
+			}
+
+			#sq100nopos {
+				background-color: black;
+				color: white;
+				width: 100px;
+				height: 100px;
+				padding: 0px;
+				margin: 0px;
+			}
+
+		</style>
+	</head>
+	<body>
+		<h1>testing Core HTML/DOM/CSS/Style utils</h1>
+		<div id="sq100">
+			100px square, abs
+		</div>
+		<div id="sq100margin10">
+			100px square, abs, 10px margin
+		</div>
+		<div id="sq100margin10pad10">
+			100px square, abs, 10px margin, 10px padding
+		</div>
+		<div id="sq100pad10">
+			100px square, abs, 10px padding
+		</div>
+		<div id="sq100ltpad10">
+			100px square, abs, 10px left and top padding
+		</div>
+		<div id="sq100ltpad10rbmargin10">
+			100px square, abs, 10px left and top padding, 10px bottom and right margin
+		</div>
+		<div id="sq100border10">
+			100px square, abs, 10px yellow border
+		</div>
+		<div id="sq100border10margin10">
+			100px square, abs, 10px yellow border, 10px margin
+		</div>
+		<div id="sq100border10margin10pad10">
+			100px square, abs, 10px yellow border, 10px margin, 10px padding
+		</div>
+		<div id="sq100nopos">
+			100px square, no positioning
+		</div>
+	</body>
+</html>
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/html.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/html.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/html.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+dojo.provide("tests._base.html");
+if(dojo.isBrowser){
+	doh.registerUrl("tests._base.html", dojo.moduleUrl("tests", "_base/html.html"));
+	doh.registerUrl("tests._base.html_quirks", dojo.moduleUrl("tests", "_base/html_quirks.html"));
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/html_quirks.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/html_quirks.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/html_quirks.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,315 @@
+<html>
+	<!--
+		we use a quirks-mode DTD on purpose to ensure that things go tilt. Wheee!!
+	-->
+	<head>
+		<title>testing Core HTML/DOM/CSS/Style utils in quirks mode</title>
+		<style type="text/css">
+			@import "../../resources/dojo.css";
+		</style>
+		<script type="text/javascript" 
+			src="../../dojo.js" 
+			djConfig="isDebug: true"></script>
+		<script type="text/javascript">
+			dojo.require("doh.runner");
+			dojo.addOnLoad(function(){
+				doh.register("t", 
+					[
+						"t.is(100, dojo.marginBox('sq100').w);",
+						"t.is(100, dojo.marginBox('sq100').h);",
+
+						"t.is(120, dojo.marginBox('sq100margin10').w);",
+						"t.is(120, dojo.marginBox('sq100margin10').h);",
+						"t.is(100, dojo.contentBox('sq100margin10').w);",
+						"t.is(100, dojo.contentBox('sq100margin10').h);",
+
+						"t.is(100, dojo.marginBox('sq100nopos').w);",
+						"t.is(100, dojo.marginBox('sq100nopos').h);",
+
+						function coordsBasic(t){
+							var pos = dojo.coords("sq100", false);
+							// console.debug(pos);
+							t.is(100, pos.x);
+							t.is(100, pos.y);
+							t.is(100, pos.w);
+							t.is(100, pos.h);
+						},
+						function coordsMargin(t){
+							// coords is getting us the margin-box location, is
+							// this right?
+							var pos = dojo.coords("sq100margin10", false);
+							t.is(260, pos.x);
+							t.is(110, pos.y);
+							t.is(120, pos.w);
+							t.is(120, pos.h);
+						},
+						function sq100nopos(t){
+							var pos = dojo.coords("sq100nopos", false);
+							// console.debug(pos);
+							t.is(0, pos.x);
+							t.t(pos.y > 0);
+							t.is(100, pos.w);
+							t.is(100, pos.h);
+						}
+					]
+				);
+				if(dojo.isIE){ 
+					// IE collapses padding in quirks mode. We just report on it.
+					doh.register("t", 
+						[
+							"t.is(120, dojo.marginBox('sq100margin10pad10').w);",
+							"t.is(120, dojo.marginBox('sq100margin10pad10').h);",
+
+							"t.is(100, dojo.marginBox('sq100pad10').w);",
+							"t.is(100, dojo.marginBox('sq100pad10').h);",
+
+							"t.is(100, dojo.marginBox('sq100ltpad10').w);",
+							"t.is(100, dojo.marginBox('sq100ltpad10').h);",
+							"t.is(90, dojo.contentBox('sq100ltpad10').w);",
+							"t.is(90, dojo.contentBox('sq100ltpad10').h);",
+
+							"t.is(110, dojo.marginBox('sq100ltpad10rbmargin10').w);",
+							"t.is(110, dojo.marginBox('sq100ltpad10rbmargin10').h);",
+
+							"t.is(100, dojo.marginBox('sq100border10').w);",
+							"t.is(100, dojo.marginBox('sq100border10').h);",
+							"t.is(80, dojo.contentBox('sq100border10').w);",
+							"t.is(80, dojo.contentBox('sq100border10').h);",
+
+							"t.is(120, dojo.marginBox('sq100border10margin10').w);",
+							"t.is(120, dojo.marginBox('sq100border10margin10').h);",
+							"t.is(80, dojo.contentBox('sq100border10margin10').w);",
+							"t.is(80, dojo.contentBox('sq100border10margin10').h);",
+
+							"t.is(120, dojo.marginBox('sq100border10margin10pad10').w);",
+							"t.is(120, dojo.marginBox('sq100border10margin10pad10').h);",
+							"t.is(60, dojo.contentBox('sq100border10margin10pad10').w);",
+							"t.is(60, dojo.contentBox('sq100border10margin10pad10').h);"
+						]
+					);
+				}else{
+					doh.register("t", 
+						[
+							"t.is(140, dojo.marginBox('sq100margin10pad10').w);",
+							"t.is(140, dojo.marginBox('sq100margin10pad10').h);",
+
+							"t.is(120, dojo.marginBox('sq100pad10').w);",
+							"t.is(120, dojo.marginBox('sq100pad10').h);",
+
+							"t.is(110, dojo.marginBox('sq100ltpad10').w);",
+							"t.is(110, dojo.marginBox('sq100ltpad10').h);",
+							"t.is(100, dojo.contentBox('sq100ltpad10').w);",
+							"t.is(100, dojo.contentBox('sq100ltpad10').h);",
+
+							"t.is(120, dojo.marginBox('sq100ltpad10rbmargin10').w);",
+							"t.is(120, dojo.marginBox('sq100ltpad10rbmargin10').h);",
+
+							"t.is(120, dojo.marginBox('sq100border10').w);",
+							"t.is(120, dojo.marginBox('sq100border10').h);",
+							"t.is(100, dojo.contentBox('sq100border10').w);",
+							"t.is(100, dojo.contentBox('sq100border10').h);",
+
+							"t.is(140, dojo.marginBox('sq100border10margin10').w);",
+							"t.is(140, dojo.marginBox('sq100border10margin10').h);",
+							"t.is(100, dojo.contentBox('sq100border10margin10').w);",
+							"t.is(100, dojo.contentBox('sq100border10margin10').h);",
+
+							"t.is(160, dojo.marginBox('sq100border10margin10pad10').w);",
+							"t.is(160, dojo.marginBox('sq100border10margin10pad10').h);",
+							"t.is(100, dojo.contentBox('sq100border10margin10pad10').w);",
+							"t.is(100, dojo.contentBox('sq100border10margin10pad10').h);"
+						]
+					);
+				}
+
+				doh.run();
+			});
+		</script>
+		<style type="text/css">
+			html, body {
+				padding: 0px;
+				margin: 0px;
+				border: 0px;
+			}
+
+			#sq100 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 100px;
+				top: 100px;
+				width: 100px;
+				height: 100px;
+				border: 0px;
+				padding: 0px;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#sq100margin10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 250px;
+				top: 100px;
+				width: 100px;
+				height: 100px;
+				border: 0px;
+				padding: 0px;
+				margin: 10px;
+				overflow: hidden;
+			}
+
+			#sq100margin10pad10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 400px;
+				top: 100px;
+				width: 100px;
+				height: 100px;
+				border: 0px;
+				padding: 10px;
+				margin: 10px;
+				overflow: hidden;
+			}
+
+			#sq100pad10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 100px;
+				top: 250px;
+				width: 100px;
+				height: 100px;
+				border: 0px;
+				padding: 10px;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#sq100ltpad10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 250px;
+				top: 250px;
+				width: 100px;
+				height: 100px;
+				border: 0px;
+				padding-left: 10px;
+				padding-top: 10px;
+				padding-right: 0px;
+				padding-bottom: 0px;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#sq100ltpad10rbmargin10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 400px;
+				top: 250px;
+				width: 100px;
+				height: 100px;
+				border: 0px;
+				padding-left: 10px;
+				padding-top: 10px;
+				padding-right: 0px;
+				padding-bottom: 0px;
+				margin-left: 0px;
+				margin-top: 0px;
+				margin-right: 10px;
+				margin-bottom: 10px;
+				overflow: hidden;
+			}
+
+			#sq100border10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 100px;
+				top: 400px;
+				width: 100px;
+				height: 100px;
+				border: 10px solid yellow;
+				padding: 0px;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#sq100border10margin10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 250px;
+				top: 400px;
+				width: 100px;
+				height: 100px;
+				border: 10px solid yellow;
+				padding: 0px;
+				margin: 10px;
+				overflow: hidden;
+			}
+
+			#sq100border10margin10pad10 {
+				background-color: black;
+				color: white;
+				position: absolute;
+				left: 400px;
+				top: 400px;
+				width: 100px;
+				height: 100px;
+				border: 10px solid yellow;
+				padding: 10px;
+				margin: 10px;
+				overflow: hidden;
+			}
+
+			#sq100nopos {
+				background-color: black;
+				color: white;
+				width: 100px;
+				height: 100px;
+				padding: 0px;
+				margin: 0px;
+			}
+
+		</style>
+	</head>
+	<body>
+		<h1>testing Core HTML/DOM/CSS/Style utils</h1>
+		<div id="sq100">
+			100px square, abs
+		</div>
+		<div id="sq100margin10">
+			100px square, abs, 10px margin
+		</div>
+		<div id="sq100margin10pad10">
+			100px square, abs, 10px margin, 10px padding
+		</div>
+		<div id="sq100pad10">
+			100px square, abs, 10px padding
+		</div>
+		<div id="sq100ltpad10">
+			100px square, abs, 10px left and top padding
+		</div>
+		<div id="sq100ltpad10rbmargin10">
+			100px square, abs, 10px left and top padding, 10px bottom and right margin
+		</div>
+		<div id="sq100border10">
+			100px square, abs, 10px yellow border
+		</div>
+		<div id="sq100border10margin10">
+			100px square, abs, 10px yellow border, 10px margin
+		</div>
+		<div id="sq100border10margin10pad10">
+			100px square, abs, 10px yellow border, 10px margin, 10px padding
+		</div>
+		<div id="sq100nopos">
+			100px square, no positioning
+		</div>
+	</body>
+</html>
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/json.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/json.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/json.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,27 @@
+dojo.provide("tests._base.json");
+
+tests.register("tests._base.json", 
+	[
+		//Not testing dojo.toJson() on its own since Rhino will output the object properties in a different order.
+		//Still valid json, but just in a different order than the source string.
+
+		// take a json-compatible object, convert it to a json string, then put it back into json.
+		function toAndFromJson(t){
+			var testObj = {a:"a", b:1, c:"c", d:"d", e:{e1:"e1", e2:2}, f:[1,2,3], g:"g",h:{h1:{h2:{h3:"h3"}}}};
+
+			var mirrorObj = dojo.fromJson(dojo.toJson(testObj));
+			t.assertEqual("a", mirrorObj.a);
+			t.assertEqual(1, mirrorObj.b);
+			t.assertEqual("c", mirrorObj.c);
+			t.assertEqual("d", mirrorObj.d);
+			t.assertEqual("e1", mirrorObj.e.e1);
+			t.assertEqual(2, mirrorObj.e.e2);
+			t.assertEqual(1, mirrorObj.f[0]);
+			t.assertEqual(2, mirrorObj.f[1]);
+			t.assertEqual(3, mirrorObj.f[2]);
+			t.assertEqual("g", mirrorObj.g);
+			t.assertEqual("h3", mirrorObj.h.h1.h2.h3);
+		}
+	]
+);
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/lang.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/lang.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/lang.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,156 @@
+dojo.provide("tests._base.lang");
+
+tests.register("tests._base.lang", 
+	[
+		function mixin(t){
+			var src = {
+				foo: function(){
+					t.debug("foo");
+				},
+				bar: "bar"
+			};
+			var dest = {};
+			dojo.mixin(dest, src);
+			t.assertEqual("function", typeof dest["foo"]);
+			t.assertEqual("string", typeof dest["bar"]);
+		},
+
+		function extend(t){
+			var src = {
+				foo: function(){
+					t.debug("foo");
+				},
+				bar: "bar"
+			};
+			function dest(){}
+			dojo.extend(dest, src);
+			var test = new dest();
+			t.assertEqual("function", typeof test["foo"]);
+			t.assertEqual("string", typeof test["bar"]);
+		},
+
+		function isObject(t){
+			t.assertFalse(dojo.isObject(true));
+			t.assertFalse(dojo.isObject(false));
+			t.assertFalse(dojo.isObject("foo"));
+			t.assertTrue(dojo.isObject(new String("foo")));
+			t.assertTrue(dojo.isObject(null));
+			t.assertTrue(dojo.isObject({}));
+			t.assertTrue(dojo.isObject([]));
+			t.assertTrue(dojo.isObject(new Array()));
+		},
+
+		function isArray(t){
+			t.assertTrue(dojo.isArray([]));
+			t.assertTrue(dojo.isArray(new Array()));
+			t.assertFalse(dojo.isArray({}));
+		},
+
+		function isArrayLike(t){
+			t.assertFalse(dojo.isArrayLike("thinger"));
+			t.assertTrue(dojo.isArrayLike(new Array()));
+			t.assertFalse(dojo.isArrayLike({}));
+			t.assertTrue(dojo.isArrayLike(arguments));
+		},
+
+		function isString(t){
+			t.assertFalse(dojo.isString(true));
+			t.assertFalse(dojo.isString(false));
+			t.assertTrue(dojo.isString("foo"));
+			t.assertTrue(dojo.isString(new String("foo")));
+			t.assertFalse(dojo.isString(null));
+			t.assertFalse(dojo.isString({}));
+			t.assertFalse(dojo.isString([]));
+		},
+
+		function partial(t){
+			var scope = { foo: "bar" };
+			var scope2 = { foo: "baz" };
+			function thinger(arg1, arg2){
+				return [this.foo, arg1, arg2];
+			}
+			
+			var st1 = dojo.partial(thinger);
+			t.assertEqual("bar", st1.call(scope)[0]);
+			t.assertEqual(undefined, st1()[0]);
+			var st2 = dojo.partial(thinger, "foo", "bar");
+			t.assertEqual("bar", st2()[2]);
+			var st3 = dojo.partial(thinger, "foo", "bar");
+		},
+
+		function nestedPartial(t){
+			function thinger(arg1, arg2){
+				return [arg1, arg2];
+			}
+			
+			var st1 = dojo.partial(thinger, "foo");
+			t.assertEqual(undefined, st1()[1]);
+			t.assertEqual("bar", st1("bar")[1]);
+
+			// partials can accumulate
+			var st2 = dojo.partial(st1, "thud");
+			t.assertEqual("foo", st2()[0]);
+			t.assertEqual("thud", st2()[1]);
+		},
+
+		function hitch(t){
+			var scope = { foo: "bar" };
+			var scope2 = { foo: "baz" };
+			function thinger(){
+				return [this.foo, arguments.length];
+			}
+			
+			var st1 = dojo.hitch(scope, thinger);
+			t.assertEqual("bar", st1()[0]);
+			t.assertEqual(0, st1()[1]);
+
+			var st2 = dojo.hitch(scope2, thinger);
+			t.assertEqual("baz", st2()[0]);
+			t.assertEqual(0, st1()[1]);
+			t.assertEqual(1, st1("blah")[1]);
+
+			// st2 should be "scope proof"
+			t.assertEqual("baz", st2.call(scope)[0]);
+		},
+
+		function hitchWithArgs(t){
+			var scope = { foo: "bar" };
+			var scope2 = { foo: "baz" };
+			function thinger(){
+				return [this.foo, arguments.length];
+			}
+			
+			var st1 = dojo.hitch(scope, thinger, "foo", "bar");
+			t.assertEqual("bar", st1()[0]);
+			t.assertEqual(2, st1()[1]);
+			var st2 = dojo.hitch(scope2, thinger, "foo", "bar");
+			t.assertEqual("baz", st2()[0]);
+			t.assertEqual(2, st2()[1]);
+		},
+
+		function hitchAsPartial(t){
+			var scope = { foo: "bar" };
+			var scope2 = { foo: "baz" };
+			function thinger(arg1, arg2){
+				return [this.foo, arg1, arg2];
+			}
+			
+			var st1 = dojo.hitch(null, thinger);
+			t.assertEqual("bar", st1.call(scope)[0]);
+			t.assertEqual(undefined, st1()[0]);
+			var st2 = dojo.hitch(null, thinger, "foo", "bar");
+			t.assertEqual("bar", st2()[2]);
+			var st3 = dojo.hitch(null, thinger, "foo", "bar");
+		},
+
+		function _toArray(t){
+			var obj1 = [ 'foo', 'bar', 'spam', 'ham' ];
+
+			function thinger(){
+				return dojo._toArray(arguments);
+			}
+			var obj2 = thinger.apply(this, obj1);
+			t.assertEqual(obj1[0], obj2[0]);
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/query.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/query.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/query.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,58 @@
+<html>
+	<head>
+		<title>testing dojo.query()</title>
+		<style type="text/css">
+			@import "../../resources/dojo.css";
+		</style>
+		<script type="text/javascript" src="../../dojo.js" 
+			djConfig="isDebug: true, noFirebugLite: true"></script>
+		<script type="text/javascript">
+			dojo.require("doh.runner");
+			dojo.addOnLoad(function(){
+				doh.register("t", 
+					[
+						"t.is(4, (dojo.query('h3')).length);",
+						"t.is(4, (dojo.query('#t h3')).length);",
+						"t.is(1, (dojo.query('#t div > h3')).length);",
+						"t.is(3, (dojo.query('#t > h3')).length);",
+						"t.is(3, (dojo.query('> h3', dojo.byId('t'))).length);",
+						"t.is(2, (dojo.query('.foo, .bar')).length);",
+						"t.is(2, (dojo.query('.foo,.bar')).length);",
+						"t.is(2, (dojo.query('.foo')).length);",
+						"t.is(2, (dojo.query('.baz')).length);",
+						"t.is(1, (dojo.query('span.baz')).length);",
+						// FIXME: need to support [foo="foo bar"]. We're incorrectly tokenizing!
+						"t.is(2, (dojo.query('[foo~=\"bar\"]')).length);",
+						"t.is(3, (dojo.query('[foo]')).length);",
+						"t.is(1, (dojo.query('[foo$=\"thud\"]')).length);",
+						"t.is(1, (dojo.query('[foo|=\"bar\"]')).length);",
+						"t.is(1, (dojo.query('[foo|=\"bar-baz\"]')).length);",
+						"t.is(0, (dojo.query('[foo|=\"baz\"]')).length);",
+						"t.is(dojo.byId('_foo'), dojo.query('.foo:nth-child(2)')[0]);"
+					]
+				);
+				doh.run();
+			});
+		</script>
+	</head>
+	<body>
+		<h1>testing dojo.query()</h1>
+		<div id="t">
+			<h3>h3 <span>span</span> endh3 </h3>
+			<!-- comment to throw things off -->
+			<div class="foo bar" id="_foo">
+				<h3>h3</h3>
+				<span id="foo"></span>
+				<span></span>
+			</div>
+			<h3>h3</h3>
+			<h3 class="baz">h3</h3>
+			<span class="foobar baz foo"></span>
+			<span foo="bar"></span>
+			<span foo="baz bar thud"></span>
+			<!-- FIXME: should foo="bar-baz-thud" match? [foo$=thud] ??? -->
+			<span foo="bar-baz-thudish"></span>
+		</div>
+	</body>
+</html>
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/query.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/query.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/query.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+dojo.provide("tests._base.query");
+if(dojo.isBrowser){
+	doh.registerUrl("tests._base.query", dojo.moduleUrl("tests", "_base/query.html"));
+	doh.registerUrl("tests._base.NodeList", dojo.moduleUrl("tests", "_base/NodeList.html"));
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/xhr.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/xhr.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/xhr.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,291 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>testing form and xhr utils</title>
+		<style type="text/css">
+			@import "../../resources/dojo.css";
+		</style>
+		<script type="text/javascript" 
+			src="../../dojo.js" djConfig="isDebug: true"></script>
+		<script type="text/javascript">
+			dojo.require("doh.runner");
+			dojo.addOnLoad(function(){
+				var f1fo = { blah: "blah" };
+				var f1foStr = "blah=blah";
+				var f1foJson = '{"blah":"blah"}';
+
+				var f2fo = { 
+					blah: "blah",
+					multi: [
+						"thud",
+						"thonk"
+					],
+					textarea: "textarea_value"
+				};
+				var f2foStr = "blah=blah&multi=thud&multi=thonk&textarea=textarea_value";
+				var f2foJson = '{"blah":"blah","multi":["thud","thonk"],"textarea":"textarea_value"}';
+
+				var f3fo = { 
+					spaces: "string with spaces"
+				};
+				var f3foStr = "spaces=string%20with%20spaces&";
+				var f3foJson = '{"spaces":"string with spaces"}';
+
+				doh.register("t", 
+					[
+						function formNodeToObject(t){
+							t.is(f1fo , dojo.formToObject(dojo.byId("f1")));
+						},
+						function formIdToObject(t){
+							t.is(f1fo , dojo.formToObject("f1"));
+						},
+						function formToObjectWithMultiSelect(t){
+							t.is(f2fo , dojo.formToObject("f2"));
+						},
+						function objectToQuery(t){
+							t.is(f1foStr , dojo.objectToQuery(f1fo));
+						},
+						function objectToQueryArr(t){
+							t.is(f2foStr, dojo.objectToQuery(f2fo));
+						},
+						function formToQuery(t){
+							t.is(f1foStr, dojo.formToQuery("f1"));
+						},
+						function formToQueryArr(t){
+							t.is(f2foStr, dojo.formToQuery("f2"));
+						},
+						function formToJson(t){
+							t.is(f1foJson, dojo.formToJson("f1"));
+						},
+						function formToJsonArr(t){
+							t.is(f2foJson, dojo.formToJson("f2"));
+						},
+						function queryToObject(t){
+							t.is(f1fo , dojo.queryToObject(f1foStr));
+							t.is(f2fo , dojo.queryToObject(f2foStr));
+							t.is(f3fo , dojo.queryToObject(f3foStr));
+						},
+						function textContentHandler(t){
+							t.is("foo bar baz ", 
+								dojo._contentHandlers.text({
+									responseText: "foo bar baz "
+								})
+							);
+						},
+						function jsonContentHandler(t){
+							var jsonObj = {
+								foo: "bar",
+								baz: [
+									{ thonk: "blarg" },
+									"xyzzy!"
+								]
+							};
+							t.is(jsonObj, 
+								dojo._contentHandlers.json({
+									responseText: dojo.toJson(jsonObj)
+								})
+							);
+						},
+						function jsonCFContentHandler(t){
+							var jsonObj = {
+								foo: "bar",
+								baz: [
+									{ thonk: "blarg" },
+									"xyzzy!"
+								]
+							};
+							t.is("",  // did we fail closed?
+								dojo._contentHandlers["json-comment-filtered"]({
+									responseText: dojo.toJson(jsonObj)
+								})
+							);
+							t.is(jsonObj,
+								dojo._contentHandlers["json-comment-filtered"]({
+									responseText: "\tblag\n/*"+dojo.toJson(jsonObj)+"*/\n\r\t\r"
+								})
+							);
+						},
+						function jsContentHandler(t){
+							var jsonObj = {
+								foo: "bar",
+								baz: [
+									{ thonk: "blarg" },
+									"xyzzy!"
+								]
+							};
+							t.is(jsonObj,
+								dojo._contentHandlers["javascript"]({
+									responseText: "("+dojo.toJson(jsonObj)+")"
+								})
+							);
+							t.t(dojo._contentHandlers["javascript"]({
+									responseText: "true;"
+								})
+							);
+							t.f(dojo._contentHandlers["javascript"]({
+									responseText: "false;"
+								})
+							);
+						},
+						function xmlContentHandler(t){
+							var fauxObj = {
+								foo: "bar",
+								baz: [
+									{ thonk: "blarg" },
+									"xyzzy!"
+								]
+							};
+							t.is(fauxObj,
+								dojo._contentHandlers["xml"]({ responseXML: fauxObj })
+							);
+						},
+						function xhrGet(t){
+							var d = new doh.Deferred();
+							var td = dojo.xhrGet({
+								url: "xhr.html", // self
+								preventCache: true
+							});
+							td.addCallback(function(text){
+								t.is(4, td.ioArgs.xhr.readyState);
+								return text; //must return a value here or the parent test deferred fails.
+							});
+							t.t(td instanceof dojo.Deferred);
+							td.addCallback(d, "callback");
+							return d;
+						},
+						function xhrGet404(t){
+							var d = new doh.Deferred();
+							try{
+								var td = dojo.xhrGet({
+									url: "xhr_blarg.html" // doesn't exist
+								}).addErrback(
+									function(err){
+										t.is(404, td.ioArgs.xhr.status);
+										return err; //must return a value here or the parent test deferred fails.
+									}
+								);
+								// td.addErrback(d, "callback");
+							}catch(e){
+								d.callback(true);
+							}
+							// return d;
+						},
+						function xhrGetContent(t){
+							var d = new doh.Deferred();
+							var td = dojo.xhrGet({
+								url: "xhr.html",
+								content: {
+									foo: [ "bar", "baz" ],
+									thud: "thonk",
+									xyzzy: 3
+								}
+							});
+							td.addCallback(function(text){
+								// console.debug(td, td.xhr, td.args);
+								t.is("xhr.html?foo=bar&foo=baz&thud=thonk&xyzzy=3", 
+										td.ioArgs.url);
+								d.callback(true);
+							});
+							return d;
+						},
+						function xhrGetForm(t){
+							var d = new doh.Deferred();
+							var td = dojo.xhrGet({
+								url: "xhr.html", // self
+								form: "f3"
+							});
+							td.addCallback(function(xhr){
+								// console.debug(td.args.url);
+								t.is("xhr.html?spaces=string%20with%20spaces", td.ioArgs.url);
+								d.callback(true);
+							});
+							return d;
+						},
+						function xhrGetFormWithContent(t){
+							// ensure that stuff passed via content over-rides
+							// what's specified in the form
+							var d = new doh.Deferred();
+							var td = dojo.xhrGet({
+								url: "xhr.html", // self
+								form: "f3",
+								content: { spaces: "blah" }
+							});
+							td.addCallback(function(xhr){
+								// console.debug(td.args.url);
+								t.is("xhr.html?spaces=blah", td.ioArgs.url);
+								d.callback(true);
+							});
+							return d;
+						},
+						function xhrPost(t){
+							var d = new doh.Deferred();
+							var td = dojo.xhrPost({
+								url: "xhr.html" // self
+							});
+							// t.t(td instanceof dojo.Deferred);
+							td.addBoth(function(res){
+								if(	(dojo._isDocumentOk(td.ioArgs.xhr))||
+									(td.ioArgs.xhr.status == 405)
+								){
+									d.callback(true);
+								}else{
+									d.errback(false);
+								}
+							});
+							return d;
+						},
+						function xhrPostWithContent(t){
+							var d = new doh.Deferred();
+							var td = dojo.xhrPost({
+								url: "xhr.html",
+								content: {
+									foo: [ "bar", "baz" ],
+									thud: "thonk",
+									xyzzy: 3
+								}
+							});
+							td.addBoth(function(text){
+								t.is("foo=bar&foo=baz&thud=thonk&xyzzy=3", 
+										td.ioArgs.query);
+								if(	(dojo._isDocumentOk(td.ioArgs.xhr))||
+									(td.ioArgs.xhr.status == 405)
+								){
+									d.callback(true);
+								}else{
+									d.errback(false);
+								}
+							});
+							return d;
+						}
+						// FIXME: need to add tests for rawPost
+						// FIXME: need to add tests for wrapForm
+					]
+				);
+				doh.run();
+			});
+		</script>
+	</head>
+	<body>
+		<form id="f1" style="border: 1px solid black;">
+			<input type="text" name="blah" value="blah">
+			<input type="text" name="no_value" value="blah" disabled>
+			<input type="button" name="no_value2" value="blah">
+		</form>
+		<form id="f2" style="border: 1px solid black;">
+			<input type="text" name="blah" value="blah">
+			<input type="text" name="no_value" value="blah" disabled>
+			<input type="button" name="no_value2" value="blah">
+			<select type="select" multiple name="multi" size="5">
+				<option value="blah">blah</option>
+				<option value="thud" selected>thud</option>
+				<option value="thonk" selected>thonk</option>
+			</select>
+			<textarea name="textarea">textarea_value</textarea>
+		</form>
+		<form id="f3" style="border: 1px solid black;">
+			<input type="hidden" name="spaces" value="string with spaces">
+		</form>
+	</body>
+</html>
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base/xhr.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base/xhr.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base/xhr.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+dojo.provide("tests._base.xhr");
+if(dojo.isBrowser){
+	doh.registerUrl("tests._base.xhr", dojo.moduleUrl("tests", "_base/xhr.html"));
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/_base.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/_base.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/_base.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,131 @@
+var testGlobal = this;
+try{
+	dojo.provide("tests._base");
+	testGlobal = dojo.global;
+}catch(e){ }
+
+// the test suite for the bootstrap. Requires hostenv and other base tests at
+// the end
+
+if(doh.selfTest){
+
+	doh.register("doh.smokeTest", 
+		[
+			function sanityCheckHarness(t){
+				// sanity checks
+				t.assertTrue(true);
+				t.assertFalse(false);
+				t.assertFalse(0);
+				t.assertFalse(null);
+				var tObj = { w00t: false, blarg: true };
+				t.assertEqual(
+					["thinger", "blah", tObj], 
+					["thinger", "blah", tObj]
+				);
+				t.assertEqual(tObj, tObj);
+			},
+			/*
+			// uncomment to tests exception handling
+			function sanityCheckassertTrue(t){
+				// should throw an error
+				t.assertTrue(false);
+			},
+			function sanityCheckassertFalse(t){
+				// should throw an error
+				t.assertFalse(true);
+			},
+			function sanityCheckassertEqual(t){
+				// should throw an error
+				t.assertEqual("foo", "bar");
+			},
+			*/
+			{
+				name: "eqTest",
+				// smoke test the fixture system
+				setUp: function(t){
+					this.foo = "blah";
+				},
+				runTest: function(t){
+					t.assertEqual("blah", this.foo);
+				},
+				tearDown: function(t){
+				}
+			}
+		]
+	);
+
+	if(testGlobal["dojo"]){
+		doh.register("tests._base", 
+			[
+				function dojoIsAvailable(t){
+					t.assertTrue(testGlobal["dojo"]);
+				}
+			]
+		);
+	}
+
+	if(testGlobal["setTimeout"]){
+		// a stone-stupid async test
+		doh.register("tests.async", 
+			[
+				{
+					name: "deferredSuccess",
+					runTest: function(t){
+						var d = new doh.Deferred();
+						setTimeout(d.getTestCallback(function(){
+							t.assertTrue(true);
+							t.assertFalse(false);
+						}), 50);
+						return d;
+					}
+				},
+				{
+					name: "deferredFailure",
+					runTest: function(t){
+						var d = new doh.Deferred();
+						setTimeout(function(){
+							d.errback(new Error("hrm..."));
+						}, 50);
+						return d;
+					}
+				},
+				{
+					name: "timeoutFailure",
+					timeout: 50,
+					runTest: function(t){
+						// timeout of 50
+						var d = new doh.Deferred();
+						setTimeout(function(){
+							d.callback(true);
+						}, 100);
+						return d;
+					}
+				}
+			]
+		);
+	}
+}
+
+try{
+	// go grab the others
+	dojo.require("tests._base._loader.bootstrap");
+	dojo.require("tests._base._loader.loader");
+	dojo.platformRequire({
+		browser: ["tests._base._loader.hostenv_browser"],
+		rhino: ["tests._base._loader.hostenv_rhino"],
+		spidermonkey: ["tests._base._loader.hostenv_spidermonkey"]
+	});
+	dojo.require("tests._base.array");
+	dojo.require("tests._base.lang");
+	dojo.require("tests._base.declare");
+	dojo.require("tests._base.connect");
+	dojo.require("tests._base.Deferred");
+	dojo.require("tests._base.json");
+	// FIXME: add test includes for the rest of the Dojo Base groups here
+	dojo.requireIf(dojo.isBrowser, "tests._base.html");
+	dojo.requireIf(dojo.isBrowser, "tests._base.fx");
+	dojo.requireIf(dojo.isBrowser, "tests._base.query");
+	dojo.requireIf(dojo.isBrowser, "tests._base.xhr");
+}catch(e){
+	doh.debug(e);
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/back-bookmark.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/back-bookmark.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/back-bookmark.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,163 @@
+<html>
+<head>
+	<script language="JavaScript" type="text/javascript">
+		// Dojo configuration
+		djConfig = {
+			//debugAtAllCosts: true, //Don't normally need this in applications.
+			isDebug: true,
+			dojoIframeHistoryUrl: "../../resources/iframe_history.html", //for xdomain
+			preventBackButtonFix: false
+		};
+	</script>
+	<script language="JavaScript" type="text/javascript" src="../../dojo.js"></script>
+	<script language="JavaScript" type="text/javascript" src="browser/ApplicationState.js"></script>
+	<script language="JavaScript" type="text/javascript">
+		dojo.require("dojo.lang.common");
+		dojo.require("dojo.undo.browser");
+		dojo.require("dojo.io.*");
+		//dojo.hostenv.writeIncludes(); //Don't normally need this in applications.
+	
+		//****************************************
+		function goIoBind(id){
+			doApplicationStateBind("browser/" + id + ".xml", "output", "dataOutput", id);
+		}
+
+		//****************************************
+		/*
+		This method illustrates using dojo.io.bind() that also saves an application
+		state via dojo.undo.browser (dojo.io.bind() will automatically use dojo.undo.browser
+		if the dojo.io.bind() request object contains a back for forward function).
+		*/
+		function doApplicationStateBind(url, outputDivId, backForwardOutputDivId, bookmarkValue){
+			dojo.io.bind({
+				//Standard dojo.io.bind parameter
+				url: url,
+		
+				//Standard dojo.io.bind parameter.
+				//For this test, all of the bind requests are for text/xml documents.
+				mimetype: "text/xml",
+				
+				//Standard dojo.io.bind parameter: if this is a value that evaluates
+				//to true, then the page URL will change (by adding a fragment identifier
+				//to the URL)
+				changeUrl: bookmarkValue,
+		
+				//Data for use once we have data for an ApplicationState object
+				outputDivId: outputDivId,
+				backForwardOutputDivId: backForwardOutputDivId,
+				
+				//A holder for the application state object.
+				//It will be created once we have a response from the bind request.
+				appState: null,
+				
+				//Standard dojo.io.bind parameter. The ioRequest object is returned
+				//to the load function as the fourth parameter. The ioRequest object
+				//is the object we are creating and passing to this dojo.io.bind() call.
+				load: function(type, evaldObj, xhrObject, ioRequest){
+					var stateData = "XHR: " + evaldObj.getElementsByTagName("data")[0].childNodes[0].nodeValue;
+					ioRequest.appState = new ApplicationState(stateData, ioRequest.outputDivId, ioRequest.backForwardOutputDivId);
+					ioRequest.appState.showStateData();
+				},
+		
+				back: function(){
+					this.appState.back();
+				},
+				
+				forward: function(){
+					this.appState.forward();
+				}
+			});
+		}
+
+		//****************************************
+		dojo.addOnLoad(function(){
+			//See if there is a bookmark hash on the page URL.
+			var bookmarkId = location.hash;
+			if(bookmarkId){
+				bookmarkId = bookmarkId.substring(1, bookmarkId.length);
+			}
+
+			//If we have a bookmark, load that as the initial state.
+			if(bookmarkId && bookmarkId.indexOf("xhr") == 0){
+				//Load the XHR data for the bookmarked URL
+				dojo.io.bind({
+					url: "browser/" + bookmarkId + ".xml",
+					mimetype: "text/xml",
+					dataId: bookmarkId,
+					load: function(type, evaldObj, http, kwArgs){
+						var stateData = "(Initial State) XHR: " + evaldObj.getElementsByTagName("data")[0].childNodes[0].nodeValue;
+						var appState = new ApplicationState(stateData, "output", "dataOutput");
+						appState.showStateData();
+
+						//Since this is the initial state, don't add it to the dojo.undo.browser
+						//history stack (notice that this dojo.io.bind() request does not define
+						//any back or forward functions). Instead, register the result of this bind
+						//as the initial state for the page.
+						dojo.undo.browser.setInitialState(appState);
+					}
+				});
+			}else{
+				var appState = new ApplicationState("This is the initial state (page first loaded, no dojo.io.bind() calls yet)", "output", "dataOutput");
+				appState.showStateData();
+				dojo.undo.browser.setInitialState(appState);
+			}
+		});
+	</script>
+</head>
+<body>
+	<div style="padding-bottom: 20px; width: 100%; border-bottom: 1px solid gray">
+	<h3>dojo.undo.browser test (dojo.io.bind() with bookmarking)</h3>
+	
+	See the Dojo Book entry for 
+	<a href="http://manual.dojotoolkit.org/WikiHome/DojoDotBook/DocFn1">Back Button and Bookmarking</a>.
+		
+	<p>This page tests the dojo.undo.browser back/forward integration with dojo.io.bind(),
+	and dojo.undo.browser's bookmarking facility. For a back/forward test without bookmarking,
+	see <a href="test_browser.html">test_browser.html</a>.</p>
+	
+	<p>The buttons that start with "XHR" use
+	dojo.io.bind to do some XMLHTTPRequest calls for some test data, and they
+	also define back/forward handlers, so dojo.io should use dojo.undo.browser
+	add to history tracking.</p>
+
+	<p>To test the bookmarking facility:</p>
+	<ul>
+		<li>Click on one of the buttons below.</li>
+		<li>Save the resulting URL as a bookmark.</li>
+		<li>Close the browser window, or navigate to a different page.</li>
+		<li>Click on the bookmark to jump to that state in the page</li>
+	</p>
+
+	<p>Other notes:</p>
+	
+	<ul>
+		<li>Don't test this page using local disk for MSIE. MSIE will not
+		create a history list for iframe_history.html if served from a file:
+		URL. The XML served back from the XHR tests will also not be properly
+		created if served from local disk. Serve the test pages from a web
+		server to test in that browser.</li>
+		<li>Safari 2.0.3+ (and probably 1.3.2+): Only the back button works OK
+		(not the forward button), and only if changeUrl is NOT used (so it <b>will not</b>
+		work for this test page, since it is using bookmarking -- changeUrl). 
+		When changeUrl is used, Safari jumps all the way
+		back to whatever page was shown before the page that uses
+		dojo.undo.browser support.</li>
+		<li>Opera 8.5.3: Does not work.</li>
+		<li>Konqueror: Unknown. The latest may have Safari's behavior.</li>
+	</ul>
+	</div>
+	<div style="float:left; padding: 20px">
+		<button onclick="goIoBind('xhr1')">XHR 1</button><br />
+		<button onclick="goIoBind('xhr2')">XHR 2</button><br />
+		<button onclick="goIoBind('xhr3')">XHR 3</button><br />
+		<button onclick="goIoBind('xhr4')">XHR 4</button><br />	
+	</div>
+	<div style="float: left; padding: 20px">
+		<b>Data Output:</b><br />
+		<div id="output"></div>
+		<hr />
+		<i>Back/Forward Info:</i><br />
+		<div id="dataOutput"></div>
+	</div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/back.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/back.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/back.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,105 @@
+<html>
+<head>
+	<script language="JavaScript" type="text/javascript">
+		// Dojo configuration
+		djConfig = {
+			//debugAtAllCosts: true, //Don't normally need this in applications.
+			isDebug: true,
+			dojoIframeHistoryUrl: "../../resources/iframe_history.html", //for xdomain
+			preventBackButtonFix: false
+		};
+	</script>
+	<script type="text/javascript" 
+	        src="../dojo.js" 
+	        djConfig="isDebug:true, dojoIframeHistoryUrl: '../resources/iframe_history.html'"></script>
+	<script type="text/javascript" src="../back.js"></script>
+	<script type="text/javascript">	
+		ApplicationState = function(stateData, outputDivId, backForwardOutputDivId, bookmarkValue){
+			this.stateData = stateData;
+			this.outputDivId = outputDivId;
+			this.backForwardOutputDivId = backForwardOutputDivId;
+			this.changeUrl = bookmarkValue;
+		}
+	
+		dojo.extend(ApplicationState, {
+			back: function(){
+				this.showBackForwardMessage("BACK for State Data: " + this.stateData);
+				this.showStateData();
+			},
+			forward: function(){
+				this.showBackForwardMessage("FORWARD for State Data: " + this.stateData);
+				this.showStateData();
+			},
+			showStateData: function(){
+				dojo.byId(this.outputDivId).innerHTML += this.stateData + '<br />';
+			},
+			showBackForwardMessage: function(message){
+				dojo.byId(this.backForwardOutputDivId).innerHTML += message + '<br />';
+			}
+		});
+		
+		var data = {
+			link0: "This is the initial state (page first loaded)",
+			link1: "This is data for link 1",
+			link2: "This is data for link 2",
+			link3: "This is data for link 3",
+			link4: "This is data for link 4",
+			link5: "This is data for link 5",
+			link6: "This is data for link 6",
+			link7: "This is data for link 7"
+		};
+
+		function goNav(id){
+			var appState = new ApplicationState(data[id], "output", "dataOutput", id);
+			appState.showStateData();
+			dojo.back.addToHistory(appState);
+		}
+
+		dojo.addOnLoad(function(){
+			var appState = new ApplicationState(data["link0"], "output", "dataOutput");
+			appState.showStateData();
+			dojo.back.setInitialState(appState);
+		});
+	</script>
+</head>
+<body>
+	<script type="text/javascript">dojo.back.init();</script>
+	<div style="padding-bottom: 20px; width: 100%; border-bottom: 1px solid gray">
+	<h3>dojo.back test</h3>
+	
+	
+	<p>This page tests the dojo.back back/forward code. It <b>does not</b>
+	use the bookmarking facility of dojo.back. For that test,
+	see <a href="back-bookmark.html">back-bookmark.html</a>.</p>
+	
+	<p>The buttons that start with "Link" on them don't use any dojo.xhr* calls,
+	just JS data already in the page.</p>
+	
+	<ul>
+		<li>Don't test this page using local disk for MSIE. MSIE will not
+		create a history list for iframe_history.html if served from a file:
+		URL. Serve the test pages from a web server to test in that browser.</li>
+		<li>Safari 2.0.3+ (and probably 1.3.2+): Only the back button works OK
+		(not the forward button).</li>
+		<li>Opera 8.5.3: Does not work.</li>
+		<li>Konqueror: Unknown. The latest may have Safari's behavior.</li>
+	</ul>
+	</div>
+	<div style="float:left; padding: 20px">
+		<button onclick="goNav('link1')">Link 1</button><br />
+		<button onclick="goNav('link2')">Link 2</button><br />
+		<button onclick="goNav('link3')">Link 3</button><br />
+		<button onclick="goNav('link4')">Link 4</button><br />
+		<button onclick="goNav('link5')">Link 5</button><br />
+		<button onclick="goNav('link6')">Link 6</button><br />
+		<button onclick="goNav('link7')">Link 7</button><br />
+	</div>
+	<div style="float: left; padding: 20px">
+		<b>Data Output:</b><br />
+		<div id="output"></div>
+		<hr />
+		<i>Back/Forward Info:</i><br />
+		<div id="dataOutput"></div>
+	</div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/back.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/back.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/back.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+dojo.provide("tests.back");
+if(dojo.isBrowser){
+	doh.registerUrl("tests.back", dojo.moduleUrl("tests", "back.html"));
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/behavior.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/behavior.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/behavior.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,98 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>Testing dojo.behavior</title>
+		<style type="text/css">
+			@import "../resources/dojo.css";
+		</style>
+		<script type="text/javascript" 
+			src="../dojo.js" djConfig="isDebug: false"></script>
+		<script type="text/javascript">
+			dojo.require("doh.runner");
+			dojo.require("dojo.behavior");
+
+			var applyCount = 0;
+
+			var behaviorObj = {
+				".bar": 		function(elem){ 
+					dojo.style(elem, "opacity", 0.5);
+					applyCount++;
+				},
+				".foo > span":	function(elem){ 
+					elem.style.fontStyle = "italic";
+					applyCount++;
+				}
+			}
+
+			var topicCount = 0;
+			dojo.subscribe("/foo", function(){ topicCount++; });
+
+			// no behaviors should be executed when onload fires
+			dojo.addOnLoad(function(){
+				doh.register("t", 
+					[
+						function add(t){
+							t.f(dojo.behavior._behaviors[".bar"]);
+							t.f(dojo.behavior._behaviors[".foo > span"]);
+							dojo.behavior.add(behaviorObj);
+							// make sure they got plopped in
+							t.t(dojo.behavior._behaviors[".bar"]);
+							t.is(1, dojo.behavior._behaviors[".bar"].length);
+							t.t(dojo.behavior._behaviors[".foo > span"]);
+							t.is(1, dojo.behavior._behaviors[".foo > span"].length);
+						},
+						function apply(t){
+							t.is(0, applyCount);
+							dojo.behavior.apply();
+							t.is(2, applyCount);
+
+							// reapply and make sure we only match once
+							dojo.behavior.apply();
+							t.is(2, applyCount);
+						},
+						function reapply(t){
+							t.is(2, applyCount);
+							// add the rules again
+							dojo.behavior.add(behaviorObj);
+							dojo.behavior.apply();
+							t.is(4, applyCount);
+							// dojo.behavior.apply();
+							// t.is(4, applyCount);
+							// dojo.query(".bar").styles("opacity", 1.0);
+						},
+						function topics(t){
+							t.is(0, topicCount);
+							dojo.behavior.add({ ".foo": "/foo" });
+							dojo.behavior.apply();
+							t.is(2, topicCount);
+
+							dojo.behavior.add({ ".foo": {
+									"onfocus": "/foo" 
+								}
+							});
+							dojo.behavior.apply();
+							t.is(2, topicCount);
+							dojo.byId("blah").focus();
+							t.is(3, topicCount);
+							dojo.byId("blah").blur();
+							dojo.byId("blah").focus();
+							t.is(4, topicCount);
+
+						}
+					]
+				);
+				doh.run();
+			});
+		</script>
+	</head>
+	<body>
+		<div class="foo" id="fooOne">
+			<span>.foo &gt; span</span>	
+			<div class="bar">
+				<span>.foo &gt; .bar &gt; span</span>	
+			</div>
+		</div>
+		<input type="text" id="blah" class="foo blah" name="thinger" value="thinger">
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/behavior.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/behavior.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/behavior.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+dojo.provide("tests.behavior");
+if(dojo.isBrowser){
+	doh.registerUrl("tests.behavior", dojo.moduleUrl("tests", "behavior.html"));
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/cldr.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/cldr.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/cldr.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,15 @@
+dojo.provide("tests.cldr");
+
+dojo.require("dojo.cldr.supplemental");
+dojo.require("dojo.cldr.monetary");
+
+tests.register("tests.cldr", 
+	[
+		function test_date_getWeekend(t){
+			t.is(6, dojo.cldr.supplemental.getWeekend('en-us').start);
+			t.is(0, dojo.cldr.supplemental.getWeekend('en-us').end);
+			t.is(5, dojo.cldr.supplemental.getWeekend('he-il').start);
+			t.is(6, dojo.cldr.supplemental.getWeekend('he-il').end);
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/cookie.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/cookie.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/cookie.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,67 @@
+<html>
+	<head>
+		<title>testing Cookies</title>
+		<style type="text/css">
+			@import "../resources/dojo.css";
+		</style>
+		<script type="text/javascript"
+			src="../dojo.js"
+			djConfig="isDebug:true"></script>
+		<script type="text/javascript" src="../cookie.js"></script>
+		<script type="text/javascript">
+			dojo.require("doh.runner");
+			dojo.addOnLoad(function(){
+				doh.register("t",
+					[
+						{
+							name: "basicSet",
+							runTest: function(t){
+								// make sure the cookie is dead
+								var old = new Date(1976, 8, 15);
+								document.cookie = "dojo_test=blah; expires=" + old.toUTCString();
+								t.is(-1, document.cookie.indexOf("dojo_test="));
+								
+								// set the new one
+								var n = "dojo_test";
+								var v = "test value";
+								dojo.cookie(n, v);
+								t.t(document.cookie.indexOf(n+"=") >= 0);
+								var start = document.cookie.indexOf(n+"=") + n.length + 1;
+								var end = document.cookie.indexOf(";", start);
+								if(end == -1) end = document.cookie.length;
+								t.is(v, decodeURIComponent(document.cookie.substring(start, end)));
+							}
+						},
+						{
+							name: "basicGet",
+							runTest: function(t){
+								// set the cookie
+								var n = "dojo_test";
+								var v = "foofoo";
+								document.cookie = n + "=" + v;
+								
+								t.is(v, dojo.cookie(n));
+							}
+						},
+						{
+							name: "daysAsNumber",
+							runTest: function(t){
+								// set a cookie with a numerical expires
+								dojo.cookie("dojo_num", "foo", { expires: 10 });
+								t.is("foo", dojo.cookie("dojo_num"));
+								
+								// remove the cookie by setting it with a negative
+								// numerical expires. value doesn't really matter here
+								dojo.cookie("dojo_num", "-deleted-", { expires: -10 });
+								t.is(null, dojo.cookie("dojo_num"));
+							}
+						}
+					]
+				);
+				doh.run();
+			})
+		</script>
+	</head>
+	<body>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/cookie.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/cookie.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/cookie.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+dojo.provide("tests.cookie");
+if(dojo.isBrowser){
+	doh.registerUrl("tests.cookie", dojo.moduleUrl("tests", "cookie.html"));
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/currency.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/currency.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/currency.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,48 @@
+dojo.provide("tests.currency");
+
+dojo.require("dojo.currency");
+
+tests.register("tests.currency", 
+	[
+		{
+			// Test formatting and parsing of currencies in various locales pre-built in dojo.cldr
+			// NOTE: we can't set djConfig.extraLocale before bootstrapping unit tests, so directly
+			// load resources here for specific locales:
+
+			name: "currency",
+			setUp: function(){
+				var partLocaleList = ["en-us", "en-ca", "de-de"];
+				for(var i = 0 ; i < partLocaleList.length; i ++){
+					dojo.requireLocalization("dojo.cldr","currency",partLocaleList[i]);
+				}
+			},
+			runTest: function(t){
+				t.is("\u20ac123.45", dojo.currency.format(123.45, {currency: "EUR", locale: "en-us"}));
+				t.is("$123.45", dojo.currency.format(123.45, {currency: "USD", locale: "en-us"}));
+				t.is("$1,234.56", dojo.currency.format(1234.56, {currency: "USD", locale: "en-us"}));
+				t.is("US$123.45", dojo.currency.format(123.45, {currency: "USD", locale: "en-ca"}));
+				t.is("$123.45", dojo.currency.format(123.45, {currency: "CAD", locale: "en-ca"}));
+				t.is("Can$123.45", dojo.currency.format(123.45, {currency: "CAD", locale: "en-us"}));
+				t.is("123,45 \u20ac", dojo.currency.format(123.45, {currency: "EUR", locale: "de-de"}));
+				t.is("1.234,56 \u20ac", dojo.currency.format(1234.56, {currency: "EUR", locale: "de-de"}));
+				// There is no special currency symbol for ADP, so expect the ISO code instead
+				t.is("ADP123", dojo.currency.format(123, {currency: "ADP", locale: "en-us"}));
+
+				t.is(123.45, dojo.currency.parse("$123.45", {currency: "USD", locale: "en-us"}));
+				t.is(1234.56, dojo.currency.parse("$1,234.56", {currency: "USD", locale: "en-us"}));
+				t.is(123.45, dojo.currency.parse("123,45 \u20ac", {currency: "EUR", locale: "de-de"}));
+				t.is(1234.56, dojo.currency.parse("1.234,56 \u20ac", {currency: "EUR", locale: "de-de"}));
+				t.is(1234.56, dojo.currency.parse("1.234,56\u20ac", {currency: "EUR", locale: "de-de"}));
+
+				t.is(1234, dojo.currency.parse("$1,234", {currency: "USD", locale: "en-us"}));
+				t.is(1234, dojo.currency.parse("$1,234", {currency: "USD", fractional: false, locale: "en-us"}));
+				t.t(isNaN(dojo.currency.parse("$1,234", {currency: "USD", fractional: true, locale: "en-us"})));
+			},
+			tearDown: function(){
+				//Clean up bundles that should not exist if
+				//the test is re-run.
+				delete dojo.cldr.nls.currency;
+			}
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/data/JsonItemStore.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/data/JsonItemStore.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/data/JsonItemStore.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,1450 @@
+dojo.provide("tests.data.JsonItemStore");
+dojo.require("dojo.data.JsonItemStore");
+dojo.require("dojo.data.api.Read");
+dojo.require("dojo.data.api.Identity");
+
+
+tests.data.JsonItemStore.getCountriesStore = function(){
+	if(dojo.isBrowser){
+		return new dojo.data.JsonItemStore({url: dojo.moduleUrl("tests", "data/countries.json").toString() } );            
+	}else{
+		var jsonData = {};
+		jsonData.identifier="abbr";
+		jsonData.items= [];
+		jsonData.items.push({abbr:"ec",name:"Ecuador",capital:"Quito"});
+		jsonData.items.push({abbr:'eg',name:'Egypt',capital:'Cairo'});
+		jsonData.items.push({abbr:'sv',name:'El Salvador',capital:'San Salvador'});
+		jsonData.items.push({abbr:'gq',name:'Equatorial Guinea',capital:'Malabo'});
+		jsonData.items.push({abbr:'er',name:'Eritrea',capital:'Asmara'});
+		jsonData.items.push({abbr:'ee',name:'Estonia',capital:'Tallinn' });
+		jsonData.items.push({abbr:'et',name:'Ethiopia',capital:'Addis Ababa'});
+		return new dojo.data.JsonItemStore({data: jsonData});
+	}
+};
+
+tests.data.JsonItemStore.getCountriesAttrsStore = function(){
+	if(dojo.isBrowser){
+		return new dojo.data.JsonItemStore({url:  dojo.moduleUrl("tests", "data/countries_withattributes.json").toString() } ); 
+	}else{
+		var jsonData = {};
+		jsonData.identifier="name";
+		jsonData.items= [];
+		jsonData.items.push({name:"abbr"});
+		jsonData.items.push({name:"name"});
+		jsonData.items.push({name:"capital"});
+		jsonData.items.push({abbr:"ec",name:"Ecuador",capital:"Quito"});
+		jsonData.items.push({abbr:'eg',name:'Egypt',capital:'Cairo'});
+		jsonData.items.push({abbr:'sv',name:'El Salvador',capital:'San Salvador'});
+		jsonData.items.push({abbr:'gq',name:'Equatorial Guinea',capital:'Malabo'});
+		jsonData.items.push({abbr:'er',name:'Eritrea',capital:'Asmara'});
+		jsonData.items.push({abbr:'ee',name:'Estonia',capital:'Tallinn' });
+		jsonData.items.push({abbr:'et',name:'Ethiopia',capital:'Addis Ababa'});
+		return new dojo.data.JsonItemStore({data: jsonData});
+	}
+};
+
+doh.register("tests.data.JsonItemStore", 
+	[
+		function testIdentityAPI_getItemByIdentity(t){
+			//	summary: 
+			//		Simple test of the getItemByIdentity function of the store.
+			//	description:
+			//		Simple test of the getItemByIdentity function of the store.
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+
+			var item = jsonItemStore.getItemByIdentity("sv");
+			t.assertTrue(item !== null);
+			if(item !== null){
+				var name = jsonItemStore.getValue(item,"name");
+				t.assertEqual(name, "El Salvador");
+			}
+			item = jsonItemStore.getItemByIdentity("sv_not");
+			t.assertTrue(item === null);
+		},
+		function testIdentityAPI_getItemByIdentity_commentFilteredJson(t){
+			//	summary: 
+			//		Simple test of the getItemByIdentity function of the store.
+			//	description:
+			//		Simple test of the getItemByIdentity function of the store.
+			//		This tests loading a comment-filtered json file so that people using secure
+			//		data with this store can bypass the JavaSceipt hijack noted in Fortify's
+			//		paper.
+
+			var jsonItemStore = new dojo.data.JsonItemStore({url: dojo.moduleUrl("tests", "data/countries_commentFiltered.json").toString()});
+
+			var item = jsonItemStore.getItemByIdentity("sv");
+			t.assertTrue(item !== null);
+			if(item !== null){
+				var name = jsonItemStore.getValue(item,"name");
+				t.assertEqual(name, "El Salvador");
+			}
+		},
+		function testIdentityAPI_getItemByIdentity_nullValue(t){
+			//	summary: 
+			//		Simple test of the getItemByIdentity function of the store, checling a null value.
+			//	description:
+			//		Simple test of the getItemByIdentity function of the store, checking a null value.
+			//		This tests handling attributes in json that were defined as null properly.
+			//		Introduced because of tracker: #3153
+
+			var jsonItemStore = new dojo.data.JsonItemStore({url: dojo.moduleUrl("tests", "data/countries_withNull.json").toString()});
+
+			var item = jsonItemStore.getItemByIdentity("ec");
+			t.assertTrue(item !== null);
+			if(item !== null){
+				var name = jsonItemStore.getValue(item,"name");
+				t.assertEqual(name, null);
+			}
+
+			item = jsonItemStore.getItemByIdentity("sv");
+			t.assertTrue(item !== null);
+			if(item !== null){
+				var name = jsonItemStore.getValue(item,"name");
+				t.assertEqual(name, "El Salvador");
+			}
+		},
+		function testIdentityAPI_getItemByIdentity_booleanValue(t){
+			//	summary: 
+			//		Simple test of the getItemByIdentity function of the store, checking a boolean value.
+			//	description:
+			//		Simple test of the getItemByIdentity function of the store, checking a boolean value.
+
+			var jsonItemStore = new dojo.data.JsonItemStore({url: dojo.moduleUrl("tests", "data/countries_withBoolean.json").toString()});
+
+			try{
+				var item = jsonItemStore.getItemByIdentity("sv");
+				t.assertTrue(item !== null);
+				if(item !== null){
+				    var name = jsonItemStore.getValue(item,"name");
+					t.assertEqual(name, "El Salvador");
+					var real = jsonItemStore.getValue(item,"real");
+					t.assertEqual(real, true);
+				}
+
+				item = jsonItemStore.getItemByIdentity("ut");
+				t.assertTrue(item !== null);
+				if(item !== null){
+					var name = jsonItemStore.getValue(item,"name");
+					t.assertEqual(name, "Utopia");
+					var real = jsonItemStore.getValue(item,"real");
+					t.assertEqual(real, false);
+				}
+			}catch(e){
+				for(i in e){
+					console.log("I is: [" + i + "] with value: [" +e[i] + "]");
+				}
+				throw e;
+			}
+		},
+		function testIdentityAPI_getIdentity(t){
+			//	summary: 
+			//		Simple test of the getIdentity function of the store.
+			//	description:
+			//		Simple test of the getIdentity function of the store.
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+
+			var item = jsonItemStore.getItemByIdentity("sv");
+			t.assertTrue(item !== null);
+			t.assertTrue(jsonItemStore.getIdentity(item) === "sv");
+		},
+		function testReadAPI_fetch_all(t){
+			//	summary: 
+			//		Simple test of a basic fetch on JsonItemStore.
+			//	description:
+			//		Simple test of a basic fetch on JsonItemStore.
+			
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+			
+			var d = new doh.Deferred();
+            function completedAll(items, request){
+				t.is(7, items.length);
+				d.callback(true);
+			}
+			function error(errData, request){
+				t.assertTrue(false);
+				d.errback(errData);
+			}
+
+			//Get everything...
+			jsonItemStore.fetch({ onComplete: completedAll, onError: error});
+			return d;
+		},
+		function testReadAPI_fetch_one(t){
+			//	summary: 
+			//		Simple test of a basic fetch on JsonItemStore of a single item.
+			//	description:
+			//		Simple test of a basic fetch on JsonItemStore of a single item.
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+			
+			var d = new doh.Deferred();
+			function onComplete(items, request){
+				t.assertEqual(items.length, 1);
+				d.callback(true);
+			}
+			function onError(errData, request){
+				t.assertTrue(false);
+				d.errback(errData);
+			}
+			jsonItemStore.fetch({ 	query: {abbr: "ec"}, 
+									onComplete: onComplete, 
+									onError: onError
+								});
+			return d;
+		},
+		function testReadAPI_fetch_one_commentFilteredJson(t){
+			//	summary: 
+			//		Simple test of a basic fetch on JsonItemStore of a single item.
+			//	description:
+			//		Simple test of a basic fetch on JsonItemStore of a single item.
+			//		This tests loading a comment-filtered json file so that people using secure
+			//		data with this store can bypass the JavaSceipt hijack noted in Fortify's
+			//		paper.
+			var jsonItemStore = new dojo.data.JsonItemStore({url: dojo.moduleUrl("tests", "data/countries_commentFiltered.json").toString()});
+			
+			var d = new doh.Deferred();
+			function onComplete(items, request){
+				t.assertEqual(items.length, 1);
+				d.callback(true);
+			}
+			function onError(errData, request){
+				t.assertTrue(false);
+				d.errback(errData);
+			}
+			jsonItemStore.fetch({ 	query: {abbr: "ec"}, 
+									onComplete: onComplete, 
+									onError: onError
+								});
+			return d;
+		},
+		function testReadAPI_fetch_withNull(t){
+			//	summary: 
+			//		Simple test of a basic fetch on JsonItemStore of a single item where some attributes are null.
+			//	description:
+			//		Simple test of a basic fetch on JsonItemStore of a single item where some attributes are null.
+			//		Introduced because of tracker: #3153
+
+			var jsonItemStore = new dojo.data.JsonItemStore({url: dojo.moduleUrl("tests", "data/countries_withNull.json").toString()});
+			
+			var d = new doh.Deferred();
+			function onComplete(items, request){
+				t.assertEqual(4, items.length);
+				d.callback(true);
+			}
+			function onError(errData, request){
+				t.assertTrue(false);
+				d.errback(errData);
+			}
+			jsonItemStore.fetch({ 	query: {name: "E*"}, 
+									onComplete: onComplete, 
+									onError: onError
+								});
+			return d;
+		},
+		function testReadAPI_fetch_all_streaming(t){
+			//	summary: 
+			//		Simple test of a basic fetch on JsonItemStore.
+			//	description:
+			//		Simple test of a basic fetch on JsonItemStore.
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+
+			var d = new doh.Deferred();
+			count = 0;
+
+			function onBegin(size, requestObj){
+				t.assertEqual(size, 7);
+			}
+			function onItem(item, requestObj){
+				t.assertTrue(jsonItemStore.isItem(item));
+				count++;
+			}
+			function onComplete(items, request){
+				t.assertEqual(count, 7);
+				t.assertTrue(items === null);
+			    d.callback(true);
+			}
+			function onError(errData, request){
+				t.assertTrue(false);
+				d.errback(errData);
+			}
+
+			//Get everything...
+			jsonItemStore.fetch({	onBegin: onBegin,
+									onItem: onItem, 
+									onComplete: onComplete,
+									onError: onError
+								});
+			return d;
+		},
+		function testReadAPI_fetch_paging(t){
+			 //	summary: 
+			 //		Test of multiple fetches on a single result.  Paging, if you will.
+			 //	description:
+			 //		Test of multiple fetches on a single result.  Paging, if you will.
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+			
+			var d = new doh.Deferred();
+			function dumpFirstFetch(items, request){
+				t.assertEqual(items.length, 5);
+				request.start = 3;
+				request.count = 1;
+				request.onComplete = dumpSecondFetch;
+				jsonItemStore.fetch(request);
+			}
+
+			function dumpSecondFetch(items, request){
+				t.assertEqual(items.length, 1);
+				request.start = 0;
+				request.count = 5;
+				request.onComplete = dumpThirdFetch;
+				jsonItemStore.fetch(request);
+			}
+
+			function dumpThirdFetch(items, request){
+				t.assertEqual(items.length, 5);
+				request.start = 2;
+				request.count = 20;
+				request.onComplete = dumpFourthFetch;
+				jsonItemStore.fetch(request);
+			}
+
+			function dumpFourthFetch(items, request){
+				t.assertEqual(items.length, 5);
+                request.start = 9;
+				request.count = 100;
+				request.onComplete = dumpFifthFetch;
+				jsonItemStore.fetch(request);
+			}
+
+			function dumpFifthFetch(items, request){
+				t.assertEqual(items.length, 0);
+				request.start = 2;
+				request.count = 20;
+				request.onComplete = dumpSixthFetch;
+				jsonItemStore.fetch(request);
+			}
+
+			function dumpSixthFetch(items, request){
+				t.assertEqual(items.length, 5);
+			    d.callback(true);
+			}
+
+			function completed(items, request){
+				t.assertEqual(items.length, 7);
+				request.start = 1;
+				request.count = 5;
+				request.onComplete = dumpFirstFetch;
+				jsonItemStore.fetch(request);
+			}
+
+			function error(errData, request){
+				t.assertTrue(false);
+				d.errback(errData);
+			}
+			jsonItemStore.fetch({onComplete: completed, onError: error});
+			return d;
+
+		},
+		function testReadAPI_getValue(t){
+			//	summary: 
+			//		Simple test of the getValue function of the store.
+			//	description:
+			//		Simple test of the getValue function of the store.
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+
+			var item = jsonItemStore.getItemByIdentity("sv");
+			t.assertTrue(item !== null);
+			var name = jsonItemStore.getValue(item,"name");
+			t.assertTrue(name === "El Salvador");
+		},
+		function testReadAPI_getValue_byattributeItem(t){
+			//	summary: 
+			// 		Simple test of the getValue function passing in an item as the attribute identifier.
+			//	description:
+			// 		Simple test of the getValue function passing in an item as the attribute identifier.
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesAttrsStore();
+
+			var itemAttribute = jsonItemStore.getItemByIdentity("abbr");
+			t.assertTrue(itemAttribute !== null);
+			var name = jsonItemStore.getValue(itemAttribute,"name");
+			t.assertTrue(name === "abbr");
+			var item = jsonItemStore.getItemByIdentity("Ecuador");
+			var attrValue = jsonItemStore.getValue(item,itemAttribute);
+			t.assertTrue(attrValue === "ec");
+		},
+		function testReadAPI_getValues(t){
+			//	summary: 
+			//		Simple test of the getValues function of the store.
+			//	description:
+			//		Simple test of the getValues function of the store.
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+
+			var item = jsonItemStore.getItemByIdentity("sv");
+			t.assertTrue(item !== null);
+			var names = jsonItemStore.getValues(item,"name");
+            t.assertTrue(dojo.isArray(names));
+			t.assertEqual(names.length, 1);
+			t.assertEqual(names[0], "El Salvador");
+		},
+		function testReadAPI_getValues_byattributeItem(t){
+			//	summary: 
+			// 		Simple test of the getValue function passing in an item as the attribute identifier.
+			//	description:
+			// 		Simple test of the getValue function passing in an item as the attribute identifier.
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesAttrsStore();
+
+			var itemAttribute = jsonItemStore.getItemByIdentity("abbr");
+			t.assertTrue(itemAttribute !== null);
+			var name = jsonItemStore.getValue(itemAttribute,"name");
+			t.assertTrue(name === "abbr");
+			var item = jsonItemStore.getItemByIdentity("Ecuador");
+			var attrValues = jsonItemStore.getValues(item,itemAttribute);
+            t.assertTrue(dojo.isArray(attrValues));
+			t.assertEqual(attrValues.length, 1);
+			t.assertEqual(attrValues[0], "ec");
+		},
+		function testReadAPI_isItem(t){
+			//	summary: 
+			//		Simple test of the isItem function of the store
+			//	description:
+			//		Simple test of the isItem function of the store
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+
+			var item = jsonItemStore.getItemByIdentity("sv");
+			t.assertTrue(item !== null);
+			t.assertTrue(jsonItemStore.isItem(item));
+			t.assertTrue(!jsonItemStore.isItem({}));
+		},
+		function testReadAPI_isItem_multistore(t){
+			//	summary: 
+			//		Simple test of the isItem function of the store
+			//		to verify two different store instances do not accept
+			//		items from each other.
+			//	description:
+			//		Simple test of the isItem function of the store
+			//		to verify two different store instances do not accept
+			//		items from each other.
+
+			// Two different instances, even  if they read from the same URL 
+			// should not accept items between each other!
+			var jsonItemStore1 = tests.data.JsonItemStore.getCountriesStore();
+			var jsonItemStore2 = tests.data.JsonItemStore.getCountriesStore();
+
+			var item1 = jsonItemStore1.getItemByIdentity("sv");
+			var item2 = jsonItemStore2.getItemByIdentity("sv");
+			t.assertTrue(item1 !== null);
+			t.assertTrue(item2 !== null);
+			t.assertTrue(jsonItemStore1.isItem(item1));
+			t.assertTrue(jsonItemStore2.isItem(item2));
+			t.assertTrue(!jsonItemStore1.isItem(item2));
+			t.assertTrue(!jsonItemStore2.isItem(item1));
+		},
+		function testReadAPI_hasAttribute(t){
+			//	summary: 
+			//		Simple test of the hasAttribute function of the store
+			//	description:
+			//		Simple test of the hasAttribute function of the store
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+
+			var item = jsonItemStore.getItemByIdentity("sv");
+			t.assertTrue(item !== null);
+			t.assertTrue(jsonItemStore.hasAttribute(item, "abbr"));
+			t.assertTrue(!jsonItemStore.hasAttribute(item, "abbr_not"));
+
+			//Test that null attributes throw an exception
+			var passed = false;
+			try{
+				jsonItemStore.hasAttribute(item, null);
+			}catch (e){
+				passed = true;
+			}
+			t.assertTrue(passed);
+		},
+		function testReadAPI_hasAttribute_byattributeItem(t){
+			//	summary: 
+			//		Simple test of the hasAttribute passing in an item as the attribute identifier.
+			//	description:
+			//		Simple test of the hasAttribute passing in an item as the attribute identifier.
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesAttrsStore();
+
+			//First fine the item in the store that represents the attribute with name 'abbr'.
+			var itemAttribute = jsonItemStore.getItemByIdentity("abbr");
+			t.assertTrue(itemAttribute !== null);
+			if(itemAttribute !== null){
+				var name = jsonItemStore.getValue(itemAttribute,"name");
+				t.assertEqual(name, "abbr");
+			}
+			var item = jsonItemStore.getItemByIdentity("Ecuador");
+			t.assertTrue(jsonItemStore.hasAttribute(item,itemAttribute));
+			var attrValue = jsonItemStore.getValue(item,itemAttribute);
+			t.assertEqual(attrValue, "ec");
+		},
+		function testReadAPI_containsValue(t){
+			//	summary: 
+			//		Simple test of the containsValue function of the store
+			//	description:
+			//		Simple test of the containsValue function of the store
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+
+			var item = jsonItemStore.getItemByIdentity("sv");
+			t.assertTrue(item !== null);
+			t.assertTrue(jsonItemStore.containsValue(item, "abbr", "sv"));
+			t.assertTrue(!jsonItemStore.containsValue(item, "abbr", "sv1"));
+			t.assertTrue(!jsonItemStore.containsValue(item, "abbr", null));
+
+			//Test that null attributes throw an exception
+			var passed = false;
+			try{
+				jsonItemStore.containsValue(item, null, "foo");
+			}catch (e){
+				passed = true;
+			}
+			t.assertTrue(passed);
+		},
+		function testReadAPI_containsValue_byattributeItem(t){
+			//	summary: 
+			//		Simple test of the getAttributes function of the store
+			//	description:
+			//		Simple test of the containsValue function of the store using attribute lookup.
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesAttrsStore();
+
+			var attributeItem = jsonItemStore.getItemByIdentity("abbr");
+			var item          = jsonItemStore.getItemByIdentity("El Salvador");
+			t.assertTrue(item !== null);
+			t.assertTrue(attributeItem !== null);
+			t.assertTrue(jsonItemStore.containsValue(item, attributeItem, "sv"));
+			t.assertTrue(!jsonItemStore.containsValue(item, attributeItem, "sv1"));
+			t.assertTrue(!jsonItemStore.containsValue(item, attributeItem, null));
+		},
+		function testReadAPI_getAttributes(t){
+			//	summary: 
+			//		Simple test of the getAttributes function of the store
+			//	description:
+			//		Simple test of the getAttributes function of the store
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+
+			var item = jsonItemStore.getItemByIdentity("sv");
+			t.assertTrue(item !== null);
+			t.assertTrue(jsonItemStore.isItem(item));
+
+			var attributes = jsonItemStore.getAttributes(item);
+			t.assertEqual(attributes.length, 3);
+			for(var i = 0; i < attributes.length; i++){
+				t.assertTrue((attributes[i] === "name" || attributes[i] === "abbr" || attributes[i] === "capital"));
+			}
+		},
+		function testReadAPI_getFeatures(t){
+			//	summary: 
+			//		Simple test of the getFeatures function of the store
+			//	description:
+			//		Simple test of the getFeatures function of the store
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+
+			var features = jsonItemStore.getFeatures(); 
+			var count = 0;
+			for(i in features){
+				t.assertTrue((i === "dojo.data.api.Read" || i === "dojo.data.api.Identity"));
+				count++;
+			}
+			t.assertEqual(count, 2);
+		},
+		function testReadAPI_fetch_patternMatch0(t){
+			//	summary: 
+			//		Function to test pattern matching of everything starting with lowercase e
+			//	description:
+			//		Function to test pattern matching of everything starting with lowercase e
+
+			var jsonItemStore = tests.data.JsonItemStore.getCountriesStore();
+
+			var d = new doh.Deferred();
+			function completed(items, request) {
+				t.assertEqual(items.length, 5);
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "abbr");
+					if(!(value === "ec" || value === "eg" || value === "er" || value === "ee" || value === "et")){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected abbreviation found, match failure."));
+				}
+			}
+			function error(error, request) {
+				t.assertTrue(false);
+				d.errback(error);
+			}
+			jsonItemStore.fetch({query: {abbr: "e*"}, onComplete: completed, onError: error});
+			return d;
+		},
+		function testReadAPI_fetch_patternMatch1(t){
+			//	summary: 
+			//		Function to test pattern matching of everything with $ in it.
+			//	description:
+			//		Function to test pattern matching of everything with $ in it.
+
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											  items: [ {uniqueId: 1, value:"foo*bar"},
+												   {uniqueId: 2, value:"bar*foo"}, 
+												   {uniqueId: 3, value:"boomBam"},
+												   {uniqueId: 4, value:"bit$Bite"},
+												   {uniqueId: 5, value:"ouagadogou"},
+												   {uniqueId: 6, value:"BaBaMaSaRa***Foo"},
+												   {uniqueId: 7, value:"squawl"},
+												   {uniqueId: 8, value:"seaweed"},
+												   {uniqueId: 9, value:"jfq4@#!$!@Rf14r14i5u"}
+												 ]
+										}
+								 });
+			
+			var d = new doh.Deferred();
+			function completed(items, request){
+				t.assertEqual(items.length, 2);
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "value");
+					if(!(value === "bit$Bite" || value === "jfq4@#!$!@Rf14r14i5u")){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected pattern matched.  Filter failure."));
+				}
+			}
+			function error(error, request){
+				t.assertTrue(false);
+				d.errback(error);
+			}
+			jsonItemStore.fetch({query: {value: "*$*"}, onComplete: completed, onError: error});
+			return d;
+		},
+		function testReadAPI_fetch_patternMatch2(t){
+			//	summary: 
+			//		Function to test exact pattern match
+			//	description:
+			//		Function to test exact pattern match
+
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											  items: [ {uniqueId: 1, value:"foo*bar"},
+												   {uniqueId: 2, value:"bar*foo"}, 
+												   {uniqueId: 3, value:"boomBam"},
+												   {uniqueId: 4, value:"bit$Bite"},
+												   {uniqueId: 5, value:"ouagadogou"},
+												   {uniqueId: 6, value:"BaBaMaSaRa***Foo"},
+												   {uniqueId: 7, value:"squawl"},
+												   {uniqueId: 8, value:"seaweed"},
+												   {uniqueId: 9, value:"jfq4@#!$!@Rf14r14i5u"}
+												 ]
+										}
+								 });
+
+			var d = new doh.Deferred();
+			function completed(items, request){
+				t.assertEqual(items.length, 1);
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "value");
+					if(!(value === "bar*foo")){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected abbreviation found, match failure."));
+				}
+			}
+			function error(error, request){
+				t.assertTrue(false);
+				d.errback(error);
+			}
+			jsonItemStore.fetch({query: {value: "bar\*foo"}, onComplete: completed, onError: error});
+			return d;
+		},
+		function testReadAPI_fetch_patternMatch_caseSensitive(t){
+			//	summary: 
+			//		Function to test pattern matching of a pattern case-sensitively
+			//	description:
+			//		Function to test pattern matching of a pattern case-sensitively
+
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											  items: [ {uniqueId: 1, value:"foo*bar"},
+												   {uniqueId: 2, value:"bar*foo"}, 
+												   {uniqueId: 3, value:"BAR*foo"},
+												   {uniqueId: 4, value:"BARBananafoo"}
+												 ]
+										}
+								 });
+			
+			var d = new doh.Deferred();
+			function completed(items, request){
+				t.assertEqual(1, items.length);
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "value");
+					if(!(value === "bar*foo")){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected pattern matched.  Filter failure."));
+				}
+			}
+			function error(error, request){
+				t.assertTrue(false);
+				d.errback(error);
+			}
+			jsonItemStore.fetch({query: {value: "bar\\*foo"}, queryOptions: {ignoreCase: false} , onComplete: completed, onError: error});
+			return d;
+		},
+		function testReadAPI_fetch_patternMatch_caseInsensitive(t){
+			//	summary: 
+			//		Function to test pattern matching of a pattern case-insensitively
+			//	description:
+			//		Function to test pattern matching of a pattern case-insensitively
+
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											  items: [ {uniqueId: 1, value:"foo*bar"},
+												   {uniqueId: 2, value:"bar*foo"}, 
+												   {uniqueId: 3, value:"BAR*foo"},
+												   {uniqueId: 4, value:"BARBananafoo"}
+												 ]
+										}
+								 });
+			
+			var d = new doh.Deferred();
+			function completed(items, request){
+				t.assertEqual(items.length, 2);
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "value");
+					if(!(value === "BAR*foo" || value === "bar*foo")){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected pattern matched.  Filter failure."));
+				}
+			}
+			function error(error, request){
+				t.assertTrue(false);
+				d.errback(error);
+			}
+			jsonItemStore.fetch({query: {value: "bar\\*foo"}, queryOptions: {ignoreCase: true}, onComplete: completed, onError: error});
+			return d;
+		},
+		function testReadAPI_fetch_sortNumeric(t){
+			//	summary: 
+			//		Function to test sorting numerically.
+			//	description:
+			//		Function to test sorting numerically.
+			
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											  items: [ {uniqueId: 0, value:"fo|o*b.ar"},
+												   {uniqueId: 1, value:"ba|r*foo"}, 
+												   {uniqueId: 2, value:"boomBam"},
+												   {uniqueId: 3, value:"bit$Bite"},
+												   {uniqueId: 4, value:"ouagadogou"},
+												   {uniqueId: 5, value:"jfq4@#!$!@|f1.$4r14i5u"},
+												   {uniqueId: 6, value:"BaB{aMa|SaRa***F}oo"},
+												   {uniqueId: 7, value:"squawl"},
+												   {uniqueId: 9, value:"seaweed"},
+												   {uniqueId: 10, value:"zulu"},
+												   {uniqueId: 8, value:"seaweed"}
+												 ]
+										}
+								 });
+
+			var d = new doh.Deferred();
+			function completed(items, request){
+				t.assertEqual(items.length, 11);
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "value");
+					if(!(jsonItemStore.getValue(items[i], "uniqueId") === i)){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected sorting order found, sort failure."));
+				}
+			}
+
+			function error(error, request){
+				t.assertTrue(false);
+				d.errback(error);
+			}
+
+			var sortAttributes = [{attribute: "uniqueId"}];
+			jsonItemStore.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+			return d;
+		},
+		function testReadAPI_fetch_sortNumericDescending(t){
+			//	summary: 
+			//		Function to test sorting numerically.
+			//	description:
+			//		Function to test sorting numerically.
+
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											  items: [ {uniqueId: 0, value:"fo|o*b.ar"},
+												   {uniqueId: 1, value:"ba|r*foo"}, 
+												   {uniqueId: 2, value:"boomBam"},
+												   {uniqueId: 3, value:"bit$Bite"},
+												   {uniqueId: 4, value:"ouagadogou"},
+												   {uniqueId: 5, value:"jfq4@#!$!@|f1.$4r14i5u"},
+												   {uniqueId: 6, value:"BaB{aMa|SaRa***F}oo"},
+												   {uniqueId: 7, value:"squawl"},
+												   {uniqueId: 9, value:"seaweed"},
+												   {uniqueId: 10, value:"zulu"},
+												   {uniqueId: 8, value:"seaweed"}
+												 ]
+										}
+								 });
+			var d = new doh.Deferred();
+			function completed(items, request){
+				t.assertEqual(items.length, 11);
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "value");
+					if(!((items.length - (jsonItemStore.getValue(items[i], "uniqueId") + 1)) === i)){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected sorting order found, sort failure."));
+				}
+			}
+
+			function error(error, request){
+				t.assertTrue(false);
+				d.errback(error);
+			}
+
+			var sortAttributes = [{attribute: "uniqueId", descending: true}];
+			jsonItemStore.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+			return d;
+		},
+		function testReadAPI_fetch_sortNumericWithCount(t){
+			//	summary: 
+			//		Function to test sorting numerically in descending order, returning only a specified number of them.
+			//	description:
+			//		Function to test sorting numerically in descending order, returning only a specified number of them.
+		
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											 items: [ {uniqueId: 0, value:"fo|o*b.ar"},
+												  {uniqueId: 1, value:"ba|r*foo"}, 
+												  {uniqueId: 2, value:"boomBam"},
+												  {uniqueId: 3, value:"bit$Bite"},
+												  {uniqueId: 4, value:"ouagadogou"},
+												  {uniqueId: 5, value:"jfq4@#!$!@|f1.$4r14i5u"},
+												  {uniqueId: 6, value:"BaB{aMa|SaRa***F}oo"},
+												  {uniqueId: 7, value:"squawl"},
+												  {uniqueId: 9, value:"seaweed"},
+												  {uniqueId: 10, value:"zulu"},
+												  {uniqueId: 8, value:"seaweed"}
+												]
+									   }
+								});
+			
+			var d = new doh.Deferred();
+			function completed(items, request){
+				t.assertEqual(items.length, 5);
+				var itemId = 10;
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "value");
+					if(!(jsonItemStore.getValue(items[i], "uniqueId") === itemId)){
+						passed=false;
+						break;
+					}
+					itemId--; // Decrement the item id.  We are descending sorted, so it should go 10, 9, 8, etc.
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected sorting order found, sort failure."));
+				}
+			}
+		
+			function error(error, request){
+				t.assertTrue(false);
+				d.errback(error);
+			}
+		
+			var sortAttributes = [{attribute: "uniqueId", descending: true}];
+			jsonItemStore.fetch({onComplete: completed, onError: error, sort: sortAttributes, count: 5});
+			return d;
+		},
+		function testReadAPI_fetch_sortAlphabetic(t){
+			//	summary: 
+			//		Function to test sorting alphabetic ordering.
+			//	description:
+			//		Function to test sorting alphabetic ordering.
+		
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											 items: [ {uniqueId: 0, value:"abc"},
+												  {uniqueId: 1, value:"bca"}, 
+												  {uniqueId: 2, value:"abcd"},
+												  {uniqueId: 3, value:"abcdefg"},
+												  {uniqueId: 4, value:"lmnop"},
+												  {uniqueId: 5, value:"foghorn"},
+												  {uniqueId: 6, value:"qberty"},
+												  {uniqueId: 7, value:"qwerty"},
+												  {uniqueId: 8, value:""},
+												  {uniqueId: 9, value:"seaweed"},
+												  {uniqueId: 10, value:"123abc"}
+		
+												]
+									   }
+								});
+			
+			var d = new doh.Deferred();
+			function completed(items, request){
+				//Output should be in this order...
+				var orderedArray = [ 	"",
+										"123abc",
+										"abc",
+										"abcd",
+										"abcdefg",
+										"bca",
+										"foghorn",
+										"lmnop",
+										"qberty",
+										"qwerty",
+										"seaweed"
+					];
+				t.assertEqual(items.length, 11);
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "value");
+					if(!(jsonItemStore.getValue(items[i], "value") === orderedArray[i])){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected sorting order found, sort failure."));
+				}
+			}
+		
+			function error(error, request) {
+				t.assertTrue(false);
+				d.errback(error);
+			}
+		
+			var sortAttributes = [{attribute: "value"}];
+			jsonItemStore.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+			return d;
+		},
+		function testReadAPI_fetch_sortAlphabeticDescending(t){
+			//	summary: 
+			//		Function to test sorting alphabetic ordering in descending mode.
+			//	description:
+			//		Function to test sorting alphabetic ordering in descending mode.
+		
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											 items: [ {uniqueId: 0, value:"abc"},
+												  {uniqueId: 1, value:"bca"}, 
+												  {uniqueId: 2, value:"abcd"},
+												  {uniqueId: 3, value:"abcdefg"},
+												  {uniqueId: 4, value:"lmnop"},
+												  {uniqueId: 5, value:"foghorn"},
+												  {uniqueId: 6, value:"qberty"},
+												  {uniqueId: 7, value:"qwerty"},
+												  {uniqueId: 8, value:""},
+												  {uniqueId: 9, value:"seaweed"},
+												  {uniqueId: 10, value:"123abc"}
+		
+												]
+									   }
+								});
+			var d = new doh.Deferred();
+			function completed(items, request){
+				//Output should be in this order...
+				var orderedArray = [ 	"",
+										"123abc",
+										"abc",
+										"abcd",
+										"abcdefg",
+										"bca",
+										"foghorn",
+										"lmnop",
+										"qberty",
+										"qwerty",
+										"seaweed"
+					];
+				orderedArray = orderedArray.reverse();
+				t.assertEqual(items.length, 11);
+
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "value");
+					if(!(jsonItemStore.getValue(items[i], "value") === orderedArray[i])){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected sorting order found, sort failure."));
+				}
+			}
+		
+			function error(error, request) {
+				t.assertTrue(false);
+				d.errback(error);
+			}
+		
+			var sortAttributes = [{attribute: "value", descending: true}];
+			jsonItemStore.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+			return d;
+		},
+		function testReadAPI_fetch_sortDate(t){
+			//	summary: 
+			//		Function to test sorting date.
+			//	description:
+			//		Function to test sorting date.
+		
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											 items: [ {uniqueId: 0, value: new Date(0)},
+												  {uniqueId: 1, value: new Date(100)}, 
+												  {uniqueId: 2, value:new Date(1000)},
+												  {uniqueId: 3, value:new Date(2000)},
+												  {uniqueId: 4, value:new Date(3000)},
+												  {uniqueId: 5, value:new Date(4000)},
+												  {uniqueId: 6, value:new Date(5000)},
+												  {uniqueId: 7, value:new Date(6000)},
+												  {uniqueId: 8, value:new Date(7000)},
+												  {uniqueId: 9, value:new Date(8000)},
+												  {uniqueId: 10, value:new Date(9000)}
+		
+												]
+									   }
+								});
+			
+			var d = new doh.Deferred();
+			function completed(items,request){
+				var orderedArray =	[0,100,1000,2000,3000,4000,5000,6000,7000,8000,9000];
+				t.assertEqual(items.length, 11);
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "value");
+					if(!(jsonItemStore.getValue(items[i], "value").getTime() === orderedArray[i])){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected sorting order found, sort failure."));
+				}
+			}
+		
+			function error(error, request){
+				t.assertTrue(false);
+				d.errback(error);
+			}
+		
+			var sortAttributes = [{attribute: "value"}];
+			jsonItemStore.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+			return d;
+		},
+		function testReadAPI_fetch_sortDateDescending(t){
+			//	summary: 
+			//		Function to test sorting date in descending order.
+			//	description:
+			//		Function to test sorting date in descending order.
+		
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											 items: [ {uniqueId: 0, value: new Date(0)},
+												  {uniqueId: 1, value: new Date(100)}, 
+												  {uniqueId: 2, value:new Date(1000)},
+												  {uniqueId: 3, value:new Date(2000)},
+												  {uniqueId: 4, value:new Date(3000)},
+												  {uniqueId: 5, value:new Date(4000)},
+												  {uniqueId: 6, value:new Date(5000)},
+												  {uniqueId: 7, value:new Date(6000)},
+												  {uniqueId: 8, value:new Date(7000)},
+												  {uniqueId: 9, value:new Date(8000)},
+												  {uniqueId: 10, value:new Date(9000)}
+		
+												]
+									   }
+								});
+		
+			var d = new doh.Deferred();
+			function completed(items,request){
+				var orderedArray =	[0,100,1000,2000,3000,4000,5000,6000,7000,8000,9000];
+				orderedArray = orderedArray.reverse();
+				t.assertEqual(items.length, 11);
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "value");
+					if(!(jsonItemStore.getValue(items[i], "value").getTime() === orderedArray[i])){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected sorting order found, sort failure."));
+				}
+			}
+		
+			function error(error, request){
+				t.assertTrue(false);
+				d.errback(error);
+			}
+		
+			var sortAttributes = [{attribute: "value", descending: true}];
+			jsonItemStore.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+			return d;
+		},
+		function testReadAPI_fetch_sortMultiple(t){
+			//	summary: 
+			//		Function to test sorting on multiple attributes.
+			//	description:
+			//		Function to test sorting on multiple attributes.
+			
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											 items: [ {uniqueId: 1, value:"fo|o*b.ar"},
+												  {uniqueId: 2, value:"ba|r*foo"}, 
+												  {uniqueId: 3, value:"boomBam"},
+												  {uniqueId: 4, value:"bit$Bite"},
+												  {uniqueId: 5, value:"ouagadogou"},
+												  {uniqueId: 6, value:"jfq4@#!$!@|f1.$4r14i5u"},
+												  {uniqueId: 7, value:"BaB{aMa|SaRa***F}oo"},
+												  {uniqueId: 8, value:"squawl"},
+												  {uniqueId: 10, value:"seaweed"},
+												  {uniqueId: 12, value:"seaweed"},
+												  {uniqueId: 11, value:"zulu"},
+												  {uniqueId: 9, value:"seaweed"}
+												]
+									   }
+								});
+		
+			var d = new doh.Deferred();
+			function completed(items, request){
+				var orderedArray0 = [7,2,4,3,1,6,5,12,10,9,8,11];
+				var orderedArray1 = [	"BaB{aMa|SaRa***F}oo",
+										"ba|r*foo",
+										"bit$Bite",
+										"boomBam",
+										"fo|o*b.ar",
+										"jfq4@#!$!@|f1.$4r14i5u",
+										"ouagadogou",
+										"seaweed",
+										"seaweed",
+										"seaweed",
+										"squawl",
+										"zulu"
+									];
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "value");
+					if(!(	(jsonItemStore.getValue(items[i], "uniqueId") === orderedArray0[i])&&
+							(jsonItemStore.getValue(items[i], "value") === orderedArray1[i]))
+						){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected sorting order found, sort failure."));
+				}
+			}
+		
+			function error(error, request){
+				t.assertTrue(false);
+				d.errback(error);
+			}
+		
+			var sortAttributes = [{ attribute: "value"}, { attribute: "uniqueId", descending: true}];
+			jsonItemStore.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+			return d;
+		},
+		function testReadAPI_fetch_sortMultipleSpecialComparator(t){
+			//	summary: 
+			//		Function to test sorting on multiple attributes with a custom comparator.
+			//	description:
+			//		Function to test sorting on multiple attributes with a custom comparator.
+
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											 items: [ {uniqueId: 1, status:"CLOSED"},
+												  {uniqueId: 2,  status:"OPEN"}, 
+												  {uniqueId: 3,  status:"PENDING"},
+												  {uniqueId: 4,  status:"BLOCKED"},
+												  {uniqueId: 5,  status:"CLOSED"},
+												  {uniqueId: 6,  status:"OPEN"},
+												  {uniqueId: 7,  status:"PENDING"},
+												  {uniqueId: 8,  status:"PENDING"},
+												  {uniqueId: 10, status:"BLOCKED"},
+												  {uniqueId: 12, status:"BLOCKED"},
+												  {uniqueId: 11, status:"OPEN"},
+												  {uniqueId: 9,  status:"CLOSED"}
+												]
+									   }
+								});
+		
+		
+			jsonItemStore.comparatorMap = {};
+			jsonItemStore.comparatorMap["status"] = function(a,b) { 
+				var ret = 0;
+				// We want to map these by what the priority of these items are, not by alphabetical.
+				// So, custom comparator.
+				var enumMap = { OPEN: 3, BLOCKED: 2, PENDING: 1, CLOSED: 0};
+				if (enumMap[a] > enumMap[b]) {
+					ret = 1;
+				}
+				if (enumMap[a] < enumMap[b]) {
+					ret = -1;
+				}
+				return ret;
+			};
+		
+			var sortAttributes = [{attribute: "status", descending: true}, { attribute: "uniqueId", descending: true}];
+		
+			var d = new doh.Deferred();
+			function completed(items, findResult){
+				var orderedArray = [11,6,2,12,10,4,8,7,3,9,5,1];
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					var value = jsonItemStore.getValue(items[i], "value");
+					if(!(jsonItemStore.getValue(items[i], "uniqueId") === orderedArray[i])){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected sorting order found, sort failure."));
+				}
+			}
+		
+			function error(errData, request){
+				t.assertTrue(false);
+				d.errback(errData);
+			}
+			jsonItemStore.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+			return d;
+		},
+		function testReadAPI_fetch_sortAlphabeticWithUndefined(t){
+			//	summary: 
+			//		Function to test sorting alphabetic ordering.
+			//	description:
+			//		Function to test sorting alphabetic ordering.
+		
+			var jsonItemStore = new dojo.data.JsonItemStore({data: { identifier: "uniqueId", 
+											 items: [ {uniqueId: 0, value:"abc"},
+												  {uniqueId: 1, value:"bca"}, 
+												  {uniqueId: 2, value:"abcd"},
+												  {uniqueId: 3, value:"abcdefg"},
+												  {uniqueId: 4, value:"lmnop"},
+												  {uniqueId: 5, value:"foghorn"},
+												  {uniqueId: 6, value:"qberty"},
+												  {uniqueId: 7, value:"qwerty"},
+												  {uniqueId: 8 },  //Deliberate undefined value
+												  {uniqueId: 9, value:"seaweed"},
+												  {uniqueId: 10, value:"123abc"}
+		
+												]
+									   }
+								});
+			
+			var d = new doh.Deferred();
+			function completed(items, request){
+				//Output should be in this order...
+				var orderedArray = [10,0,2,3,1,5,4,6,7,9,8];
+				t.assertEqual(items.length, 11);
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					if(!(jsonItemStore.getValue(items[i], "uniqueId") === orderedArray[i])){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				if (passed){
+					d.callback(true);
+				}else{
+					d.errback(new Error("Unexpected sorting order found, sort failure."));
+				}
+			}
+		
+			function error(error, request) {
+				t.assertTrue(false);
+				d.errback(error);
+			}
+		
+			var sortAttributes = [{attribute: "value"}];
+			jsonItemStore.fetch({onComplete: completed, onError: error, sort: sortAttributes});
+			return d;
+		},
+		function testReadAPI_errorCondition_idCollision_inMemory(t){
+			//	summary: 
+			//		Simple test of the errors thrown when there is an id collision in the data.
+			//		Added because of tracker: #2546
+			//	description:
+			//		Simple test of the errors thrown when there is an id collision in the data.
+			//		Added because of tracker: #2546
+
+			var jsonItemStore = new dojo.data.JsonItemStore({	data: { identifier: "uniqueId", 
+																items: [{uniqueId: 12345, value:"foo"},
+																		{uniqueId: 123456, value:"bar"}, 
+																		{uniqueId: 12345, value:"boom"},
+																		{uniqueId: 123457, value:"bit"}
+																	]
+																}
+															});
+			var d = new doh.Deferred();
+			function onComplete(items, request){
+				//This is bad if this fires, this case should fail and not call onComplete.
+				t.assertTrue(false);
+				d.callback(false);
+			}
+		
+			function reportError(errData, request){
+				//This is good if this fires, it is expected.
+				t.assertTrue(true);
+				d.callback(true);
+			}
+			jsonItemStore.fetch({onComplete: onComplete, onError: reportError});
+			return d;
+		},
+		function testReadAPI_errorCondition_idCollision_xhr(t){
+			//	summary: 
+			//		Simple test of the errors thrown when there is an id collision in the data.
+			//		Added because of tracker: #2546
+			//	description:
+			//		Simple test of the errors thrown when there is an id collision in the data.
+			//		Added because of tracker: #2546
+
+			if(dojo.isBrowser){
+				var jsonItemStore = new dojo.data.JsonItemStore({url: dojo.moduleUrl("tests", "data/countries_idcollision.json").toString() });
+				var d = new doh.Deferred();
+				function onComplete(items, request){
+					//This is bad if this fires, this case should fail and not call onComplete.
+					t.assertTrue(false);
+					d.callback(false);
+				}
+
+				function reportError(errData, request){
+					//This is good if this fires, it is expected.
+					t.assertTrue(true);
+                    d.callback(true);
+				}
+				jsonItemStore.fetch({onComplete: onComplete, onError: reportError});
+				return d;
+			}
+		},
+		function testReadAPI_functionConformance(t){
+			//	summary: 
+			//		Simple test read API conformance.  Checks to see all declared functions are actual functions on the instances.
+			//	description:
+			//		Simple test read API conformance.  Checks to see all declared functions are actual functions on the instances.
+
+			var testStore = tests.data.JsonItemStore.getCountriesStore();
+			var readApi = new dojo.data.api.Read();
+			var passed = true;
+
+			for(i in readApi){
+				if(i.toString().charAt(0) !== '_')
+				{
+					var member = readApi[i];
+					//Check that all the 'Read' defined functions exist on the test store.
+					if(typeof member === "function"){
+						var testStoreMember = testStore[i];
+						if(!(typeof testStoreMember === "function")){
+							passed = false;
+							break;
+						}
+					}
+				}
+			}
+			t.assertTrue(passed);
+		},
+		function testIdentityAPI_functionConformance(t){
+			//	summary: 
+			//		Simple test identity API conformance.  Checks to see all declared functions are actual functions on the instances.
+			//	description:
+			//		Simple test identity API conformance.  Checks to see all declared functions are actual functions on the instances.
+
+			var testStore = tests.data.JsonItemStore.getCountriesStore();
+			var identityApi = new dojo.data.api.Identity();
+			var passed = true;
+
+			for(i in identityApi){
+
+				if(i.toString().charAt(0) !== '_')
+				{
+					var member = identityApi[i];
+					//Check that all the 'Read' defined functions exist on the test store.
+					if(typeof member === "function"){
+						var testStoreMember = testStore[i];
+						if(!(typeof testStoreMember === "function")){
+							passed = false;
+							break;
+						}
+					}
+				}
+			}
+			t.assertTrue(passed);
+		}
+	]
+);
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries.json
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries.json	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries.json	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,10 @@
+{ identifier: 'abbr', 
+  items: [
+	{ abbr:'ec', name:'Ecuador',           capital:'Quito' },
+	{ abbr:'eg', name:'Egypt',             capital:'Cairo' },
+	{ abbr:'sv', name:'El Salvador',       capital:'San Salvador' },
+	{ abbr:'gq', name:'Equatorial Guinea', capital:'Malabo' },
+	{ abbr:'er', name:'Eritrea',           capital:'Asmara' },
+	{ abbr:'ee', name:'Estonia',           capital:'Tallinn' },
+	{ abbr:'et', name:'Ethiopia',          capital:'Addis Ababa' }
+]}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_commentFiltered.json
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_commentFiltered.json	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_commentFiltered.json	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,12 @@
+/*
+{ identifier: 'abbr', 
+  items: [
+	{ abbr:'ec', name:'Ecuador',           capital:'Quito' },
+	{ abbr:'eg', name:'Egypt',             capital:'Cairo' },
+	{ abbr:'sv', name:'El Salvador',       capital:'San Salvador' },
+	{ abbr:'gq', name:'Equatorial Guinea', capital:'Malabo' },
+	{ abbr:'er', name:'Eritrea',           capital:'Asmara' },
+	{ abbr:'ee', name:'Estonia',           capital:'Tallinn' },
+	{ abbr:'et', name:'Ethiopia',          capital:'Addis Ababa' }
+]}
+*/

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_idcollision.json
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_idcollision.json	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_idcollision.json	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,10 @@
+{ identifier: 'abbr', 
+  items: [
+		{ abbr:'ec', name:'Ecuador',           capital:'Quito' },
+		{ abbr:'sv', name:'El Salvador',       capital:'San Salvador' },
+		{ abbr:'gq', name:'Equatorial Guinea', capital:'Malabo' },
+		{ abbr:'er', name:'Eritrea',           capital:'Asmara' },
+		{ abbr:'ec', name:'Egypt',             capital:'Cairo' },
+		{ abbr:'ee', name:'Estonia',           capital:'Tallinn' },
+		{ abbr:'et', name:'Ethiopia',          capital:'Addis Ababa' }
+]}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_withBoolean.json
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_withBoolean.json	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_withBoolean.json	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,11 @@
+{ identifier: 'abbr', 
+  items: [
+	{ abbr:'ec', name:'Ecuador',           capital:'Quito',        real:true},
+	{ abbr:'eg', name:'Egypt',             capital:'Cairo',        real:true},
+	{ abbr:'sv', name:'El Salvador',       capital:'San Salvador', real:true},
+	{ abbr:'gq', name:'Equatorial Guinea', capital:'Malabo',       real:true},
+	{ abbr:'er', name:'Eritrea',           capital:'Asmara',       real:true},
+	{ abbr:'ee', name:'Estonia',           capital:'Tallinn',      real:true},
+	{ abbr:'et', name:'Ethiopia',          capital:'Addis Ababa',  real:true},
+	{ abbr:'ut', name:'Utopia',            capital:'Paradise',     real:false}
+]}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_withNull.json
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_withNull.json	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_withNull.json	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,10 @@
+{ identifier: 'abbr', 
+  items: [
+	{ abbr:'ec', name:null,                capital:'Quito' },
+	{ abbr:'eg', name:null,                capital:'Cairo' },
+	{ abbr:'sv', name:'El Salvador',       capital:'San Salvador' },
+	{ abbr:'gq', name:'Equatorial Guinea', capital:'Malabo' },
+	{ abbr:'er', name:'Eritrea',           capital:'Asmara' },
+	{ abbr:'ee', name:null,                capital:'Tallinn' },
+	{ abbr:'et', name:'Ethiopia',          capital:'Addis Ababa' }
+]}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_withattributes.json
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_withattributes.json	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/data/countries_withattributes.json	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,14 @@
+{ "identifier": "name", 
+	"items": [
+		{ "name":"abbr" },
+		{ "name":"name" },
+		{ "name":"capital" },
+		{ "abbr":"ec", "name":"Ecuador",           "capital":"Quito" },
+		{ "abbr":"eg", "name":"Egypt",             "capital":"Cairo" },
+		{ "abbr":"sv", "name":"El Salvador",       "capital":"San Salvador" },
+		{ "abbr":"gq", "name":"Equatorial Guinea", "capital":"Malabo" },
+		{ "abbr":"er", "name":"Eritrea",           "capital":"Asmara" },
+		{ "abbr":"ee", "name":"Estonia",           "capital":"Tallinn" },
+		{ "abbr":"et", "name":"Ethiopia",          "capital":"Addis Ababa" }
+	]
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/data/utils.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/data/utils.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/data/utils.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,199 @@
+dojo.provide("tests.data.utils");
+dojo.require("dojo.data.util.filter");
+dojo.require("dojo.data.util.sorter");
+
+tests.register("tests.data.utils", 
+	[
+		function testWildcardFilter_1(t){
+			var pattern = "ca*";
+			var values = ["ca", "california", "Macca", "Macca*b", "Macca\\b"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testWildcardFilter_2(t){
+			var pattern = "*ca";
+			var values = ["ca", "california", "Macca", "Macca*b", "Macca\\b"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testWildcardFilter_3(t){
+			var pattern = "*ca*";
+			var values = ["ca", "california", "Macca", "Macca*b", "Macca\\b"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testWildcardFilter_4(t){
+			//Try and match <anything>c<anything>a*b
+			var pattern = "*c*a\\*b*";
+			var values = ["ca", "california", "Macca", "Macca*b", "Macca\\b"];
+
+			t.assertFalse(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testWildcardFilter_5(t){
+			var pattern = "*c*a\\\\*b";
+			var values = ["ca", "california", "Macca", "Macca*b", "Macca\\b"];
+
+			t.assertFalse(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testWildcardFilter_caseInsensitive(t){
+			var pattern = "ca*";
+			var values = ["CA", "california", "Macca", "Macca*b", "Macca\\b"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern, true))!== null);
+			t.assertTrue(values[1].match(dojo.data.util.filter.patternToRegExp(pattern, true))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern, true))!== null);
+			t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern, true))!== null);
+			t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern, true))!== null);
+		},
+		function testSingleChar_1(t){
+			var pattern = "bob?le";
+			var values = ["bobble", "boble", "foo", "bobBle", "bar"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testSingleChar_2(t){
+			var pattern = "?ob?le";
+			var values = ["bobble", "cob1le", "foo", "bobBle", "bar"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testBracketChar(t){
+			//Make sure we don't treat this as regexp
+			var pattern = "*[*]*";
+			var values = ["bo[b]ble", "cob1le", "foo", "[bobBle]", "b[]ar"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testBraceChar(t){
+			//Make sure we don't treat this as regexp
+			var pattern = "*{*}*";
+			var values = ["bo{b}ble", "cob1le", "foo", "{bobBle}", "b{}ar"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testParenChar(t){
+			//Make sure we don't treat this as regexp
+			var pattern = "*(*)*";
+			var values = ["bo(b)ble", "cob1le", "foo", "{bobBle}", "b()ar"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testPlusChar(t){
+			//Make sure we don't treat this as regexp, so match anything with a + in it.
+			var pattern = "*+*";
+			var values = ["bo+ble", "cob1le", "foo", "{bobBle}", "b{}ar"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testPeriodChar(t){
+			//Make sure we don't treat this as regexp, so match anything with a period
+			var pattern = "*.*";
+			var values = ["bo.ble", "cob1le", "foo", "{bobBle}", "b{}ar"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testBarChar(t){
+			//Make sure we don't treat this as regexp, so match anything with a pipe bar
+			var pattern = "*|*";
+			var values = ["bo.ble", "cob|le", "foo", "{bobBle}", "b{}ar"];
+
+			t.assertFalse(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testDollarSignChar(t){
+			//Make sure we don't treat this as regexp, so match anything with a $ in it
+			var pattern = "*$*";
+			var values = ["bo$ble", "cob$le", "foo", "{bobBle}", "b{}ar"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testCarrotChar(t){
+			//Make sure we don't treat this as regexp, so match anything with a ^ in it
+			var pattern = "*^*";
+			var values = ["bo$ble", "cob$le", "f^oo", "{bobBle}", "b{}ar"];
+
+			t.assertFalse(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertTrue(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testEscapeChar(t){
+			//Make sure we escape properly, so match this single word.
+			var pattern = "bob\*ble";
+			var values = ["bob*ble", "cob$le", "f^oo", "{bobBle}", "b{}ar"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		},
+		function testAbsoluteMatch(t){
+			var pattern = "bobble";
+			var values = ["bobble", "cob$le", "f^oo", "{bobBle}", "b{}ar"];
+
+			t.assertTrue(values[0].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[1].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[2].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[3].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+			t.assertFalse(values[4].match(dojo.data.util.filter.patternToRegExp(pattern))!== null);
+		}
+	]
+);
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/data.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/data.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/data.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+dojo.provide("tests.data");
+dojo.require("tests.data.utils");
+dojo.require("tests.data.JsonItemStore");
+
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/date/locale.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/date/locale.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/date/locale.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,375 @@
+dojo.provide("tests.date.locale");
+
+dojo.require("dojo.date.locale");
+
+tests.register("tests.date.locale", 
+	[
+		{
+			// Test formatting and parsing of dates in various locales pre-built in dojo.cldr
+			// NOTE: we can't set djConfig.extraLocale before bootstrapping unit tests, so directly
+			// load resources here for specific locales:
+
+			name: "date.locale",
+			setUp: function(){
+				var partLocaleList = ["en-us", "fr-fr", "es", "de-at", "ja-jp", "zh-cn"];
+
+				for(var i = 0 ; i < partLocaleList.length; i ++){
+					dojo.requireLocalization("dojo.cldr","gregorian",partLocaleList[i]);
+				}
+			},
+			runTest: function(t){
+			},
+			tearDown: function(){
+				//Clean up bundles that should not exist if
+				//the test is re-run.
+				delete dojo.cldr.nls.gregorian;
+			}
+		},
+		{
+			name: "isWeekend",
+			runTest: function(t){
+				var thursday = new Date(2006, 8, 21);
+				var friday = new Date(2006, 8, 22);
+				var saturday = new Date(2006, 8, 23);
+				var sunday = new Date(2006, 8, 24);
+				var monday = new Date(2006, 8, 25);
+				t.f(dojo.date.locale.isWeekend(thursday, 'en-us'));
+				t.t(dojo.date.locale.isWeekend(saturday, 'en-us'));
+				t.t(dojo.date.locale.isWeekend(sunday, 'en-us'));
+				t.f(dojo.date.locale.isWeekend(monday, 'en-us'));
+//	t.f(dojo.date.locale.isWeekend(saturday, 'en-in'));
+//	t.t(dojo.date.locale.isWeekend(sunday, 'en-in'));
+//	t.f(dojo.date.locale.isWeekend(monday, 'en-in'));
+//	t.t(dojo.date.locale.isWeekend(friday, 'he-il'));
+//	t.f(dojo.date.locale.isWeekend(sunday, 'he-il'));
+			}
+		},
+		{
+			name: "format",
+			runTest: function(t){
+
+	var date = new Date(2006, 7, 11, 0, 55, 12, 345);
+
+	t.is("Friday, August 11, 2006", dojo.date.locale.format(date, {formatLength:'full',selector:'date', locale:'en-us'}));
+	t.is("vendredi 11 ao\xFBt 2006", dojo.date.locale.format(date, {formatLength:'full',selector:'date', locale:'fr-fr'}));
+	t.is("Freitag, 11. August 2006", dojo.date.locale.format(date, {formatLength:'full',selector:'date', locale:'de-at'}));
+	t.is("2006\u5E748\u670811\u65E5\u91D1\u66DC\u65E5", dojo.date.locale.format(date, {formatLength:'full',selector:'date', locale:'ja-jp'}));
+
+	t.is("8/11/06", dojo.date.locale.format(date, {formatLength:'short',selector:'date', locale:'en-us'}));
+	t.is("11/08/06", dojo.date.locale.format(date, {formatLength:'short',selector:'date', locale:'fr-fr'}));
+	t.is("11.08.06", dojo.date.locale.format(date, {formatLength:'short',selector:'date', locale:'de-at'}));
+	t.is("06/08/11", dojo.date.locale.format(date, {formatLength:'short',selector:'date', locale:'ja-jp'}));
+
+	t.is("12:55 AM", dojo.date.locale.format(date, {formatLength:'short',selector:'time', locale:'en-us'}));
+	t.is("12:55:12", dojo.date.locale.format(date, {timePattern:'h:m:s',selector:'time'}));
+	t.is("12:55:12.35", dojo.date.locale.format(date, {timePattern:'h:m:s.SS',selector:'time'}));
+	t.is("24:55:12.35", dojo.date.locale.format(date, {timePattern:'k:m:s.SS',selector:'time'}));
+	t.is("0:55:12.35", dojo.date.locale.format(date, {timePattern:'H:m:s.SS',selector:'time'}));
+	t.is("0:55:12.35", dojo.date.locale.format(date, {timePattern:'K:m:s.SS',selector:'time'}));
+
+	t.is("11082006", dojo.date.locale.format(date, {datePattern:"ddMMyyyy", selector:"date"}));
+
+	// compare without timezone
+	t.is("\u4e0a\u534812\u65f655\u520612\u79d2", dojo.date.locale.format(date, {formatLength:'full',selector:'time', locale:'zh-cn'}).split(' ')[0]);
+			}
+		},
+		{
+			name: "parse_dates",
+			runTest: function(t){
+
+	var aug_11_2006 = new Date(2006, 7, 11, 0);
+	var aug_11_06CE = new Date(2006, 7, 11, 0);
+	aug_11_06CE.setFullYear(6); //literally the year 6 C.E.
+
+	//en: 'short' fmt: M/d/yy
+	// Tolerate either 8 or 08 for month part.
+	t.is( aug_11_2006, dojo.date.locale.parse("08/11/06", {formatLength:'short', selector:'date', locale:'en'}));
+	t.is( aug_11_2006, dojo.date.locale.parse("8/11/06", {formatLength:'short', selector:'date', locale:'en'}));	
+	// Tolerate yyyy input in yy part...
+	t.is( aug_11_2006, dojo.date.locale.parse("8/11/2006", {formatLength:'short', selector:'date', locale:'en'}));
+	// ...but not in strict mode
+	t.is( null, dojo.date.locale.parse("8/11/2006", {formatLength:'short', selector:'date', locale:'en', strict:true}));
+
+	//en: 'medium' fmt: MMM d, yyyy
+	// Tolerate either 8 or 08 for month part.
+	t.is( aug_11_2006, dojo.date.locale.parse("Aug 11, 2006", {formatLength:'medium', selector:'date', locale:'en'}));
+	t.is( aug_11_2006, dojo.date.locale.parse("Aug 11, 2006", {formatLength:'medium', selector:'date', locale:'en'}));	
+	// Tolerate abbreviating period in month part...
+	t.is( aug_11_2006, dojo.date.locale.parse("Aug. 11, 2006", {formatLength:'medium', selector:'date', locale:'en'}));
+	// ...but not in strict mode
+	t.is( null, dojo.date.locale.parse("Aug. 11, 2006", {formatLength:'medium', selector:'date', locale:'en', strict:true}));
+	// Note: 06 for year part will be translated literally as the year 6 C.E.
+	t.is( aug_11_06CE, dojo.date.locale.parse("Aug 11, 06", {formatLength:'medium', selector:'date', locale:'en'}));
+	//en: 'long' fmt: MMMM d, yyyy
+	t.is( aug_11_2006, dojo.date.locale.parse("August 11, 2006", {formatLength:'long', selector:'date', locale:'en'}));
+
+	//en: 'full' fmt: EEEE, MMMM d, yyyy
+	t.is( aug_11_2006, dojo.date.locale.parse("Friday, August 11, 2006", {formatLength:'full', selector:'date', locale:'en'}));
+	//TODO: wrong day-of-week should fail
+	//t.is( null, dojo.date.locale.parse("Thursday, August 11, 2006", {formatLength:'full', selector:'date', locale:'en'}));
+
+	//Whitespace tolerance
+	t.is( aug_11_2006, dojo.date.locale.parse(" August 11, 2006", {formatLength:'long', selector:'date', locale:'en'}));
+	t.is( aug_11_2006, dojo.date.locale.parse("August  11, 2006", {formatLength:'long', selector:'date', locale:'en'}));
+	t.is( aug_11_2006, dojo.date.locale.parse("August 11 , 2006", {formatLength:'long', selector:'date', locale:'en'}));
+	t.is( aug_11_2006, dojo.date.locale.parse("August 11,  2006", {formatLength:'long', selector:'date', locale:'en'}));
+	t.is( aug_11_2006, dojo.date.locale.parse("August 11, 2006 ", {formatLength:'long', selector:'date', locale:'en'}));
+
+	//Simple Validation Tests
+	//catch "month" > 12 (note: month/day reversals are common when user expectation isn't met wrt european versus US formats)
+	t.is( null, dojo.date.locale.parse("15/1/2005", {formatLength:'short', selector:'date', locale:'en'}));
+	//day of month typo rolls over to the next month
+	t.is( null, dojo.date.locale.parse("Aug 32, 2006", {formatLength:'medium', selector:'date', locale:'en'}));
+
+	//German (de)
+	t.is( aug_11_2006, dojo.date.locale.parse("11.08.06", {formatLength:'short', selector:'date', locale:'de'}));
+	t.is( null, dojo.date.locale.parse("11.8/06", {formatLength:'short', selector:'date', locale:'de'}));
+	t.is( null, dojo.date.locale.parse("11.8x06", {formatLength:'short', selector:'date', locale:'de'}));
+	t.is( null, dojo.date.locale.parse("11.13.06", {formatLength:'short', selector:'date', locale:'de'}));
+	t.is( null, dojo.date.locale.parse("11.0.06", {formatLength:'short', selector:'date', locale:'de'}));
+	t.is( null, dojo.date.locale.parse("32.08.06", {formatLength:'short', selector:'date', locale:'de'}));
+
+	//Spanish (es)
+	//es: 'short' fmt: d/MM/yy
+	t.is( aug_11_2006, dojo.date.locale.parse("11/08/06", {formatLength:'short', selector:'date', locale:'es'}));
+	t.is( aug_11_2006, dojo.date.locale.parse("11/8/06", {formatLength:'short', selector:'date', locale:'es'}));	
+	// Tolerate yyyy input in yy part...
+	t.is( aug_11_2006, dojo.date.locale.parse("11/8/2006", {formatLength:'short', selector:'date', locale:'es'}));
+	// ...but not in strict mode
+	t.is( null, dojo.date.locale.parse("11/8/2006", {formatLength:'short', selector:'date', locale:'es', strict:true}));
+	//es: 'medium' fmt: dd-MMM-yy
+	t.is( aug_11_2006, dojo.date.locale.parse("11-ago-06", {formatLength:'medium', selector:'date', locale:'es'}));
+	t.is( aug_11_2006, dojo.date.locale.parse("11-ago-2006", {formatLength:'medium', selector:'date', locale:'es'}));	
+	// Tolerate abbreviating period in month part...
+	t.is( aug_11_2006, dojo.date.locale.parse("11-ago.-2006", {formatLength:'medium', selector:'date', locale:'es'}));
+	// ...but not in strict mode
+	t.is( null, dojo.date.locale.parse("11-ago.-2006", {formatLength:'medium', selector:'date', locale:'es', strict:true}));
+	//es: 'long' fmt: d' de 'MMMM' de 'yyyy
+	t.is( aug_11_2006, dojo.date.locale.parse("11 de agosto de 2006", {formatLength:'long', selector:'date', locale:'es'}));
+	//case-insensitive month...
+	t.is( aug_11_2006, dojo.date.locale.parse("11 de Agosto de 2006", {formatLength:'long', selector:'date', locale:'es'}));
+	//...but not in strict mode
+	t.is( null, dojo.date.locale.parse("11 de Agosto de 2006", {formatLength:'long', selector:'date', locale:'es', strict:true}));
+	//es 'full' fmt: EEEE d' de 'MMMM' de 'yyyy
+	t.is( aug_11_2006, dojo.date.locale.parse("viernes 11 de agosto de 2006", {formatLength:'full', selector:'date', locale:'es'}));
+	//case-insensitive day-of-week...
+	t.is( aug_11_2006, dojo.date.locale.parse("Viernes 11 de agosto de 2006", {formatLength:'full', selector:'date', locale:'es'}));
+	//...but not in strict mode
+	t.is( null, dojo.date.locale.parse("Viernes 11 de agosto de 2006", {formatLength:'full', selector:'date', locale:'es', strict:true}));
+
+	//Japanese (ja)
+	//note: to avoid garbling from non-utf8-aware editors that may touch this file, using the \uNNNN format 
+	//for expressing double-byte chars.
+	//toshi (year): \u5e74
+	//getsu (month): \u6708
+	//nichi (day): \u65e5
+	//kinyoubi (Friday): \u91d1\u66dc\u65e5
+	//zenkaku space: \u3000
+	
+	//ja: 'short' fmt: yy/MM/dd (note: the "short" fmt isn't actually defined in the CLDR data...)
+	t.is( aug_11_2006, dojo.date.locale.parse("06/08/11", {formatLength:'short', selector:'date', locale:'ja'}));
+	t.is( aug_11_2006, dojo.date.locale.parse("06/8/11", {formatLength:'short', selector:'date', locale:'ja'}));	
+ 	// Tolerate yyyy input in yy part...
+	t.is( aug_11_2006, dojo.date.locale.parse("2006/8/11", {formatLength:'short', selector:'date', locale:'ja'}));
+	// ...but not in strict mode
+	t.is( null, dojo.date.locale.parse("2006/8/11", {formatLength:'short', selector:'date', locale:'ja', strict:true}));
+	//ja: 'medium' fmt: yyyy/MM/dd
+	t.is( aug_11_2006, dojo.date.locale.parse("2006/08/11", {formatLength:'medium', selector:'date', locale:'ja'}));
+	t.is( aug_11_2006, dojo.date.locale.parse("2006/8/11", {formatLength:'medium', selector:'date', locale:'ja'}));		
+	//ja: 'long' fmt: yyyy'\u5e74'\u6708'd'\u65e5'
+	t.is( aug_11_2006, dojo.date.locale.parse("2006\u5e748\u670811\u65e5", {formatLength:'long', selector:'date', locale:'ja'}));
+	//ja 'full' fmt: yyyy'\u5e74'M'\u6708'd'\u65e5'EEEE
+	t.is( aug_11_2006, dojo.date.locale.parse("2006\u5e748\u670811\u65e5\u91d1\u66dc\u65e5", {formatLength:'full', selector:'date', locale:'ja'}));
+
+	//Whitespace tolerance
+	//tolerate ascii space
+	t.is( aug_11_2006, dojo.date.locale.parse(" 2006\u5e748\u670811\u65e5\u91d1\u66dc\u65e5 ", {formatLength:'full', selector:'date', locale:'ja'}));
+	t.is( aug_11_2006, dojo.date.locale.parse("2006\u5e74 8\u670811\u65e5 \u91d1\u66dc\u65e5", {formatLength:'full', selector:'date', locale:'ja'}));
+	//tolerate zenkaku space
+	t.is( aug_11_2006, dojo.date.locale.parse("\u30002006\u5e748\u670811\u65e5\u91d1\u66dc\u65e5\u3000", {formatLength:'full', selector:'date', locale:'ja'}));
+	t.is( aug_11_2006, dojo.date.locale.parse("2006\u5e74\u30008\u670811\u65e5\u3000\u91d1\u66dc\u65e5", {formatLength:'full', selector:'date', locale:'ja'}));
+
+	var apr_11_2006 = new Date(2006, 3, 11, 0);
+	//Roundtrip
+	var options={formatLength:'medium',selector:'date', locale:'fr-fr'};
+	t.is(0, dojo.date.compare(apr_11_2006, dojo.date.locale.parse(dojo.date.locale.format(apr_11_2006, options), options)));
+
+	//Tolerance for abbreviations
+	t.is(0, dojo.date.compare(apr_11_2006, dojo.date.locale.parse("11 avr 06", options)));
+			}
+		},
+		{
+			name: "parse_datetimes",
+			runTest: function(t){
+
+	var aug_11_2006_12_30_am = new Date(2006, 7, 11, 0, 30);
+	var aug_11_2006_12_30_pm = new Date(2006, 7, 11, 12, 30);
+
+	//en: 'short' datetime fmt: M/d/yy h:mm a
+	//note: this is concatenation of dateFormat-short and timeFormat-short, 
+	//cldr provisionally defines datetime fmts as well, but we're not using them at the moment
+	t.is( aug_11_2006_12_30_pm, dojo.date.locale.parse("08/11/06 12:30 PM", {formatLength:'short', locale:'en'}));
+	//case-insensitive
+	t.is( aug_11_2006_12_30_pm, dojo.date.locale.parse("08/11/06 12:30 pm", {formatLength:'short', locale:'en'}));
+	//...but not in strict mode
+	t.is( null, dojo.date.locale.parse("08/11/06 12:30 pm", {formatLength:'short', locale:'en', strict:true}));
+
+	t.is( aug_11_2006_12_30_am, dojo.date.locale.parse("08/11/06 12:30 AM", {formatLength:'short', locale:'en'}));
+
+	t.is( new Date(2006, 7, 11), dojo.date.locale.parse("11082006", {datePattern:"ddMMyyyy", selector:"date"}));
+
+			}
+		},
+		{
+			name: "parse_times",
+			runTest: function(t){
+
+	var time = new Date(2006, 7, 11, 12, 30);
+	var tformat = {selector:'time', strict:true, timePattern:"h:mm a", locale:'en'};
+
+	t.is(time.getHours(), dojo.date.locale.parse("12:30 PM", tformat).getHours());
+	t.is(time.getMinutes(), dojo.date.locale.parse("12:30 PM", tformat).getMinutes());
+			}
+		},
+		{
+			name: "day_week_ofYear",
+			runTest: function(t){
+
+//	t.is(23, dojo.date.setDayOfYear(new Date(2006,0,1), 23).getDate());
+	t.is(1, dojo.date.locale._getDayOfYear(new Date(2006,0,1)));
+	t.is(32, dojo.date.locale._getDayOfYear(new Date(2006,1,1)));
+	//dojo.date.setWeekOfYear(new Date(2006,2,1), 34);
+	//dojo.date.setWeekOfYear(new Date(2006,2,1), 34, 1);
+	//dojo.date.getWeekOfYear(new Date(2006,1,1));
+	//dojo.date.getWeekOfYear(new Date(2006,1,1), 1);
+			}
+		}
+	]
+);
+
+/*
+// workaround deprecated methods. Should decide whether we should convert the tests or add a helper method (in dojo.date?) to do this.
+
+dojo_validate_isValidTime = function(str, props){
+	props = props || {};
+	if(!props.format){props.format="h:mm:ss";}
+	if(!props.am){props.am="a.m.";}
+	if(!props.pm){props.pm="p.m.";}
+	var result = false;
+	if(/[hk]/.test(props.format) && props.format.indexOf('a') == -1){
+		result = dojo.date.locale.parse(str, {selector: 'time', timePattern: props.format + " a"});
+	}
+	return Boolean(result || dojo.date.locale.parse(str, {selector: 'time', timePattern: props.format}));
+}
+
+dojo_validate_is12HourTime = function(str){
+	return dojo_validate_isValidTime(str, {format: 'h:mm:ss'}) || 	dojo_validate_isValidTime(str, {format: 'h:mm'});
+}
+
+dojo_validate_is24HourTime = function(str){
+	return dojo_validate_isValidTime(str, {format: 'H:mm:ss'}) || 	dojo_validate_isValidTime(str, {format: 'H:mm'});
+}
+
+dojo_validate_isValidDate = function(str, fmt){
+	return Boolean(dojo.date.locale.parse(str, {selector: 'date', datePattern: fmt}));
+}
+
+function test_validate_datetime_isValidTime(){
+	jum.assertTrue("test1", dojo_validate_isValidTime('5:15:05 pm'));
+// FAILURE	jum.assertTrue("test2", dojo_validate_isValidTime('5:15:05 p.m.', {pm: "P.M."} ));
+	jum.assertFalse("test3", dojo_validate_isValidTime('5:15:05 f.m.'));
+	jum.assertTrue("test4", dojo_validate_isValidTime('5:15 pm', {format: "h:mm a"} ) );
+	jum.assertFalse("test5", dojo_validate_isValidTime('5:15 fm', {}) );
+	jum.assertTrue("test6", dojo_validate_isValidTime('15:15:00', {format: "H:mm:ss"} ) );
+// FAILURE	jum.assertFalse("test7", dojo_validate_isValidTime('15:15:00', {}) );
+	jum.assertTrue("test8", dojo_validate_isValidTime('17:01:30', {format: "H:mm:ss"} ) );
+	jum.assertFalse("test9", dojo_validate_isValidTime('17:1:30', {format: "H:mm:ss"} ) );
+// FAILURE	jum.assertFalse("test10", dojo_validate_isValidTime('17:01:30', {format: "H:m:ss"} ) );
+	// Greek
+// FAILURE	jum.assertTrue("test11", dojo_validate_isValidTime('5:01:30 \u0924\u0924', {am: "\u0928\u0924", pm: "\u0924\u0924"} ) );
+	// Italian
+	jum.assertTrue("test12", dojo_validate_isValidTime('17.01.30', {format: "H.mm.ss"} ) );
+	// Mexico
+// FAILURE	jum.assertTrue("test13", dojo_validate_isValidTime('05:01:30 p.m.', {format: "hh:mm:ss a", am: "a.m.", pm: "p.m."} ) );
+}
+
+
+function test_validate_datetime_is12HourTime(){
+	jum.assertTrue("test1", dojo_validate_is12HourTime('5:15:05 pm'));
+// FAILURE	jum.assertFalse("test2", dojo_validate_is12HourTime('05:15:05 pm'));
+	jum.assertFalse("test3", dojo_validate_is12HourTime('5:5:05 pm'));
+	jum.assertFalse("test4", dojo_validate_is12HourTime('5:15:5 pm'));
+// FAILURE	jum.assertFalse("test5", dojo_validate_is12HourTime('13:15:05 pm'));
+	jum.assertFalse("test6", dojo_validate_is12HourTime('5:60:05 pm'));
+	jum.assertFalse("test7", dojo_validate_is12HourTime('5:15:60 pm'));
+	jum.assertTrue("test8", dojo_validate_is12HourTime('5:59:05 pm'));
+	jum.assertTrue("test9", dojo_validate_is12HourTime('5:15:59 pm'));
+// FAILURE	jum.assertFalse("test10", dojo_validate_is12HourTime('5:15:05'));
+
+	// optional seconds
+	jum.assertTrue("test11", dojo_validate_is12HourTime('5:15 pm'));
+	jum.assertFalse("test12", dojo_validate_is12HourTime('5:15: pm'));
+}
+
+function test_validate_datetime_is24HourTime(){
+	jum.assertTrue("test1", dojo_validate_is24HourTime('00:03:59'));
+	jum.assertTrue("test2", dojo_validate_is24HourTime('22:03:59'));
+//FIXME: fix tests or code?
+//	jum.assertFalse("test3", dojo_validate_is24HourTime('22:03:59 pm'));
+//	jum.assertFalse("test4", dojo_validate_is24HourTime('2:03:59'));
+	jum.assertFalse("test5", dojo_validate_is24HourTime('0:3:59'));
+	jum.assertFalse("test6", dojo_validate_is24HourTime('00:03:5'));
+	jum.assertFalse("test7", dojo_validate_isValidTime('24:03:59', {format: 'kk:mm:ss'}));
+	jum.assertFalse("test8", dojo_validate_is24HourTime('02:60:59'));
+	jum.assertFalse("test9", dojo_validate_is24HourTime('02:03:60'));
+
+	// optional seconds
+	jum.assertTrue("test10", dojo_validate_is24HourTime('22:53'));
+	jum.assertFalse("test11", dojo_validate_is24HourTime('22:53:'));
+}
+
+function test_validate_datetime_isValidDate(){
+	
+	// Month date year
+	jum.assertTrue("test1", dojo_validate_isValidDate("08/06/2005", "MM/dd/yyyy"));
+	jum.assertTrue("test2", dojo_validate_isValidDate("08.06.2005", "MM.dd.yyyy"));
+	jum.assertTrue("test3", dojo_validate_isValidDate("08-06-2005", "MM-dd-yyyy"));
+	jum.assertTrue("test4", dojo_validate_isValidDate("8/6/2005", "M/d/yyyy"));
+	jum.assertTrue("test5", dojo_validate_isValidDate("8/6", "M/d"));
+	jum.assertFalse("test6", dojo_validate_isValidDate("09/31/2005", "MM/dd/yyyy"));
+	jum.assertFalse("test7", dojo_validate_isValidDate("02/29/2005", "MM/dd/yyyy"));
+	jum.assertTrue("test8", dojo_validate_isValidDate("02/29/2004", "MM/dd/yyyy"));
+
+	// year month date
+	jum.assertTrue("test9", dojo_validate_isValidDate("2005-08-06", "yyyy-MM-dd"));
+	jum.assertTrue("test10", dojo_validate_isValidDate("20050806", "yyyyMMdd"));
+
+	// year month
+	jum.assertTrue("test11", dojo_validate_isValidDate("2005-08", "yyyy-MM"));
+	jum.assertTrue("test12", dojo_validate_isValidDate("200508", "yyyyMM"));
+
+	// year
+	jum.assertTrue("test13", dojo_validate_isValidDate("2005", "yyyy"));
+
+	// year week day
+//TODO: need to support 'w'?
+//	jum.assertTrue("test14", dojo_validate_isValidDate("2005-W42-3", "yyyy-'W'ww-d"));
+//	jum.assertTrue("test15", dojo_validate_isValidDate("2005W423", "yyyy'W'wwd"));
+//	jum.assertFalse("test16", dojo_validate_isValidDate("2005-W42-8", "yyyy-'W'ww-d"));
+//	jum.assertFalse("test17", dojo_validate_isValidDate("2005-W54-3", "yyyy-'W'ww-d"));
+
+	// year week
+//	jum.assertTrue("test18", dojo_validate_isValidDate("2005-W42", "yyyy-'W'ww"));
+//	jum.assertTrue("test19", dojo_validate_isValidDate("2005W42", "yyyy'W'ww"));
+
+	// year ordinal-day
+	jum.assertTrue("test20", dojo_validate_isValidDate("2005-292", "yyyy-DDD"));
+	jum.assertTrue("test21", dojo_validate_isValidDate("2005292", "yyyyDDD"));
+	jum.assertFalse("test22", dojo_validate_isValidDate("2005-366", "yyyy-DDD"));
+	jum.assertTrue("test23", dojo_validate_isValidDate("2004-366", "yyyy-DDD"));
+
+	// date month year
+	jum.assertTrue("test24", dojo_validate_isValidDate("19.10.2005", "dd.MM.yyyy"));
+	jum.assertTrue("test25", dojo_validate_isValidDate("19-10-2005", "d-M-yyyy"));
+}
+*/

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/date/stamp.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/date/stamp.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/date/stamp.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,165 @@
+dojo.provide("tests.date.stamp");
+
+dojo.require("dojo.date.stamp");
+
+tests.register("tests.date.stamp", 
+	[
+function test_date_rfc3339(t){
+	var rfc  = "2005-06-29T08:05:00-07:00";
+	var date = dojo.date.stamp.fromRfc3339(rfc);
+	t.is(2005,date.getFullYear());
+	t.is(5,date.getMonth());
+	t.is(29,date.getDate());
+	t.is(15,date.getUTCHours());
+	t.is(5,date.getMinutes());
+	t.is(0,date.getSeconds());
+
+	rfc  = "2004-02-29Tany";
+	date = dojo.date.stamp.fromRfc3339(rfc);
+	t.is(2004,date.getFullYear());
+	t.is(1,date.getMonth());
+	t.is(29,date.getDate());
+
+	date = new Date(2005,5,29,8,5,0);
+	rfc = dojo.date.stamp.toRfc3339(date);
+	//truncate for comparison
+	t.is("2005-06",rfc.substring(0,7));
+},
+
+/* ISO 8601 Functions
+ *********************/
+
+function test_date_fromIso8601(t){
+	var iso  = "20060210T000000Z";
+	var date = dojo.date.stamp.fromIso8601(iso);
+	t.is(2006,date.getFullYear());
+	t.is(1,date.getMonth());
+	t.is(10,date.getUTCDate());
+
+	iso = "20070116T141500+09";
+	date = dojo.date.stamp.fromIso8601(iso);
+	t.is(2007,date.getFullYear());
+},
+
+function test_date_fromIso8601Date(t){
+	
+	//YYYY-MM-DD
+	var date = dojo.date.stamp.fromIso8601Date("2005-02-22");
+	t.is(2005, date.getFullYear());
+	t.is(1, date.getMonth());
+	t.is(22, date.getDate());
+	
+	//YYYYMMDD
+	var date = dojo.date.stamp.fromIso8601Date("20050222");
+	t.is(2005, date.getFullYear());
+	t.is(1, date.getMonth());
+	t.is(22, date.getDate());
+	
+	//YYYY-MM
+	var date = dojo.date.stamp.fromIso8601Date("2005-08");
+	t.is(2005, date.getFullYear());
+	t.is(7, date.getMonth());
+	
+	//YYYYMM
+	var date = dojo.date.stamp.fromIso8601Date("200502");
+	t.is(2005, date.getFullYear());
+	t.is(1, date.getMonth());
+	
+	//YYYY
+	var date = dojo.date.stamp.fromIso8601Date("2005");
+	t.is(2005, date.getFullYear());
+	
+	//1997-W01 or 1997W01
+	var date = dojo.date.stamp.fromIso8601Date("2005-W22");
+	t.is(2005, date.getFullYear());
+	t.is(5, date.getMonth());
+	t.is(6, date.getDate());
+
+	var date = dojo.date.stamp.fromIso8601Date("2005W22");
+	t.is(2005, date.getFullYear());
+	t.is(5, date.getMonth());
+	t.is(6, date.getDate());
+	
+	//1997-W01-2 or 1997W012
+	var date = dojo.date.stamp.fromIso8601Date("2005-W22-4");
+	t.is(2005, date.getFullYear());
+	t.is(5, date.getMonth());
+	t.is(9, date.getDate());
+
+	var date = dojo.date.stamp.fromIso8601Date("2005W224");
+	t.is(2005, date.getFullYear());
+	t.is(5, date.getMonth());
+	t.is(9, date.getDate());
+
+		
+	//1995-035 or 1995035
+	var date = dojo.date.stamp.fromIso8601Date("2005-146");
+	t.is(2005, date.getFullYear());
+	t.is(4, date.getMonth());
+	t.is(26, date.getDate());
+	
+	var date = dojo.date.stamp.fromIso8601Date("2005146");
+	t.is(2005, date.getFullYear());
+	t.is(4, date.getMonth());
+	t.is(26, date.getDate());
+	
+},
+
+function test_date_fromIso8601Time(t){
+	
+	//23:59:59
+	var date = dojo.date.stamp.fromIso8601Time("18:46:39");
+	t.is(18, date.getHours());
+	t.is(46, date.getMinutes());
+	t.is(39, date.getSeconds());
+	
+	//235959
+	var date = dojo.date.stamp.fromIso8601Time("184639");
+	t.is(18, date.getHours());
+	t.is(46, date.getMinutes());
+	t.is(39, date.getSeconds());
+	
+	//23:59, 2359, or 23
+	var date = dojo.date.stamp.fromIso8601Time("18:46");
+	t.is(18, date.getHours());
+	t.is(46, date.getMinutes());
+
+	var date = dojo.date.stamp.fromIso8601Time("1846");
+	t.is(18, date.getHours());
+	t.is(46, date.getMinutes());
+
+	var date = dojo.date.stamp.fromIso8601Time("18");
+	t.is(18, date.getHours());
+
+	//23:59:59.9942 or 235959.9942
+	var date = dojo.date.stamp.fromIso8601Time("18:46:39.9942");
+	t.is(18, date.getHours());
+	t.is(46, date.getMinutes());
+	t.is(39, date.getSeconds());
+	t.is(994, date.getMilliseconds());
+
+	var date = dojo.date.stamp.fromIso8601Time("184639.9942");
+	t.is(18, date.getHours());
+	t.is(46, date.getMinutes());
+	t.is(39, date.getSeconds());
+	t.is(994, date.getMilliseconds());
+	
+	//1995-02-04 24:00 = 1995-02-05 00:00
+
+	//timezone tests
+	var offset = new Date().getTimezoneOffset()/60;
+	var date = dojo.date.stamp.fromIso8601Time("18:46:39+07:00");
+	t.is(11, date.getUTCHours());
+
+	var date = dojo.date.stamp.fromIso8601Time("18:46:39+00:00");
+	t.is(18, date.getUTCHours());
+
+	var date = dojo.date.stamp.fromIso8601Time("16:46:39-07:00");
+	t.is(23, date.getUTCHours());
+	
+	//+hh:mm, +hhmm, or +hh
+	
+	//-hh:mm, -hhmm, or -hh
+	}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/date.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/date.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/date.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,490 @@
+dojo.provide("tests.date");
+
+dojo.require("dojo.date");
+
+tests.register("tests.date.util", 
+	[
+
+/* Informational Functions
+ **************************/
+
+function test_date_getDaysInMonth(t){
+	// months other than February
+	t.is(31, dojo.date.getDaysInMonth(new Date(2006,0,1)));
+	t.is(31, dojo.date.getDaysInMonth(new Date(2006,2,1)));
+	t.is(30, dojo.date.getDaysInMonth(new Date(2006,3,1)));
+	t.is(31, dojo.date.getDaysInMonth(new Date(2006,4,1)));
+	t.is(30, dojo.date.getDaysInMonth(new Date(2006,5,1)));
+	t.is(31, dojo.date.getDaysInMonth(new Date(2006,6,1)));
+	t.is(31, dojo.date.getDaysInMonth(new Date(2006,7,1)));
+	t.is(30, dojo.date.getDaysInMonth(new Date(2006,8,1)));
+	t.is(31, dojo.date.getDaysInMonth(new Date(2006,9,1)));
+	t.is(30, dojo.date.getDaysInMonth(new Date(2006,10,1)));
+	t.is(31, dojo.date.getDaysInMonth(new Date(2006,11,1)));
+
+	// Februarys
+	t.is(28, dojo.date.getDaysInMonth(new Date(2006,1,1)));
+	t.is(29, dojo.date.getDaysInMonth(new Date(2004,1,1)));
+	t.is(29, dojo.date.getDaysInMonth(new Date(2000,1,1)));
+	t.is(28, dojo.date.getDaysInMonth(new Date(1900,1,1)));
+	t.is(28, dojo.date.getDaysInMonth(new Date(1800,1,1)));
+	t.is(28, dojo.date.getDaysInMonth(new Date(1700,1,1)));
+	t.is(29, dojo.date.getDaysInMonth(new Date(1600,1,1)));
+},
+
+function test_date_isLeapYear(t){
+	t.f(dojo.date.isLeapYear(new Date(2006,0,1)));
+	t.t(dojo.date.isLeapYear(new Date(2004,0,1)));
+	t.t(dojo.date.isLeapYear(new Date(2000,0,1)));
+	t.f(dojo.date.isLeapYear(new Date(1900,0,1)));
+	t.f(dojo.date.isLeapYear(new Date(1800,0,1)));
+	t.f(dojo.date.isLeapYear(new Date(1700,0,1)));
+	t.t(dojo.date.isLeapYear(new Date(1600,0,1)));
+},
+
+// The getTimezone function pulls from either the date's toString or
+// toLocaleString method -- it's really just a string-processing
+// function (assuming the Date obj passed in supporting both toString 
+// and toLocaleString) and as such can be tested for multiple browsers
+// by manually settting up fake Date objects with the actual strings
+// produced by various browser/OS combinations.
+// FIXME: the function and tests are not localized.
+function test_date_getTimezoneName(t){
+	
+	// Create a fake Date object with toString and toLocaleString
+	// results manually set to simulate tests for multiple browsers
+	function fakeDate(str, strLocale){
+		this.str = str || '';
+		this.strLocale = strLocale || '';
+		this.toString = function() {
+			return this.str;
+		};
+		this.toLocaleString = function(){
+			return this.strLocale;
+		};
+	}
+	var dt = new fakeDate();
+	
+	// FF 1.5 Ubuntu Linux (Breezy)
+	dt.str = 'Sun Sep 17 2006 22:25:51 GMT-0500 (CDT)';
+	dt.strLocale = 'Sun 17 Sep 2006 10:25:51 PM CDT';
+	t.is('CDT', dojo.date.getTimezoneName(dt));
+
+	// Safari 2.0 Mac OS X 10.4
+	dt.str = 'Sun Sep 17 2006 22:55:01 GMT-0500';
+	dt.strLocale = 'September 17, 2006 10:55:01 PM CDT';
+	t.is('CDT', dojo.date.getTimezoneName(dt));
+
+	// FF 1.5 Mac OS X 10.4
+	dt.str = 'Sun Sep 17 2006 22:57:18 GMT-0500 (CDT)';
+	dt.strLocale = 'Sun Sep 17 22:57:18 2006';
+	t.is('CDT', dojo.date.getTimezoneName(dt));
+
+	// Opera 9 Mac OS X 10.4 -- no TZ data expect empty string return
+	dt.str = 'Sun, 17 Sep 2006 22:58:06 GMT-0500';
+	dt.strLocale = 'Sunday September 17, 22:58:06 GMT-0500 2006';
+	t.is('', dojo.date.getTimezoneName(dt));
+	
+	// IE 6 Windows XP
+	dt.str = 'Mon Sep 18 11:21:07 CDT 2006';
+	dt.strLocale = 'Monday, September 18, 2006 11:21:07 AM';
+	t.is('CDT', dojo.date.getTimezoneName(dt));
+
+	// Opera 9 Ubuntu Linux (Breezy) -- no TZ data expect empty string return 
+	dt.str = 'Mon, 18 Sep 2006 13:30:32 GMT-0500';
+	dt.strLocale = 'Monday September 18, 13:30:32 GMT-0500 2006';
+	t.is('', dojo.date.getTimezoneName(dt));
+	
+	// IE 5.5 Windows 2000
+	dt.str = 'Mon Sep 18 13:49:22 CDT 2006';
+	dt.strLocale = 'Monday, September 18, 2006 1:49:22 PM';
+	t.is('CDT', dojo.date.getTimezoneName(dt));
+}
+	]
+);
+
+tests.register("tests.date.math", 
+	[
+function test_date_compare(t){
+	var d1=new Date();
+	d1.setHours(0);
+	var d2=new Date();
+	d2.setFullYear(2005);
+	d2.setHours(12);
+	t.is(0, dojo.date.compare(d1, d1));
+	t.is(1, dojo.date.compare(d1, d2, "date"));
+	t.is(-1, dojo.date.compare(d2, d1, "date"));
+	t.is(-1, dojo.date.compare(d1, d2, "time"));
+	t.is(1, dojo.date.compare(d1, d2, "datetime"));
+},
+function test_date_add(t){
+	var interv = ''; // Interval (e.g., year, month)
+	var dtA = null; // Date to increment
+	var dtB = null; // Expected result date
+	
+	interv = "year";
+	dtA = new Date(2005, 11, 27);
+	dtB = new Date(2006, 11, 27);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+	
+	dtA = new Date(2005, 11, 27);
+	dtB = new Date(2004, 11, 27);
+	t.is(dtB, dojo.date.add(dtA, interv, -1));
+	
+	dtA = new Date(2000, 1, 29);
+	dtB = new Date(2001, 1, 28);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+	
+	dtA = new Date(2000, 1, 29);
+	dtB = new Date(2005, 1, 28);
+	t.is(dtB, dojo.date.add(dtA, interv, 5));
+	
+	dtA = new Date(1900, 11, 31);
+	dtB = new Date(1930, 11, 31);
+	t.is(dtB, dojo.date.add(dtA, interv, 30));
+	
+	dtA = new Date(1995, 11, 31);
+	dtB = new Date(2030, 11, 31);
+	t.is(dtB, dojo.date.add(dtA, interv, 35));
+
+	interv = "quarter";
+	dtA = new Date(2000, 0, 1);
+	dtB = new Date(2000, 3, 1);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+	
+	dtA = new Date(2000, 1, 29);
+	dtB = new Date(2000, 7, 29);
+	t.is(dtB, dojo.date.add(dtA, interv, 2));
+	
+	dtA = new Date(2000, 1, 29);
+	dtB = new Date(2001, 1, 28);
+	t.is(dtB, dojo.date.add(dtA, interv, 4));
+	
+	interv = "month";
+	dtA = new Date(2000, 0, 1);
+	dtB = new Date(2000, 1, 1);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+	
+	dtA = new Date(2000, 0, 31);
+	dtB = new Date(2000, 1, 29);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+	
+	dtA = new Date(2000, 1, 29);
+	dtB = new Date(2001, 1, 28);
+	t.is(dtB, dojo.date.add(dtA, interv, 12));
+	
+	interv = "week";
+	dtA = new Date(2000, 0, 1);
+	dtB = new Date(2000, 0, 8);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+	var interv = "day";
+	dtA = new Date(2000, 0, 1);
+	dtB = new Date(2000, 0, 2);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+	
+	dtA = new Date(2001, 0, 1);
+	dtB = new Date(2002, 0, 1);
+	t.is(dtB, dojo.date.add(dtA, interv, 365));
+	
+	dtA = new Date(2000, 0, 1);
+	dtB = new Date(2001, 0, 1);
+	t.is(dtB, dojo.date.add(dtA, interv, 366));
+	
+	dtA = new Date(2000, 1, 28);
+	dtB = new Date(2000, 1, 29);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+	
+	dtA = new Date(2001, 1, 28);
+	dtB = new Date(2001, 2, 1);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+	
+	dtA = new Date(2000, 2, 1);
+	dtB = new Date(2000, 1, 29);
+	t.is(dtB, dojo.date.add(dtA, interv, -1));
+	
+	dtA = new Date(2001, 2, 1);
+	dtB = new Date(2001, 1, 28);
+	t.is(dtB, dojo.date.add(dtA, interv, -1));
+	
+	dtA = new Date(2000, 0, 1);
+	dtB = new Date(1999, 11, 31);
+	t.is(dtB, dojo.date.add(dtA, interv, -1));
+	
+	interv = "weekday";
+	// Sat, Jan 1
+	dtA = new Date(2000, 0, 1);
+	// Should be Mon, Jan 3
+	dtB = new Date(2000, 0, 3);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+	
+	// Sun, Jan 2
+	dtA = new Date(2000, 0, 2);
+	// Should be Mon, Jan 3
+	dtB = new Date(2000, 0, 3);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+	
+	// Sun, Jan 2
+	dtA = new Date(2000, 0, 2);
+	// Should be Fri, Jan 7
+	dtB = new Date(2000, 0, 7);
+	t.is(dtB, dojo.date.add(dtA, interv, 5));
+	
+	// Sun, Jan 2
+	dtA = new Date(2000, 0, 2);
+	// Should be Mon, Jan 10
+	dtB = new Date(2000, 0, 10);
+	t.is(dtB, dojo.date.add(dtA, interv, 6));
+	
+	// Mon, Jan 3
+	dtA = new Date(2000, 0, 3);
+	// Should be Mon, Jan 17
+	dtB = new Date(2000, 0, 17);
+	t.is(dtB, dojo.date.add(dtA, interv, 10));
+	
+	// Sat, Jan 8
+	dtA = new Date(2000, 0, 8);
+	// Should be Mon, Jan 3
+	dtB = new Date(2000, 0, 3);
+	t.is(dtB, dojo.date.add(dtA, interv, -5));
+	
+	// Sun, Jan 9
+	dtA = new Date(2000, 0, 9);
+	// Should be Wed, Jan 5
+	dtB = new Date(2000, 0, 5);
+	t.is(dtB, dojo.date.add(dtA, interv, -3));
+	
+	// Sun, Jan 23
+	dtA = new Date(2000, 0, 23);
+	// Should be Fri, Jan 7
+	dtB = new Date(2000, 0, 7);
+	t.is(dtB, dojo.date.add(dtA, interv, -11));
+	
+	interv = "hour";
+	dtA = new Date(2000, 0, 1, 11);
+	dtB = new Date(2000, 0, 1, 12);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+	dtA = new Date(2001, 9, 28, 0);
+	dtB = new Date(2001, 9, 28, 1);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+	dtA = new Date(2001, 9, 28, 23);
+	dtB = new Date(2001, 9, 29, 0);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+	dtA = new Date(2001, 11, 31, 23);
+	dtB = new Date(2002, 0, 1, 0);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+	interv = "minute";
+	dtA = new Date(2000, 11, 31, 23, 59);
+	dtB = new Date(2001, 0, 1, 0, 0);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+	dtA = new Date(2000, 11, 27, 12, 02);
+	dtB = new Date(2000, 11, 27, 13, 02);
+	t.is(dtB, dojo.date.add(dtA, interv, 60));
+	
+	interv = "second";
+	dtA = new Date(2000, 11, 31, 23, 59, 59);
+	dtB = new Date(2001, 0, 1, 0, 0, 0);
+	t.is(dtB, dojo.date.add(dtA, interv, 1));
+
+	dtA = new Date(2000, 11, 27, 8, 10, 59);
+	dtB = new Date(2000, 11, 27, 8, 11, 59);
+	t.is(dtB, dojo.date.add(dtA, interv, 60));
+	
+	// Test environment JS Date doesn't support millisec?
+	//interv = "millisecond";
+	//
+	//dtA = new Date(2000, 11, 31, 23, 59, 59, 999);
+	//dtB = new Date(2001, 0, 1, 0, 0, 0, 0);
+	//t.is(dtB, dojo.date.add(dtA, interv, 1));
+	//
+	//dtA = new Date(2000, 11, 27, 8, 10, 53, 2);
+	//dtB = new Date(2000, 11, 27, 8, 10, 54, 2);
+	//t.is(dtB, dojo.date.add(dtA, interv, 1000));
+},
+function test_date_diff(t){
+	var dtA = null; // First date to compare
+	var dtB = null; // Second date to compare
+	var interv = ''; // Interval to compare on (e.g., year, month)
+	
+	interv = "year";
+	dtA = new Date(2005, 11, 27);
+	dtB = new Date(2006, 11, 27);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2000, 11, 31);
+	dtB = new Date(2001, 0, 1);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	interv = "quarter";
+	dtA = new Date(2000, 1, 29);
+	dtB = new Date(2001, 2, 1);
+	t.is(4, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2000, 11, 1);
+	dtB = new Date(2001, 0, 1);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	interv = "month";
+	dtA = new Date(2000, 1, 29);
+	dtB = new Date(2001, 2, 1);
+	t.is(13, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2000, 11, 1);
+	dtB = new Date(2001, 0, 1);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	interv = "week";
+	dtA = new Date(2000, 1, 1);
+	dtB = new Date(2000, 1, 8);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2000, 1, 28);
+	dtB = new Date(2000, 2, 6);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2000, 2, 6);
+	dtB = new Date(2000, 1, 28);
+	t.is(-1, dojo.date.difference(dtA, dtB, interv));
+	
+	interv = "day";
+	dtA = new Date(2000, 1, 29);
+	dtB = new Date(2000, 2, 1);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2000, 11, 31);
+	dtB = new Date(2001, 0, 1);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	// DST leap -- check for rounding err
+	// This is dependent on US calendar, but
+	// shouldn't break in other locales
+	dtA = new Date(2005, 3, 3);
+	dtB = new Date(2005, 3, 4);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	interv = "weekday";
+	dtA = new Date(2006, 7, 3);
+	dtB = new Date(2006, 7, 11);
+	t.is(6, dojo.date.difference(dtA, dtB, interv));
+	
+	// Positive diffs
+	dtA = new Date(2006, 7, 4);
+	dtB = new Date(2006, 7, 11);
+	t.is(5, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 5);
+	dtB = new Date(2006, 7, 11);
+	t.is(5, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 6);
+	dtB = new Date(2006, 7, 11);
+	t.is(5, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 7);
+	dtB = new Date(2006, 7, 11);
+	t.is(4, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 7);
+	dtB = new Date(2006, 7, 13);
+	t.is(4, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 7);
+	dtB = new Date(2006, 7, 14);
+	t.is(5, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 7);
+	dtB = new Date(2006, 7, 15);
+	t.is(6, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 7);
+	dtB = new Date(2006, 7, 28);
+	t.is(15, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 2, 2);
+	dtB = new Date(2006, 2, 28);
+	t.is(18, dojo.date.difference(dtA, dtB, interv));
+	
+	// Negative diffs
+	dtA = new Date(2006, 7, 11);
+	dtB = new Date(2006, 7, 4);
+	t.is(-5, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 11);
+	dtB = new Date(2006, 7, 5);
+	t.is(-4, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 11);
+	dtB = new Date(2006, 7, 6);
+	t.is(-4, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 11);
+	dtB = new Date(2006, 7, 7);
+	t.is(-4, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 13);
+	dtB = new Date(2006, 7, 7);
+	t.is(-5, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 14);
+	dtB = new Date(2006, 7, 7);
+	t.is(-5, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 15);
+	dtB = new Date(2006, 7, 7);
+	t.is(-6, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 7, 28);
+	dtB = new Date(2006, 7, 7);
+	t.is(-15, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2006, 2, 28);
+	dtB = new Date(2006, 2, 2);
+	t.is(-18, dojo.date.difference(dtA, dtB, interv));
+
+	// Two days on the same weekend -- no weekday diff
+	dtA = new Date(2006, 7, 5);
+	dtB = new Date(2006, 7, 6);
+	t.is(0, dojo.date.difference(dtA, dtB, interv));
+	
+	interv = "hour";
+	dtA = new Date(2000, 11, 31, 23);
+	dtB = new Date(2001, 0, 1, 0);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2000, 11, 31, 12);
+	dtB = new Date(2001, 0, 1, 0);
+	t.is(12, dojo.date.difference(dtA, dtB, interv));
+	
+	interv = "minute";
+	dtA = new Date(2000, 11, 31, 23, 59);
+	dtB = new Date(2001, 0, 1, 0, 0);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2000, 1, 28, 23, 59);
+	dtB = new Date(2000, 1, 29, 0, 0);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	interv = "second";
+	dtA = new Date(2000, 11, 31, 23, 59, 59);
+	dtB = new Date(2001, 0, 1, 0, 0, 0);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	interv = "millisecond";
+	dtA = new Date(2000, 11, 31, 23, 59, 59, 999);
+	dtB = new Date(2001, 0, 1, 0, 0, 0, 0);
+	t.is(1, dojo.date.difference(dtA, dtB, interv));
+	
+	dtA = new Date(2000, 11, 31, 23, 59, 59, 0);
+	dtB = new Date(2001, 0, 1, 0, 0, 0, 0);
+	t.is(1000, dojo.date.difference(dtA, dtB, interv));
+}
+	]
+);
+
+dojo.require("tests.date.locale");
+dojo.require("tests.date.stamp");

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_container.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_container.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_container.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,75 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+	<title>Dojo DnD container test</title>
+	<style type="text/css">
+		@import "../../resources/dojo.css";
+
+		body {
+			padding: 1em;
+		}
+
+		.container				{border: 3px solid #ccc; padding: 1em 3em; cursor: default;}
+		.dojoDndContainerOver	{border: 3px solid #888; background: #ffe;}
+		.dojoDndItemOver		{background: #feb;}
+	</style>
+	<script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true"></script>
+	<script type="text/javascript" src="../../dnd/container.js"></script>
+	<script type="text/javascript">
+		// dojo.require("dojo.dnd.container");
+		var c1, c2, c3, c4, c5;
+		var init = function(){
+			c1 = new dojo.dnd.Container(dojo.byId("container1"));
+			c2 = new dojo.dnd.Container(dojo.byId("container2"));
+			c3 = new dojo.dnd.Container(dojo.byId("container3"));
+			c4 = new dojo.dnd.Container(dojo.byId("container4"));
+			c5 = new dojo.dnd.Container(dojo.byId("container5"));
+		};
+		dojo.addOnLoad(init);
+	</script>
+</head>
+<body>
+	<h1>Dojo DnD container test</h1>
+	<p>Containers have a notion of a "current container", and one element can be "current".</p>
+	<h2>DIV container</h2>
+	<div id="container1" class="container">
+		<div>Item 1</div>
+		<div>Item 2</div>
+		<div>Item 3</div>
+	</div>
+	<h2>UL container</h2>
+	<ul id="container2" class="container">
+		<li>Item 1</li>
+		<li>Item 2</li>
+		<li>Item 3</li>
+	</ul>
+	<h2>OL container</h2>
+	<ol id="container3" class="container">
+		<li>Item 1</li>
+		<li>Item 2</li>
+		<li>Item 3</li>
+	</ol>
+	<h2>TABLE container</h2>
+	<table id="container4" class="container" border="1px solid black">
+		<tr>
+			<td>A</td>
+			<td>row 1</td>
+		</tr>
+		<tr>
+			<td>B</td>
+			<td>row 2</td>
+		</tr>
+		<tr>
+			<td>C</td>
+			<td>row 3</td>
+		</tr>
+	</table>
+	<h2>P container with SPAN elements</h2>
+	<p>Elements of this container are layed out horizontally.</p>
+	<p id="container5" class="container">
+		<span>&nbsp;Item 1&nbsp;</span>
+		<span>&nbsp;Item 2&nbsp;</span>
+		<span>&nbsp;Item 3&nbsp;</span>
+	</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_dnd.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_dnd.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_dnd.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+	<title>Dojo DnD test</title>
+	<style type="text/css">
+		@import "../../resources/dojo.css";
+
+		body {
+			padding: 1em;
+		}
+
+		.container				{border: 3px solid #ccc; padding: 1em 3em; cursor: default;}
+		.dojoDndContainerOver	{border: 3px solid #888; background: #ffe;}
+		.dojoDndItemOver		{background: #feb;}
+		.dojoDndItemSelected	{background: #ccf; color: #444;}
+		.dojoDndItemAnchor		{background: #ccf; color: black;}
+		.dojoDndItemOver.dojoDndItemSelected	{background: #ec8;}
+		.dojoDndItemOver.dojoDndItemAnchor		{background: #ec8;}
+		.dojoDndItemBefore		{border-top: 3px solid red;}
+		.dojoDndItemAfter		{border-bottom: 3px solid red;}
+		.dojoDndAvatar			{font-size: 75%;}
+		.dojoDndAvatarHeader	{background: #aaa;}
+		.dojoDndAvatarItem		{background: #eee;}
+	</style>
+	<script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true"></script>
+	<script type="text/javascript" src="../../dnd/container.js"></script>
+	<script type="text/javascript" src="../../dnd/selector.js"></script>
+	<script type="text/javascript" src="../../dnd/source.js"></script>
+	<script type="text/javascript" src="../../dnd/avatar.js"></script>
+	<script type="text/javascript" src="../../dnd/manager.js"></script>
+	<script type="text/javascript">
+		//dojo.require("dojo.dnd.source");
+		//dojo.require("dojo.dnd.manager");
+		var c1, c2;
+		var init = function(){
+			//c1 = new dojo.dnd.Source(dojo.byId("container1"));
+			c1 = new dojo.dnd.Source("container1");
+			c1.insertNodes(false, [1, 2, 3, 4, 5, 6, [1, 2, 3], function(x){ return x + x; }]);
+			//c2 = new dojo.dnd.Source(dojo.byId("container2"));
+			c2 = new dojo.dnd.Source("container2");
+			c2.insertNodes(false, ["A", "B", "C", "D", "E", "F", {repr: function(){ return "CUSTOM!"; }}, null]);
+		};
+		dojo.addOnLoad(init);
+	</script>
+</head>
+<body>
+	<h1>Dojo DnD test</h1>
+	<p>Elements of both sources/targets were created dynamically.</p>
+	<p>Following selection modes are supported by default:</p>
+	<ul>
+		<li>Simple click &mdash; selects a single element, all other elements will be unselected.</li>
+		<li>Ctrl+click &mdash; toggles a selection state of an element (use Meta key on Mac).</li>
+		<li>Shift+click &mdash; selects a range of element from the previous anchor to the current element.</li>
+		<li>Ctrl+Shift+click &mdash; adds a range of element from the previous anchor to the current element (use Meta key on Mac).</li>
+	</ul>
+	<p>Following drop modes are supported by default:</p>
+	<ul>
+		<li>Simple drop &mdash; moves elements to the valid target removing them from the source. It can be used to reorganize elements within a single source/target.</li>
+		<li>Ctrl+drop &mdash; copies elements to the valid target (use Meta key on Mac).</li>
+	</ul>
+	<p id="container1" class="container"></p>
+	<p id="container2" class="container"></p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_moveable.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_moveable.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_moveable.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>Dojo Moveable test</title>
+	<style type="text/css">
+		@import "../../resources/dojo.css";
+
+		body {
+			padding: 1em;
+		}
+
+		#moveable1 {
+			background: yellow;
+			border: 1px solid black;
+		}
+		#handle1 {
+			background: blue;
+			color: white;
+			cursor: pointer;
+			border: 1px solid black;
+		}
+		#moveable2 {
+			background: yellow;
+			position: absolute;
+			width:  200px;
+			height: 200px;
+			left: 100px;
+			top:  100px;
+			padding: 10px 20px;
+			margin: 10px 20px;
+			border: 10px solid black;
+			cursor: pointer;
+		}
+	</style>
+	<script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true"></script>
+	<script type="text/javascript" src="../../dnd/move.js"></script>
+	<script type="text/javascript">
+		dojo.require("dojo.dnd.move");
+		var m1, m2;
+		var init = function(){
+			//m1 = new dojo.dnd.Moveable(dojo.byId("moveable1"), dojo.byId("handle1"));
+			//m2 = new dojo.dnd.Moveable(dojo.byId("moveable2"));
+			m1 = new dojo.dnd.Moveable("moveable1", "handle1");
+			m2 = new dojo.dnd.Moveable("moveable2");
+		};
+		dojo.addOnLoad(init);
+	</script>
+</head>
+<body>
+	<h1>Dojo Moveable test</h1>
+	<h2>1st run</h2>
+	<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Praesent erat. In malesuada ultricies velit. Vestibulum tempor odio vitae diam. Morbi arcu lectus, laoreet eget, nonummy at, elementum a, quam. Pellentesque ac lacus. Cras quis est. Etiam suscipit, quam at eleifend nonummy, elit nunc sollicitudin tellus, at mattis est ligula interdum urna. Vivamus id augue sed mi consectetuer dictum. Suspendisse dapibus elit non urna. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam gravida dapibus ante. Nam viverra ligula in neque. Nullam at metus. Aenean ipsum.</p>
+	<p>Mauris vulputate elit a risus. Praesent pellentesque velit ac neque. Fusce ultrices augue vitae orci. Proin a ante. Nulla consectetuer arcu quis est. Suspendisse potenti. Aliquam erat volutpat. Morbi purus augue, eleifend eu, consectetuer sed, tristique ut, wisi. Cras ac tellus. Phasellus adipiscing, libero ac consequat volutpat, ligula purus mollis lectus, ac porttitor ipsum diam non urna. Donec lorem. Pellentesque diam tortor, posuere et, placerat vitae, iaculis et, sapien. Proin sodales vehicula purus. Quisque bibendum mi ac mauris. Quisque tellus. Morbi sagittis. Integer euismod rhoncus augue. Ut accumsan. Curabitur quis tellus sit amet odio ultricies tristique. Etiam malesuada.</p>
+	<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec est. Cras semper nunc ut metus. Pellentesque blandit pede at erat. Quisque nonummy leo id metus. Donec mi mi, viverra id, adipiscing vitae, consectetuer ut, elit. In lectus augue, porttitor quis, viverra id, dignissim id, leo. Maecenas sapien. Nam adipiscing sem. Aenean ligula. Etiam vel velit. In mollis cursus dolor. Suspendisse ac nibh id leo tempor posuere. Aliquam sapien tellus, elementum non, aliquam sed, luctus eu, augue. Aliquam elementum leo nec enim. Donec ornare sagittis magna. Mauris ac tellus.</p>
+	<p>Duis ac augue rhoncus neque adipiscing feugiat. Donec pulvinar sem vitae neque. Donec commodo metus at ipsum. Cras vel magna vehicula lorem varius consequat. Morbi at enim vitae lectus mollis sodales. Sed tincidunt quam ut mi varius hendrerit. Sed porta arcu non libero. Quisque et wisi. Pellentesque lobortis. Ut enim felis, varius vitae, ornare quis, auctor ut, risus. Ut porta lorem vel quam. Etiam nunc purus, consectetuer non, lobortis eu, fermentum eu, magna. Aenean ultrices ante. Aliquam erat volutpat. Morbi quis velit eu mi sollicitudin lacinia. Suspendisse potenti. Donec lectus.</p>
+	<p>Quisque egestas turpis. Sed id ipsum id libero euismod nonummy. Nam sed dolor. Mauris in turpis. Duis nec wisi eget ante ultrices varius. Ut eget neque. Suspendisse sagittis iaculis tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Phasellus at justo. Donec imperdiet, elit et commodo bibendum, leo augue pellentesque arcu, ac dapibus lorem nulla eget erat. In viverra, tellus eu luctus eleifend, urna nibh lobortis sapien, ac pulvinar massa enim vel turpis. Sed orci neque, sagittis eu, mattis vitae, rutrum condimentum, leo. Fusce wisi odio, convallis at, condimentum vel, imperdiet id, mi. Mauris semper, magna pretium consectetuer sollicitudin, eros enim vehicula risus, eu ultrices turpis quam at wisi. Nam mollis.</p>
+	<table id="moveable1">
+		<tr><td id="handle1" colspan="2">You can drag the table using this handle.</td></tr>
+		<tr><td>1</td><td>Lorem ipsum dolor sit amet...</td></tr>
+		<tr><td>2</td><td>Mauris vulputate elit a risus...</td></tr>
+		<tr><td>3</td><td>Pellentesque habitant morbi tristique senectus...</td></tr>
+		<tr><td>4</td><td>Duis ac augue rhoncus neque...</td></tr>
+		<tr><td>5</td><td>Quisque egestas turpis. Sed id...</td></tr>
+	</table>	
+	<h2>2nd run</h2>
+	<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Praesent erat. In malesuada ultricies velit. Vestibulum tempor odio vitae diam. Morbi arcu lectus, laoreet eget, nonummy at, elementum a, quam. Pellentesque ac lacus. Cras quis est. Etiam suscipit, quam at eleifend nonummy, elit nunc sollicitudin tellus, at mattis est ligula interdum urna. Vivamus id augue sed mi consectetuer dictum. Suspendisse dapibus elit non urna. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam gravida dapibus ante. Nam viverra ligula in neque. Nullam at metus. Aenean ipsum.</p>
+	<p>Mauris vulputate elit a risus. Praesent pellentesque velit ac neque. Fusce ultrices augue vitae orci. Proin a ante. Nulla consectetuer arcu quis est. Suspendisse potenti. Aliquam erat volutpat. Morbi purus augue, eleifend eu, consectetuer sed, tristique ut, wisi. Cras ac tellus. Phasellus adipiscing, libero ac consequat volutpat, ligula purus mollis lectus, ac porttitor ipsum diam non urna. Donec lorem. Pellentesque diam tortor, posuere et, placerat vitae, iaculis et, sapien. Proin sodales vehicula purus. Quisque bibendum mi ac mauris. Quisque tellus. Morbi sagittis. Integer euismod rhoncus augue. Ut accumsan. Curabitur quis tellus sit amet odio ultricies tristique. Etiam malesuada.</p>
+	<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec est. Cras semper nunc ut metus. Pellentesque blandit pede at erat. Quisque nonummy leo id metus. Donec mi mi, viverra id, adipiscing vitae, consectetuer ut, elit. In lectus augue, porttitor quis, viverra id, dignissim id, leo. Maecenas sapien. Nam adipiscing sem. Aenean ligula. Etiam vel velit. In mollis cursus dolor. Suspendisse ac nibh id leo tempor posuere. Aliquam sapien tellus, elementum non, aliquam sed, luctus eu, augue. Aliquam elementum leo nec enim. Donec ornare sagittis magna. Mauris ac tellus.</p>
+	<p>Duis ac augue rhoncus neque adipiscing feugiat. Donec pulvinar sem vitae neque. Donec commodo metus at ipsum. Cras vel magna vehicula lorem varius consequat. Morbi at enim vitae lectus mollis sodales. Sed tincidunt quam ut mi varius hendrerit. Sed porta arcu non libero. Quisque et wisi. Pellentesque lobortis. Ut enim felis, varius vitae, ornare quis, auctor ut, risus. Ut porta lorem vel quam. Etiam nunc purus, consectetuer non, lobortis eu, fermentum eu, magna. Aenean ultrices ante. Aliquam erat volutpat. Morbi quis velit eu mi sollicitudin lacinia. Suspendisse potenti. Donec lectus.</p>
+	<p>Quisque egestas turpis. Sed id ipsum id libero euismod nonummy. Nam sed dolor. Mauris in turpis. Duis nec wisi eget ante ultrices varius. Ut eget neque. Suspendisse sagittis iaculis tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Phasellus at justo. Donec imperdiet, elit et commodo bibendum, leo augue pellentesque arcu, ac dapibus lorem nulla eget erat. In viverra, tellus eu luctus eleifend, urna nibh lobortis sapien, ac pulvinar massa enim vel turpis. Sed orci neque, sagittis eu, mattis vitae, rutrum condimentum, leo. Fusce wisi odio, convallis at, condimentum vel, imperdiet id, mi. Mauris semper, magna pretium consectetuer sollicitudin, eros enim vehicula risus, eu ultrices turpis quam at wisi. Nam mollis.</p>
+	<div id="moveable2">You can drag this whole paragraph around.</div>	
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_selector.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_selector.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/dnd/test_selector.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+	<title>Dojo DnD selector test</title>
+	<style type="text/css">
+		@import "../../resources/dojo.css";
+
+		body {
+			padding: 1em;
+		}
+
+		.container				{border: 3px solid #ccc; padding: 1em 3em; cursor: default;}
+		.dojoDndContainerOver	{border: 3px solid #888; background: #ffe;}
+		.dojoDndItemOver		{background: #feb;}
+		.dojoDndItemSelected	{background: #ccf; color: #444;}
+		.dojoDndItemAnchor		{background: #ccf; color: black;}
+		.dojoDndItemOver.dojoDndItemSelected {background: #ec8;}
+		.dojoDndItemOver.dojoDndItemAnchor   {background: #ec8;}
+	</style>
+	<script type="text/javascript" src="../../dojo.js" djConfig="isDebug: true"></script>
+	<script type="text/javascript" src="../../dnd/common.js"></script>
+	<script type="text/javascript" src="../../dnd/container.js"></script>
+	<script type="text/javascript" src="../../dnd/selector.js"></script>
+	<script type="text/javascript">
+		//dojo.require("dojo.dnd.selector");
+		var c1, c2, c3, c4, c5;
+		var init = function(){
+			c1 = new dojo.dnd.Selector(dojo.byId("container1"), {singular: true});
+			c2 = new dojo.dnd.Selector(dojo.byId("container2"));
+			c3 = new dojo.dnd.Selector(dojo.byId("container3"));
+			c4 = new dojo.dnd.Selector(dojo.byId("container4"));
+			c5 = new dojo.dnd.Selector(dojo.byId("container5"));
+		};
+		dojo.addOnLoad(init);
+	</script>
+</head>
+<body>
+	<h1>Dojo DnD selector test</h1>
+	<p>Containers have a notion of a "current container", and one element can be "current". All containers on this page are selectors that allow to select elements.</p>
+	<p>Following selection modes are supported by default:</p>
+	<ul>
+		<li>Simple click &mdash; selects a single element, all other elements will be unselected.</li>
+		<li>Ctrl+click &mdash; toggles a selection state of an element (use Meta key on Mac).</li>
+		<li>Shift+click &mdash; selects a range of elements from the previous anchor to the current element.</li>
+		<li>Ctrl+Shift+click &mdash; adds a range of elements from the previous anchor to the current element (use Meta key on Mac).</li>
+	</ul>
+	<h2>DIV selector</h2>
+	<p>This selector can select just one element a time. It was specified during the creation time.</p>
+	<div id="container1" class="container">
+		<div>Item 1</div>
+		<div>Item 2</div>
+		<div>Item 3</div>
+	</div>
+	<h2>UL selector</h2>
+	<ul id="container2" class="container">
+		<li>Item 1</li>
+		<li>Item 2</li>
+		<li>Item 3</li>
+	</ul>
+	<h2>OL selector</h2>
+	<ol id="container3" class="container">
+		<li>Item 1</li>
+		<li>Item 2</li>
+		<li>Item 3</li>
+	</ol>
+	<h2>TABLE selector</h2>
+	<table id="container4" class="container" border="1px solid black">
+		<tr>
+			<td>A</td>
+			<td>row 1</td>
+		</tr>
+		<tr>
+			<td>B</td>
+			<td>row 2</td>
+		</tr>
+		<tr>
+			<td>C</td>
+			<td>row 3</td>
+		</tr>
+	</table>
+	<h2>P selector with SPAN elements</h2>
+	<p>Elements of this container are layed out horizontally.</p>
+	<p id="container5" class="container">
+		<span>&nbsp;Item 1&nbsp;</span>
+		<span>&nbsp;Item 2&nbsp;</span>
+		<span>&nbsp;Item 3&nbsp;</span>
+	</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/i18n.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/i18n.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/i18n.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,84 @@
+dojo.provide("tests.i18n");
+
+dojo.require("dojo.i18n");
+
+(function(){
+	var setUp = function(locale){
+		return function(){
+			dojo.requireLocalization("tests","salutations",locale);
+		}
+	}
+
+	var getTest = function(value, locale){
+		return function(){
+			doh.assertEqual(value, dojo.i18n.getLocalization("tests", "salutations", locale).hello);
+		}
+	}
+
+	var getFixture = function(locale, value){
+		return {
+			name: "salutations-"+locale,
+			setUp: setUp(locale),
+			runTest: getTest(value, locale)
+		};
+	}
+
+	var testSet = [
+	/* needs dojo.string,
+		// This doesn't actually test anything, it just gives an impressive list of translated output to the console
+		// See the 'salutations' test for something verifyable
+		function fun(t){
+			var salutations_default = dojo.i18n.getLocalization("tests", "salutations");
+			console.debug("In the local language: "+salutations_default.hello);
+
+			var salutations_en = dojo.i18n.getLocalization("tests", "salutations", "en");
+
+			for (i in tests.nls.salutations) {
+				var loc = i.replace('_', '-');
+				var salutations = dojo.i18n.getLocalization("tests", "salutations", loc);
+				var language_as_english = salutations_en[loc];
+				var language_as_native = salutations[loc];
+				var hello_dojo = dojo.string.substitute(salutations.hello_dojo, salutations);
+				if (!dojo.i18n.isLeftToRight(loc)) {
+					var RLE = "\u202b";
+					var PDF = "\u202c";
+					hello_dojo = RLE + hello_dojo + PDF;					
+				}
+				hello_dojo += "\t[" + loc + "]";
+				if(language_as_english){hello_dojo += " " + language_as_english;}
+				if(language_as_native){hello_dojo += " (" + language_as_native + ")";}
+				console.debug(hello_dojo);
+			}
+
+			t.assertTrue(true);
+		},
+	*/
+
+		// Test on-the-fly loading of localized string bundles from different locales, and
+		// the expected inheritance behavior
+
+		// Locale which overrides root translation
+		getFixture("de", "Hallo"),
+		// Locale which does not override root translation
+		getFixture("en", "Hello"),
+		// Locale which overrides its parent
+		getFixture("en-au", "G'day"),
+		// Locale which does not override its parent
+		getFixture("en-us", "Hello"),
+		// Locale which overrides its parent
+		getFixture("en-us-texas", "Howdy"),
+		// 3rd level variant which overrides its parent
+		getFixture("en-us-new_york", "Hello"),
+		// Locale which overrides its grandparent
+		getFixture("en-us-new_york-brooklyn", "Yo"),
+		// Locale which does not have any translation available
+		getFixture("xx", "Hello"),
+		// A double-byte string.  Everything should be read in as UTF-8 and treated as unicode within Javascript.
+		getFixture("zh-cn", "\u4f60\u597d")
+	];
+	testSet[testSet.length-1].tearDown = function(){
+		// Clean up bundles that should not exist if the test is re-run.
+		delete tests.nls.salutations;
+	};
+	tests.register("tests.i18n", testSet);
+})();

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/io/script.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/io/script.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/io/script.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+	"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<title>Testing dojo.io.script</title>
+		<style type="text/css">
+			@import "../../resources/dojo.css";
+		</style>
+		<script type="text/javascript" 
+			src="../../dojo.js" djConfig="isDebug: true"></script>
+		<script type="text/javascript">
+			dojo.require("doh.runner");
+			dojo.require("dojo.io.script");
+
+			dojo.addOnLoad(function(){
+				doh.register("t", 
+					[
+						function ioScriptSimple(t){
+							var d = new doh.Deferred();
+							var td = dojo.io.script.get({
+								url: "scriptSimple.js",
+								checkString: "myTasks"
+							});
+							td.addBoth(function(res){
+								if(typeof(myTasks) != "undefined"
+									&& t.is("Do dishes.", myTasks[1])){
+									d.callback(true);
+								}else{
+									d.errback(false);
+								}
+							});
+							return d;
+						},
+						function ioScriptJsonp(t){
+							var d = new doh.Deferred();
+							var td = dojo.io.script.get({
+								url: "scriptJsonp.js",
+								jsonpParam: "callback"
+							});
+							td.addBoth(function(res){
+								if(!(res instanceof Error) && 
+									t.is("mammal", res.animalType)){
+									d.callback(true);
+								}else{
+									d.errback(false);
+								}
+							});
+							return d;							
+						}
+					]
+				);
+				doh.run();
+			});
+
+/*
+			dojo.addOnLoad(function(){
+				td = dojo.io.script.get({
+					url: "scriptSimple.js",
+					checkString: "myTasks"
+				});
+				td.addCallback(function(res){
+					alert(myTasks);
+					alert(myTasks[1]);
+					if(typeof(myTasks) != "undefined"
+						&& "Do dishes." == myTasks[1]){
+						alert("yeah");
+					}else{
+						alert("boo");
+					}
+				});
+			});
+*/
+
+		</script>
+	</head>
+	<body>
+
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/io/script.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/io/script.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/io/script.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+dojo.provide("tests.io.script");
+if(dojo.isBrowser){
+	doh.registerUrl("tests.io.script", dojo.moduleUrl("tests.io", "script.html"));
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/io/scriptJsonp.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/io/scriptJsonp.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/io/scriptJsonp.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,57 @@
+function getJsonpCallback(url){
+	var result = null;
+	var idMatch = url.match(/jsonp=(.*?)(&|$)/);
+	if(idMatch){
+		result = idMatch[1];
+	}else{
+		//jsonp didn't match, so maybe it is the jsonCallback thing.
+		idMatch = url.match(/callback=(.*?)(&|$)/);
+		if(idMatch){
+			result = idMatch[1];
+		}
+	}
+	
+	if(result){
+		result = decodeURIComponent(result);
+	}
+	return result;
+}
+
+function findJsonpDone(){
+	var result = false;
+	var scriptUrls = getScriptUrls();
+	
+	for(var i = 0; i < scriptUrls.length; i++){
+		var jsonp = getJsonpCallback(scriptUrls[i]);
+		if(jsonp){
+			eval(jsonp + "({animalType: 'mammal'});");
+			result = true;
+			break;
+		}
+	}
+	return result;
+}
+
+function getScriptUrls(){
+	//Get the script tags in the page to figure what state we are in.
+	var scripts = document.getElementsByTagName('script');
+	var scriptUrls = new Array();
+	for(var i = 0; scripts && i < scripts.length; i++){
+		var scriptTag = scripts[i];
+		if(scriptTag.id.indexOf("dojoIoScript") == 0){
+			scriptUrls.push(scriptTag.src);
+		}
+	}
+
+	return scriptUrls;
+}
+
+function doJsonpCallback(){
+	if(!findJsonpDone()){
+		 alert('ERROR: Could not jsonp callback!');
+	}
+}
+
+//Set a timeout to do the callback check, since MSIE won't see the SCRIPT tag until
+//we complete processing of this page.
+setTimeout('doJsonpCallback()', 300);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/io/scriptSimple.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/io/scriptSimple.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/io/scriptSimple.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+myTasks = new Array();
+myTasks[0] = 'Take out trash.';
+myTasks[1] = 'Do dishes.';
+myTasks[2] = 'Brush teeth.';
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/module.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/module.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/module.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,19 @@
+dojo.provide("dojo.tests.module");
+
+try{
+	dojo.require("tests._base");
+	dojo.require("tests.i18n"); 
+	dojo.require("tests.cldr");
+	dojo.require("tests.data");
+	dojo.require("tests.date");
+	dojo.require("tests.number");
+	dojo.require("tests.currency");
+	dojo.require("tests.AdapterRegistry");
+	dojo.require("tests.io.script");
+	dojo.require("tests.rpc");
+	dojo.require("tests.string");
+}catch(e){
+	doh.debug(e);
+}
+
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ar/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ar/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ar/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,8 @@
+/*<?xml version="1.0" encoding="UTF-8" ?>*/
+// The above is a workaround for Konqueror and Safari (see bug #1010)
+// The parentheses are optional, but make this file a valid JS expression for
+// tools to inspect
+({
+ ar: "العربية",
+ hello: "ﺎﺑﺣﺮﻣ"
+})

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/cs/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/cs/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/cs/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ cs: "česky",
+ hello: "Ahoj"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/de/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/de/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/de/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ de: "Deutsch",
+ hello: "Hallo"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/el/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/el/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/el/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ el: "Ελληνικά",
+ hello: "Γειά"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-au/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-au/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-au/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,3 @@
+{
+ hello: "G'day"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-hawaii/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-hawaii/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-hawaii/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,3 @@
+{
+ hello: "Aloha"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-new_york-brooklyn/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-new_york-brooklyn/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-new_york-brooklyn/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,3 @@
+{
+ hello: "Yo"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-texas/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-texas/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/en-us-texas/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,3 @@
+{
+ hello: "Howdy"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/es/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/es/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/es/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+{
+ es: "Español",
+ hello: "Hola",
+ hello_dojo: "¡${hello}, ${dojo}!"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/fa/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/fa/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/fa/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ fa: "فارسی",
+ hello: "درود"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/fr/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/fr/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/fr/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ fr: "Français",
+ hello: "Bonjour"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/he/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/he/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/he/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ he: "עברית",
+ hello: "שלום"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/hi/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/hi/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/hi/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ hi: "हिन्दी",
+ hello: "नमस्ते"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/it/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/it/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/it/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ it: "italiano",
+ hello: "Ciao"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ja/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ja/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ja/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ ja: "\u65E5\u672C\u8A9E",
+ hello: "こにちは"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ko/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ko/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ko/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ ko: "\uD55C\uAD6D\uC5B4",
+ hello: "\uc548\ub155"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/pl/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/pl/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/pl/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ pl: "Polski",
+ hello: "Dzièn dobry"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/pt/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/pt/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/pt/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ pt: "Português",
+ hello: "Olá"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ru/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ru/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/ru/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ ru: "русский",
+ hello: "Привет"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,32 @@
+{
+ ar: "Arabic",
+ cs: "Czech",
+ de: "German",
+ el: "Greek",
+ en: "English",
+ 'en-au': "English (Australia)",
+ 'en-us-hawaii': "English (US-Hawaii)",
+ 'en-us-new_york-brooklyn': "English (Brooklynese)",
+ 'en-us-texas': "English (Texas)",
+ es: "Spanish",
+ fa: "Farsi",
+ fr: "French",
+ he: "Hebrew",
+ hi: "Hindi",
+ it: "Italian",
+ ja: "Japanese",
+ ko: "Korean",
+ pl: "Polish",
+ pt: "Portugese",
+ ru: "Russian",
+ sw: "Kiswahili",
+ th: "Thai",
+ tr: "Turkish",
+ yi: "Yiddish",
+ 'zh-cn': "Chinese (Simplified)",
+ 'zh-tw': "Chinese (Traditional)",
+ hello: "Hello",
+ dojo: "Dojo",
+ hello_dojo: "${hello}, ${dojo}!",
+ file_not_found:"The file you requested, ${0}, is not found."
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/sw/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/sw/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/sw/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,3 @@
+{
+ hello: "Hujambo"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/th/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/th/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/th/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ th: "ქართული ენაქართული ენაქართული ენაสวัสดีครับ/คะ",
+ hello: "ภาษาไทย"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/tr/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/tr/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/tr/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ tr: "Türkçe",
+ hello: "Merhaba"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/yi/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/yi/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/yi/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ yi: "ייִדיש",
+ hello: "אַ גוטן טאָג"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/zh-cn/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/zh-cn/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/zh-cn/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ 'zh-cn': "汉语",
+ hello: "你好"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/nls/zh-tw/salutations.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/nls/zh-tw/salutations.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/nls/zh-tw/salutations.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+{
+ 'zh-tw': "漢語",
+ hello: "你好"
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/number.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/number.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/number.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,961 @@
+dojo.provide("tests.number");
+
+dojo.require("dojo.number");
+
+/**
+ * Refer to ICU4J's NumberFormatTest.expect(...) 
+ */
+tests.number.check=function(t,options,sourceInput,expectResult){
+	tests.number.checkFormatParseCycle(t, t,options,sourceInput,expectResult,false);
+	tests.number.checkParse(t, t,options,expectResult,sourceInput);	
+}
+
+/**
+ * Perform a single formatting check or a backward check
+ * backward check:number1 -(formatted)-> string1 -(parsed)-> number2 -(formated)-> string2
+ * then number should == number2; string1 should == string2
+ */
+tests.number.checkFormatParseCycle=function(t,options,sourceInput,expectResult,
+		 backwardCheck/*boolean,indicates whether need a backward chain check,like formate->parse->format*/){	
+	if(null != options){
+		var pattern = options.pattern;
+		var locale = options.locale;
+		//TODO: add more fields
+	}
+	
+	//print("\n");
+	var str = null==pattern?"default":pattern;
+	//print("pattern:" + str + "| locale:" + locale);
+	//print("input:" + sourceInput);
+	var result = dojo.number.format(sourceInput,options);
+	//print("result:" + result);
+	if(null != expectResult){
+	    t.is(expectResult,result);
+	}
+	if(backwardCheck){
+		var resultParsed = dojo.number.parse(result,options);
+		//print("resultParsed:" + resultParsed);		
+		if(!tests.number._decimalNumberDiff(sourceInput,resultParsed)){	
+		    t.is(sourceInput,resultParsed);
+		}		
+		var resultParsedReformatted = dojo.number.format(resultParsed,options);
+		//print("resultParsedReformatted:" + resultParsedReformatted);
+	    if(!tests.number._decimalNumberDiff(result,resultParsedReformatted)){
+			t.is(result,resultParsedReformatted);
+		}
+	}	
+}
+
+/**
+ * Perform a single parsing check
+ */
+tests.number.checkParse=function(t,options,sourceInput,expectResult){
+	var str = "default";
+	if(null != options && null != options.pattern){	
+		str = options.pattern;
+	}
+	//print("input:" + sourceInput);
+	var result = dojo.number.parse(sourceInput,options);
+	//print("result :" + result);
+	if(null != expectResult){
+	    t.is(expectResult,result);
+	}
+}
+
+/**
+ * //TODO:Round a given number
+ */
+tests.number.rounding = function(t,number,maxFractionDigits,expected){
+	var pattern="#0.";
+	for(var i=0; i<maxFractionDigits; i++){pattern += "#";}
+	var result = dojo.number.format(number,{pattern:pattern});
+	t.is(expected,result);	
+}
+
+/**
+ * Run a batch parsing
+ */
+function runBatchParse(options,dataArray/*array*/,pass/*boolean*/){
+	var exception = null;
+	var result;
+	var i=0;
+	var str = (null==options.pattern)?"default":options.pattern;
+	
+	//print("\n");
+	for(; i<dataArray.length; i++){
+		try{
+			//print("["+i+"]"+"input:"+dataArray[i]);
+			result = dojo.number.parse(dataArray[i],options);			
+			if(isNaN(result)){
+				throw "\"" + dataArray[i] + "\" is parsed to NaN with pattern " + str;
+			}
+			//print("["+i+"]"+"output:"+result);	
+		}catch(e){
+			exception = e;
+			break;
+		}
+	}
+		
+	if(!pass && (exception == null)) {
+		throw "runBatchParse() - stric parse failed, no exception when parsing illegal data"; 
+	}else if(exception != null){
+		if(!pass && i == 0){
+			//strict parsing should fail for all the dataArray elements as expected
+			//pass condition for strict parsing
+			return;
+		}
+		throw "runBatchParse() failed: " + exception;		
+	}
+}
+
+/**
+ * Check whether the given two numbers differ under the decimal bound
+ * 
+ */
+tests.number._decimalNumberDiff = function(num1,num2){
+	//TODO: should be more accurate when dojo.number finish rounding in the future
+	var diffBound = 1e-3;
+	var diff = num1 - num2;
+	//print("Math.abs(diff) " + Math.abs(diff));
+	if(Math.abs(diff) < diffBound ){
+		return true;
+	}else if(isNaN(Math.abs(diff))){	
+		var s = num1.toString().split(num2);
+		s[1] = s[1].replace(",","0");
+		s[1] = s[1].replace('\u066b','0');
+		return (new Number(s[1])< diffBound);
+	}
+	return false;	
+}
+
+tests.register("tests.number", 
+	[
+		{
+			// Test formatting and parsing of currencies in various locales pre-built in dojo.cldr
+			// NOTE: we can't set djConfig.extraLocale before bootstrapping unit tests, so directly
+			// load resources here for specific locales:
+
+			name: "number",
+			setUp: function(){
+				var partLocaleList = ["en-us", "fr-fr", "de-de"];
+
+				for(var i = 0 ; i < partLocaleList.length; i ++){
+					dojo.requireLocalization("dojo.cldr","number",partLocaleList[i]);
+				}
+			},
+			runTest: function(t){
+			},
+			tearDown: function(){
+				//Clean up bundles that should not exist if
+				//the test is re-run.
+				delete dojo.cldr.nls.number;
+			}
+		},
+		{
+			name: "format", // old tests
+			runTest: function(t){
+
+	t.is("0123", dojo.number.format(123, {pattern: "0000"}));
+	t.is("-12,34,567.890", dojo.number.format(-1234567.89, {pattern: "#,##,##0.000##"}));
+	t.is("-12,34,567.89012", dojo.number.format(-1234567.890123, {pattern: "#,##,##0.000##"}));
+	t.is("(1,234,567.89012)", dojo.number.format(-1234567.890123, {pattern: "#,##0.000##;(#,##0.000##)"}));
+	t.is("(1,234,567.89012)", dojo.number.format(-1234567.890123, {pattern: "#,##0.000##;(#)"}));
+	t.is("50.1%", dojo.number.format(0.501, {pattern: "#0.#%"}));
+	t.is("98", dojo.number.format(1998, {pattern: "00"}));
+	t.is("01998", dojo.number.format(1998, {pattern: "00000"}));
+	t.is("0.13", dojo.number.format(0.125, {pattern: "0.##"})); //NOTE: expects round_half_up, not round_half_even
+	t.is("0.1250", dojo.number.format(0.125, {pattern: "0.0000"}));
+	t.is("0.1", dojo.number.format(0.100004, {pattern: "0.####"}));
+
+	t.is("-12", dojo.number.format(-12.3, {places:0, locale: "en-us"}));
+	t.is("-1,234,567.89", dojo.number.format(-1234567.89, {locale: "en-us"}));
+//	t.is("-12,34,567.89", dojo.number.format(-1234567.89, {locale: "en-in"}));
+	t.is("-1,234,568", dojo.number.format(-1234567.89, {places:0, locale: "en-us"}));
+//	t.is("-12,34,568", dojo.number.format(-1234567.89, {places:0, locale: "en-in"}));
+	t.is("-1\xa0000,10", dojo.number.format(-1000.1, {places:2, locale: "fr-fr"}));
+	t.is("-1,000.10", dojo.number.format(-1000.1, {places:2, locale: "en-us"}));
+	t.is("-1\xa0000,10", dojo.number.format(-1000.1, {places:2, locale: "fr-fr"}));
+	t.is("-1.234,56", dojo.number.format(-1234.56, {places:2, locale: "de-de"}));
+	t.is("-1,000.10", dojo.number.format(-1000.1, {places:2, locale: "en-us"}));
+	t.is("123.46%", dojo.number.format(1.23456, {places:2, locale: "en-us", type: "percent"}));
+
+	//rounding
+	t.is("-1,234,568", dojo.number.format(-1234567.89, {places:0, locale: "en-us"}));
+//	t.is("-12,34,568", dojo.number.format(-1234567.89, {places:0, locale: "en-in"}));
+	t.is("-1,000.11", dojo.number.format(-1000.114, {places:2, locale: "en-us"}));
+	t.is("-1,000.11", dojo.number.format(-1000.115, {places:2, locale: "en-us"}));
+	t.is("-1,000.12", dojo.number.format(-1000.116, {places:2, locale: "en-us"}));
+	t.is("-0.00", dojo.number.format(-0.0001, {places:2, locale: "en-us"}));
+	t.is("0.00", dojo.number.format(0, {places:2, locale: "en-us"}));
+
+	//change decimal places
+	t.is("-1\xa0000,100", dojo.number.format(-1000.1, {places:3, locale: "fr-fr"}));
+	t.is("-1,000.100", dojo.number.format(-1000.1, {places:3, locale: "en-us"}));
+			}
+		},
+		{
+			name: "parse", // old tests
+			runTest: function(t){
+	t.is(1000, dojo.number.parse("1000", {locale: "en-us"}));
+	t.is(1000.123, dojo.number.parse("1000.123", {locale: "en-us"}));
+	t.is(1000, dojo.number.parse("1,000", {locale: "en-us"}));
+	t.is(-1000, dojo.number.parse("-1000", {locale: "en-us"}));
+	t.is(-1000.123, dojo.number.parse("-1000.123", {locale: "en-us"}));
+	t.is(-1234567.89, dojo.number.parse("-1,234,567.89", {locale: "en-us"}));
+	t.is(-1234567.89, dojo.number.parse("-1 234 567,89", {locale: "fr-fr"}));
+	t.t(isNaN(dojo.number.parse("-1 234 567,89", {locale: "en-us"})));
+
+	t.t(isNaN(dojo.number.parse("10,00", {locale: "en-us"})));
+	t.t(isNaN(dojo.number.parse("1000.1", {locale: "fr-fr"})));
+
+	t.t(isNaN(dojo.number.parse("")));
+	t.t(isNaN(dojo.number.parse("abcd")));
+
+	//test whitespace
+//	t.is(-1234567, dojo.number.parse("  -1,234,567  ", {locale: "en-us"}));
+
+//	t.t(dojo.number.parse("9.1093826E-31"));
+	t.is(0.501, dojo.number.parse("50.1%", {pattern: "#0.#%"}));
+
+	t.is(123.4, dojo.number.parse("123.4", {pattern: "#0.#"}));
+	t.is(-123.4, dojo.number.parse("-123.4", {pattern: "#0.#"}));
+	t.is(123.4, dojo.number.parse("123.4", {pattern: "#0.#;(#0.#)"}));
+	t.is(-123.4, dojo.number.parse("(123.4)", {pattern: "#0.#;(#0.#)"}));
+
+	t.is(null, dojo.number.format("abcd", {pattern: "0000"}));
+			}
+		},
+		{
+			name: "format_icu4j3_6",
+			runTest: function(t){
+
+/*************************************************************************************************
+ * Evan:The following test cases are referred from ICU4J 3.6 (NumberFormatTest etc.) 
+ * see http://icu.sourceforge.net/download/3.6.html#ICU4J
+ *************************************************************************************************/
+
+
+/**
+ * In ICU4J, testing logic for NumberFormat.format() is seperated into 
+ * differernt single tese cases. So part of these logic are 
+ * collected together in this single method.
+ * 
+ * !!Failed cases are as follows:
+ * 1.1234567890987654321234567890987654321 should be formatted as 
+ *   1,234,567,890,987,654,321,234,567,890,987,654,321 with all the default parameters,
+ *   but got 1.234 instead, may due to the unimplemeted exponent.
+ * 2.\u00a4 and ' are not replaced
+ * 	 with pattern "'*&'' '\u00a4' ''&*' #,##0.00"
+ *   1.0 should be formatted to "*&' Re. '&* 1.00",but got "'*&'' '\u00a4' ''&*' 1.00" instead
+ *   etc.   
+ * 		
+ */
+	//print("test_number_format_icu4j3_6() start..............");
+	/* !!Failed case, 1.234 returned instead
+	//refer to ICU4J's NumberFormatTest.TestCoverage() 
+	var bigNum = 1234567890987654321234567890987654321;
+	var expectResult = "1,234,567,890,987,654,321,234,567,890,987,654,321";
+	tests.number.checkFormatParseCycle(t, null,bigNum,expectResult,false);
+	*/	
+	
+	//in icu4j should throw out an exception when formatting a string,
+	//but it seems dojo.number.format can deal with strings
+	//return 123,456,789
+	dojo.number.format("123456789");
+	
+	//!!Failed case, \u00a4 and ' are not replaced
+	/*
+	var options = {pattern:"'*&'' '\u00a4' ''&*' #,##0.00",locale:"en-us"};
+	tests.number.check(t, options,1.0, "*&' Re. '&* 1.00");
+	tests.number.check(t, options,-2.0, "-*&' Rs. '&* 2.00");	
+
+	options = {pattern:"#,##0.00 '*&'' '\u00a4' ''&*'",locale:"en-us"};
+	tests.number.check(t, options,1.0,"1.00 *&' Re. '&*");
+	tests.number.check(t, options,-2.0,"-2.00 *&' Rs. '&*");
+	*/
+	//print("test_number_format_icu4j3_6() end..............\n");
+			}
+		},
+		{
+			name: "format_patterns",
+			runTest: function(t){
+
+/**
+ * Refer to ICU4J's NumberFormatTest.TestPatterns() which now only coveres us locale	
+ */
+	//print("test_number_format_Patterns() start..............");
+	var patterns = (["#0.#", "#0.", "#.0", "#"]);
+	var patternsLength = patterns.length;    
+	var num = (["0","0", "0.0", "0"]);
+	var options;
+	//icu4j result seems doesn't work as:
+	//var num = (["0","0.", ".0", "0"]);      
+	for (var i=0; i<patternsLength; ++i)
+	{	
+		options = {pattern:patterns[i]};
+		tests.number.checkFormatParseCycle(t, options,0,num[i],false);       
+	}
+	
+	//!!Failed case
+	//In ICU4J:
+	//        unquoted special characters in the suffix are illegal
+	//        so "000.000|###" is illegal; "000.000'|###'" is legal
+	//dojo.number.format:
+	//        when formatting 1.2 with illegal pattern "000.000|###"
+	//		  no exception was thrown but got "001.200|###" instead.
+	
+	/*
+	patterns = (["000.000|###","000.000'|###'"]);
+	var exception = false;
+	var result;
+	for(var i = 0; i < patterns.length; i ++){
+		try{
+			//"001.200'|###'" is return for "000.000'|###'"
+			//"001.200|###" is return for "000.000|###"
+			result = dojo.number.format(1.2,{pattern:patterns[i]});
+			print("["+i+"] 1.2 is formatted to " + result + " with pattern " + patterns[i]);
+		}catch(e){
+			exception = true;
+		}
+		if(exception && i==1){
+			throw "["+i+"]Failed when formatting 1.2 using legal pattern " + patterns[i];
+		}else if(!exception && i==0){
+			throw "["+i+"]Failed when formatting 1.2 using illegal pattern  " + patterns[i];
+		}
+	}*/	
+	//print("test_number_format_Patterns() end..............\n");
+			}
+		},
+		{
+			name: "exponential",
+			runTest: function(t){
+/**
+ * TODO: For dojo.number future version 
+ * Refer to ICU4J's NumberFormatTest.TestExponential()
+ */
+			}
+		},
+		{
+			name: "format_quotes",
+			runTest: function(t){
+/**
+ * TODO: Failed case
+ * Refer to ICU4J's NumberFormatTest.TestQuotes()
+ */
+	//print("test_number_format_Quotes() start..............");
+	//TODO: add more locales 
+	
+	//TODO:!!Failed case	
+	//Pattern "s'aa''s'c#" should format 6666 to "saa'sc6666", but got s'aa''s'c6666 instead
+	// is this case necessary?
+	/*
+	var pattern = "s'aa''s'c#";   
+	var result = dojo.number.format(6666,{pattern:pattern,locale:"en-us"});
+	var expectResult = "saa'sc6666";
+	t.is(expectResult,result);
+	*/
+	//print("test_number_format_Quotes() end..............");     
+			}
+		},
+		{
+			name: "format_rounding",
+			runTest: function(t){
+/**
+ * Refer to ICU4J's NumberFormatTest.TestRounding487() and NumberFormatTest.TestRounding()
+ */
+	//print("test_number_format_rounding() start..............");
+	tests.number.rounding(t,0.000179999, 5, "0.00018");
+	tests.number.rounding(t,0.00099, 4, "0.001");
+	tests.number.rounding(t,17.6995, 3, "17.7");
+	tests.number.rounding(t,15.3999, 0, "15");
+	tests.number.rounding(t,-29.6, 0, "-30");
+	
+	//TODO refer to NumberFormatTest.TestRounding()
+	
+	//print("test_number_format_rounding() end..............");
+			}
+		},
+		{
+			name: "format_scientific",
+			runTest: function(t){
+/**
+ * TODO: For dojo.number future version
+ * Refer to ICU4J's NumberFormatTest.TestScientific()- Exponential testing 
+ * Refer to ICU4J's NumberFormatTest.TestScientific2() 
+ * Refer to ICU4J's NumberFormatTest.TestScientificGrouping()
+ */
+			}
+		},
+		{
+			name: "format_perMill",
+			runTest: function(t){
+/**
+ * TODO: Failed case 
+ * Refer to ICU4J's NumberFormatTest.TestPerMill()
+ */
+	//print("test_number_format_PerMill() start..............");
+	var pattern;
+	var result;
+	var expectResult;
+	
+    //TODO: !!Failed case - ###.###\u2030(\u2030 is ä)
+	//Pattern ###.###\u2030 should format 0.4857 as 485.7\u2030,but got 485.700\u2030 instead    
+	pattern = "###.###\u2030";
+	expectResult = "485.7\u2030";
+	result = dojo.number.format(0.4857,{pattern:pattern});
+	t.is(expectResult,result);
+
+    //TODO: !!Failed mile percent case - ###.###m
+	//Pattern "###.###m" should format 0.4857 to 485.7m, but got 0.485m instead
+	/*
+	pattern = "###.###m";
+	expectResult = "485.7m";
+	result = dojo.number.format(0.4857,{pattern:pattern,locale:"en"});
+	t.is(expectResult,result);	
+	*/
+	//print("test_number_format_PerMill() end..............\n");
+			}
+		},
+		{
+			name: "format_grouping",
+			runTest: function(t){
+/**
+ * Only test en-us and en-in 
+ * Refer to ICU4J's NumberFormatTest.TestSecondaryGrouping()
+ */
+	//print("test_number_format_Grouping() start..............");
+	//primary grouping
+	var sourceInput = 123456789;
+	var expectResult = "12,34,56,789";
+	var options = {pattern:"#,##,###",locale:"en-us"};	
+
+	//step1: 123456789 formated=> 12,34,56,789
+	//step2:12,34,56,789 parsed=> 123456789 => formated => 12,34,56,789
+	tests.number.checkFormatParseCycle(t, options,sourceInput,expectResult,true);
+						  
+	//TODO: sencondary grouping not implemented yet ?
+	//Pattern "#,###" and secondaryGroupingSize=4 should format 123456789 to "12,3456,789"			
+	
+	//Special case for "en-in" locale
+	//1876543210 should be formated as 1,87,65,43,210 in "en-in" (India)
+/*
+	sourceInput = 1876543210;
+	expectResult = "1,87,65,43,210";
+	var result = dojo.number.format(sourceInput,{locale:"en-in"});
+	t.is(expectResult,result);   
+*/
+	//print("test_number_format_Grouping() end..............\n");    
+			}
+		},
+		{
+			name: "format_pad",
+			runTest: function(t){
+/**
+ * TODO:!!Failed cases:
+ * According to ICU4J test criteria:
+ * 1.with pattern "*^##.##":
+ * 	 0 should be formatted to "^^^^0",but got "*^0" instead,
+ *   -1.3 should be formatted to "^-1.3",but got "-*^1.3" instead.
+ *   
+ * 2.with pattern "##0.0####*_ 'g-m/s^2'" :
+ *   0 should be formatted to "0.0______ g-m/s^2",but got ":0.0*_ 'g-m/s^2'" instead
+ *   1.0/3 should be formatted to "0.33333__ g-m/s^2",but got "0.33333*_ 'g-m/s^2'" instead
+ *   
+ * 3.with pattern "*x#,###,###,##0.0#;*x(###,###,##0.0#)":
+ * 	 -10 should be formatted to "xxxxxxxxxx(10.0)",but got "*x(10.0)" instead.
+ *   10 should be formatted to "xxxxxxxxxxxx10.0",but got "*x10.0" instead.
+ *   ......
+ *   -1120456.37 should be formatted to "xx(1,120,456.37)",but got "*x(1,120,456.37)" instead.
+ *   1120456.37 should be formatted to "xxxx1,120,456.37",but got "*x1,120,456.37" instead.
+ *   -1252045600.37 should be formatted to "(1,252,045,600.37)",but got "*x(1,252,045,600.37)" instead.
+ *   1252045600.37 should be formatted to "10,252,045,600.37",but got "*x10,252,045,600.37" instead.
+ *   
+ * 4.with pattern "#,###,###,##0.0#*x;(###,###,##0.0#*x)"
+ * 	 -10 should be formatted to (10.0xxxxxxxxxx),but got "(10.0*x)" instead.
+ *   10 should be formatted to "10.0xxxxxxxxxxxx",but got "10.0*x" instead.
+ *   ......
+ *   -1120456.37 should be formatted to "(1,120,456.37xx)",but got "(1,120,456.37*x)" instead.
+ *   1120456.37 should be formatted to "xxxx1,120,456.37",but got "1,120,456.37*x" instead.
+ *   -1252045600.37 should be formatted to "(1,252,045,600.37)",but got "(1,252,045,600.37*x)" instead.
+ *   1252045600.37 should be formatted to ""10,252,045,600.37"",but got "10,252,045,600.37*x" instead.*   
+ * 
+ * Refer to ICU4J's NumberFormatTest.TestPad()
+ */
+/*
+function test_number_format_pad(){
+	var locale = "en-us";
+	print("test_number_format_Pad() start..............");
+	var options = {pattern:"*^##.##",locale:locale};
+
+	tests.number.check(t, options,0,"^^^^0");
+	tests.number.check(t, options,-1.3,"^-1.3");	
+	
+	
+	options = {pattern:"##0.0####*_ 'g-m/s^2'",locale:locale};
+	tests.number.check(t, options,0,"0.0______ g-m/s^2");	
+	tests.number.checkFormatParseCycle(t, options,1.0/3,"0.33333__ g-m/s^2",true);	
+	
+	//exponent not implemented
+	//options = {pattern:"##0.0####E0*_ 'g-m/s^2'",locale:locale};
+	//tests.number.check(t, options,0,"0.0E0______ g-m/s^2");
+	//tests.number.checkFormatParseCycle(t, options,1.0/3,"333.333E-3_ g-m/s^2",true);
+	
+	// Test padding before a sign
+	options = {pattern:"*x#,###,###,##0.0#;*x(###,###,##0.0#)",locale:locale};
+
+	tests.number.check(t, options,-10,"xxxxxxxxxx(10.0)");
+	tests.number.check(t, options,-1000, "xxxxxxx(1,000.0)");
+	tests.number.check(t, options,-1000000, "xxx(1,000,000.0)");
+	tests.number.check(t, options,-100.37, "xxxxxxxx(100.37)");
+	tests.number.check(t, options,-10456.37, "xxxxx(10,456.37)");
+	tests.number.check(t, options,-1120456.37, "xx(1,120,456.37)");
+	tests.number.check(t, options,-112045600.37, "(112,045,600.37)");    
+	tests.number.check(t, options,-1252045600.37, "(1,252,045,600.37)");
+
+
+	tests.number.check(t, options,10, "xxxxxxxxxxxx10.0");
+	tests.number.check(t, options,1000, "xxxxxxxxx1,000.0");
+	tests.number.check(t, options,1000000, "xxxxx1,000,000.0");
+	tests.number.check(t, options,100.37, "xxxxxxxxxx100.37");
+	tests.number.check(t, options,10456.37, "xxxxxxx10,456.37");        
+	tests.number.check(t, options,1120456.37, "xxxx1,120,456.37");
+	tests.number.check(t, options,112045600.37, "xx112,045,600.37");
+	tests.number.check(t, options,10252045600.37, "10,252,045,600.37");
+
+	// Test padding between a sign and a number
+	options = {pattern:"#,###,###,##0.0#*x;(###,###,##0.0#*x)",locale:locale};
+	tests.number.check(t, options, -10, "(10.0xxxxxxxxxx)");
+	tests.number.check(t, options, -1000, "(1,000.0xxxxxxx)");
+	tests.number.check(t, options, -1000000, "(1,000,000.0xxx)");
+	tests.number.check(t, options, -100.37, "(100.37xxxxxxxx)");
+	tests.number.check(t, options, -10456.37, "(10,456.37xxxxx)");    
+	tests.number.check(t, options, -1120456.37, "(1,120,456.37xx)");
+	tests.number.check(t, options, -112045600.37, "(112,045,600.37)");   
+	tests.number.check(t, options, -1252045600.37, "(1,252,045,600.37)");  
+
+	tests.number.check(t, options, 10, "10.0xxxxxxxxxxxx");
+	tests.number.check(t, options, 1000, "1,000.0xxxxxxxxx");
+	tests.number.check(t, options, 1000000, "1,000,000.0xxxxx");
+	tests.number.check(t, options, 100.37, "100.37xxxxxxxxxx");
+	tests.number.check(t, options, 10456.37, "10,456.37xxxxxxx");
+	tests.number.check(t, options, 1120456.37, "1,120,456.37xxxx");
+	tests.number.check(t, options, 112045600.37, "112,045,600.37xx");
+	tests.number.check(t, options, 10252045600.37, "10,252,045,600.37");	
+	
+	//Not implemented yet,refer to NumberFormatTest.TestPatterns2()
+	//For future use - maily test pad patterns
+	print("test_number_format_Pad() end..............");
+}
+*/
+			}
+		},
+		{
+			name: "parse_icu4j3_6",
+			runTest: function(t){
+/**
+ * In ICU4J, testing logic for NumberFormat.parse() is seperated into 
+ * differernt single tese cases. So part of these logic are 
+ * collected together in this test case. * 
+ */
+	//print("test_number_parse_icu4j3_6() start..............");
+	//Refer to ICU4J's NumberFormatTest.TestParse() which is only a rudimentary version
+	var pattern = "00";
+	var str = "0.0";	
+	var result = dojo.number.parse(str,{pattern:pattern});
+	//TODO: add more locales
+//FIXME: is this a valid test?
+//	t.is(0,result);
+
+	/**************************************** tolerant parse *****************************************
+	 * refere to ICU4J's NumberFormatTest.TestStrictParse()??
+	 * TODO: Seems dojo.number parses string in a tolerant way.  
+	 */
+	 var options = {locale:"en"};
+	/*
+	 * TODO: !!Failed case,Should all pass,
+	 * but the following elements failed (all parsed to NaN):
+	 * [1]-"0 ",[2]-"0.",[3]-"0,",[5]-"0. ",[6]-"0.100,5",
+	 * [7]-".00",[9]-"12345, ",[10]-"1,234, ",[12]-"0E" 
+	 */
+	var passData = ([
+		"0",           //[0] single zero before end of text is not leading
+        //"0 ",        //[1] single zero at end of number is not leading
+        //"0.",        //[2] single zero before period (or decimal, it's ambiguous) is not leading
+        //"0,",          //[3] single zero before comma (not group separator) is not leading
+        "0.0",         //[4] single zero before decimal followed by digit is not leading
+        //"0. ",       //[5] same as above before period (or decimal) is not leading
+        //"0.100,5",   //[6] comma stops parse of decimal (no grouping)
+        //".00",       //[7] leading decimal is ok, even with zeros
+        "1234567",     //[8] group separators are not required
+        //"12345, ",   //[9] comma not followed by digit is not a group separator, but end of number
+        //"1,234, ",   //[10] if group separator is present, group sizes must be appropriate
+        "1,234,567"   //[11] ...secondary too
+        //,"0E"         //[12]not implemented yet,an exponnent not followed by zero or digits is not an exponent 
+         ]);
+	runBatchParse(options,passData,true/*tolerant parse*/);	
+	
+	/* 
+	 * TODO:!!Failed case,should all pass,
+	 * but the following failed,
+	 * [10]-"1,45 that" implies that we partially parse input
+	 */
+	var failData = ([            
+		"00",          //[0] leading zero before zero
+        "012",         //[1] leading zero before digit
+        "0,456",       //[2] leading zero before group separator
+        "1,2",         //[3] wrong number of digits after group separator
+        ",0",          //[4] leading group separator before zero
+        ",1",          //[5] leading group separator before digit
+        ",.02",        //[6] leading group separator before decimal
+        "1,.02",       //[7] group separator before decimal
+        "1,,200",      //[8] multiple group separators
+        "1,45",        //[9] wrong number of digits in primary group
+        //"1,45 that",   //[10] wrong number of digits in primary group
+        "1,45.34",     //[11] wrong number of digits in primary group
+        "1234,567",    //[12] wrong number of digits in secondary group
+        "12,34,567",   //[13] wrong number of digits in secondary group
+        "1,23,456,7890" //[14] wrong number of digits in primary and secondary groups
+		]);
+	runBatchParse(options,failData,false);
+	
+	 options = {pattern:"#,##,##0.#",locale:"en-us"};
+	/*
+	 * TODO:!!Failed case,shoudl all pass.
+	 
+	 * but [1] [2] and [3] failed
+	 * should be parsed to 1234567,but NaN instead 
+	 */
+	var mixedPassData = ([            
+		"12,34,567"    	//[0]
+        //,"12,34,567,"		//[1]
+        //"12,34,567, that",//[2]
+        //"12,34,567 that"	//[3]
+		]);	
+	runBatchParse(options,mixedPassData,true/*tolerant parse*/);
+	
+	/*
+	 * TODO:!!Failed case,should all pass,
+	 * but actually mixedFailData[2] and mixedFailData[3] passed.
+	 * "12,34,56, that " and [3]-"12,34,56 that" should be parsed to 123456,but NaN instead
+	 */
+	var mixedFailData = ([
+        "12,34,56",			//[0]
+        "12,34,56,"		//[1]
+        //,"12,34,56, that ",//[2]
+        //"12,34,56 that",	//[3]
+		]);			
+	runBatchParse(options,mixedFailData,false);
+	
+
+	/**************************************** strict parse ******************************************
+	 * TODO:May need to test strict parsing in the future?
+	 * e.g. A strict parsing like (with pattern "#,##0.#") 
+	 * 1.Leading zeros
+	 * 		'00', '0123' fail the parse, but '0' and '0.001' pass
+	 * 2.Leading or doubled grouping separators
+	 * 		',123' and '1,,234" fail
+	 * 3.Groups of incorrect length when grouping is used
+	 * 		'1,23' and '1234,567' fail, but '1234' passes
+	 * 4.Grouping separators used in numbers followed by exponents
+	 * 		'1,234E5' fails, but '1234E5' and '1,234E' pass
+	 */	
+	//options={locale:"en",strict:true};
+	//runBatchParse(options,passData,false/*strict parse*/);
+	//runBatchParse(options,failData,false/*strict parse*/);	
+	
+	//options = {pattern:"#,##,##0.#",locale:"en-us",strict:true};
+	//runBatchParse(options,mixedPassData,false/*strict parse*/);
+	//runBatchParse(options,mixedFailData,false/*strict parse*/);		
+
+	//print("test_number_parse_icu4j3_6() end..............\n");
+			}
+		},
+		{
+			name: "parse_whitespace",
+			runTest: function(t){
+/**
+ * TODO:!!Failed case
+ * With pattern "a  b#0c  ",both "a b3456c " and and "a   b1234c   " should be parsed to 3456,but got NaN instead.
+ * 
+ * Refer to ICU4J's NumberFormatTest.TestWhiteSpaceParsing
+ */
+    /*
+	print("test_number_parse_WhiteSpace() start..............");
+   	var pattern = "a  b#0c  ";
+	var expectResult = 3456;   
+	result =  dojo.number.parse("a b3456c ",{pattern:pattern,locale:"en-us"});
+   	t.is(expectResult,result);	
+	result =  dojo.number.parse("a   b3456c   ",{pattern:pattern,locale:"en-us"});
+	t.is(expectResult,result);
+	print("test_number_parse_WhiteSpace() end..............\n");
+	*/   
+			}
+		},
+/*************************************************************************************************
+ *                            Regression test cases
+ * These test cases are referred to ICU4J's NumberFormatRegressionTest and NumberFormatRegression.
+ * The regression cases in ICU4J are used as unit test cases for bug fixing, 
+ * They are inluced here so that dojo.number may avoid those similar bugs. 
+ *************************************************************************************************/
+		{
+			name: "number_regression_1",
+			runTest: function(t){
+/**
+ * Refer to ICU4J's NumberFormatRegressionTest.Test4161100()
+ */
+	tests.number.checkFormatParseCycle(t, {pattern:"#0.#"},-0.09,"-0.1",false);
+			}
+		},
+		{
+			name: "number_regression_2",
+			runTest: function(t){
+/**
+ * !!Failed case,rounding hasn't been implemented yet.
+ * Refer to ICU4J's NumberFormatRegressionTest.Test4408066()
+ */
+	/*
+	var data =   ([-3.75, -2.5, -1.5, 
+                   -1.25, 0,    1.0, 
+                   1.25,  1.5,  2.5, 
+                   3.75,  10.0, 255.5]);
+	var expected = (["-4", "-2", "-2",
+                    "-1", "0",  "1",
+                	"1",  "2",  "2",
+                	"4",  "10", "256"]);
+	var options = {locale:"zh-cn",round:true};
+	for(var i =0; i < data.length; i++){
+		tests.number.checkFormatParseCycle(t, options,data[i],expected[i],false);
+	}	
+
+	data = ([ 	"-3.75", "-2.5", "-1.5", 
+              	"-1.25", "0",    "1.0", 
+              	"1.25",  "1.5",  "2.5", 
+              	"3.75",  "10.0", "255.5"]);
+	expected =([ -3, -2, -1,
+                 -1, 0,  1,
+                 1,  1,  2,
+                 3,  10, 255]);
+	
+	for(var i =0; i < data.length; i++){
+		tests.number.checkParse(t, options,data[i],expected[i]);
+	}
+	*/
+			}
+		},
+		{
+			name: "number_regression_3",
+			runTest: function(t){
+/**
+ * Refer to ICU4J's NumberRegression.Test4087535() and Test4243108()
+ */
+	tests.number.checkFormatParseCycle(t, {places:0},0,"0",false);
+	//TODO:in icu4j,0.1 should be formatted to ".1" when minimumIntegerDigits=0
+	tests.number.checkFormatParseCycle(t, {places:0},0.1,"0",false);	
+	tests.number.checkParse(t, {pattern:"#0.#####"},123.55456,123.55456);
+//!! fails because default pattern only has 3 decimal places
+//	tests.number.checkParse(t, null,123.55456,123.55456);
+	
+	//See whether it fails first format 0.0 ,parse "99.99",and then reformat 0.0 
+	tests.number.checkFormatParseCycle(t, {pattern:"#.#"},0.0,"0",false);
+	tests.number.checkParse(t, null,"99.99",99.99);
+	tests.number.checkFormatParseCycle(t, {pattern:"#.#"},0.0,"0",false);
+			}
+		},
+		{
+			name: "number_regression_4",
+			runTest: function(t){
+/**
+ * TODO:
+ * In ICU -0.0 and -0.0001 should be formatted to "-0" with FieldPosition(0)
+ * dojo.i18n.number format -0.0 to "-0"; -0.0001 to "-0.000100" 
+ * 
+ * Refer to ICU4J's NumberRegression.Test4088503() and Test4106658()
+ */
+	tests.number.checkFormatParseCycle(t, {places:0},123,"123",false);
+	
+	//TODO: differernt from ICU where -0.0 is formatted to "-0"
+	tests.number.checkFormatParseCycle(t, {locale:"en-us"},-0.0,"0",false);
+	
+	//TODO: differernt from ICU where -0.0001 is formatted to "-0"
+	tests.number.checkFormatParseCycle(t, {locale:"en-us",places:6},-0.0001,"-0.000100",false);
+			}
+		},
+		{
+			name: "number_regression_5",
+			runTest: function(t){
+/**
+ * !!Failed case,rounding has not implemented yet.
+ * 0.00159999 should be formatted as 0.0016 but got 0.0015 instead.
+ * Refer to ICU4J's NumberRegression.Test4071492()
+ */
+	//tests.number.checkFormatParseCycle(t, {places:4,round:true},0.00159999,"0.0016",false);	
+			}
+		},
+		{
+			name: "number_regression_6",
+			runTest: function(t){
+/**
+ * Refer to ICU4J's NumberRegression.Test4086575()
+ */
+	var pattern = "###.00;(###.00)";
+	var locale = "fr";
+	var options = {pattern:pattern,locale:locale};
+	
+	//no group separator
+	tests.number.checkFormatParseCycle(t, options,1234,"1234,00",false);
+	tests.number.checkFormatParseCycle(t, options,-1234,"(1234,00)",false);	
+	
+	//space as group separator
+	pattern = "#,###.00;(#,###.00)";
+	options = {pattern:pattern,locale:locale};
+	tests.number.checkFormatParseCycle(t, options,1234,"1\u00a0234,00",false);// Expect 1 234,00
+	tests.number.checkFormatParseCycle(t, options,-1234,"(1\u00a0234,00)",false);  // Expect (1 234,00)
+			}
+		},
+		{
+			name: "number_regression_7",
+			runTest: function(t){
+/**
+ * !!Failed case - expontent has not implemented yet 
+ * shuold format 1.000000000000001E7 to 10000000.00000001, but got 10,000,000.000 instead
+ * Refer to ICU4J's NumberRegression.Test4090489() - loses precision
+ */
+	//tests.number.checkFormatParseCycle(t, null,1.000000000000001E7,"10000000.00000001",false);	
+			}
+		},
+		{
+			name: "number_regression_8",
+			runTest: function(t){
+/** 
+ * !!Failed case
+ * 1.with pattern "#,#00.00 p''ieces;-#,#00.00 p''ieces"
+ *   3456.78 should be formated to "3,456.78 p'ieces",
+ *   but got "3,456.78 p''ieces","''" should be replaced with "'"
+ * 2.with illegal pattern "000.0#0"
+ * 	 no error for the illegal pattern, and 3456.78 is formatted to 456.780
+ * 3.with illegal pattern "0#0.000"
+ * 	 no error for the illegal pattern, and 3456.78 is formatted to 3456.780
+ * 
+ * Refer to ICU4J's NumberRegression.Test4092480(),Test4074454() 
+ */
+	var patterns = (["#0000","#000","#00","#0","#"]);
+	var expect = (["0042","042","42","42","42"]);
+	
+	for(var i =0; i < patterns.length; i ++){
+		tests.number.checkFormatParseCycle(t, {pattern:patterns[i]},42,expect[i],false);
+		tests.number.checkFormatParseCycle(t, {pattern:patterns[i]},-42,"-"+expect[i],false);	
+	}
+	
+	tests.number.checkFormatParseCycle(t, {pattern:"#,#00.00;-#.#"},3456.78,"3,456.78",false);
+	//!!Failed case
+	//tests.number.checkFormatParseCycle(t, {pattern:"#,#00.00 p''ieces;-#,#00.00 p''ieces"},3456.78,"3,456.78 p'ieces",false);	
+	//tests.number.checkFormatParseCycle(t, {pattern:"000.0#0"},3456.78,null,false);
+	//tests.number.checkFormatParseCycle(t, {pattern:"0#0.000"},3456.78,null,false);	
+			}
+		},
+		{
+			name: "number_regression_9",
+			runTest: function(t){
+/**
+ * TODO
+ * Refer to ICU4J's NumberRegression.Test4052223()
+ */
+	//TODO:only got NaN,need an illegal pattern exception? 
+	tests.number.checkParse(t, {pattern:"#,#00.00"},"abc3");	
+	
+	//TODO: got NaN instead of 1.222, is it ok?
+	//tests.number.checkParse(t, {pattern:"#,##0.###",locale:"en-us"},"1.222,111",1.222);
+	//tests.number.checkParse(t, {pattern:"#,##0.###",locale:"en-us"},"1.222x111",1.222);
+	
+	//got NaN for illeal input,ok
+	tests.number.checkParse(t, null,"hello: ,.#$@^&**10x");	
+			}
+		},
+		{
+			name: "number_regression_10",
+			runTest: function(t){
+/**
+ * Refer to ICU4J's NumberRegression.Test4125885()
+ */
+	tests.number.checkFormatParseCycle(t, {pattern:"000.00"},12.34,"012.34",false);
+	tests.number.checkFormatParseCycle(t, {pattern:"+000.00%;-000.00%"},0.1234,"+012.34%",false);
+	tests.number.checkFormatParseCycle(t, {pattern:"##,###,###.00"},9.02,"9.02",false);
+	
+	var patterns =(["#.00", "0.00", "00.00", "#0.0#", "#0.00"]);
+	var expect =  (["1.20", "1.20", "01.20", "1.2",   "1.20" ]);
+	for(var i =0 ; i < patterns.length; i ++){
+		tests.number.checkFormatParseCycle(t, {pattern:patterns[i]},1.2,expect[i],false);
+	}
+			}
+		},
+		{
+			name: "number_regression_11",
+			runTest: function(t){
+/**
+ * TODO:!!Failed case
+ * Make sure that all special characters, when quoted in a suffix or prefix, lose their special meaning.
+ * The detail error info :  
+ * for input 123
+ * pattern:'0'#0'0'; expect:"01230"; but got "'3'#0'0'" instead
+ * pattern:','#0','; expect:",123,"; but got "','123','" instead
+ * pattern:'.'#0'.'; expect:".123."; but got "'.'123'.'" instead
+ * pattern:'ä'#0'ä'; expect:"ä123ä"; but got "'ä'123000'ä'" instead
+ * pattern:'%'#0'%'; expect:"%123%"; but got "'%'12300'%'" instead
+ * pattern:'#'#0'#'; expect:"#123#"; but got "'123'#0'#'" instead
+ * pattern:';'#0';'; expect:";123;"; but got "[dojo-test] FATAL exception raised: 
+ * 											  unable to find a number expression in pattern: '"
+ * pattern:'E'#0'E'; expect:"E123E"; not implemeted yet
+ * pattern:'*'#0'*'; expect:"*123*"; but got "'*'123'*'" instead
+ * pattern:'+'#0'+'; expect:"+123+"; but got "'+'123'+'" instead
+ * pattern:'-'#0'-'; expect:"-123-"; but got "'-'123'-'" instead
+ * 
+ * TODO: is it ok to remain "'" in the formatted result as above??
+ * 
+ * Refer to ICU4J's NumberRegression.Test4212072()
+ */
+/*
+	var specials = ([ '0', ',', '.', '\u2030', '%', '#',';', 'E', '*', '+', '-']);
+	var pattern; 
+	var expect;
+	
+	for(var i=0; i < specials.length; i ++){
+		pattern = "'" + specials[i] + "'#0'" + specials[i] + "'";
+		expect = "" +  specials[i] + "123" +  specials[i];
+		tests.number.checkFormatParseCycle(t, {pattern:pattern,locale:"en-us"},123,expect,false);
+	}
+*/
+			}
+		},
+		{
+			name: "number_regression_12",
+			runTest: function(t){
+/**
+ * TODO: add more rounding test cases, refer to ICU4J's NumberRegression.Test4071005(),Test4071014() etc.. 
+ */
+
+/**
+ * TODO:Decimal format doesnt round a double properly when the number is less than 1
+ * 
+ * Refer to ICU4J's NumberRegression.test4241880()
+ */
+/*
+	var input = ([ .019, .009, .015, .016, .014,
+                	.004, .005, .006, .007, .008,
+                	.5, 1.5, .05, .15, .005,
+                	.015, .0005, .0015]);
+	var patterns = (["##0%", "##0%", "##0%", "##0%", "##0%",
+                	 "##0%", "##0%", "##0%", "##0%", "##0%",
+                	 "#,##0", "#,##0", "#,##0.0", "#,##0.0", "#,##0.00",
+                	 "#,##0.00", "#,##0.000", "#,##0.000"]);
+	var expect =([   "2%", "1%", "2%", "2%", "1%",
+                	 "0%", "0%", "1%", "1%", "1%",
+                	 "0", "2", "0.0", "0.2", "0.00",
+                	 "0.02", "0.000", "0.002",]);
+	for(var i = 0; i <input.length; i ++){
+		tests.number.checkFormatParseCycle(t, {pattern:patterns[i],round:true},input[i],expect[i],false);
+	}
+*/
+			}
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/resources/ApplicationState.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/resources/ApplicationState.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/resources/ApplicationState.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,28 @@
+/*
+ApplicationState is an object that represents the application state.
+It will be given to dojo.undo.browser to represent the current application state.
+*/
+ApplicationState = function(stateData, outputDivId, backForwardOutputDivId, bookmarkValue){
+	this.stateData = stateData;
+	this.outputDivId = outputDivId;
+	this.backForwardOutputDivId = backForwardOutputDivId;
+	this.changeUrl = bookmarkValue;
+}
+
+ApplicationState.prototype.back = function(){
+	this.showBackForwardMessage("BACK for State Data: " + this.stateData);
+	this.showStateData();
+}
+
+ApplicationState.prototype.forward = function(){
+	this.showBackForwardMessage("FORWARD for State Data: " + this.stateData);
+	this.showStateData();
+}
+
+ApplicationState.prototype.showStateData = function(){
+	dojo.byId(this.outputDivId).innerHTML += this.stateData + '<br />';
+}
+
+ApplicationState.prototype.showBackForwardMessage = function(message){
+	dojo.byId(this.backForwardOutputDivId).innerHTML += message + '<br />';
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/resources/JSON.php
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/resources/JSON.php	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/resources/JSON.php	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,724 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/** 
+ * Converts to and from JSON format.
+ * 
+ * JSON (JavaScript Object Notation) is a lightweight data-interchange
+ * format. It is easy for humans to read and write. It is easy for machines
+ * to parse and generate. It is based on a subset of the JavaScript
+ * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
+ * This feature can also be found in  Python. JSON is a text format that is
+ * completely language independent but uses conventions that are familiar
+ * to programmers of the C-family of languages, including C, C++, C#, Java,
+ * JavaScript, Perl, TCL, and many others. These properties make JSON an
+ * ideal data-interchange language.
+ * 
+ * This package provides a simple encoder and decoder for JSON notation. It
+ * is intended for use with client-side Javascript applications that make
+ * use of HTTPRequest to perform server communication functions - data can
+ * be encoded into JSON notation for use in a client-side javascript, or
+ * decoded from incoming Javascript requests. JSON format is native to
+ * Javascript, and can be directly eval()'ed with no further parsing
+ * overhead
+ *
+ * All strings should be in ASCII or UTF-8 format!
+ *
+ * LICENSE: Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met: Redistributions of source code must retain the
+ * above copyright notice, this list of conditions and the following
+ * disclaimer. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * 
+ * @category   
+ * @package     Services_JSON
+ * @author      Michal Migurski <mike-json at teczno.com>
+ * @author      Matt Knapp <mdknapp[at]gmail[dot]com>
+ * @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
+ * @copyright   2005 Michal Migurski
+ * @license     http://www.opensource.org/licenses/bsd-license.php
+ * @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198
+ */
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_SLICE',   1);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_STR',  2);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_ARR',  4);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_OBJ',  8);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_CMT', 16);
+
+/**
+ * Behavior switch for Services_JSON::decode()
+ */
+define('SERVICES_JSON_LOOSE_TYPE', 10);
+
+/**
+ * Behavior switch for Services_JSON::decode()
+ */
+define('SERVICES_JSON_STRICT_TYPE', 11);
+
+/** 
+ * Converts to and from JSON format.
+ *
+ * Brief example of use:
+ *
+ * <code>
+ * // create a new instance of Services_JSON
+ * $json = new Services_JSON();
+ * 
+ * // convert a complexe value to JSON notation, and send it to the browser
+ * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
+ * $output = $json->encode($value);
+ *
+ * print($output);
+ * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
+ * 
+ * // accept incoming POST data, assumed to be in JSON notation
+ * $input = file_get_contents('php://input', 1000000);
+ * $value = $json->decode($input);
+ * </code>
+ */
+class Services_JSON
+{
+   /**
+    * constructs a new JSON instance
+    *
+    * @param    int     $use    object behavior: when encoding or decoding,
+    *                           be loose or strict about object/array usage
+    *
+    *                           possible values:
+    *                           - SERVICES_JSON_STRICT_TYPE: strict typing, default.
+    *                                                        "{...}" syntax creates objects in decode().
+    *                           - SERVICES_JSON_LOOSE_TYPE:  loose typing.
+    *                                                        "{...}" syntax creates associative arrays in decode().
+    */
+    function Services_JSON($use = SERVICES_JSON_STRICT_TYPE)
+    {
+        $this->use = $use;
+    }
+
+   /**
+    * convert a string from one UTF-16 char to one UTF-8 char
+    *
+    * Normally should be handled by mb_convert_encoding, but
+    * provides a slower PHP-only method for installations
+    * that lack the multibye string extension.
+    *
+    * @param    string  $utf16  UTF-16 character
+    * @return   string  UTF-8 character
+    * @access   private
+    */
+    function utf162utf8($utf16)
+    {
+        // oh please oh please oh please oh please oh please
+        if(function_exists('mb_convert_encoding'))
+            return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
+        
+        $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
+
+        switch(true) {
+            case ((0x7F & $bytes) == $bytes):
+                // this case should never be reached, because we are in ASCII range
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr(0x7F & $bytes);
+
+            case (0x07FF & $bytes) == $bytes:
+                // return a 2-byte UTF-8 character
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr(0xC0 | (($bytes >> 6) & 0x1F))
+                     . chr(0x80 | ($bytes & 0x3F));
+
+            case (0xFFFF & $bytes) == $bytes:
+                // return a 3-byte UTF-8 character
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr(0xE0 | (($bytes >> 12) & 0x0F))
+                     . chr(0x80 | (($bytes >> 6) & 0x3F))
+                     . chr(0x80 | ($bytes & 0x3F));
+        }
+
+        // ignoring UTF-32 for now, sorry
+        return '';
+    }        
+
+   /**
+    * convert a string from one UTF-8 char to one UTF-16 char
+    *
+    * Normally should be handled by mb_convert_encoding, but
+    * provides a slower PHP-only method for installations
+    * that lack the multibye string extension.
+    *
+    * @param    string  $utf8   UTF-8 character
+    * @return   string  UTF-16 character
+    * @access   private
+    */
+    function utf82utf16($utf8)
+    {
+        // oh please oh please oh please oh please oh please
+        if(function_exists('mb_convert_encoding'))
+            return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
+        
+        switch(strlen($utf8)) {
+            case 1:
+                // this case should never be reached, because we are in ASCII range
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return $ut8;
+
+            case 2:
+                // return a UTF-16 character from a 2-byte UTF-8 char
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr(0x07 & (ord($utf8{0}) >> 2))
+                     . chr((0xC0 & (ord($utf8{0}) << 6))
+                         | (0x3F & ord($utf8{1})));
+                
+            case 3:
+                // return a UTF-16 character from a 3-byte UTF-8 char
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr((0xF0 & (ord($utf8{0}) << 4))
+                         | (0x0F & (ord($utf8{1}) >> 2)))
+                     . chr((0xC0 & (ord($utf8{1}) << 6))
+                         | (0x7F & ord($utf8{2})));
+        }
+
+        // ignoring UTF-32 for now, sorry
+        return '';
+    }        
+
+   /**
+    * encodes an arbitrary variable into JSON format
+    *
+    * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
+    *                           see argument 1 to Services_JSON() above for array-parsing behavior.
+    *                           if var is a strng, note that encode() always expects it
+    *                           to be in ASCII or UTF-8 format!
+    *
+    * @return   string  JSON string representation of input var
+    * @access   public
+    */
+    function encode($var)
+    {
+        switch (gettype($var)) {
+            case 'boolean':
+                return $var ? 'true' : 'false';
+            
+            case 'NULL':
+                return 'null';
+            
+            case 'integer':
+                return (int) $var;
+                
+            case 'double':
+            case 'float':
+                return (float) $var;
+                
+            case 'string':
+                // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
+                $ascii = '';
+                $strlen_var = strlen($var);
+
+               /*
+                * Iterate over every character in the string,
+                * escaping with a slash or encoding to UTF-8 where necessary
+                */
+                for ($c = 0; $c < $strlen_var; ++$c) {
+                    
+                    $ord_var_c = ord($var{$c});
+                    
+                    switch (true) {
+                        case $ord_var_c == 0x08:
+                            $ascii .= '\b';
+                            break;
+                        case $ord_var_c == 0x09:
+                            $ascii .= '\t';
+                            break;
+                        case $ord_var_c == 0x0A:
+                            $ascii .= '\n';
+                            break;
+                        case $ord_var_c == 0x0C:
+                            $ascii .= '\f';
+                            break;
+                        case $ord_var_c == 0x0D:
+                            $ascii .= '\r';
+                            break;
+
+                        case $ord_var_c == 0x22:
+                        case $ord_var_c == 0x2F:
+                        case $ord_var_c == 0x5C:
+                            // double quote, slash, slosh
+                            $ascii .= '\\'.$var{$c};
+                            break;
+                            
+                        case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
+                            // characters U-00000000 - U-0000007F (same as ASCII)
+                            $ascii .= $var{$c};
+                            break;
+                        
+                        case (($ord_var_c & 0xE0) == 0xC0):
+                            // characters U-00000080 - U-000007FF, mask 110XXXXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
+                            $c += 1;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+    
+                        case (($ord_var_c & 0xF0) == 0xE0):
+                            // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}));
+                            $c += 2;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+    
+                        case (($ord_var_c & 0xF8) == 0xF0):
+                            // characters U-00010000 - U-001FFFFF, mask 11110XXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}),
+                                         ord($var{$c + 3}));
+                            $c += 3;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+    
+                        case (($ord_var_c & 0xFC) == 0xF8):
+                            // characters U-00200000 - U-03FFFFFF, mask 111110XX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}),
+                                         ord($var{$c + 3}),
+                                         ord($var{$c + 4}));
+                            $c += 4;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+    
+                        case (($ord_var_c & 0xFE) == 0xFC):
+                            // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}),
+                                         ord($var{$c + 3}),
+                                         ord($var{$c + 4}),
+                                         ord($var{$c + 5}));
+                            $c += 5;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+                    }
+                }
+                
+                return '"'.$ascii.'"';
+                
+            case 'array':
+               /*
+                * As per JSON spec if any array key is not an integer
+                * we must treat the the whole array as an object. We
+                * also try to catch a sparsely populated associative
+                * array with numeric keys here because some JS engines
+                * will create an array with empty indexes up to
+                * max_index which can cause memory issues and because
+                * the keys, which may be relevant, will be remapped
+                * otherwise.
+                * 
+                * As per the ECMA and JSON specification an object may
+                * have any string as a property. Unfortunately due to
+                * a hole in the ECMA specification if the key is a
+                * ECMA reserved word or starts with a digit the
+                * parameter is only accessible using ECMAScript's
+                * bracket notation.
+                */
+                
+                // treat as a JSON object  
+                if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
+                    return '{' .
+                           join(',', array_map(array($this, 'name_value'),
+                                               array_keys($var),
+                                               array_values($var)))
+                           . '}';
+                }
+
+                // treat it like a regular array
+                return '[' . join(',', array_map(array($this, 'encode'), $var)) . ']';
+                
+            case 'object':
+                $vars = get_object_vars($var);
+                return '{' .
+                       join(',', array_map(array($this, 'name_value'),
+                                           array_keys($vars),
+                                           array_values($vars)))
+                       . '}';
+
+            default:
+                return '';
+        }
+    }
+    
+   /**
+    * array-walking function for use in generating JSON-formatted name-value pairs
+    *
+    * @param    string  $name   name of key to use
+    * @param    mixed   $value  reference to an array element to be encoded
+    *
+    * @return   string  JSON-formatted name-value pair, like '"name":value'
+    * @access   private
+    */
+    function name_value($name, $value)
+    {
+        return $this->encode(strval($name)) . ':' . $this->encode($value);
+    }        
+
+   /**
+    * reduce a string by removing leading and trailing comments and whitespace
+    *
+    * @param    $str    string      string value to strip of comments and whitespace
+    *
+    * @return   string  string value stripped of comments and whitespace
+    * @access   private
+    */
+    function reduce_string($str)
+    {
+        $str = preg_replace(array(
+        
+                // eliminate single line comments in '// ...' form
+                '#^\s*//(.+)$#m',
+    
+                // eliminate multi-line comments in '/* ... */' form, at start of string
+                '#^\s*/\*(.+)\*/#Us',
+    
+                // eliminate multi-line comments in '/* ... */' form, at end of string
+                '#/\*(.+)\*/\s*$#Us'
+    
+            ), '', $str);
+        
+        // eliminate extraneous space
+        return trim($str);
+    }
+
+   /**
+    * decodes a JSON string into appropriate variable
+    *
+    * @param    string  $str    JSON-formatted string
+    *
+    * @return   mixed   number, boolean, string, array, or object
+    *                   corresponding to given JSON input string.
+    *                   See argument 1 to Services_JSON() above for object-output behavior.
+    *                   Note that decode() always returns strings
+    *                   in ASCII or UTF-8 format!
+    * @access   public
+    */
+    function decode($str)
+    {
+        $str = $this->reduce_string($str);
+    
+        switch (strtolower($str)) {
+            case 'true':
+                return true;
+
+            case 'false':
+                return false;
+            
+            case 'null':
+                return null;
+            
+            default:
+                if (is_numeric($str)) {
+                    // Lookie-loo, it's a number
+
+                    // This would work on its own, but I'm trying to be
+                    // good about returning integers where appropriate:
+                    // return (float)$str;
+
+                    // Return float or int, as appropriate
+                    return ((float)$str == (integer)$str)
+                        ? (integer)$str
+                        : (float)$str;
+                    
+                } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
+                    // STRINGS RETURNED IN UTF-8 FORMAT
+                    $delim = substr($str, 0, 1);
+                    $chrs = substr($str, 1, -1);
+                    $utf8 = '';
+                    $strlen_chrs = strlen($chrs);
+                    
+                    for ($c = 0; $c < $strlen_chrs; ++$c) {
+                    
+                        $substr_chrs_c_2 = substr($chrs, $c, 2);
+                        $ord_chrs_c = ord($chrs{$c});
+                        
+                        switch (true) {
+                            case $substr_chrs_c_2 == '\b':
+                                $utf8 .= chr(0x08);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\t':
+                                $utf8 .= chr(0x09);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\n':
+                                $utf8 .= chr(0x0A);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\f':
+                                $utf8 .= chr(0x0C);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\r':
+                                $utf8 .= chr(0x0D);
+                                ++$c;
+                                break;
+
+                            case $substr_chrs_c_2 == '\\"':
+                            case $substr_chrs_c_2 == '\\\'':
+                            case $substr_chrs_c_2 == '\\\\':
+                            case $substr_chrs_c_2 == '\\/':
+                                if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
+                                   ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
+                                    $utf8 .= $chrs{++$c};
+                                }
+                                break;
+                                
+                            case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
+                                // single, escaped unicode character
+                                $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
+                                       . chr(hexdec(substr($chrs, ($c + 4), 2)));
+                                $utf8 .= $this->utf162utf8($utf16);
+                                $c += 5;
+                                break;
+        
+                            case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
+                                $utf8 .= $chrs{$c};
+                                break;
+        
+                            case ($ord_chrs_c & 0xE0) == 0xC0:
+                                // characters U-00000080 - U-000007FF, mask 110XXXXX
+                                //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 2);
+                                ++$c;
+                                break;
+    
+                            case ($ord_chrs_c & 0xF0) == 0xE0:
+                                // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 3);
+                                $c += 2;
+                                break;
+    
+                            case ($ord_chrs_c & 0xF8) == 0xF0:
+                                // characters U-00010000 - U-001FFFFF, mask 11110XXX
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 4);
+                                $c += 3;
+                                break;
+    
+                            case ($ord_chrs_c & 0xFC) == 0xF8:
+                                // characters U-00200000 - U-03FFFFFF, mask 111110XX
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 5);
+                                $c += 4;
+                                break;
+    
+                            case ($ord_chrs_c & 0xFE) == 0xFC:
+                                // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 6);
+                                $c += 5;
+                                break;
+
+                        }
+
+                    }
+                    
+                    return $utf8;
+                
+                } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
+                    // array, or object notation
+
+                    if ($str{0} == '[') {
+                        $stk = array(SERVICES_JSON_IN_ARR);
+                        $arr = array();
+                    } else {
+                        if ($this->use == SERVICES_JSON_LOOSE_TYPE) {
+                            $stk = array(SERVICES_JSON_IN_OBJ);
+                            $obj = array();
+                        } else {
+                            $stk = array(SERVICES_JSON_IN_OBJ);
+                            $obj = new stdClass();
+                        }
+                    }
+                    
+                    array_push($stk, array('what'  => SERVICES_JSON_SLICE,
+                                           'where' => 0,
+                                           'delim' => false));
+
+                    $chrs = substr($str, 1, -1);
+                    $chrs = $this->reduce_string($chrs);
+                    
+                    if ($chrs == '') {
+                        if (reset($stk) == SERVICES_JSON_IN_ARR) {
+                            return $arr;
+
+                        } else {
+                            return $obj;
+
+                        }
+                    }
+
+                    //print("\nparsing {$chrs}\n");
+                    
+                    $strlen_chrs = strlen($chrs);
+                    
+                    for ($c = 0; $c <= $strlen_chrs; ++$c) {
+                    
+                        $top = end($stk);
+                        $substr_chrs_c_2 = substr($chrs, $c, 2);
+                    
+                        if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
+                            // found a comma that is not inside a string, array, etc.,
+                            // OR we've reached the end of the character list
+                            $slice = substr($chrs, $top['where'], ($c - $top['where']));
+                            array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
+                            //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                            if (reset($stk) == SERVICES_JSON_IN_ARR) {
+                                // we are in an array, so just push an element onto the stack
+                                array_push($arr, $this->decode($slice));
+
+                            } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
+                                // we are in an object, so figure
+                                // out the property name and set an
+                                // element in an associative array,
+                                // for now
+                                if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+                                    // "name":value pair
+                                    $key = $this->decode($parts[1]);
+                                    $val = $this->decode($parts[2]);
+
+                                    if ($this->use == SERVICES_JSON_LOOSE_TYPE) {
+                                        $obj[$key] = $val;
+                                    } else {
+                                        $obj->$key = $val;
+                                    }
+                                } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+                                    // name:value pair, where name is unquoted
+                                    $key = $parts[1];
+                                    $val = $this->decode($parts[2]);
+
+                                    if ($this->use == SERVICES_JSON_LOOSE_TYPE) {
+                                        $obj[$key] = $val;
+                                    } else {
+                                        $obj->$key = $val;
+                                    }
+                                }
+
+                            }
+
+                        } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
+                            // found a quote, and we are not inside a string
+                            array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
+                            //print("Found start of string at {$c}\n");
+
+                        } elseif (($chrs{$c} == $top['delim']) &&
+                                 ($top['what'] == SERVICES_JSON_IN_STR) &&
+                                 (($chrs{$c - 1} != '\\') ||
+                                 ($chrs{$c - 1} == '\\' && $chrs{$c - 2} == '\\'))) {
+                            // found a quote, we're in a string, and it's not escaped
+                            array_pop($stk);
+                            //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
+
+                        } elseif (($chrs{$c} == '[') &&
+                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+                            // found a left-bracket, and we are in an array, object, or slice
+                            array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
+                            //print("Found start of array at {$c}\n");
+
+                        } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
+                            // found a right-bracket, and we're in an array
+                            array_pop($stk);
+                            //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        } elseif (($chrs{$c} == '{') &&
+                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+                            // found a left-brace, and we are in an array, object, or slice
+                            array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
+                            //print("Found start of object at {$c}\n");
+
+                        } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
+                            // found a right-brace, and we're in an object
+                            array_pop($stk);
+                            //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        } elseif (($substr_chrs_c_2 == '/*') &&
+                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+                            // found a comment start, and we are in an array, object, or slice
+                            array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
+                            $c++;
+                            //print("Found start of comment at {$c}\n");
+
+                        } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
+                            // found a comment end, and we're in one now
+                            array_pop($stk);
+                            $c++;
+                            
+                            for ($i = $top['where']; $i <= $c; ++$i)
+                                $chrs = substr_replace($chrs, ' ', $i, 1);
+                            
+                            //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        }
+                    
+                    }
+                    
+                    if (reset($stk) == SERVICES_JSON_IN_ARR) {
+                        return $arr;
+
+                    } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
+                        return $obj;
+
+                    }
+                
+                }
+        }
+    }
+    
+}
+    
+?>
\ No newline at end of file

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/resources/testClass.php
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/resources/testClass.php	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/resources/testClass.php	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,20 @@
+<?php
+class testClass {
+
+	function myecho ($somestring) {
+		return "<P>" . $somestring . "</P>";
+	}
+
+	function contentB () {
+		return "<P>Content B</P>";
+	}
+
+	function contentC () {
+		return "<P>Content C</P>";
+	}
+
+	function add($x,$y) {
+		return $x + $y;
+	}
+}
+?>

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/resources/testClass.smd
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/resources/testClass.smd	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/resources/testClass.smd	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,40 @@
+{
+	"SMDVersion":".1",
+	"objectName":"testClass",
+	"serviceType":"JSON-RPC",
+	"serviceURL":"../../dojo/tests/resources/test_JsonRPCMediator.php",
+	"methods":[
+		{
+			"name":"myecho",
+			"parameters":[
+				{
+					"name":"somestring",
+					"type":"STRING"
+				}
+			]
+		},
+		{
+			"name":"contentB"
+		},
+		{
+			"name":"contentC"
+		},
+		{
+			"name":"add",
+			"parameters":[
+				{
+					"name":"x",
+					"type":"STRING"
+				},
+				{
+					"name":"y",
+					"type":"STRING"
+				}
+			]
+		},
+		{
+			"name":"triggerRpcError"
+		},
+
+	]
+}

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/resources/test_JsonRPCMediator.php
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/resources/test_JsonRPCMediator.php	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/resources/test_JsonRPCMediator.php	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,39 @@
+<?php
+	require_once("./JSON.php");
+	// NOTE: File.php is installed via Pear using:
+	//	%> sudo pear install File
+	// Your server will also need the Pear library directory included in PHP's
+	// include_path configuration directive
+	require_once('File.php');
+
+	// ensure that we don't try to send "html" down to the client
+	header("Content-Type: text/plain");
+
+	$json = new Services_JSON;
+	$fp = new File();
+
+	$results = array();
+	$results['error'] = null;
+
+	$jsonRequest = file_get_contents('php://input');
+//	$jsonRequest = '{"params":["Blah"],"method":"myecho","id":86}';
+
+
+	$req = $json->decode($jsonRequest);
+
+	include("./testClass.php");
+	$testObject = new testClass();
+
+	$method = $req->method;
+	if ($method != "triggerRpcError") {
+		$ret = call_user_func_array(array($testObject,$method),$req->params);
+		$results['result'] = $ret;
+	} else {
+		$results['error'] = "Triggered RPC Error test";
+	}
+	$results['id'] = $req->id;
+
+	$encoded = $json->encode($results);
+
+	print $encoded;
+?>

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/resources/test_css.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/resources/test_css.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/resources/test_css.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,65 @@
+<html>
+	<head>
+		<title>Dojo CSS Stylesheet Test</title>
+		<link rel="stylesheet" type="text/css" href="../../resources/dojo.css" />
+	</head>
+	<body>
+		<h1>Lorem ipsum dolor sit amet.</h1>
+		<p>Lorem ipsum dolor sit amet, <a href="">consectetuer adipiscing elit</a>. In porta. Etiam mattis libero nec ante. Nam porta lacus eu ligula. Cras mauris. Suspendisse vel augue. Vivamus aliquam orci ut eros. Nunc eleifend sagittis turpis. Nullam consequat iaculis augue. Aliquam pellentesque egestas massa. Curabitur pulvinar, enim vel porta dapibus, ligula lectus vulputate purus, eu tempus ante dolor id quam. Sed luctus fermentum nulla. Donec sollicitudin imperdiet risus. Cras cursus, sapien ac faucibus feugiat, ligula felis laoreet justo, eu sollicitudin purus purus in nibh. Phasellus in nunc.</p>
+		<q>Donec eu nunc vitae lorem egestas convallis <code>var test=null;</code> Nullam at enim id mauris vestibulum ornare. Cras facilisis tellus at risus. Phasellus ut pede at erat posuere vehicula. Donec auctor sodales risus. Maecenas dictum erat at justo. Nullam fringilla dictum orci. Ut vitae erat. Fusce nunc. Duis quis orci. Morbi faucibus. Ut fermentum augue ac nulla. Duis cursus eleifend felis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Mauris tincidunt, justo quis venenatis congue, nisi purus dignissim nisi, ullamcorper tempus dolor nulla at metus.</q>
+		<h2>Donec eu nunc vitae lorem.</h2>
+		<p>Donec eu nunc vitae lorem egestas convallis. Nullam at enim id mauris vestibulum ornare. Cras facilisis tellus at risus. Phasellus ut pede at erat posuere vehicula. Donec auctor sodales risus. Maecenas dictum erat at justo. Nullam fringilla dictum orci. Ut vitae erat. Fusce nunc. Duis quis orci. Morbi faucibus. Ut fermentum augue ac nulla. Duis cursus eleifend felis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Mauris tincidunt, justo quis venenatis congue, nisi purus dignissim nisi, ullamcorper tempus dolor nulla at metus.</p>
+		<p>Vestibulum ultricies bibendum tortor. Nam auctor dignissim neque. Cras vehicula. Nulla facilisi. Duis quis tellus in est aliquet condimentum. Sed elementum, felis vel pharetra bibendum, neque lorem pulvinar nulla, consequat tempor libero enim vel nulla. Nulla eleifend, lorem accumsan convallis lobortis, diam dui eleifend urna, eu imperdiet purus urna nec nibh. Nullam pede odio, molestie eu, interdum sagittis, imperdiet ac, lectus. Sed pede nisl, vulputate at, pellentesque id, consectetuer ac, elit. Duis laoreet, elit sed tempus vehicula, lacus orci pulvinar nibh, non malesuada ante mi in enim. Etiam pulvinar, sapien ut vulputate venenatis, risus lectus sollicitudin sapien, in dapibus felis ligula congue ante. Vivamus sit amet ligula. Morbi pharetra augue egestas massa. Sed a ligula. In ac mi id nibh semper accumsan. Nunc luctus nibh vel magna. Nunc viverra nonummy tortor. Curabitur interdum convallis dui. Integer mollis hendrerit elit. Nam a lorem.</p>
+		<ol>
+			<li>A List item.</li>
+			<li>A List item.</li>
+			<li>A List item.</li>
+			<li>A List item.</li>
+			<li>A List item.</li>
+			<li>A List item.</li>
+		</ol>
+		<h2>Cras pellentesque</h2>
+		<h3>Aliquam dapibus</h3>
+		<pre>
+var test = someVariable;
+function foo(bar){
+	alert(baz);
+} </pre>
+		<p>Cras pellentesque tristique lorem. Aliquam dapibus, massa id posuere volutpat, sem sem nonummy turpis, ut ultricies nibh neque sed dolor. Duis commodo elit et massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed eu urna. Donec sit amet odio sit amet turpis facilisis molestie. In id mi. Nulla consequat ante ut elit. In risus urna, venenatis imperdiet, consequat vel, porttitor et, quam. In hac habitasse platea dictumst. Vestibulum id velit. Donec a eros. Donec quis quam at pede aliquet porta. Donec id ligula mollis turpis pulvinar dapibus. Praesent imperdiet, justo pulvinar accumsan scelerisque, lacus felis bibendum justo, id posuere augue libero eu velit.</p>
+		<table>
+			<thead>
+				<tr>
+					<th>Foo</th>
+					<th>Bar</th>
+					<th>Baz</th>
+				</tr>
+			</thead>
+			<tbody>
+				<tr>
+					<td>baz</td>
+					<td>foo</td>
+					<td>bar</td>
+				</tr>
+				<tr>
+					<td>bar</td>
+					<td>baz</td>
+					<td>foo</td>
+				</tr>
+				<tr>
+					<td>foo</td>
+					<td>bar</td>
+					<td>baz</td>
+				</tr>
+			</tbody>
+			<tfoot>
+				<tr>
+					<td>Foo</td>
+					<td>Bar</td>
+					<td>Baz</td>
+				</tr>
+			</tfoot>
+		</table>
+		<blockquote>Donec eu nunc vitae lorem egestas convallis. Nullam at enim id mauris vestibulum ornare. Cras facilisis tellus at risus. Phasellus ut pede at erat posuere vehicula. Donec auctor sodales risus. Maecenas dictum erat at justo. Nullam fringilla dictum orci. Ut vitae erat. Fusce nunc. Duis quis orci. Morbi faucibus. Ut fermentum augue ac nulla. Duis cursus eleifend felis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Mauris tincidunt, justo quis venenatis congue, nisi purus dignissim nisi, ullamcorper tempus dolor nulla at metus.</blockquote>
+		<p>Phasellus quis velit. Curabitur porta dolor in arcu. Maecenas mollis purus. Donec nec erat et tellus laoreet elementum. Pellentesque vitae mi. Aenean pharetra libero ultricies augue. Vestibulum et nibh. Proin nibh quam, rutrum faucibus, auctor eget, mollis vel, orci. Duis tortor quam, tincidunt eu, lacinia id, fermentum at, turpis. Mauris at augue. Nulla facilisi. Pellentesque ut enim.</p>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/rpc.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/rpc.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/rpc.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,146 @@
+dojo.provide("tests.rpc");
+
+dojo.require("dojo.rpc.RpcService");
+dojo.require("dojo.rpc.JsonService");
+dojo.require("dojo.rpc.JsonPService");
+
+tests.register("tests.rpc", 
+	[ 
+
+		{
+			name: "JsonRPC-EchoTest",
+			timeout: 2000,
+			setUp: function(){
+				var testSmd = {
+					serviceURL:"../../dojo/tests/resources/test_JsonRPCMediator.php",
+					methods:[
+						{
+							name:"myecho",
+							parameters:[
+								{
+									name:"somestring",
+									type:"STRING"
+								}
+							]
+						}
+					]	
+				}
+			
+				this.svc = new dojo.rpc.JsonService(testSmd);
+			},
+			runTest: function(){
+				var d = new doh.Deferred();
+				var td = this.svc.myecho("RPC TEST");
+
+				td.addCallbacks(function(result) {
+					if(result=="<P>RPC TEST</P>"){
+						return true;
+					}else{
+						return new Error("JsonRpc-EchoTest test failed, resultant content didn't match");
+					}
+				}, function(result){
+					return new Error(result);
+				});
+
+				td.addBoth(d, "callback");
+
+				return d;
+			}
+
+		},
+
+		{
+			name: "JsonRPC-EmptyParamTest",
+			timeout: 2000,
+			setUp: function(){
+				var testSmd={
+					serviceURL:"../../dojo/tests/resources/test_JsonRPCMediator.php",
+					methods:[
+						{
+							name:"contentB",
+						}
+					]	
+				}
+			
+				this.svc = new dojo.rpc.JsonService(testSmd);
+			},
+			runTest: function(){
+				var d = new doh.Deferred();
+				var td = this.svc.contentB();
+
+				td.addCallbacks(function(result){
+					if(result=="<P>Content B</P>"){
+						return true;
+					}else{
+						return new Error("JsonRpc-EmpytParamTest test failed, resultant content didn't match");
+					}
+				}, function(result){
+					return new Error(result);
+				});
+
+				td.addBoth(d, "callback");
+
+				return d;
+			}
+		},
+
+		{
+			name: "JsonRPC_SMD_Loading_test",
+			timeout: 2000,
+			setUp: function(){
+				this.svc = new dojo.rpc.JsonService("../../dojo/tests/resources/testClass.smd");
+			},
+			runTest: function(){
+				var d = new doh.Deferred();
+				var td = this.svc.contentB();
+
+				td.addCallbacks(function(result){
+					if(result=="<P>Content B</P>"){
+						return true;
+					}else{
+						return new Error("JsonRpc_SMD_Loading_Test failed, resultant content didn't match");
+					}
+				}, function(result){
+					return new Error(result);
+				});
+
+				td.addBoth(d, "callback");
+
+				return d;
+			}
+		},
+
+		{
+			name: "JsonP_test",
+			timeout: 2000,
+			setUp: function(){
+				this.svc = new dojo.rpc.JsonPService("../../dojox/rpc/yahoo.smd", {appId: "foo"});
+			},
+			runTest: function(){
+				var d = new doh.Deferred();
+				var td = this.svc.webSearch({query:"dojotoolkit"});
+
+				td.addCallbacks(function(result){
+					console.debug(result);
+					return true;
+					if(result=="<P>Content B</P>"){
+						return true;
+					}else{
+						return new Error("JsonRpc_SMD_Loading_Test failed, resultant content didn't match");
+					}
+				}, function(result){
+					return new Error(result);
+				});
+
+				td.addBoth(d, "callback");
+
+				return d;
+			}
+		}
+
+
+
+	]
+);
+
+

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/runTests.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/runTests.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/runTests.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+    <head>
+    <title>Dojo CORE and BASE D.O.H. Unit Test Runner</title>
+    <meta http-equiv="REFRESH" content="0;url=../../util/doh/runner.html?testModule=dojo.tests.module"></HEAD>
+    <BODY>
+        Redirecting to D.O.H runner.
+    </BODY>
+</HTML> 

Added: trunk/examples/typeface/root/static/dojo/dojo/tests/string.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests/string.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests/string.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,18 @@
+dojo.provide("tests.string");
+
+dojo.require("dojo.string");
+
+tests.register("tests.string", 
+	[
+		function test_string_pad(t){
+			t.is("00001", dojo.string.pad("1", 5));
+			t.is("000001", dojo.string.pad("000001", 5));
+			t.is("10000", dojo.string.pad("1", 5, null, true));
+		},
+
+		function test_string_substitute(t){
+			t.is("File 'foo.html' is not found in directory '/temp'.", dojo.string.substitute("File '${0}' is not found in directory '${1}'.", ["foo.html","/temp"]));
+			t.is("File 'foo.html' is not found in directory '/temp'.", dojo.string.substitute("File '${name}' is not found in directory '${info.dir}'.", {name: "foo.html", info: {dir: "/temp"}}));
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojo/tests.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojo/tests.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojo/tests.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,6 @@
+//This file is the command-line entry point for running the tests in
+//Rhino and Spidermonkey.
+
+load("dojo.js");
+load("tests/runner.js");
+tests.run();

Added: trunk/examples/typeface/root/static/dojo/dojox/_cometd/README
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/_cometd/README	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/_cometd/README	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,29 @@
+-------------------------------------------------------------------------------
+Cometd (client)
+-------------------------------------------------------------------------------
+Version 0.4
+Release date: May 29, 2007
+-------------------------------------------------------------------------------
+Project state: beta 
+-------------------------------------------------------------------------------
+Project authors
+	Alex Russell (alex at dojotoolkit.org)
+	Greg Wilkins
+-------------------------------------------------------------------------------
+Project description
+
+Low-latency data transfer from servers to clients. dojox.cometd implements a
+Bayeux protocol client for use with most Bayeux servers. See cometd.com for
+details on Cometd or on the Bayeux protocol.
+-------------------------------------------------------------------------------
+Dependencies:
+
+Needs a cooperating Bayeux server
+-------------------------------------------------------------------------------
+Documentation
+
+See http://cometd.com
+-------------------------------------------------------------------------------
+Installation instructions
+
+Use this library with (preferably through) an existing Cometd server.

Added: trunk/examples/typeface/root/static/dojo/dojox/_cometd/cometd.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/_cometd/cometd.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/_cometd/cometd.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,674 @@
+dojo.provide("dojox._cometd.cometd");
+dojo.require("dojo.AdapterRegistry");
+// FIXME: determine if we can use XMLHTTP to make x-domain posts despite not
+//        being able to hear back about the result
+dojo.require("dojo.io.script");
+// dojo.require("dojo.cookie"); // for peering
+
+/*
+ * this file defines Comet protocol client. Actual message transport is
+ * deferred to one of several connection type implementations. The default is a
+ * forever-frame implementation. A single global object named "cometd" is
+ * used to mediate for these connection types in order to provide a stable
+ * interface.
+ */
+
+// TODO: the auth handling in this file is a *mess*. It should probably live in
+// the cometd object with the ability to mix in or call down to an auth-handler
+// object, the prototypical variant of which is a no-op
+
+dojox.cometd = new function(){
+
+	this.initialized = false;
+	this.connected = false;
+
+	this.connectionTypes = new dojo.AdapterRegistry(true);
+
+	this.version = 0.1;
+	this.minimumVersion = 0.1;
+	this.clientId = null;
+
+	this._isXD = false;
+	this.handshakeReturn = null;
+	this.currentTransport = null;
+	this.url = null;
+	this.lastMessage = null;
+	this.globalTopicChannels = {};
+	this.backlog = [];
+	this.handleAs="json-comment-optional";
+	this.advice;
+
+	this.tunnelInit = function(childLocation, childDomain){
+		// placeholder
+	}
+
+	this.tunnelCollapse = function(){
+		console.debug("tunnel collapsed!");
+		// placeholder
+	}
+
+	this.init = function(props, root, bargs){
+		// FIXME: if the root isn't from the same host, we should automatically
+		// try to select an XD-capable transport
+		props = props||{};
+		// go ask the short bus server what we can support
+		props.version = this.version;
+		props.minimumVersion = this.minimumVersion;
+		props.channel = "/meta/handshake";
+		// FIXME: do we just assume that the props knows
+		// everything we care about WRT to auth? Should we be trying to
+		// call back into it for subsequent auth actions? Should we fire
+		// local auth functions to ask for/get auth data?
+
+        props.ext = { "json-comment-filtered": true };
+
+		// FIXME: what about ScriptSrcIO for x-domain comet?
+		this.url = root||djConfig["cometdRoot"];
+		if(!this.url){
+			console.debug("no cometd root specified in djConfig and no root passed");
+			return;
+		}
+		
+		// FIXME: we need to select a way to handle JSONP-style stuff
+		// generically here. We already know if the server is gonna be on
+		// another domain (or can know it), so we should select appropriate
+		// negotiation methods here as well as in final transport type
+		// selection.
+		var bindArgs = {
+			url: this.url,
+			handleAs: this.handleAs,
+			content: { "message": dojo.toJson([props]) },
+			jsonpParam: "jsonp" // usually ignored
+		};
+		// dojo.hitch(this, "finishInit"),
+
+		// borrowed from dojo.uri.Uri in lieu of fixed host and port properties
+        var regexp = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$";
+		var r = (""+window.location).match(new RegExp(regexp));
+		if(r[4]){
+			var tmp = r[4].split(":");
+			var thisHost = tmp[0];
+			var thisPort = tmp[1]||"80"; // FIXME: match 443
+
+			r = this.url.match(new RegExp(regexp));
+			if(r[4]){
+				tmp = r[4].split(":");
+				var urlHost = tmp[0];
+				var urlPort = tmp[1]||"80";
+				this._isXD = ((urlHost != thisHost)||(urlPort != thisPort));
+			}
+		}
+		if(bargs){
+			dojo.mixin(bindArgs, bargs);
+		}
+		var d;
+		if(this._isXD){
+			d = dojo.io.script.get(bindArgs);
+		}else{
+			d = dojo.xhrPost(bindArgs);
+		}
+		d.addCallback(dojo.hitch(this, "finishInit"));
+		d.addErrback(function(e){ console.debug("handshake error!:", e); });
+		return d;
+	}
+
+	this.finishInit = function(data){
+		data = data[0];
+		this.handshakeReturn = data;
+		// pick a transport
+		if (data["advice"]){
+			this.advice = data.advice;
+		}
+		if((!data.successful)&&(!data.authSuccessful)){
+			console.debug("cometd init failed");
+			// TODO follow advice
+			return;
+		}
+		if(data.version < this.minimumVersion){
+			console.debug("cometd protocol version mismatch. We wanted", this.minimumVersion, "but got", data.version);
+			return;
+		}
+		this.currentTransport = this.connectionTypes.match(
+			data.supportedConnectionTypes,
+			data.version,
+			this._isXD
+		);
+		this.currentTransport.version = data.version;
+		this.clientId = data.clientId;
+		this.tunnelInit = dojo.hitch(this.currentTransport, "tunnelInit");
+		this.tunnelCollapse = dojo.hitch(this.currentTransport, "tunnelCollapse");
+
+		this.initialized = true;
+		this.currentTransport.startup(data);
+		while(this.backlog.length != 0){
+			var cur = this.backlog.shift();
+			var fn = cur.shift();
+			this[fn].apply(this, cur);
+		}
+	}
+
+	this._getRandStr = function(){
+		return Math.random().toString().substring(2, 10);
+	}
+
+	// public API functions called by cometd or by the transport classes
+	this.deliver = function(messages){
+		dojo.forEach(messages, this._deliver, this);
+		return messages;
+	}
+
+	this._deliver = function(message){
+		// dipatch events along the specified path
+		if(!this.currentTransport){
+			this.backlog.push(["deliver", message]);
+			return;
+		}
+
+		if(!message["channel"]){
+			if(message["success"] !== true){
+				console.debug("cometd error: no channel for message!", message);
+				return;
+			}
+		}
+		this.lastMessage = message;
+
+		if(message.advice){
+			this.advice = message.advice; // TODO maybe merge?
+		}
+
+		// check to see if we got a /meta channel message that we care about
+		if(	(message["channel"]) &&
+			(message.channel.length > 5)&&
+			(message.channel.substr(0, 5) == "/meta")){
+			// check for various meta topic actions that we need to respond to
+			switch(message.channel){
+				case "/meta/subscribe":
+					if(!message.successful){
+						console.debug("cometd subscription error for channel", message.channel, ":", message.error);
+						return;
+					}
+					this.subscribed(message.subscription, message);
+					break;
+				case "/meta/unsubscribe":
+					if(!message.successful){
+						console.debug("cometd unsubscription error for channel", message.channel, ":", message.error);
+						return;
+					}
+					this.unsubscribed(message.subscription, message);
+					break;
+			}
+		}
+		// send the message down for processing by the transport
+		this.currentTransport.deliver(message);
+
+		if(message.data){
+			// dispatch the message to any locally subscribed listeners
+			var tname = (this.globalTopicChannels[message.channel]) ? message.channel : "/cometd"+message.channel;
+			dojo.publish(tname, [ message ]);
+		}
+	}
+
+	this.disconnect = function(){
+		if(!this.currentTransport){
+			console.debug("no current transport to disconnect from");
+			return;
+		}
+		this.currentTransport.disconnect();
+	}
+
+	// public API functions called by end users
+	this.publish = function(/*string*/channel, /*object*/data, /*object*/properties){
+		// summary: 
+		//		publishes the passed message to the cometd server for delivery
+		//		on the specified topic
+		// channel:
+		//		the destination channel for the message
+		// data:
+		//		a JSON object containing the message "payload"
+		// properties:
+		//		Optional. Other meta-data to be mixed into the top-level of the
+		//		message
+		if(!this.currentTransport){
+			this.backlog.push(["publish", channel, data, properties]);
+			return;
+		}
+		var message = {
+			data: data,
+			channel: channel
+		};
+		if(properties){
+			dojo.mixin(message, properties);
+		}
+		return this.currentTransport.sendMessage(message);
+	}
+
+	this.subscribe = function(	/*string*/				channel, 
+								/*boolean, optional*/	useLocalTopics, 
+								/*object, optional*/	objOrFunc, 
+								/*string, optional*/	funcName){ // return: boolean
+		// summary:
+		//		inform the server of this client's interest in channel
+		// channel:
+		//		name of the cometd channel to subscribe to
+		// useLocalTopics:
+		//		Determines if up a local event topic subscription to the passed
+		//		function using the channel name that was passed is constructed,
+		//		or if the topic name will be prefixed with some other
+		//		identifier for local message distribution. Setting this to
+		//		"true" is a good way to hook up server-sent message delivery to
+		//		pre-existing local topics.
+		// objOrFunc:
+		//		an object scope for funcName or the name or reference to a
+		//		function to be called when messages are delivered to the
+		//		channel
+		// funcName:
+		//		the second half of the objOrFunc/funcName pair for identifying
+		//		a callback function to notifiy upon channel message delivery
+		if(!this.currentTransport){
+			this.backlog.push(["subscribe", channel, useLocalTopics, objOrFunc, funcName]);
+			return;
+		}
+		if(objOrFunc){
+			var tname = (useLocalTopics) ? channel : "/cometd"+channel;
+			if(useLocalTopics){
+				this.globalTopicChannels[channel] = true;
+			}
+			dojo.subscribe(tname, objOrFunc, funcName);
+		}
+		// FIXME: would we handle queuing of the subscription if not connected?
+		// Or should the transport object?
+		return this.currentTransport.sendMessage({
+			channel: "/meta/subscribe",
+			subscription: channel
+		});
+	}
+
+	this.subscribed = function(	/*string*/				channel, 
+								/*obj*/					message){
+		// console.debug(channel, message);
+	}
+
+	this.unsubscribe = function(/*string*/				channel, 
+								/*boolean, optional*/	useLocalTopics, 
+								/*object, optional*/	objOrFunc, 
+								/*string, optional*/	funcName){ // return: boolean
+		// summary:
+		//		inform the server of this client's disinterest in channel
+		// channel:
+		//		name of the cometd channel to subscribe to
+		// useLocalTopics:
+		//		Determines if up a local event topic subscription to the passed
+		//		function using the channel name that was passed is destroyed,
+		//		or if the topic name will be prefixed with some other
+		//		identifier for stopping message distribution.
+		// objOrFunc:
+		//		an object scope for funcName or the name or reference to a
+		//		function to be called when messages are delivered to the
+		//		channel
+		// funcName:
+		//		the second half of the objOrFunc/funcName pair for identifying
+		if(!this.currentTransport){
+			this.backlog.push(["unsubscribe", channel, useLocalTopics, objOrFunc, funcName]);
+			return;
+		}
+		//		a callback function to notifiy upon channel message delivery
+		if(objOrFunc){
+			// FIXME: should actual local topic unsubscription be delayed for
+			// successful unsubcribe notices from the other end? (guessing "no")
+			// FIXME: if useLocalTopics is false, should we go ahead and
+			// destroy the local topic?
+			var tname = (useLocalTopics) ? channel : "/cometd"+channel;
+			dojo.unsubscribe(tname, objOrFunc, funcName);
+		}
+		return this.currentTransport.sendMessage({
+			channel: "/meta/unsubscribe",
+			subscription: channel
+		});
+	}
+
+	this.unsubscribed = function(/*string*/				channel, 
+								/*obj*/					message){
+		// console.debug(channel, message);
+	}
+
+	// FIXME: add an "addPublisher" function
+}
+
+/*
+transport objects MUST expose the following methods:
+	- check
+	- startup
+	- sendMessage
+	- deliver
+	- disconnect
+optional, standard but transport dependent methods are:
+	- tunnelCollapse
+	- tunnelInit
+
+Transports SHOULD be namespaced under the cometd object and transports MUST
+register themselves with cometd.connectionTypes
+
+here's a stub transport defintion:
+
+cometd.blahTransport = new function(){
+	this.connected = false;
+	this.authToken = null;
+	this.lastTimestamp = null;
+	this.lastId = null;
+
+	this.check = function(types, version, xdomain){
+		// summary:
+		//		determines whether or not this transport is suitable given a
+		//		list of transport types that the server supports
+		return dojo.lang.inArray(types, "blah");
+	}
+
+	this.startup = function(){
+		if(this.connected){ return; }
+		// FIXME: fill in startup routine here
+		this.connected = true;
+	}
+
+	this.sendMessage = function(message){
+		// FIXME: fill in message sending logic
+	}
+
+	this.deliver = function(message){
+		if(message["timestamp"]){
+			this.lastTimestamp = message.timestamp;
+		}
+		if(message["id"]){
+			this.lastId = message.id;
+		}
+		if(	(message.channel.length > 5)&&
+			(message.channel.substr(0, 5) == "/meta")){
+			// check for various meta topic actions that we need to respond to
+			// switch(message.channel){
+			// 	case "/meta/connect":
+			//		// FIXME: fill in logic here
+			//		break;
+			//	// case ...: ...
+			//	}
+		}
+	}
+
+	this.disconnect = function(){
+		if(!this.connected){ return; }
+		// FIXME: fill in shutdown routine here
+		this.connected = false;
+	}
+}
+cometd.connectionTypes.register("blah", cometd.blahTransport.check, cometd.blahTransport);
+*/
+
+dojox.cometd.longPollTransport = new function(){
+	this.connected = false;
+
+	this.authToken = null;
+	this.lastTimestamp = null;
+	this.lastId = null;
+	this.backlog = [];
+
+	this.check = function(types, version, xdomain){
+		return ((!xdomain)&&(dojo.indexOf(types, "long-polling") >= 0));
+	}
+
+	this.tunnelInit = function(){
+		if(this.connected){ return; }
+		// FIXME: open up the connection here
+		this.openTunnelWith({
+			message: dojo.toJson([
+				{
+					channel:	"/meta/connect",
+					clientId:	dojox.cometd.clientId,
+					connectionType: "long-polling"
+					// FIXME: auth not passed here!
+					// "authToken": this.authToken
+				}
+			])
+		});
+		this.connected = true;
+	}
+
+	this.tunnelCollapse = function(){
+		if(!this.connected){
+			// try to restart the tunnel
+			this.connected = false;
+			// console.debug("clientId:", dojox.cometd.clientId);
+			
+			// TODO handle transport specific advice
+			
+			if(dojox.cometd["advice"]){
+				if(dojox.cometd.advice["reconnect"]=="none"){
+					return;
+				}
+			
+	            if(	(dojox.cometd.advice["interval"])&&
+					(dojox.cometd.advice.interval>0) ){
+					setTimeout(function(){
+						dojox.cometd.currentTransport._reconnect();
+					}, dojox.cometd.advice.interval);
+				}else{
+					this._reconnect();
+				}
+			}else{
+				this._reconnect();
+			}
+	    }
+	}	
+			
+	this._reconnect = function(){
+		if(	(dojox.cometd["advice"])&&
+			(dojox.cometd.advice["reconnect"]=="handshake")
+		){
+			dojox.io.cometd.init(null,dojox.io.cometd.url);
+		}else{
+			this.openTunnelWith({
+				message: dojo.toJson([
+					{
+						channel:	"/meta/reconnect",
+						connectionType: "long-polling",
+						clientId:	dojox.cometd.clientId,
+						timestamp:	this.lastTimestamp,
+						id:			this.lastId
+						// FIXME: no authToken provision!
+					}
+				])
+			});
+		}
+	}
+
+	this.deliver = function(message){
+		// handle delivery details that this transport particularly cares
+		// about. Most functions of should be handled by the main cometd object
+		// with only transport-specific details and state being tracked here.
+		if(message["timestamp"]){
+			this.lastTimestamp = message.timestamp;
+		}
+		if(message["id"]){
+			this.lastId = message.id;
+		}
+
+		// check to see if we got a /meta channel message that we care about
+		if(	(message.channel.length > 5)&&
+			(message.channel.substr(0, 5) == "/meta")){
+			// check for various meta topic actions that we need to respond to
+			switch(message.channel){
+				case "/meta/connect":
+					if(!message.successful){
+						console.debug("cometd connection error:", message.error);
+						return;
+					}
+					this.connected = true;
+					this.processBacklog();
+					break;
+				case "/meta/reconnect":
+					if(!message.successful){
+						console.debug("cometd reconnection error:", message.error);
+						return;
+					}
+					this.connected = true;
+					break;
+				case "/meta/subscribe":
+					if(!message.successful){
+						console.debug("cometd subscription error for channel", message.channel, ":", message.error);
+						return;
+					}
+					this.subscribed(message.channel);
+					// console.debug(message.channel);
+					break;
+			}
+		}
+	}
+
+	this.openTunnelWith = function(content, url){
+		// console.debug("openTunnelWith:", content, (url||cometd.url));
+		var d = dojo.xhrPost({
+			url: (url||dojox.cometd.url),
+			content: content,
+			// handleAs: "json",
+			handleAs: dojox.cometd.handleAs,
+		});
+		d.addCallback(dojo.hitch(this, function(data){
+			// console.debug(evt.responseText);
+			// console.debug(data);
+			dojox.cometd.deliver(data);
+			this.connected = false;
+			this.tunnelCollapse();
+		}));
+		d.addErrback(function(err){ 
+			console.debug("tunnel opening failed:", err);
+
+			// TODO - follow advice to reconnect or rehandshake?
+		});
+		this.connected = true;
+	}
+
+	this.processBacklog = function(){
+		while(this.backlog.length > 0){
+			this.sendMessage(this.backlog.shift(), true);
+		}
+	}
+
+	this.sendMessage = function(message, bypassBacklog){
+		// FIXME: what about auth fields?
+		if((bypassBacklog)||(this.connected)){
+			message.clientId = dojox.cometd.clientId;
+
+			return dojo.xhrPost({
+				url: dojox.cometd.url||djConfig["cometdRoot"],
+				handleAs: dojox.cometd.handleAs,
+				content: { 
+					message: dojo.toJson([ message ]) 
+				}
+			}).addCallback(dojox.cometd, "deliver");
+		}else{
+			this.backlog.push(message);
+		}
+	}
+
+	this.startup = function(handshakeData){
+		if(this.connected){ return; }
+		this.tunnelInit();
+	}
+}
+
+dojox.cometd.callbackPollTransport = new function(){
+	this.connected = false;
+
+	this.authToken = null;
+	this.lastTimestamp = null;
+	this.lastId = null;
+	this.backlog = [];
+
+	this.check = function(types, version, xdomain){
+		// we handle x-domain!
+		return (dojo.indexOf(types, "callback-polling") >= 0);
+	}
+
+	this.tunnelInit = function(){
+		if(this.connected){ return; }
+		// FIXME: open up the connection here
+		this.openTunnelWith({
+			message: dojo.toJson([
+				{
+					channel:	"/meta/connect",
+					clientId:	dojox.cometd.clientId,
+					connectionType: "callback-polling"
+					// FIXME: auth not passed here!
+					// "authToken": this.authToken
+				}
+			])
+		});
+		this.connected = true;
+	}
+
+	this.tunnelCollapse = function(){
+		if(!this.connected){
+			// try to restart the tunnel
+			this.connected = false;
+			this.openTunnelWith({
+				message: dojo.toJson([
+					{
+						channel:	"/meta/reconnect",
+						connectionType: "long-polling",
+						clientId:	dojox.cometd.clientId,
+						timestamp:	this.lastTimestamp,
+						id:			this.lastId
+						// FIXME: no authToken provision!
+					}
+				])
+			});
+		}
+	}
+
+	// the logic appears to be the same
+	this.deliver = dojox.cometd.longPollTransport.deliver;
+
+	this.openTunnelWith = function(content, url){
+		// create a <script> element to generate the request
+		dojo.io.script.get({
+			url: (url||dojox.cometd.url),
+			content: content,
+			handleAs: dojox.cometd.handleAs,
+			jsonpParam: "jsonp",
+		}).addCallback(dojo.hitch(this, function(data){
+				dojox.cometd.deliver(data);
+				this.connected = false;
+				this.tunnelCollapse();
+			})
+		).addErrback(
+			function(){ console.debug("tunnel opening failed"); }
+		);
+		this.connected = true;
+	}
+
+	this.processBacklog = function(){
+		while(this.backlog.length > 0){
+			this.sendMessage(this.backlog.shift(), true);
+		}
+	}
+
+	this.sendMessage = function(message, bypassBacklog){
+		// FIXME: what about auth fields?
+		if((bypassBacklog)||(this.connected)){
+			message.clientId = dojox.cometd.clientId;
+			var bindArgs = {
+				url: dojox.cometd.url||djConfig["cometdRoot"],
+				handleAs: dojox.io.cometd.handleAs,
+				jsonpParam: "jsonp",
+				content: { message: dojo.toJson([ message ]) },
+			};
+			return dojo.io.script.get(bindArgs).addCallback(dojox.cometd, "deliver");
+		}else{
+			this.backlog.push(message);
+		}
+	}
+
+	this.startup = function(handshakeData){
+		if(this.connected){ return; }
+		this.tunnelInit();
+	}
+}
+dojox.cometd.connectionTypes.register("long-polling", dojox.cometd.longPollTransport.check, dojox.cometd.longPollTransport);
+dojox.cometd.connectionTypes.register("callback-polling", dojox.cometd.callbackPollTransport.check, dojox.cometd.callbackPollTransport);

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/ArrayList.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/ArrayList.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/ArrayList.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,136 @@
+dojo.provide("dojox.collections.ArrayList");
+dojo.require("dojox.collections");
+
+dojox.collections.ArrayList=function(/* array? */arr){
+	//	summary
+	//	Returns a new object of type dojox.collections.ArrayList
+	var items=[];
+	if(arr) items=items.concat(arr);
+	this.count=items.length;
+	this.add=function(/* object */obj){
+		//	summary
+		//	Add an element to the collection.
+		items.push(obj);
+		this.count=items.length;
+	};
+	this.addRange=function(/* array */a){
+		//	summary
+		//	Add a range of objects to the ArrayList
+		if(a.getIterator){
+			var e=a.getIterator();
+			while(!e.atEnd()){
+				this.add(e.get());
+			}
+			this.count=items.length;
+		}else{
+			for(var i=0; i<a.length; i++){
+				items.push(a[i]);
+			}
+			this.count=items.length;
+		}
+	};
+	this.clear=function(){
+		//	summary
+		//	Clear all elements out of the collection, and reset the count.
+		items.splice(0, items.length);
+		this.count=0;
+	};
+	this.clone=function(){
+		//	summary
+		//	Clone the array list
+		return new dojox.collections.ArrayList(items);	//	dojox.collections.ArrayList
+	};
+	this.contains=function(/* object */obj){
+		//	summary
+		//	Check to see if the passed object is a member in the ArrayList
+		for(var i=0; i < items.length; i++){
+			if(items[i] == obj) {
+				return true;	//	bool
+			}
+		}
+		return false;	//	bool
+	};
+	this.forEach=function(/* function */ fn, /* object? */ scope){
+		//	summary
+		//	functional iterator, following the mozilla spec.
+		var s=scope||dj_global;
+		if(Array.forEach){
+			Array.forEach(items, fn, s);
+		}else{
+			for(var i=0; i<items.length; i++){
+				fn.call(s, items[i], i, items);
+			}
+		}
+	};
+	this.getIterator=function(){
+		//	summary
+		//	Get an Iterator for this object
+		return new dojox.collections.Iterator(items);	//	dojox.collections.Iterator
+	};
+	this.indexOf=function(/* object */obj){
+		//	summary
+		//	Return the numeric index of the passed object; will return -1 if not found.
+		for(var i=0; i < items.length; i++){
+			if(items[i] == obj) {
+				return i;	//	int
+			}
+		}
+		return -1;	// int
+	};
+	this.insert=function(/* int */ i, /* object */ obj){
+		//	summary
+		//	Insert the passed object at index i
+		items.splice(i,0,obj);
+		this.count=items.length;
+	};
+	this.item=function(/* int */ i){
+		//	summary
+		//	return the element at index i
+		return items[i];	//	object
+	};
+	this.remove=function(/* object */obj){
+		//	summary
+		//	Look for the passed object, and if found, remove it from the internal array.
+		var i=this.indexOf(obj);
+		if(i >=0) {
+			items.splice(i,1);
+		}
+		this.count=items.length;
+	};
+	this.removeAt=function(/* int */ i){
+		//	summary
+		//	return an array with function applied to all elements
+		items.splice(i,1);
+		this.count=items.length;
+	};
+	this.reverse=function(){
+		//	summary
+		//	Reverse the internal array
+		items.reverse();
+	};
+	this.sort=function(/* function? */ fn){
+		//	summary
+		//	sort the internal array
+		if(fn){
+			items.sort(fn);
+		}else{
+			items.sort();
+		}
+	};
+	this.setByIndex=function(/* int */ i, /* object */ obj){
+		//	summary
+		//	Set an element in the array by the passed index.
+		items[i]=obj;
+		this.count=items.length;
+	};
+	this.toArray=function(){
+		//	summary
+		//	Return a new array with all of the items of the internal array concatenated.
+		return [].concat(items);
+	}
+	this.toString=function(/* string */ delim){
+		//	summary
+		//	implementation of toString, follows [].toString();
+		return items.join((delim||","));
+	};
+};

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/BinaryTree.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/BinaryTree.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/BinaryTree.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,207 @@
+dojo.provide("dojox.collections.BinaryTree");
+dojo.require("dojox.collections");
+
+dojox.collections.BinaryTree=function(data){
+	function node(data, rnode, lnode){
+		this.value=data||null;
+		this.right=rnode||null;
+		this.left=lnode||null;
+		this.clone=function(){
+			var c=new node();
+			if(this.value.value){
+				c.value=this.value.clone();
+			}else{ 
+				c.value=this.value;
+			}
+			if(this.left!=null){
+				c.left=this.left.clone();
+			}
+			if(this.right!=null){
+				c.right=this.right.clone();
+			}
+			return c;
+		}
+		this.compare=function(n){
+			if(this.value>n.value){ return 1; }
+			if(this.value<n.value){ return -1; }
+			return 0;
+		}
+		this.compareData=function(d){
+			if(this.value>d){ return 1; }
+			if(this.value<d){ return -1; }
+			return 0;
+		}
+	}
+
+	function inorderTraversalBuildup(current, a){
+		if(current){
+			inorderTraversalBuildup(current.left, a);
+			a.push(current.value);
+			inorderTraversalBuildup(current.right, a);
+		}
+	}
+
+	function preorderTraversal(current, sep){
+		var s="";
+		if (current){
+			s=current.value.toString() + sep;
+			s+=preorderTraversal(current.left, sep);
+			s+=preorderTraversal(current.right, sep);
+		}
+		return s;
+	}
+	function inorderTraversal(current, sep){
+		var s="";
+		if (current){
+			s=inorderTraversal(current.left, sep);
+			s+=current.value.toString() + sep;
+			s+=inorderTraversal(current.right, sep);
+		}
+		return s;
+	}
+	function postorderTraversal(current, sep){
+		var s="";
+		if (current){
+			s=postorderTraversal(current.left, sep);
+			s+=postorderTraversal(current.right, sep);
+			s+=current.value.toString() + sep;
+		}
+		return s;
+	}
+	
+	function searchHelper(current, data){
+		if(!current){ return null; }
+		var i=current.compareData(data);
+		if(i==0){ return current; }
+		if(i>0){ return searchHelper(current.left, data); }
+		else{ return searchHelper(current.right, data); }
+	}
+
+	this.add=function(data){
+		var n=new node(data);
+		var i;
+		var current=root;
+		var parent=null;
+		while(current){
+			i=current.compare(n);
+			if(i==0){ return; }
+			parent=current;
+			if(i>0){ current=current.left; }
+			else{ current=current.right; }
+		}
+		this.count++;
+		if(!parent){
+			root=n;
+		}else{
+			i=parent.compare(n);
+			if(i>0){ 
+				parent.left=n;
+			}else{
+				parent.right=n;
+			}
+		}
+	};
+	this.clear=function(){
+		root=null;
+		this.count=0;
+	};
+	this.clone=function(){
+		var c=new dojox.collections.BinaryTree();
+		var itr=this.getIterator();
+		while(!itr.atEnd()){
+			c.add(itr.get());
+		}
+		return c;
+	};
+	this.contains=function(data){
+		return this.search(data) != null;
+	};
+	this.deleteData=function(data){
+		var current=root;
+		var parent=null;
+		var i=current.compareData(data);
+		while(i!=0&&current!=null){
+			if(i>0){
+				parent=current;
+				current=current.left;
+			}else if(i<0){
+				parent=current;
+				current=current.right;
+			}
+			i=current.compareData(data);
+		}
+		if(!current){ return; }
+		this.count--;
+		if(!current.right){
+			if(!parent){ 
+				root=current.left;
+			}else{
+				i=parent.compare(current);
+				if(i>0){ parent.left=current.left; }
+				else if(i<0){ parent.right=current.left; }
+			}
+		} 
+		else if(!current.right.left){
+			if(!parent){
+				root=current.right;
+			}else{
+				i=parent.compare(current);
+				if(i>0){ parent.left=current.right; }
+				else if(i<0){ parent.right=current.right; }
+			}
+		}
+		else{
+			var leftmost=current.right.left;
+			var lmParent=current.right;
+			while(leftmost.left!=null){
+				lmParent=leftmost;
+				leftmost=leftmost.left;
+			}
+			lmParent.left=leftmost.right;
+			leftmost.left=current.left;
+			leftmost.right=current.right;
+			if(!parent){ 
+				root=leftmost;
+			}else{
+				i=parent.compare(current);
+				if(i>0){ parent.left=leftmost; }
+				else if(i<0){ parent.right=leftmost; }
+			}
+		}
+	};
+	this.getIterator=function(){
+		var a=[];
+		inorderTraversalBuildup(root, a);
+		return new dojox.collections.Iterator(a);
+	};
+	this.search=function(data){
+		return searchHelper(root, data);
+	};
+	this.toString=function(order, sep){
+		if(!order){ order=dojox.collections.BinaryTree.TraversalMethods.Inorder; }
+		if(!sep){ sep=","; }
+		var s="";
+		switch(order){
+			case dojox.collections.BinaryTree.TraversalMethods.Preorder:
+				s=preorderTraversal(root, sep);
+				break;
+			case dojox.collections.BinaryTree.TraversalMethods.Inorder:
+				s=inorderTraversal(root, sep);
+				break;
+			case dojox.collections.BinaryTree.TraversalMethods.Postorder:
+				s=postorderTraversal(root, sep);
+				break;
+		};
+		if(s.length==0){ return ""; }
+		else{ return s.substring(0, s.length - sep.length); }
+	};
+
+	this.count=0;
+	var root=this.root=null;
+	if(data){
+		this.add(data);
+	}
+}
+dojox.collections.BinaryTree.TraversalMethods={
+	Preorder: 1, Inorder: 2, Postorder: 3
+};

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/Dictionary.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/Dictionary.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/Dictionary.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,119 @@
+dojo.provide("dojox.collections.Dictionary");
+dojo.require("dojox.collections");
+
+dojox.collections.Dictionary=function(/* dojox.collections.Dictionary? */dictionary){
+	//	summary
+	//	Returns an object of type dojox.collections.Dictionary
+	var items={};
+	this.count=0;
+
+	//	comparator for property addition and access.
+	var testObject={};
+
+	this.add=function(/* string */k, /* object */v){
+		//	summary
+		//	Add a new item to the Dictionary.
+		var b=(k in items);
+		items[k]=new dojox.collections.DictionaryEntry(k,v);
+		if(!b){
+			this.count++;
+		}
+	};
+	this.clear=function(){
+		//	summary
+		//	Clears the internal dictionary.
+		items={};
+		this.count=0;
+	};
+	this.clone=function(){
+		//	summary
+		//	Returns a new instance of dojox.collections.Dictionary; note the the dictionary is a clone but items might not be.
+		return new dojox.collections.Dictionary(this);	//	dojox.collections.Dictionary
+	};
+	this.contains=this.containsKey=function(/* string */k){
+		//	summary
+		//	Check to see if the dictionary has an entry at key "k".
+		if(testObject[k]){
+			return false;			// bool
+		}
+		return (items[k]!=null);	//	bool
+	};
+	this.containsValue=function(/* object */v){
+		//	summary
+		//	Check to see if the dictionary has an entry with value "v".
+		var e=this.getIterator();
+		while(e.get()){
+			if(e.element.value==v){
+				return true;	//	bool
+			}
+		}
+		return false;	//	bool
+	};
+	this.entry=function(/* string */k){
+		//	summary
+		//	Accessor method; similar to dojox.collections.Dictionary.item but returns the actual Entry object.
+		return items[k];	//	dojox.collections.DictionaryEntry
+	};
+	this.forEach=function(/* function */ fn, /* object? */ scope){
+		//	summary
+		//	functional iterator, following the mozilla spec.
+		var a=[];	//	Create an indexing array
+		for(var p in items) {
+			if(!testObject[p]){
+				a.push(items[p]);	//	fill it up
+			}
+		}
+		var s=scope||dj_global;
+		if(Array.forEach){
+			Array.forEach(a, fn, s);
+		}else{
+			for(var i=0; i<a.length; i++){
+				fn.call(s, a[i], i, a);
+			}
+		}
+	};
+	this.getKeyList=function(){
+		//	summary
+		//	Returns an array of the keys in the dictionary.
+		return (this.getIterator()).map(function(entry){ 
+			return entry.key; 
+		});	//	array
+	};
+	this.getValueList=function(){
+		//	summary
+		//	Returns an array of the values in the dictionary.
+		return (this.getIterator()).map(function(entry){ 
+			return entry.value; 
+		});	//	array
+	};
+	this.item=function(/* string */k){
+		//	summary
+		//	Accessor method.
+		if(k in items){
+			return items[k].valueOf();	//	object
+		}
+		return undefined;	//	object
+	};
+	this.getIterator=function(){
+		//	summary
+		//	Gets a dojox.collections.DictionaryIterator for iteration purposes.
+		return new dojox.collections.DictionaryIterator(items);	//	dojox.collections.DictionaryIterator
+	};
+	this.remove=function(/* string */k){
+		//	summary
+		//	Removes the item at k from the internal collection.
+		if(k in items && !testObject[k]){
+			delete items[k];
+			this.count--;
+			return true;	//	bool
+		}
+		return false;	//	bool
+	};
+
+	if (dictionary){
+		var e=dictionary.getIterator();
+		while(e.get()) {
+			 this.add(e.element.key, e.element.value);
+		}
+	}
+};

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/Queue.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/Queue.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/Queue.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,77 @@
+dojo.provide("dojox.collections.Queue");
+dojo.require("dojox.collections");
+
+dojox.collections.Queue=function(/* array? */arr){
+	//	summary
+	//	return an object of type dojox.collections.Queue
+	var q=[];
+	if (arr){
+		q=q.concat(arr);
+	}
+	this.count=q.length;
+	this.clear=function(){
+		//	summary
+		//	clears the internal collection
+		q=[];
+		this.count=q.length;
+	};
+	this.clone=function(){
+		//	summary
+		//	creates a new Queue based on this one
+		return new dojox.collections.Queue(q);	//	dojox.collections.Queue
+	};
+	this.contains=function(/* object */ o){
+		//	summary
+		//	Check to see if the passed object is an element in this queue
+		for(var i=0; i<q.length; i++){
+			if (q[i]==o){
+				return true;	//	bool
+			}
+		}
+		return false;	//	bool
+	};
+	this.copyTo=function(/* array */ arr, /* int */ i){
+		//	summary
+		//	Copy the contents of this queue into the passed array at index i.
+		arr.splice(i,0,q);
+	};
+	this.dequeue=function(){
+		//	summary
+		//	shift the first element off the queue and return it
+		var r=q.shift();
+		this.count=q.length;
+		return r;	//	object
+	};
+	this.enqueue=function(/* object */ o){
+		//	summary
+		//	put the passed object at the end of the queue
+		this.count=q.push(o);
+	};
+	this.forEach=function(/* function */ fn, /* object? */ scope){
+		//	summary
+		//	functional iterator, following the mozilla spec.
+		var s=scope||dj_global;
+		if(Array.forEach){
+			Array.forEach(q, fn, s);
+		}else{
+			for(var i=0; i<q.length; i++){
+				fn.call(s, q[i], i, q);
+			}
+		}
+	};
+	this.getIterator=function(){
+		//	summary
+		//	get an Iterator based on this queue.
+		return new dojox.collections.Iterator(q);	//	dojox.collections.Iterator
+	};
+	this.peek=function(){
+		//	summary
+		//	get the next element in the queue without altering the queue.
+		return q[0];
+	};
+	this.toArray=function(){
+		//	summary
+		//	return an array based on the internal array of the queue.
+		return [].concat(q);
+	};
+};

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/README
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/README	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/README	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,39 @@
+-------------------------------------------------------------------------------
+DojoX Collections
+-------------------------------------------------------------------------------
+Version 0.9
+Release date: 05/27/2007
+-------------------------------------------------------------------------------
+Project state: stable
+-------------------------------------------------------------------------------
+Project authors
+	Tom Trenka (ttrenka at gmail.com)
+-------------------------------------------------------------------------------
+Project description
+
+DojoX Collections is the port of the original Dojo 0.4.x collection classes.
+It is intended for use by people who are looking for a little bit more 
+functionality out of common collections, like ArrayLists or Dictionaries.
+
+Included are the Iterator and DictionaryIterator classes, both of which can
+operate on standard arrays and objects (respectively).
+-------------------------------------------------------------------------------
+Dependencies:
+
+DojoX Collections has no dependencies, outside of Dojo Core.
+-------------------------------------------------------------------------------
+Documentation
+
+See the API documentation for Dojo (http://dojotoolkit.org/api).
+-------------------------------------------------------------------------------
+Installation instructions
+
+Grab the following from the Dojo SVN Repository:
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/collections.js
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/collections/*
+
+Install into the following directory structure:
+/dojox/collections/
+
+...which should be at the same level as your Dojo checkout.
+-------------------------------------------------------------------------------

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/Set.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/Set.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/Set.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,86 @@
+dojo.provide("dojox.collections.Set");
+dojo.require("dojox.collections");
+dojo.require("dojox.collections.ArrayList");
+
+(function(){
+	var dxc=dojox.collections;
+	dxc.Set=new (function(){
+		function conv(arr){
+			if(arr.constructor==Array){
+				return new dojox.collections.ArrayList(arr);	//	dojox.collections.ArrayList
+			}
+			return arr;		//	dojox.collections.ArrayList
+		}
+		this.union = function(/* array */setA, /* array */setB){
+			//	summary
+			//	Return the union of the two passed sets.
+			setA=conv(setA);
+			setB=conv(setB);
+			var result = new dojox.collections.ArrayList(setA.toArray());
+			var e = setB.getIterator();
+			while(!e.atEnd()){
+				var item=e.get();
+				if(!result.contains(item)){
+					result.add(item);
+				}
+			}
+			return result;	//	dojox.collections.ArrayList
+		};
+		this.intersection = function(/* array */setA, /* array */setB){
+			//	summary
+			//	Return the intersection of the two passed sets.
+			setA=conv(setA);
+			setB=conv(setB);
+			var result = new dojox.collections.ArrayList();
+			var e = setB.getIterator();
+			while(!e.atEnd()){
+				var item=e.get();
+				if(setA.contains(item)){
+					result.add(item);
+				}
+			}
+			return result;	//	dojox.collections.ArrayList
+		};
+		this.difference = function(/* array */setA, /* array */setB){
+			//	summary
+			//	Returns everything in setA that is not in setB.
+			setA=conv(setA);
+			setB=conv(setB);
+			var result = new dojox.collections.ArrayList();
+			var e=setA.getIterator();
+			while(!e.atEnd()){
+				var item=e.get();
+				if(!setB.contains(item)){
+					result.add(item);
+				}
+			}
+			return result;	//	dojox.collections.ArrayList
+		};
+		this.isSubSet = function(/* array */setA, /* array */setB) {
+			//	summary
+			//	Returns if set B is a subset of set A.
+			setA=conv(setA);
+			setB=conv(setB);
+			var e = setA.getIterator();
+			while(!e.atEnd()){
+				if(!setB.contains(e.get())){
+					return false;	//	boolean
+				}
+			}
+			return true;	//	boolean
+		};
+		this.isSuperSet = function(/* array */setA, /* array */setB){
+			//	summary
+			//	Returns if set B is a superset of set A.
+			setA=conv(setA);
+			setB=conv(setB);
+			var e = setB.getIterator();
+			while(!e.atEnd()){
+				if(!setA.contains(e.get())){
+					return false;	//	boolean
+				}
+			}
+			return true;	//	boolean
+		};
+	})();
+})();

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/SortedList.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/SortedList.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/SortedList.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,201 @@
+dojo.provide("dojox.collections.SortedList");
+dojo.require("dojox.collections");
+
+dojox.collections.SortedList=function(/* object? */ dictionary){
+	//	summary
+	//	creates a collection that acts like a dictionary but is also internally sorted.
+	//	Note that the act of adding any elements forces an internal resort, making this object potentially slow.
+	var _this=this;
+	var items={};
+	var q=[];
+	var sorter=function(a,b){
+		if (a.key > b.key) return 1;
+		if (a.key < b.key) return -1;
+		return 0;
+	};
+	var build=function(){
+		q=[];
+		var e=_this.getIterator();
+		while (!e.atEnd()){
+			q.push(e.get());
+		}
+		q.sort(sorter);
+	};
+	var testObject={};
+
+	this.count=q.length;
+	this.add=function(/* string */ k,/* object */v){
+		//	summary
+		//	add the passed value to the dictionary at location k
+		if (!items[k]) {
+			items[k]=new dojox.collections.DictionaryEntry(k,v);
+			this.count=q.push(items[k]);
+			q.sort(sorter);
+		}
+	};
+	this.clear=function(){
+		//	summary
+		//	clear the internal collections
+		items={};
+		q=[];
+		this.count=q.length;
+	};
+	this.clone=function(){
+		//	summary
+		//	create a clone of this sorted list
+		return new dojox.collections.SortedList(this);	//	dojox.collections.SortedList
+	};
+	this.contains=this.containsKey=function(/* string */ k){
+		//	summary
+		//	Check to see if the list has a location k
+		if(testObject[k]){
+			return false;			//	bool
+		}
+		return (items[k]!=null);	//	bool
+	};
+	this.containsValue=function(/* object */ o){
+		//	summary
+		//	Check to see if this list contains the passed object
+		var e=this.getIterator();
+		while (!e.atEnd()){
+			var item=e.get();
+			if(item.value==o){ 
+				return true;	//	bool
+			}
+		}
+		return false;	//	bool
+	};
+	this.copyTo=function(/* array */ arr, /* int */ i){
+		//	summary
+		//	copy the contents of the list into array arr at index i
+		var e=this.getIterator();
+		var idx=i;
+		while(!e.atEnd()){
+			arr.splice(idx,0,e.get());
+			idx++;
+		}
+	};
+	this.entry=function(/* string */ k){
+		//	summary
+		//	return the object at location k
+		return items[k];	//	dojox.collections.DictionaryEntry
+	};
+	this.forEach=function(/* function */ fn, /* object? */ scope){
+		//	summary
+		//	functional iterator, following the mozilla spec.
+		var s=scope||dj_global;
+		if(Array.forEach){
+			Array.forEach(q, fn, s);
+		}else{
+			for(var i=0; i<q.length; i++){
+				fn.call(s, q[i], i, q);
+			}
+		}
+	};
+	this.getByIndex=function(/* int */ i){
+		//	summary
+		//	return the item at index i
+		return q[i].valueOf();	//	object
+	};
+	this.getIterator=function(){
+		//	summary
+		//	get an iterator for this object
+		return new dojox.collections.DictionaryIterator(items);	//	dojox.collections.DictionaryIterator
+	};
+	this.getKey=function(/* int */ i){
+		//	summary
+		//	return the key of the item at index i
+		return q[i].key;
+	};
+	this.getKeyList=function(){
+		//	summary
+		//	return an array of the keys set in this list
+		var arr=[];
+		var e=this.getIterator();
+		while (!e.atEnd()){
+			arr.push(e.get().key);
+		}
+		return arr;	//	array
+	};
+	this.getValueList=function(){
+		//	summary
+		//	return an array of values in this list
+		var arr=[];
+		var e=this.getIterator();
+		while (!e.atEnd()){
+			arr.push(e.get().value);
+		}
+		return arr;	//	array
+	};
+	this.indexOfKey=function(/* string */ k){
+		//	summary
+		//	return the index of the passed key.
+		for (var i=0; i<q.length; i++){
+			if (q[i].key==k){
+				return i;	//	int
+			}
+		}
+		return -1;	//	int
+	};
+	this.indexOfValue=function(/* object */ o){
+		//	summary
+		//	return the first index of object o
+		for (var i=0; i<q.length; i++){
+			if (q[i].value==o){
+				return i;	//	int
+			}
+		}
+		return -1;	//	int
+	};
+	this.item=function(/* string */ k){
+		// 	summary
+		//	return the value of the object at location k.
+		if(k in items && !testObject[k]){
+			return items[k].valueOf();	//	object
+		}
+		return undefined;	//	object
+	};
+	this.remove=function(/* string */k){
+		// 	summary
+		//	remove the item at location k and rebuild the internal collections.
+		delete items[k];
+		build();
+		this.count=q.length;
+	};
+	this.removeAt=function(/* int */ i){
+		//	summary
+		//	remove the item at index i, and rebuild the internal collections.
+		delete items[q[i].key];
+		build();
+		this.count=q.length;
+	};
+	this.replace=function(/* string */ k, /* object */ v){
+		//	summary
+		//	Replace an existing item if it's there, and add a new one if not.
+		if (!items[k]){
+			//	we're adding a new object, return false
+			this.add(k,v);
+			return false; // bool
+		}else{
+			//	we're replacing an object, return true
+			items[k]=new dojox.collections.DictionaryEntry(k,v);
+			build();
+			return true; // bool
+		}
+	};
+	this.setByIndex=function(/* int */ i, /* object */ o){
+		//	summary
+		//	set an item by index
+		items[q[i].key].value=o;
+		build();
+		this.count=q.length;
+	};
+	if (dictionary){
+		var e=dictionary.getIterator();
+		while (!e.atEnd()){
+			var item=e.get();
+			q[q.length]=items[item.key]=new dojox.collections.DictionaryEntry(item.key,item.value);
+		}
+		q.sort(sorter);
+	}
+}

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/Stack.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/Stack.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/Stack.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,75 @@
+dojo.provide("dojox.collections.Stack");
+dojo.require("dojox.collections");
+
+dojox.collections.Stack=function(/* array? */arr){
+	//	summary
+	//	returns an object of type dojox.collections.Stack
+	var q=[];
+	if (arr) q=q.concat(arr);
+	this.count=q.length;
+	this.clear=function(){
+		//	summary
+		//	Clear the internal array and reset the count
+		q=[];
+		this.count=q.length;
+	};
+	this.clone=function(){
+		//	summary
+		//	Create and return a clone of this Stack
+		return new dojox.collections.Stack(q);
+	};
+	this.contains=function(/* object */o){
+		//	summary
+		//	check to see if the stack contains object o
+		for (var i=0; i<q.length; i++){
+			if (q[i] == o){
+				return true;	//	bool
+			}
+		}
+		return false;	//	bool
+	};
+	this.copyTo=function(/* array */ arr, /* int */ i){
+		//	summary
+		//	copy the stack into array arr at index i
+		arr.splice(i,0,q);
+	};
+	this.forEach=function(/* function */ fn, /* object? */ scope){
+		//	summary
+		//	functional iterator, following the mozilla spec.
+		var s=scope||dj_global;
+		if(Array.forEach){
+			Array.forEach(q, fn, s);
+		}else{
+			for(var i=0; i<q.length; i++){
+				fn.call(s, q[i], i, q);
+			}
+		}
+	};
+	this.getIterator=function(){
+		//	summary
+		//	get an iterator for this collection
+		return new dojox.collections.Iterator(q);	//	dojox.collections.Iterator
+	};
+	this.peek=function(){
+		//	summary
+		//	Return the next item without altering the stack itself.
+		return q[(q.length-1)];	//	object
+	};
+	this.pop=function(){
+		//	summary
+		//	pop and return the next item on the stack
+		var r=q.pop();
+		this.count=q.length;
+		return r;	//	object
+	};
+	this.push=function(/* object */ o){
+		//	summary
+		//	Push object o onto the stack
+		this.count=q.push(o);
+	};
+	this.toArray=function(){
+		//	summary
+		//	create and return an array based on the internal collection
+		return [].concat(q);	//	array
+	};
+}

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/_base.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/_base.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/_base.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,114 @@
+dojo.provide("dojox.collections._base");
+
+dojox.collections.DictionaryEntry=function(/* string */k, /* object */v){
+	//	summary
+	//	return an object of type dojox.collections.DictionaryEntry
+	this.key=k;
+	this.value=v;
+	this.valueOf=function(){ 
+		return this.value; 	//	object
+	};
+	this.toString=function(){ 
+		return String(this.value);	//	string 
+	};
+}
+
+/*	Iterators
+ *	The collections.Iterators (Iterator and DictionaryIterator) are built to
+ *	work with the Collections included in this module.  However, they *can*
+ *	be used with arrays and objects, respectively, should one choose to do so.
+ */
+dojox.collections.Iterator=function(/* array */arr){
+	//	summary
+	//	return an object of type dojox.collections.Iterator
+	var a=arr;
+	var position=0;
+	this.element=a[position]||null;
+	this.atEnd=function(){
+		//	summary
+		//	Test to see if the internal cursor has reached the end of the internal collection.
+		return (position>=a.length);	//	bool
+	};
+	this.get=function(){
+		//	summary
+		//	Get the next member in the collection.
+		if(this.atEnd()){
+			return null;		//	object
+		}
+		this.element=a[position++];
+		return this.element;	//	object
+	};
+	this.map=function(/* function */fn, /* object? */scope){
+		//	summary
+		//	Functional iteration with optional scope.
+		var s=scope||dojo.global;
+		if(Array.map){
+			return Array.map(a,fn,s);	//	array
+		}else{
+			var arr=[];
+			for(var i=0; i<a.length; i++){
+				arr.push(fn.call(s,a[i]));
+			}
+			return arr;		//	array
+		}
+	};
+	this.reset=function(){
+		//	summary
+		//	reset the internal cursor.
+		position=0;
+		this.element=a[position];
+	};
+}
+
+/*	Notes:
+ *	The DictionaryIterator no longer supports a key and value property;
+ *	the reality is that you can use this to iterate over a JS object
+ *	being used as a hashtable.
+ */
+dojox.collections.DictionaryIterator=function(/* object */obj){
+	//	summary
+	//	return an object of type dojox.collections.DictionaryIterator
+	var a=[];	//	Create an indexing array
+	var testObject={};
+	for(var p in obj){
+		if(!testObject[p]){
+			a.push(obj[p]);	//	fill it up
+		}
+	}
+	var position=0;
+	this.element=a[position]||null;
+	this.atEnd=function(){
+		//	summary
+		//	Test to see if the internal cursor has reached the end of the internal collection.
+		return (position>=a.length);	//	bool
+	};
+	this.get=function(){
+		//	summary
+		//	Get the next member in the collection.
+		if(this.atEnd()){
+			return null;		//	object
+		}
+		this.element=a[position++];
+		return this.element;	//	object
+	};
+	this.map=function(/* function */fn, /* object? */scope){
+		//	summary
+		//	Functional iteration with optional scope.
+		var s=scope||dojo.global;
+		if(Array.map){
+			return Array.map(a,fn,s);	//	array
+		}else{
+			var arr=[];
+			for(var i=0; i<a.length; i++){
+				arr.push(fn.call(s,a[i]));
+			}
+			return arr;		//	array
+		}
+	};
+	this.reset=function() { 
+		//	summary
+		//	reset the internal cursor.
+		position=0; 
+		this.element=a[position];
+	};
+};

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/tests/ArrayList.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/tests/ArrayList.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/tests/ArrayList.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,79 @@
+dojo.provide("dojox.collections.tests.ArrayList");
+dojo.require("dojox.collections.ArrayList");
+
+tests.register("dojox.collections.tests.ArrayList", [
+	function testCtor(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		t.assertEqual(4, al.count);
+	},
+	function testAdd(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		al.add("carp");
+		t.assertEqual("foo,bar,test,bull,carp", al.toString());
+		al.addRange(["oof","rab"]);
+		t.assertEqual("foo,bar,test,bull,carp,oof,rab", al.toString());
+	},
+	function testClear(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		al.clear();
+		t.assertEqual(0, al.count);
+	},
+	function testClone(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		var cloned=al.clone();
+		t.assertEqual(al.toString(), cloned.toString());
+	},
+	function testContains(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		t.assertTrue(al.contains("bar"));
+		t.assertFalse(al.contains("faz"));
+	},
+	function testGetIterator(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		var itr=al.getIterator();
+		while(!itr.atEnd()){
+			itr.get();
+		}
+		t.assertEqual("bull", itr.element);
+	},
+	function testIndexOf(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		t.assertEqual(1, al.indexOf("bar"));
+	},
+	function testInsert(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		al.insert(2, "baz");
+		t.assertEqual(2, al.indexOf("baz"));
+	},
+	function testItem(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		t.assertEqual("test", al.item(2));
+	},
+	function testRemove(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		al.remove("bar");
+		t.assertEqual("foo,test,bull", al.toString());
+		t.assertEqual(3, al.count);
+	},
+	function testRemoveAt(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		al.removeAt(3);
+		t.assertEqual("foo,bar,test", al.toString());
+		t.assertEqual(3, al.count);
+	},
+	function testReverse(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		al.reverse();
+		t.assertEqual("bull,test,bar,foo", al.toString());
+	},
+	function testSort(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		al.sort();
+		t.assertEqual("bar,bull,foo,test", al.toString());
+	},
+	function testToArray(t){
+		var al=new dojox.collections.ArrayList(["foo","bar","test","bull"]);
+		var a=al.toArray();
+		t.assertEqual(a.join(","), al.toString());
+	}
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/tests/BinaryTree.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/tests/BinaryTree.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/tests/BinaryTree.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,79 @@
+dojo.provide("dojox.collections.tests.BinaryTree");
+dojo.require("dojox.collections.BinaryTree");
+
+tests.register("dojox.collections.tests.BinaryTree", [
+	function testCtor(t){
+		var bt=new dojox.collections.BinaryTree("foo");
+		t.assertTrue(bt instanceof dojox.collections.BinaryTree);
+	},
+	function testAdd(t){
+		var bt=new dojox.collections.BinaryTree("foo");
+		bt.add("bar");
+		bt.add("baz");
+		bt.add("buck");
+		bt.add("shot");
+		bt.add("apple");
+		t.assertEqual("apple,bar,baz,buck,foo,shot",bt.toString());
+	},
+	function testClear(t){
+		var bt=new dojox.collections.BinaryTree("foo");
+		bt.add("bar");
+		bt.add("baz");
+		bt.add("buck");
+		bt.add("shot");
+		bt.add("apple");
+		bt.clear();
+		t.assertEqual(bt.count, 0);
+	},
+	function testClone(t){
+		var bt=new dojox.collections.BinaryTree("foo");
+		bt.add("bar");
+		bt.add("baz");
+		bt.add("buck");
+		bt.add("shot");
+		bt.add("apple");
+		var bt2=bt.clone();
+		t.assertEqual(bt2.count, 6);
+		t.assertEqual(bt.toString(), bt2.toString());
+	},
+	function testContains(t){
+		var bt=new dojox.collections.BinaryTree("foo");
+		bt.add("bar");
+		bt.add("baz");
+		bt.add("buck");
+		bt.add("shot");
+		bt.add("apple");
+		t.assertTrue(bt.contains("buck"));
+		t.assertFalse(bt.contains("duck"));
+	},
+	function testDeleteData(t){
+		var bt=new dojox.collections.BinaryTree("foo");
+		bt.add("bar");
+		bt.add("baz");
+		bt.add("buck");
+		bt.add("shot");
+		bt.add("apple");
+		bt.deleteData("buck");
+		t.assertEqual("apple,bar,baz,foo,shot",bt.toString());
+	},
+	function testGetIterator(t){
+		var bt=new dojox.collections.BinaryTree("foo");
+		bt.add("bar");
+		bt.add("baz");
+		bt.add("buck");
+		bt.add("shot");
+		bt.add("apple");
+		var itr=bt.getIterator();
+		while(!itr.atEnd()){ itr.get(); }
+		t.assertEqual("shot", itr.element);
+	},
+	function testSearch(t){
+		var bt=new dojox.collections.BinaryTree("foo");
+		bt.add("bar");
+		bt.add("baz");
+		bt.add("buck");
+		bt.add("shot");
+		bt.add("apple");
+		t.assertEqual("buck", bt.search("buck").value);
+	}
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Dictionary.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Dictionary.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Dictionary.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,78 @@
+dojo.provide("dojox.collections.tests.Dictionary");
+dojo.require("dojox.collections.Dictionary");
+
+tests.register("dojox.collections.tests.Dictionary", [
+	function testCtor(t){
+		var d=new dojox.collections.Dictionary();
+		t.assertTrue(d instanceof dojox.collections.Dictionary);
+	},
+	function testAdd(t){
+		var d=new dojox.collections.Dictionary();
+		d.add("foo","bar");
+		t.assertEqual("bar", d.item("foo").valueOf());
+	},
+	function testClear(t){
+		var d=new dojox.collections.Dictionary();
+		d.add("foo","bar");
+		d.clear()
+		t.assertEqual(0, d.count);
+	},
+	function testClone(t){
+		var d=new dojox.collections.Dictionary();
+		d.add("baz","fab");
+		d.add("buck","shot");
+		d.add("apple","orange");
+		var d2 = d.clone();
+		t.assertTrue(d2.contains("baz"));
+	},
+	function testContains(t){
+		var d=new dojox.collections.Dictionary();
+		d.add("foo","bar");
+		d.add("baz","fab");
+		d.add("buck","shot");
+		d.add("apple","orange");
+		t.assertTrue(d.contains("baz"));
+	},
+	function testContainsKey(t){
+		var d=new dojox.collections.Dictionary();
+		d.add("foo","bar");
+		d.add("baz","fab");
+		d.add("buck","shot");
+		d.add("apple","orange");
+		t.assertTrue(d.containsKey("buck"));
+	},
+	function testContainsValue(t){
+		var d=new dojox.collections.Dictionary();
+		d.add("foo","bar");
+		d.add("baz","fab");
+		d.add("buck","shot");
+		d.add("apple","orange");
+		t.assertTrue(d.containsValue("shot"));
+	},
+	function testGetKeyList(t){
+		var d=new dojox.collections.Dictionary();
+		d.add("foo","bar");
+		d.add("baz","fab");
+		d.add("buck","shot");
+		d.add("apple","orange");
+		t.assertEqual("foo,baz,buck,apple", d.getKeyList().join(","));
+	},
+	function testGetValueList(t){
+		var d=new dojox.collections.Dictionary();
+		d.add("foo","bar");
+		d.add("baz","fab");
+		d.add("buck","shot");
+		d.add("apple","orange");
+		t.assertEqual("bar,fab,shot,orange", d.getValueList().join(","));
+	},
+	function testRemove(t){
+		var d=new dojox.collections.Dictionary();
+		d.add("foo","bar");
+		d.add("baz","fab");
+		d.add("buck","shot");
+		d.add("apple","orange");
+		d.remove("baz");
+		t.assertEqual(3, d.count);
+		t.assertEqual(undefined, d.item("baz"));
+	}
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Queue.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Queue.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Queue.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,45 @@
+dojo.provide("dojox.collections.tests.Queue");
+dojo.require("dojox.collections.Queue");
+
+tests.register("dojox.collections.tests.Queue", [
+	function testCtor(t){
+		var q=new dojox.collections.Queue(["foo","bar","test","bull"]);
+		t.assertEqual(4, q.count);
+	},
+	function testClear(t){
+		var q=new dojox.collections.Queue(["foo","bar","test","bull"]);
+		q.clear();
+		t.assertEqual(0, q.count);
+	},
+	function testClone(t){
+		var q=new dojox.collections.Queue(["foo","bar","test","bull"]);
+		var cloned=q.clone();
+		t.assertEqual(q.count, cloned.count);
+		t.assertEqual(q.toArray().join(), cloned.toArray().join());
+	},
+	function testContains(t){
+		var q=new dojox.collections.Queue(["foo","bar","test","bull"]);
+		t.assertTrue(q.contains("bar"));
+		t.assertFalse(q.contains("faz"));
+	},
+	function testGetIterator(t){
+		var q=new dojox.collections.Queue(["foo","bar","test","bull"]);
+		var itr=q.getIterator();
+		while(!itr.atEnd()){ itr.get(); }
+		t.assertEqual("bull", itr.element);
+	},
+	function testPeek(t){
+		var q=new dojox.collections.Queue(["foo","bar","test","bull"]);
+		t.assertEqual("foo", q.peek());
+	},
+	function testDequeue(t){
+		var q=new dojox.collections.Queue(["foo","bar","test","bull"]);
+		t.assertEqual("foo", q.dequeue());
+		t.assertEqual("bar,test,bull", q.toArray().join(","));
+	},
+	function testEnqueue(t){
+		var q=new dojox.collections.Queue(["foo","bar","test","bull"]);
+		q.enqueue("bull");
+		t.assertEqual("bull", q.toArray().pop());
+	}
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Set.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Set.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Set.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,31 @@
+dojo.provide("dojox.collections.tests.Set");
+dojo.require("dojox.collections.Set");
+
+(function(){
+	var dxcs=dojox.collections.Set;
+	var a = ["apple","bear","candy","donut","epiphite","frank"];
+	var b = ["bear","epiphite","google","happy","joy"];
+	tests.register("dojox.collections.tests.Set", [
+		function testUnion(t){
+			var union=dxcs.union(a,b);
+			t.assertEqual("apple,bear,candy,donut,epiphite,frank,google,happy,joy", union.toArray().join(','));
+		},
+		function testIntersection(t){
+			var itsn=dxcs.intersection(a,b);
+			t.assertEqual("bear,epiphite", itsn.toArray().join(","));
+			t.assertEqual("bear", dxcs.intersection(["bear","apple"], ["bear"]));
+		},
+		function testDifference(t){
+			var d=dxcs.difference(a,b);
+			t.assertEqual("apple,candy,donut,frank",d.toArray().join(','));
+		},
+		function testIsSubSet(t){
+			t.assertFalse(dxcs.isSubSet(a,["bear","candy"]));
+			t.assertTrue(dxcs.isSubSet(["bear","candy"],a));
+		},
+		function testIsSuperSet(t){
+			t.assertTrue(dxcs.isSuperSet(a,["bear","candy"]));
+			t.assertFalse(dxcs.isSuperSet(["bear","candy"],a));
+		}
+	]);
+})();

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/tests/SortedList.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/tests/SortedList.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/tests/SortedList.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,151 @@
+dojo.provide("dojox.collections.tests.SortedList");
+dojo.require("dojox.collections.SortedList");
+
+tests.register("dojox.collections.tests.SortedList", [
+	function testCtor(t){
+		var sl=new dojox.collections.SortedList();
+		t.assertTrue(sl instanceof dojox.collections.SortedList);
+	},
+	function testAdd(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		t.assertEqual("bar", sl.item("foo").valueOf());
+	},
+	function testClear(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.clear();
+		t.assertEqual(0, sl.count);
+	},
+	function testClone(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		var sl2=sl.clone();
+		t.assertTrue(sl2.contains("baz"));
+	},
+	function testContains(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		t.assertTrue(sl.contains("baz"));
+		t.assertFalse(sl.contains("faz"));
+	},
+	function testContainsKey(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		t.assertTrue(sl.containsKey("buck"));
+		t.assertFalse(sl.containsKey("faz"));
+	},
+	function testContainsValue(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		t.assertTrue(sl.containsValue("shot"));
+		t.assertFalse(sl.containsValue("faz"));
+	},
+	function testGetKeyList(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		t.assertEqual("foo,baz,buck,apple",sl.getKeyList().join(','));
+	},
+	function testGetValueList(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		t.assertEqual("bar,fab,shot,orange",sl.getValueList().join(','));
+	},
+	function testCopyTo(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		var arr=["bek"];
+		sl.copyTo(arr,0);
+		t.assertEqual("bar,fab,shot,orange,bek", arr.join(','));
+	},
+	function testGetByIndex(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		t.assertEqual("shot", sl.getByIndex(2));
+	},
+	function testGetKey(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		t.assertEqual("apple", sl.getKey(0));
+	},
+	function testIndexOfKey(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		t.assertEqual(0, sl.indexOfKey("apple"));
+	},
+	function testIndexOfValue(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		t.assertEqual(3, sl.indexOfValue("bar"));
+	},
+	function testRemove(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		sl.remove("baz");
+		t.assertEqual(3, sl.count);
+		t.assertEqual(undefined, sl.item("baz"));
+	},
+	function testRemoveAt(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		sl.removeAt(2);
+		t.assertEqual(undefined, sl.item("buck"));
+	},
+	function testReplace(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		sl.replace("buck","dollar");
+		t.assertEqual(sl.item("buck").valueOf(), "dollar");
+	},
+	function testSetByIndex(t){
+		var sl=new dojox.collections.SortedList();
+		sl.add("foo","bar");
+		sl.add("baz","fab");
+		sl.add("buck","shot");
+		sl.add("apple","orange");
+		sl.setByIndex(0, "bar");
+		t.assertEqual("bar", sl.getByIndex(0));
+	}
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Stack.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Stack.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/tests/Stack.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,45 @@
+dojo.provide("dojox.collections.tests.Stack");
+dojo.require("dojox.collections.Stack");
+
+tests.register("dojox.collections.tests.Stack", [
+	function testCtor(t){
+		var s=new dojox.collections.Stack(["foo","bar","test","bull"]);
+		t.assertEqual(4, s.count);
+	},
+	function testClear(t){
+		var s=new dojox.collections.Stack(["foo","bar","test","bull"]);
+		s.clear();
+		t.assertEqual(0, s.count);
+	},
+	function testClone(t){
+		var s=new dojox.collections.Stack(["foo","bar","test","bull"]);
+		var cloned=s.clone();
+		t.assertEqual(s.count, cloned.count);
+		t.assertEqual(s.toArray().join(), cloned.toArray().join());
+	},
+	function testContains(t){
+		var s=new dojox.collections.Stack(["foo","bar","test","bull"]);
+		t.assertTrue(s.contains("bar"));
+		t.assertFalse(s.contains("faz"));
+	},
+	function testGetIterator(t){
+		var s=new dojox.collections.Stack(["foo","bar","test","bull"]);
+		var itr=s.getIterator();
+		while(!itr.atEnd()){ itr.get(); }
+		t.assertEqual("bull", itr.element);
+	},
+	function testPeek(t){
+		var s=new dojox.collections.Stack(["foo","bar","test","bull"]);
+		t.assertEqual("bull", s.peek());
+	},
+	function testPop(t){
+		var s=new dojox.collections.Stack(["foo","bar","test","bull"]);
+		t.assertEqual("bull", s.pop());
+		t.assertEqual("test", s.pop());
+	},
+	function testPush(t){
+		var s=new dojox.collections.Stack(["foo","bar","test","bull"]);
+		s.push("bug");
+		t.assertEqual("bug", s.peek());
+	}
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/tests/_base.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/tests/_base.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/tests/_base.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,80 @@
+dojo.provide("dojox.collections.tests._base");
+dojo.require("dojox.collections");
+
+tests.register("dojox.collections.tests._base", [
+	function testDictionaryEntry(t){
+		var d=new dojox.collections.DictionaryEntry("foo","bar");
+		t.assertEqual("bar", d.valueOf());
+		t.assertEqual("bar", d.toString());
+	},
+
+	function testIterator(t){
+		var itr=new dojox.collections.Iterator(["foo","bar","baz","zoo"]);
+		t.assertEqual("foo", itr.element);	//	test initialization
+		t.assertTrue(!itr.atEnd());
+		t.assertEqual("foo", itr.get());	//	make sure the first get doesn't advance.
+		t.assertEqual("bar", itr.get());
+		t.assertEqual("baz", itr.get());
+		t.assertEqual("zoo", itr.get());
+		t.assertTrue(itr.atEnd());
+		t.assertEqual(null, itr.get());
+
+		itr.reset();
+		t.assertTrue(!itr.atEnd());
+		t.assertEqual("foo", itr.element);
+
+		//	test map
+		var a=itr.map(function(elm){
+			return elm+"-mapped";
+		});
+		itr=new dojox.collections.Iterator(a);
+		t.assertEqual("foo-mapped", itr.element);	//	test initialization
+		t.assertTrue(!itr.atEnd());
+		t.assertEqual("foo-mapped", itr.get());	//	make sure the first get doesn't advance.
+		t.assertEqual("bar-mapped", itr.get());
+		t.assertEqual("baz-mapped", itr.get());
+		t.assertEqual("zoo-mapped", itr.get());
+		t.assertTrue(itr.atEnd());
+		t.assertEqual(null, itr.get());
+	},
+
+	function testDictionaryIterator(t){
+		/*
+			in the context of any of the Dictionary-based collections, the
+			element would normally return a DictionaryEntry.  However, since
+			the DictionaryIterator is really an iterator of pure objects,
+			we will just test with an object here.  This means all property
+			names are lost in the translation, but...that's why there's a
+			DictionaryEntry object :)
+		*/
+		var itr=new dojox.collections.DictionaryIterator({
+			first:"foo", second:"bar", third:"baz", fourth:"zoo"
+		});
+		t.assertEqual("foo", itr.element);	//	test initialization
+		t.assertTrue(!itr.atEnd());
+		t.assertEqual("foo", itr.get());	//	make sure the first get doesn't advance.
+		t.assertEqual("bar", itr.get());
+		t.assertEqual("baz", itr.get());
+		t.assertEqual("zoo", itr.get());
+		t.assertTrue(itr.atEnd());
+		t.assertEqual(null, itr.get());
+
+		itr.reset();
+		t.assertTrue(!itr.atEnd());
+		t.assertEqual("foo", itr.element);
+
+		//	test map
+		var a=itr.map(function(elm){
+			return elm+"-mapped";
+		});
+		itr=new dojox.collections.Iterator(a);
+		t.assertEqual("foo-mapped", itr.element);	//	test initialization
+		t.assertTrue(!itr.atEnd());
+		t.assertEqual("foo-mapped", itr.get());	//	make sure the first get doesn't advance.
+		t.assertEqual("bar-mapped", itr.get());
+		t.assertEqual("baz-mapped", itr.get());
+		t.assertEqual("zoo-mapped", itr.get());
+		t.assertTrue(itr.atEnd());
+		t.assertEqual(null, itr.get());
+	}
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/tests/collections.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/tests/collections.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/tests/collections.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,15 @@
+dojo.provide("dojox.collections.tests.collections");
+dojo.require("dojox.collections");
+
+try{
+	dojo.require("dojox.collections.tests._base");
+	dojo.require("dojox.collections.tests.ArrayList");
+	dojo.require("dojox.collections.tests.BinaryTree");
+	dojo.require("dojox.collections.tests.Dictionary");
+	dojo.require("dojox.collections.tests.Queue");
+	dojo.require("dojox.collections.tests.Set");
+	dojo.require("dojox.collections.tests.SortedList");
+	dojo.require("dojox.collections.tests.Stack");
+}catch(e){
+	doh.debug(e);
+}

Added: trunk/examples/typeface/root/static/dojo/dojox/collections/tests/runTests.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections/tests/runTests.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections/tests/runTests.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+    <head>
+    <title>Dojox.wire Unit Test Runner</title>
+    <meta http-equiv="REFRESH" content="0;url=../../../util/doh/runner.html?testModule=dojox.collections.tests.collections"></HEAD>
+    <BODY>
+        Redirecting to D.O.H runner.
+    </BODY>
+</HTML> 

Added: trunk/examples/typeface/root/static/dojo/dojox/collections.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/collections.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/collections.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,2 @@
+dojo.provide("dojox.collections");
+dojo.require("dojox.collections._base");

Added: trunk/examples/typeface/root/static/dojo/dojox/cometd.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/cometd.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/cometd.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,3 @@
+// stub loader for the cometd module since no implementation code is allowed to live in top-level files
+dojo.provide("dojox.cometd");
+dojo.require("dojox._cometd.cometd");

Added: trunk/examples/typeface/root/static/dojo/dojox/crypto/Blowfish.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/crypto/Blowfish.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/crypto/Blowfish.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,570 @@
+dojo.provide("dojox.crypto.Blowfish");
+
+/*	Blowfish
+ *	Created based on the C# implementation by Marcus Hahn (http://www.hotpixel.net/)
+ *	Unsigned math functions derived from Joe Gregorio's SecureSyndication GM script
+ *	http://bitworking.org/projects/securesyndication/
+ *	(Note that this is *not* an adaption of the above script)
+ *
+ *	version 1.0 
+ *	TRT 
+ *	2005-12-08
+ */
+dojox.crypto.Blowfish = new function(){
+	//	summary
+	//	Object for doing Blowfish encryption/decryption.
+	var POW2=Math.pow(2,2);
+	var POW3=Math.pow(2,3);
+	var POW4=Math.pow(2,4);
+	var POW8=Math.pow(2,8);
+	var POW16=Math.pow(2,16);
+	var POW24=Math.pow(2,24);
+	var iv=null;	//	CBC mode initialization vector
+	var boxes={
+		p:[
+			0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 
+			0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 
+			0x9216d5d9, 0x8979fb1b
+		],
+		s0:[
+			0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
+			0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
+			0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+			0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
+			0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
+			0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+			0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
+			0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
+			0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+			0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
+			0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 
+			0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 
+			0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 
+			0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
+			0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+			0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
+			0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 
+			0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 
+			0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 
+			0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 
+			0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+			0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 
+			0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
+			0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 
+			0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
+			0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
+			0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+			0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
+			0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
+			0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+			0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
+			0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
+		],
+		s1:[
+			0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
+			0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
+			0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+			0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
+			0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
+			0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+			0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
+			0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 
+			0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 
+			0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
+			0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 
+			0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+			0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 
+			0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 
+			0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+			0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 
+			0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
+			0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 
+			0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
+			0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 
+			0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 
+			0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 
+			0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
+			0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+			0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 
+			0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
+			0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+			0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
+			0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
+			0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+			0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
+			0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
+		],
+		s2:[
+			0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
+			0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
+			0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+			0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
+			0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
+			0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+			0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
+			0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
+			0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+			0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
+			0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
+			0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+			0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
+			0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
+			0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+			0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
+			0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
+			0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+			0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
+			0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
+			0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 
+			0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
+			0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
+			0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 
+			0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 
+			0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 
+			0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 
+			0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
+			0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
+			0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 
+			0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
+			0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
+		],
+		s3:[
+			0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
+			0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
+			0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 
+			0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
+			0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 
+			0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 
+			0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
+			0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 
+			0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 
+			0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 
+			0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
+			0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 
+			0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 
+			0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 
+			0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+			0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
+			0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 
+			0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+			0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 
+			0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 
+			0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 
+			0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 
+			0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
+			0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 
+			0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
+			0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 
+			0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 
+			0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 
+			0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 
+			0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+			0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
+			0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
+		]
+	}
+////////////////////////////////////////////////////////////////////////////
+	function add(x,y){
+		var sum=(x+y)&0xffffffff;
+		if (sum<0){
+			sum=-sum;
+			return (0x10000*((sum>>16)^0xffff))+(((sum&0xffff)^0xffff)+1);
+		}
+		return sum;
+	}
+	function split(x){
+		var r=x&0xffffffff;
+		if(r<0) {
+			r=-r;
+			return [((r&0xffff)^0xffff)+1,(r>>16)^0xffff];
+		}
+		return [r&0xffff,(r>>16)];
+	}
+	function xor(x,y){
+		var xs=split(x);
+		var ys=split(y);
+		return (0x10000*(xs[1]^ys[1]))+(xs[0]^ys[0]);
+	}
+	function $(v, box){
+		var d=v&0xff; v>>=8;
+		var c=v&0xff; v>>=8;
+		var b=v&0xff; v>>=8;
+		var a=v&0xff;
+		var r=add(box.s0[a],box.s1[b]);
+		r=xor(r,box.s2[c]);
+		return add(r,box.s3[d]);
+	}
+////////////////////////////////////////////////////////////////////////////
+	function eb(o, box){
+		var l=o.left;
+		var r=o.right;
+		l=xor(l,box.p[0]);
+		r=xor(r,xor($(l,box),box.p[1]));
+		l=xor(l,xor($(r,box),box.p[2]));
+		r=xor(r,xor($(l,box),box.p[3]));
+		l=xor(l,xor($(r,box),box.p[4]));
+		r=xor(r,xor($(l,box),box.p[5]));
+		l=xor(l,xor($(r,box),box.p[6]));
+		r=xor(r,xor($(l,box),box.p[7]));
+		l=xor(l,xor($(r,box),box.p[8]));
+		r=xor(r,xor($(l,box),box.p[9]));
+		l=xor(l,xor($(r,box),box.p[10]));
+		r=xor(r,xor($(l,box),box.p[11]));
+		l=xor(l,xor($(r,box),box.p[12]));
+		r=xor(r,xor($(l,box),box.p[13]));
+		l=xor(l,xor($(r,box),box.p[14]));
+		r=xor(r,xor($(l,box),box.p[15]));
+		l=xor(l,xor($(r,box),box.p[16]));
+		o.right=l;
+		o.left=xor(r,box.p[17]);
+	}
+
+	function db(o, box){
+		var l=o.left;
+		var r=o.right;
+		l=xor(l,box.p[17]);
+		r=xor(r,xor($(l,box),box.p[16]));
+		l=xor(l,xor($(r,box),box.p[15]));
+		r=xor(r,xor($(l,box),box.p[14]));
+		l=xor(l,xor($(r,box),box.p[13]));
+		r=xor(r,xor($(l,box),box.p[12]));
+		l=xor(l,xor($(r,box),box.p[11]));
+		r=xor(r,xor($(l,box),box.p[10]));
+		l=xor(l,xor($(r,box),box.p[9]));
+		r=xor(r,xor($(l,box),box.p[8]));
+		l=xor(l,xor($(r,box),box.p[7]));
+		r=xor(r,xor($(l,box),box.p[6]));
+		l=xor(l,xor($(r,box),box.p[5]));
+		r=xor(r,xor($(l,box),box.p[4]));
+		l=xor(l,xor($(r,box),box.p[3]));
+		r=xor(r,xor($(l,box),box.p[2]));
+		l=xor(l,xor($(r,box),box.p[1]));
+		o.right=l;
+		o.left=xor(r,box.p[0]);
+	}
+
+	//	Note that we aren't caching contexts here; it might take a little longer
+	//	but we should be more secure this way.
+	function init(key){
+		var k=key;
+		if (typeof(k)=="string"){
+			var a=[];
+			for(var i=0; i<k.length; i++) 
+				a.push(k.charCodeAt(i)&0xff);
+			k=a;
+		}
+		//	init the boxes
+		var box = { p:[], s0:[], s1:[], s2:[], s3:[] };
+		for(var i=0; i<boxes.p.length; i++) box.p.push(boxes.p[i]);
+		for(var i=0; i<boxes.s0.length; i++) box.s0.push(boxes.s0[i]);
+		for(var i=0; i<boxes.s1.length; i++) box.s1.push(boxes.s1[i]);
+		for(var i=0; i<boxes.s2.length; i++) box.s2.push(boxes.s2[i]);
+		for(var i=0; i<boxes.s3.length; i++) box.s3.push(boxes.s3[i]);
+
+		//	init p with the key
+		var pos=0;
+		var data=0;
+		for(var i=0; i < box.p.length; i++){
+			for (var j=0; j<4; j++){
+				data = (data*POW8) | k[pos];
+				if(++pos==k.length) pos=0;
+			}
+			box.p[i] = xor(box.p[i], data);
+		}
+
+		//	encrypt p and the s boxes
+		var res={ left:0, right:0 };
+		for(var i=0; i<box.p.length;){
+			eb(res, box);
+			box.p[i++]=res.left;
+			box.p[i++]=res.right;
+		}
+		for (var i=0; i<4; i++){
+			for(var j=0; j<box["s"+i].length;){
+				eb(res, box);
+				box["s"+i][j++]=res.left;
+				box["s"+i][j++]=res.right;
+			}
+		}
+		return box;
+	}
+
+////////////////////////////////////////////////////////////////////////////
+//	CONVERSION FUNCTIONS
+////////////////////////////////////////////////////////////////////////////
+	//	these operate on byte arrays, NOT word arrays.
+	function toBase64(ba){ 
+		var p="=";
+		var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+		var s=[];
+		var l=ba.length;
+		var rm=l%3;
+		var x=l-rm;
+		for (var i=0; i<x;){
+			var t=ba[i++]<<16|ba[i++]<<8|ba[i++];
+			s.push(tab.charAt((t>>>18)&0x3f)); 
+			s.push(tab.charAt((t>>>12)&0x3f));
+			s.push(tab.charAt((t>>>6)&0x3f));
+			s.push(tab.charAt(t&0x3f));
+		}
+		//	deal with trailers, based on patch from Peter Wood.
+		switch(rm){
+			case 2:{
+				var t=ba[i++]<<16|ba[i++]<<8;
+				s.push(tab.charAt((t>>>18)&0x3f));
+				s.push(tab.charAt((t>>>12)&0x3f));
+				s.push(tab.charAt((t>>>6)&0x3f));
+				s.push(p);
+				break;
+			}
+			case 1:{
+				var t=ba[i++]<<16;
+				s.push(tab.charAt((t>>>18)&0x3f));
+				s.push(tab.charAt((t>>>12)&0x3f));
+				s.push(p);
+				s.push(p);
+				break;
+			}
+		}
+		return s.join("");
+	}
+	function fromBase64(str){
+		var s=str.split("");
+		var p="=";
+		var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+		var out=[];
+		var l=s.length;
+		while(s[--l]==p){ }
+		for (var i=0; i<l;){
+			var t=tab.indexOf(s[i++])<<18;
+			if(i<=l){ t|=tab.indexOf(s[i++])<<12 };
+			if(i<=l){ t|=tab.indexOf(s[i++])<<6 };
+			if(i<=l){ t|=tab.indexOf(s[i++]) };
+			out.push((t>>>16)&0xff);
+			out.push((t>>>8)&0xff);
+			out.push(t&0xff);
+		}
+		//	strip off any null bytes
+		while(out[out.length-1]==0){ out.pop(); }
+		return out;
+	}
+////////////////////////////////////////////////////////////////////////////
+//	PUBLIC FUNCTIONS
+//	0.2: Only supporting ECB mode for now.
+////////////////////////////////////////////////////////////////////////////
+	this.getIV=function(/* dojox.crypto.outputTypes? */ outputType){
+		//	summary
+		//	returns the initialization vector in the output format specified by outputType
+		var out=outputType||dojox.crypto.outputTypes.Base64;
+		switch(out){
+			case dojox.crypto.outputTypes.Hex:{
+				var s=[];
+				for(var i=0; i<iv.length; i++)
+					s.push((iv[i]).toString(16));
+				return s.join("");		//	string
+			}
+			case dojox.crypto.outputTypes.String:{
+				return iv.join("");		//	string
+			}
+			case dojox.crypto.outputTypes.Raw:{
+				return iv;				//	array
+			}
+			default:{
+				return toBase64(iv); 	//	 string
+			}
+		}
+	};
+	this.setIV=function(/* string */data, /* dojox.crypto.outputTypes? */inputType){
+		//	summary
+		//	sets the initialization vector to data (as interpreted as inputType)
+		var ip=inputType||dojox.crypto.outputTypes.Base64;
+		var ba=null;
+		switch(ip){
+			case dojox.crypto.outputTypes.String:{
+				ba=[];
+				for (var i=0; i<data.length; i++){
+					ba.push(data.charCodeAt(i));
+				}
+				break;
+			}
+			case dojox.crypto.outputTypes.Hex:{
+				ba=[];
+				var i=0;
+				while (i+1<data.length){
+					ba.push(parseInt(data.substr(i,2),16));
+					i+=2;
+				}
+				break;
+			}
+			case dojox.crypto.outputTypes.Raw:{
+				ba=data;
+				break;
+			}
+			default:{
+				ba=fromBase64(data);
+				break;
+			}
+		}
+		//	make it a pair of words now
+		iv={};
+		iv.left=ba[0]*POW24|ba[1]*POW16|ba[2]*POW8|ba[3];
+		iv.right=ba[4]*POW24|ba[5]*POW16|ba[6]*POW8|ba[7];
+	}
+	this.encrypt = function(/* string */plaintext, /* string */key, /* object? */ao){
+		//	summary
+		//	encrypts plaintext using key; allows user to specify output type and cipher mode via keyword object "ao"
+		var out=dojox.crypto.outputTypes.Base64;
+		var mode=dojox.crypto.cipherModes.EBC;
+		if (ao){
+			if (ao.outputType) out=ao.outputType;
+			if (ao.cipherMode) mode=ao.cipherMode;
+		}
+
+		var bx = init(key);
+		var padding = 8-(plaintext.length&7);
+		for (var i=0; i<padding; i++) plaintext+=String.fromCharCode(padding);
+		var cipher=[];
+		var count=plaintext.length >> 3;
+		var pos=0;
+		var o={};
+		var isCBC=(mode==dojox.crypto.cipherModes.CBC);
+		var vector={left:iv.left||null, right:iv.right||null};
+		for(var i=0; i<count; i++){
+			o.left=plaintext.charCodeAt(pos)*POW24
+				|plaintext.charCodeAt(pos+1)*POW16
+				|plaintext.charCodeAt(pos+2)*POW8
+				|plaintext.charCodeAt(pos+3);
+			o.right=plaintext.charCodeAt(pos+4)*POW24
+				|plaintext.charCodeAt(pos+5)*POW16
+				|plaintext.charCodeAt(pos+6)*POW8
+				|plaintext.charCodeAt(pos+7);
+
+			if(isCBC){
+				o.left=xor(o.left, vector.left);
+				o.right=xor(o.right, vector.right);
+			}
+
+			eb(o, bx);	//	encrypt the block
+
+			if(isCBC){
+				vector.left=o.left;
+				vector.right=o.right;dojox.crypto.outputTypes.Hex
+			}
+
+			cipher.push((o.left>>24)&0xff); 
+			cipher.push((o.left>>16)&0xff); 
+			cipher.push((o.left>>8)&0xff);
+			cipher.push(o.left&0xff);
+			cipher.push((o.right>>24)&0xff); 
+			cipher.push((o.right>>16)&0xff); 
+			cipher.push((o.right>>8)&0xff);
+			cipher.push(o.right&0xff);
+			pos+=8;
+		}
+		switch(out){
+			case dojox.crypto.outputTypes.Hex:{
+				var s=[];
+				for(var i=0; i<cipher.length; i++)
+					s.push((cipher[i]).toString(16));
+				return s.join("");	//	string
+			}
+			case dojox.crypto.outputTypes.String:{
+				return cipher.join("");	//	string
+			}
+			case dojox.crypto.outputTypes.Raw:{
+				return cipher;	//	array
+			}
+			default:{
+				return toBase64(cipher);	//	string
+			}
+		}
+	};
+
+	this.decrypt = function(/* string */ciphertext, /* string */key, /* object? */ao){
+		//	summary
+		//	decrypts ciphertext using key; allows specification of how ciphertext is encoded via ao.
+		var ip=dojox.crypto.outputTypes.Base64;
+		var mode=dojox.crypto.cipherModes.EBC;
+		if (ao){
+			if (ao.outputType) ip=ao.outputType;
+			if (ao.cipherMode) mode=ao.cipherMode;
+		}
+		var bx = init(key);
+		var pt=[];
+	
+		var c=null;
+		switch(ip){
+			case dojox.crypto.outputTypes.Hex:{
+				c=[];
+				var i=0;
+				while (i+1<ciphertext.length){
+					c.push(parseInt(ciphertext.substr(i,2),16));
+					i+=2;
+				}
+				break;
+			}
+			case dojox.crypto.outputTypes.String:{
+				c=[];
+				for (var i=0; i<ciphertext.length; i++){
+					c.push(ciphertext.charCodeAt(i));
+				}
+				break;
+			}
+			case dojox.crypto.outputTypes.Raw:{
+				c=ciphertext;	//	should be a byte array
+				break;
+			}
+			default:{
+				c=fromBase64(ciphertext);
+				break;
+			}
+		}
+
+		var count=c.length >> 3;
+		var pos=0;
+		var o={};
+		var isCBC=(mode==dojox.crypto.cipherModes.CBC);
+		var vector={left:iv.left||null, right:iv.right||null};
+		for(var i=0; i<count; i++){
+			o.left=c[pos]*POW24|c[pos+1]*POW16|c[pos+2]*POW8|c[pos+3];
+			o.right=c[pos+4]*POW24|c[pos+5]*POW16|c[pos+6]*POW8|c[pos+7];
+
+			if(isCBC){
+				var left=o.left;
+				var right=o.right;
+			}
+
+			db(o, bx);	//	decrypt the block
+
+			if(isCBC){
+				o.left=xor(o.left, vector.left);
+				o.right=xor(o.right, vector.right);
+				vector.left=left;
+				vector.right=right;
+			}
+
+			pt.push((o.left>>24)&0xff);
+			pt.push((o.left>>16)&0xff);
+			pt.push((o.left>>8)&0xff);
+			pt.push(o.left&0xff);
+			pt.push((o.right>>24)&0xff);
+			pt.push((o.right>>16)&0xff);
+			pt.push((o.right>>8)&0xff);
+			pt.push(o.right&0xff);
+			pos+=8;
+		}
+
+		//	check for padding, and remove.
+		if(pt[pt.length-1]==pt[pt.length-2]||pt[pt.length-1]==0x01){
+			var n=pt[pt.length-1];
+			pt.splice(pt.length-n, n);
+		}
+
+		//	convert to string
+		for(var i=0; i<pt.length; i++)
+			pt[i]=String.fromCharCode(pt[i]);
+		return pt.join("");		//	string
+	};
+
+	this.setIV("0000000000000000", dojox.crypto.outputTypes.Hex);
+}();

Added: trunk/examples/typeface/root/static/dojo/dojox/crypto/LICENSE
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/crypto/LICENSE	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/crypto/LICENSE	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,11 @@
+License Disclaimer:
+
+All contents of this directory are Copyright (c) the Dojo Foundation, with the
+following exceptions:
+-------------------------------------------------------------------------------
+
+MD5.js, SHA1.js:
+	* Copyright 1998-2005, Paul Johnstone
+	  Distributed under the terms of the BSD License
+
+

Added: trunk/examples/typeface/root/static/dojo/dojox/crypto/MD5.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/crypto/MD5.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/crypto/MD5.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,198 @@
+dojo.provide("dojox.crypto.MD5");
+
+/*	Return to a port of Paul Johnstone's MD5 implementation
+ *	http://pajhome.org.uk/crypt/md5/index.html
+ *
+ *	Copyright (C) Paul Johnston 1999 - 2002.
+ *	Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * 	Distributed under the BSD License
+ *
+ *	Dojo port by Tom Trenka
+ *
+ *	2005-12-7
+ *	All conversions are internalized (no dependencies)
+ *	implemented getHMAC for message digest auth.
+ */
+dojox.crypto.MD5 = new function(){
+	//	summary
+	//	object for creating digests using the MD5 algorithm
+	var chrsz=8;
+	var mask=(1<<chrsz)-1;
+	function toWord(s) {
+	  var wa=[];
+	  for(var i=0; i<s.length*chrsz; i+=chrsz)
+		wa[i>>5]|=(s.charCodeAt(i/chrsz)&mask)<<(i%32);
+	  return wa;
+	}
+	function toString(wa){
+		var s=[];
+		for(var i=0; i<wa.length*32; i+=chrsz)
+			s.push(String.fromCharCode((wa[i>>5]>>>(i%32))&mask));
+		return s.join("");
+	}
+	function toHex(wa) {
+		var h="0123456789abcdef";
+		var s=[];
+		for(var i=0; i<wa.length*4; i++){
+			s.push(h.charAt((wa[i>>2]>>((i%4)*8+4))&0xF)+h.charAt((wa[i>>2]>>((i%4)*8))&0xF));
+		}
+		return s.join("");
+	}
+	function toBase64(wa){
+		var p="=";
+		var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+		var s=[];
+		for(var i=0; i<wa.length*4; i+=3){
+			var t=(((wa[i>>2]>>8*(i%4))&0xFF)<<16)|(((wa[i+1>>2]>>8*((i+1)%4))&0xFF)<<8)|((wa[i+2>>2]>>8*((i+2)%4))&0xFF);
+			for(var j=0; j<4; j++){
+				if(i*8+j*6>wa.length*32) s.push(p);
+				else s.push(tab.charAt((t>>6*(3-j))&0x3F));
+			}
+		}
+		return s.join("");
+	}
+	function add(x,y) {
+		var l=(x&0xFFFF)+(y&0xFFFF);
+		var m=(x>>16)+(y>>16)+(l>>16);
+		return (m<<16)|(l&0xFFFF);
+	}
+	function R(n,c){ return (n<<c)|(n>>>(32-c)); }
+	function C(q,a,b,x,s,t){ return add(R(add(add(a,q),add(x,t)),s),b); }
+	function FF(a,b,c,d,x,s,t){ return C((b&c)|((~b)&d),a,b,x,s,t); }
+	function GG(a,b,c,d,x,s,t){ return C((b&d)|(c&(~d)),a,b,x,s,t); }
+	function HH(a,b,c,d,x,s,t){ return C(b^c^d,a,b,x,s,t); }
+	function II(a,b,c,d,x,s,t){ return C(c^(b|(~d)),a,b,x,s,t); }
+	function core(x,len){
+		x[len>>5]|=0x80<<((len)%32);
+		x[(((len+64)>>>9)<<4)+14]=len;
+		var a= 1732584193;
+		var b=-271733879;
+		var c=-1732584194;
+		var d= 271733878;
+		for(var i=0; i<x.length; i+=16){
+			var olda=a;
+			var oldb=b;
+			var oldc=c;
+			var oldd=d;
+
+			a=FF(a,b,c,d,x[i+ 0],7 ,-680876936);
+			d=FF(d,a,b,c,x[i+ 1],12,-389564586);
+			c=FF(c,d,a,b,x[i+ 2],17, 606105819);
+			b=FF(b,c,d,a,x[i+ 3],22,-1044525330);
+			a=FF(a,b,c,d,x[i+ 4],7 ,-176418897);
+			d=FF(d,a,b,c,x[i+ 5],12, 1200080426);
+			c=FF(c,d,a,b,x[i+ 6],17,-1473231341);
+			b=FF(b,c,d,a,x[i+ 7],22,-45705983);
+			a=FF(a,b,c,d,x[i+ 8],7 , 1770035416);
+			d=FF(d,a,b,c,x[i+ 9],12,-1958414417);
+			c=FF(c,d,a,b,x[i+10],17,-42063);
+			b=FF(b,c,d,a,x[i+11],22,-1990404162);
+			a=FF(a,b,c,d,x[i+12],7 , 1804603682);
+			d=FF(d,a,b,c,x[i+13],12,-40341101);
+			c=FF(c,d,a,b,x[i+14],17,-1502002290);
+			b=FF(b,c,d,a,x[i+15],22, 1236535329);
+
+			a=GG(a,b,c,d,x[i+ 1],5 ,-165796510);
+			d=GG(d,a,b,c,x[i+ 6],9 ,-1069501632);
+			c=GG(c,d,a,b,x[i+11],14, 643717713);
+			b=GG(b,c,d,a,x[i+ 0],20,-373897302);
+			a=GG(a,b,c,d,x[i+ 5],5 ,-701558691);
+			d=GG(d,a,b,c,x[i+10],9 , 38016083);
+			c=GG(c,d,a,b,x[i+15],14,-660478335);
+			b=GG(b,c,d,a,x[i+ 4],20,-405537848);
+			a=GG(a,b,c,d,x[i+ 9],5 , 568446438);
+			d=GG(d,a,b,c,x[i+14],9 ,-1019803690);
+			c=GG(c,d,a,b,x[i+ 3],14,-187363961);
+			b=GG(b,c,d,a,x[i+ 8],20, 1163531501);
+			a=GG(a,b,c,d,x[i+13],5 ,-1444681467);
+			d=GG(d,a,b,c,x[i+ 2],9 ,-51403784);
+			c=GG(c,d,a,b,x[i+ 7],14, 1735328473);
+			b=GG(b,c,d,a,x[i+12],20,-1926607734);
+
+			a=HH(a,b,c,d,x[i+ 5],4 ,-378558);
+			d=HH(d,a,b,c,x[i+ 8],11,-2022574463);
+			c=HH(c,d,a,b,x[i+11],16, 1839030562);
+			b=HH(b,c,d,a,x[i+14],23,-35309556);
+			a=HH(a,b,c,d,x[i+ 1],4 ,-1530992060);
+			d=HH(d,a,b,c,x[i+ 4],11, 1272893353);
+			c=HH(c,d,a,b,x[i+ 7],16,-155497632);
+			b=HH(b,c,d,a,x[i+10],23,-1094730640);
+			a=HH(a,b,c,d,x[i+13],4 , 681279174);
+			d=HH(d,a,b,c,x[i+ 0],11,-358537222);
+			c=HH(c,d,a,b,x[i+ 3],16,-722521979);
+			b=HH(b,c,d,a,x[i+ 6],23, 76029189);
+			a=HH(a,b,c,d,x[i+ 9],4 ,-640364487);
+			d=HH(d,a,b,c,x[i+12],11,-421815835);
+			c=HH(c,d,a,b,x[i+15],16, 530742520);
+			b=HH(b,c,d,a,x[i+ 2],23,-995338651);
+
+			a=II(a,b,c,d,x[i+ 0],6 ,-198630844);
+			d=II(d,a,b,c,x[i+ 7],10, 1126891415);
+			c=II(c,d,a,b,x[i+14],15,-1416354905);
+			b=II(b,c,d,a,x[i+ 5],21,-57434055);
+			a=II(a,b,c,d,x[i+12],6 , 1700485571);
+			d=II(d,a,b,c,x[i+ 3],10,-1894986606);
+			c=II(c,d,a,b,x[i+10],15,-1051523);
+			b=II(b,c,d,a,x[i+ 1],21,-2054922799);
+			a=II(a,b,c,d,x[i+ 8],6 , 1873313359);
+			d=II(d,a,b,c,x[i+15],10,-30611744);
+			c=II(c,d,a,b,x[i+ 6],15,-1560198380);
+			b=II(b,c,d,a,x[i+13],21, 1309151649);
+			a=II(a,b,c,d,x[i+ 4],6 ,-145523070);
+			d=II(d,a,b,c,x[i+11],10,-1120210379);
+			c=II(c,d,a,b,x[i+ 2],15, 718787259);
+			b=II(b,c,d,a,x[i+ 9],21,-343485551);
+
+			a = add(a,olda);
+			b = add(b,oldb);
+			c = add(c,oldc);
+			d = add(d,oldd);
+		}
+		return [a,b,c,d];
+	}
+	function hmac(data,key){
+		var wa=toWord(key);
+		if(wa.length>16) wa=core(wa,key.length*chrsz);
+		var l=[], r=[];
+		for(var i=0; i<16; i++){
+			l[i]=wa[i]^0x36363636;
+			r[i]=wa[i]^0x5c5c5c5c;
+		}
+		var h=core(l.concat(toWord(data)),512+data.length*chrsz);
+		return core(r.concat(h),640);
+	}
+
+	//	Public functions
+	this.compute=function(/* string */data, /* dojox.crypto.outputTypes */outputType){
+		//	summary
+		//	computes the digest of data, and returns the result as a string of type outputType
+		var out=outputType||dojox.crypto.outputTypes.Base64;
+		switch(out){
+			case dojox.crypto.outputTypes.Hex:{
+				return toHex(core(toWord(data),data.length*chrsz));	//	string
+			}
+			case dojox.crypto.outputTypes.String:{
+				return toString(core(toWord(data),data.length*chrsz));	//	string
+			}
+			default:{
+				return toBase64(core(toWord(data),data.length*chrsz));	//	string
+			}
+		}
+	};
+	this.getHMAC=function(/* string */data, /* string */key, /* dojox.crypto.outputTypes */outputType){
+		//	summary
+		//	computes a digest of data using key, and returns the result as a string of outputType
+		var out=outputType||dojox.crypto.outputTypes.Base64;
+		switch(out){
+			case dojox.crypto.outputTypes.Hex:{
+				return toHex(hmac(data,key));	//	string
+			}
+			case dojox.crypto.outputTypes.String:{
+				return toString(hmac(data,key));	//	string
+			}
+			default:{
+				return toBase64(hmac(data,key));	//	string
+			}
+		}
+	};
+}();

Added: trunk/examples/typeface/root/static/dojo/dojox/crypto/README
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/crypto/README	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/crypto/README	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,42 @@
+-------------------------------------------------------------------------------
+DojoX Cryptography
+-------------------------------------------------------------------------------
+Version 0.9
+Release date: 05/27/2007
+-------------------------------------------------------------------------------
+Project state: beta
+-------------------------------------------------------------------------------
+Project authors
+	Tom Trenka (ttrenka at gmail.com)
+-------------------------------------------------------------------------------
+Project description
+
+The DojoX Cryptography project is a set of implementations of public crypto
+algorithms.  At the time of writing, only MD5 and Blowfish are complete and
+tested; at least 5 other algorithms will be added by the time Dojo 1.0 is
+released.
+
+DojoX Cryptography is comprised of both symmetric (Blowfish) and asymmetric
+(MD5) algorithms.  Symmetric algs always implement encrypt() and decrypt()
+methods; asymmetric algs implement compute().
+-------------------------------------------------------------------------------
+Dependencies:
+
+DojoX Cryptography has no dependencies, outside of the Dojo package system 
+and DOH.
+-------------------------------------------------------------------------------
+Installation instructions
+
+Grab the following from the Dojo SVN Repository:
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/crypto.js
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/crypto/*
+
+Install into the following directory structure:
+/dojox/crypto/
+
+...which should be at the same level as your Dojo checkout.
+-------------------------------------------------------------------------------
+Documentation
+
+See the Dojo API tool (http://dojotoolkit.org/api)
+-------------------------------------------------------------------------------

Added: trunk/examples/typeface/root/static/dojo/dojox/crypto/_base.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/crypto/_base.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/crypto/_base.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,15 @@
+dojo.provide("dojox.crypto._base");
+
+(function(){
+	var dxc=dojox.crypto;
+	dxc.cipherModes={ 
+		//	summary
+		//	Enumeration for various cipher modes.
+		ECB:0, CBC:1, PCBC:2, CFB:3, OFB:4, CTR:5 
+	};
+	dxc.outputTypes={ 
+		//	summary
+		//	Enumeration for input and output encodings.
+		Base64:0, Hex:1, String:2, Raw:3 
+	};
+})();

Added: trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/Blowfish.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/Blowfish.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/Blowfish.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,25 @@
+dojo.provide("dojox.crypto.tests.Blowfish");
+dojo.require("dojox.crypto.Blowfish");
+
+(function(){
+	var message="The rain in Spain falls mainly on the plain.";
+	var key="foobar";
+	var base64Encrypted="WI5J5BPPVBuiTniVcl7KlIyNMmCosmKTU6a/ueyQuoUXyC5dERzwwdzfFsiU4vBw";
+	var dxc=dojox.crypto;
+
+	tests.register("dojox.crypto.tests.Blowfish", [
+		function testEncrypt(t){
+			t.assertEqual(base64Encrypted, dxc.Blowfish.encrypt(message, key));
+		},
+		function testDecrypt(t){
+			t.assertEqual(message, dxc.Blowfish.decrypt(base64Encrypted, key));
+		},
+		function testShortMessage(t){
+			var msg="pass";
+			var pwd="foobar";
+			var enc=dxc.Blowfish.encrypt(msg, pwd);
+			var dec=dxc.Blowfish.decrypt(enc, pwd);
+			t.assertEqual(dec, msg);
+		}
+	]);
+})();

Added: trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/MD5.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/MD5.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/MD5.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,22 @@
+dojo.provide("dojox.crypto.tests.MD5");
+dojo.require("dojox.crypto.MD5");
+
+(function(){
+	var message="The rain in Spain falls mainly on the plain.";
+	var base64="OUhxbVZ1Mtmu4zx9LzS5cA==";
+	var hex="3948716d567532d9aee33c7d2f34b970";
+	var s="9HqmVu2\xD9\xAE\xE3<}/4\xB9p";
+	var dxc=dojox.crypto;
+
+	tests.register("dojox.crypto.tests.MD5", [
+		function testBase64Compute(t){
+			t.assertEqual(base64, dxc.MD5.compute(message));
+		},
+		function testHexCompute(t){
+			t.assertEqual(hex, dxc.MD5.compute(message, dxc.outputTypes.Hex)); 
+		},
+		function testStringCompute(t){
+			t.assertEqual(s, dxc.MD5.compute(message, dxc.outputTypes.String)); 
+		}
+	]);
+})();

Added: trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/crypto.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/crypto.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/crypto.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+dojo.provide("dojox.crypto.tests.crypto");
+dojo.require("dojox.crypto");
+
+try{
+	dojo.require("dojox.crypto.tests.MD5");
+	dojo.require("dojox.crypto.tests.Blowfish");
+}catch(e){
+	doh.debug(e);
+}

Added: trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/runTests.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/runTests.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/crypto/tests/runTests.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+    <head>
+    <title>Dojox.wire Unit Test Runner</title>
+    <meta http-equiv="REFRESH" content="0;url=../../../util/doh/runner.html?testModule=dojox.crypto.tests.crypto"></HEAD>
+    <BODY>
+        Redirecting to D.O.H runner.
+    </BODY>
+</HTML> 

Added: trunk/examples/typeface/root/static/dojo/dojox/crypto.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/crypto.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/crypto.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,2 @@
+dojo.provide("dojox.crypto");
+dojo.require("dojox.crypto._base");

Added: trunk/examples/typeface/root/static/dojo/dojox/data/CsvStore.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/CsvStore.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/CsvStore.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,416 @@
+dojo.provide("dojox.data.CsvStore");
+
+dojo.require("dojo.data.util.filter");
+dojo.require("dojo.data.util.simpleFetch");
+
+dojo.declare("dojox.data.CsvStore",
+	null,
+	function(/* Object */ keywordParameters){
+		// summary: initializer
+		// keywordParameters: {url: String}
+		// keywordParameters: {data: String}
+		
+		this._attributes = [];			// e.g. ["Title", "Year", "Producer"]
+		this._attributeIndexes = {};	// e.g. {Title: 0, Year: 1, Producer: 2}
+ 		this._dataArray = [];			// e.g. [[<Item0>],[<Item1>],[<Item2>]]
+ 		this._arrayOfAllItems = [];		// e.g. [{_csvId:0,_csvStore:store},...]
+		this._loadFinished = false;
+		this._csvFileUrl = keywordParameters.url;
+		this._csvData = keywordParameters.data;
+		this._storeProp = "_csvStore";	// Property name for the store reference on every item.
+		this._idProp = "_csvId"; 		// Property name for the Item Id on every item.
+		this._features = {	'dojo.data.api.Read': true,
+							'dojo.data.api.Identity': true };
+	},{
+	//	summary:
+	//		The CsvStore implements the dojo.data.api.Read API and reads
+	//		data from files in CSV (Comma Separated Values) format.
+	//		All values are simple string values. References to other items
+	//		are not supported as attribute values in this datastore.
+	//
+	//		Example data file:
+	//		name, color, age, tagline
+	//		Kermit, green, 12, "Hi, I'm Kermit the Frog."
+	//		Fozzie Bear, orange, 10, "Wakka Wakka Wakka!"
+	//		Miss Piggy, pink, 11, "Kermie!"
+	//
+	//		Note that values containing a comma must be enclosed with quotes ("")
+	//		Also note that values containing quotes must be escaped with two consecutive quotes (""quoted"")
+	
+	/* examples:
+	 *   var csvStore = new dojox.data.CsvStore({url:"movies.csv");
+	 *   var csvStore = new dojox.data.CsvStore({url:"http://example.com/movies.csv");
+	 */
+
+	_assertIsItem: function(/* item */ item){
+		//	summary:
+		//      This function tests whether the item passed in is indeed an item in the store.
+		//	item: 
+		//		The item to test for being contained by the store.
+		if(!this.isItem(item)){ 
+			throw new Error("dojox.data.CsvStore: a function was passed an item argument that was not an item");
+		}
+	},
+	
+	_assertIsAttribute: function(/* item || String */ attribute){
+		//	summary:
+		//      This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
+		//	attribute: 
+		//		The attribute to test for being contained by the store.
+		if(!dojo.isString(attribute)){ 
+			throw new Error("dojox.data.CsvStore: a function was passed an attribute argument that was not an attribute object nor an attribute name string");
+		}
+	},
+	
+
+/***************************************
+     dojo.data.api.Read API
+***************************************/
+	getValue: function(	/* item */ item, 
+						/* attribute || attribute-name-string */ attribute, 
+						/* value? */ defaultValue){
+		//	summary: 
+		//      See dojo.data.api.Read.getValue()
+		//		Note that for the CsvStore, an empty string value is the same as no value, 
+		// 		so the defaultValue would be returned instead of an empty string.
+		this._assertIsItem(item);
+		this._assertIsAttribute(attribute);
+		var itemValue = defaultValue;
+		if(this.hasAttribute(item, attribute)){
+			var itemData = this._dataArray[this.getIdentity(item)];
+			itemValue = itemData[this._attributeIndexes[attribute]];
+		}
+		return itemValue; //String
+	},
+
+	getValues: function(/* item */ item, 
+						/* attribute || attribute-name-string */ attribute){
+		//	summary: 
+		//		See dojo.data.api.Read.getValues()
+		// 		CSV syntax does not support multi-valued attributes, so this is just a
+		// 		wrapper function for getValue().
+		var value = this.getValue(item, attribute);
+		return (value ? [value] : []); //Array
+	},
+
+	getAttributes: function(/* item */ item){
+		//	summary: 
+		//		See dojo.data.api.Read.getAttributes()
+		this._assertIsItem(item);
+		var attributes = [];
+		var itemData = this._dataArray[this.getIdentity(item)];
+		for(var i=0; i<itemData.length; i++){
+			// Check for empty string values. CsvStore treats empty strings as no value.
+			if(itemData[i] != ""){
+				attributes.push(this._attributes[i]);
+			}
+		}
+		return attributes; //Array
+	},
+
+	hasAttribute: function(	/* item */ item,
+							/* attribute || attribute-name-string */ attribute){
+		//	summary: 
+		//		See dojo.data.api.Read.hasAttribute()
+		// 		The hasAttribute test is true if attribute has an index number within the item's array length
+		// 		AND if the item has a value for that attribute. Note that for the CsvStore, an
+		// 		empty string value is the same as no value.
+		this._assertIsItem(item);
+		this._assertIsAttribute(attribute);
+		var attributeIndex = this._attributeIndexes[attribute];
+		var itemData = this._dataArray[this.getIdentity(item)];
+		return (typeof attributeIndex != "undefined" && attributeIndex < itemData.length && itemData[attributeIndex] != ""); //Boolean
+	},
+
+	containsValue: function(/* item */ item, 
+							/* attribute || attribute-name-string */ attribute, 
+							/* anything */ value){
+		//	summary: 
+		//		See dojo.data.api.Read.containsValue()
+		return this._containsValue(item,attribute,value,false); //boolean
+	},
+
+	_containsValue: function(	/* item */ item, 
+								/* attribute || attribute-name-string */ attribute, 
+								/* anything */ value,
+								/* boolean */ ignoreCase){
+		//	summary: 
+		//		Internal function for looking at the values contained by the item.
+		//	description: 
+		//		Internal function for looking at the values contained by the item.  This 
+		//		function allows for denoting if the comparison should be case sensitive for
+		//		strings or not (for handling filtering cases where string case should not matter)
+		//	
+		//	item:
+		//		The data item to examine for attribute values.
+		//	attribute:
+		//		The attribute to inspect.
+		//	value:	
+		//		The value to match, strings may contain wildcard items like * and ?.
+		//	ignoreCase:
+		//		Flag to denote that if items are a string type, should case be used for comparison or not.
+		var possibleValue = this.getValue(item, attribute);
+		if(typeof value === "string" && typeof possibleValue != "undefined"){
+			return (possibleValue.match(dojo.data.util.filter.patternToRegExp(value, ignoreCase)) !== null); //Boolean
+		}
+		return false; // Boolean
+	},
+
+	isItem: function(/* anything */ something){
+		//	summary: 
+		//		See dojo.data.api.Read.isItem()
+		if(something && something[this._storeProp] === this){
+			var identity = something[this._idProp];
+			if(identity >= 0 && identity < this._dataArray.length){
+				return true; //Boolean
+			}
+		}
+		return false; //Boolean
+	},
+
+	isItemLoaded: function(/* anything */ something){
+		//	summary: 
+		//		See dojo.data.api.Read.isItemLoaded()
+		//		The CsvStore always loads all items, so if it's an item, then it's loaded.
+		return this.isItem(something); //Boolean
+	},
+
+	loadItem: function(/* item */ item){
+		//	summary: 
+		//		See dojo.data.api.Read.loadItem()
+		//	description:
+		//		The CsvStore always loads all items, so if it's an item, then it's loaded.
+		//		From the dojo.data.api.Read.loadItem docs:
+		//			If a call to isItemLoaded() returns true before loadItem() is even called,
+		//			then loadItem() need not do any work at all and will not even invoke
+		//			the callback handlers.
+	},
+
+	getFeatures: function(){
+		//	summary: 
+		//		See dojo.data.api.Read.getFeatures()
+		return this._features; //Object
+	},
+
+	// The dojo.data.api.Read.fetch() function is implemented as
+	// a mixin from dojo.data.util.simpleFetch.
+	// That mixin requires us to define _fetchItems().
+	_fetchItems: function(	/* Object */ keywordArgs, 
+							/* Function */ findCallback, 
+							/* Function */ errorCallback){
+		//	summary: 
+		//		See dojo.data.util.simpleFetch.fetch()
+		
+		var self = this;
+		var filter = function(requestArgs, arrayOfAllItems){
+			var items = null;
+			if(requestArgs.query){
+				items = [];
+				var ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false; 
+				for(var i = 0; i < arrayOfAllItems.length; ++i){
+					var match = true;
+					var candidateItem = arrayOfAllItems[i];
+					for(var key in requestArgs.query){
+						var value = requestArgs.query[key];
+						if(!self._containsValue(candidateItem, key, value, ignoreCase)){
+							match = false;
+						}
+					}
+					if(match){
+						items.push(candidateItem);
+					}
+				}
+			}else{
+				// We want a copy to pass back in case the parent wishes to sort the array.  We shouldn't allow resort 
+				// of the internal list so that multiple callers can get lists and sort without affecting each other.
+				if(arrayOfAllItems.length> 0){
+					items = arrayOfAllItems.slice(0,arrayOfAllItems.length); 
+				}
+			}
+			findCallback(items, requestArgs);
+		};
+
+		if(this._loadFinished){
+			filter(keywordArgs, this._dataArray);
+		}else{
+			if(this._csvFileUrl){
+				var getArgs = {
+						url: self._csvFileUrl, 
+						handleAs: "text"
+					};
+				var getHandler = dojo.xhrGet(getArgs);
+				getHandler.addCallback(function(data){
+					self._processData(data);
+					filter(keywordArgs, self._arrayOfAllItems);
+				});
+				getHandler.addErrback(function(error){
+					throw error;
+				});
+			}else if(this._csvData){
+				this._processData(this._csvData);
+				this._csvData = null;
+				filter(keywordArgs, this._arrayOfAllItems);
+			}else{
+				throw new Error("dojox.data.CsvStore: No CSV source data was provided as either URL or String data input.");
+			}
+		}
+	},
+	
+	close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+		 //	summary: 
+		 //		See dojo.data.api.Read.close()
+	},
+	
+	
+	// -------------------------------------------------------------------
+	// Private methods
+	_getArrayOfArraysFromCsvFileContents: function(/* string */ csvFileContents){
+		/* summary:
+		 *   Parses a string of CSV records into a nested array structure.
+		 * description:
+		 *   Given a string containing CSV records, this method parses
+		 *   the string and returns a data structure containing the parsed
+		 *   content.  The data structure we return is an array of length
+		 *   R, where R is the number of rows (lines) in the CSV data.  The 
+		 *   return array contains one sub-array for each CSV line, and each 
+		 *   sub-array contains C string values, where C is the number of 
+		 *   columns in the CSV data.
+		 */
+		 
+		/* example:
+		 *   For example, given this CSV string as input:
+		 *     "Title, Year, Producer \n Alien, 1979, Ridley Scott \n Blade Runner, 1982, Ridley Scott"
+		 *   this._dataArray will be set to:
+		 *     [["Alien", "1979", "Ridley Scott"],
+		 *      ["Blade Runner", "1982", "Ridley Scott"]]
+		 *   And this._attributes will be set to:
+		 *     ["Title", "Year", "Producer"]
+		 *   And this._attributeIndexes will be set to:
+		 *     { "Title":0, "Year":1, "Producer":2 }
+		 */
+		if(dojo.isString(csvFileContents)){
+			var lineEndingCharacters = new RegExp("\r\n|\n|\r");
+			var leadingWhiteSpaceCharacters = new RegExp("^\\s+",'g');
+			var trailingWhiteSpaceCharacters = new RegExp("\\s+$",'g');
+			var doubleQuotes = new RegExp('""','g');
+			var arrayOfOutputRecords = [];
+			
+			var arrayOfInputLines = csvFileContents.split(lineEndingCharacters);
+			for(var i = 0; i < arrayOfInputLines.length; ++i){
+				var singleLine = arrayOfInputLines[i];
+				if(singleLine.length > 0){
+					var listOfFields = singleLine.split(',');
+					var j = 0;
+					while(j < listOfFields.length){
+						var space_field_space = listOfFields[j];
+						var field_space = space_field_space.replace(leadingWhiteSpaceCharacters, ''); // trim leading whitespace
+						var field = field_space.replace(trailingWhiteSpaceCharacters, ''); // trim trailing whitespace
+						var firstChar = field.charAt(0);
+						var lastChar = field.charAt(field.length - 1);
+						var secondToLastChar = field.charAt(field.length - 2);
+						var thirdToLastChar = field.charAt(field.length - 3);
+						if((firstChar == '"') && 
+								((lastChar != '"') || 
+								 ((lastChar == '"') && (secondToLastChar == '"') && (thirdToLastChar != '"')))){
+							if(j+1 === listOfFields.length){
+								// alert("The last field in record " + i + " is corrupted:\n" + field);
+								return null; //null
+							}
+							var nextField = listOfFields[j+1];
+							listOfFields[j] = field_space + ',' + nextField;
+							listOfFields.splice(j+1, 1); // delete element [j+1] from the list
+						}else{
+							if((firstChar == '"') && (lastChar == '"')){
+								field = field.slice(1, (field.length - 1)); // trim the " characters off the ends
+								field = field.replace(doubleQuotes, '"');   // replace "" with "
+							}
+							listOfFields[j] = field;
+							j += 1;
+						}
+					}
+					arrayOfOutputRecords.push(listOfFields);
+				}
+			}
+			
+			// The first item of the array must be the header row with attribute names.
+			this._attributes = arrayOfOutputRecords.shift();
+			for(var i=0; i<this._attributes.length; i++){
+				// Store the index of each attribute 
+				this._attributeIndexes[this._attributes[i]] = i;
+			}
+			this._dataArray = arrayOfOutputRecords; //Array
+		}
+	},
+	
+	_processData: function(/* String */ data){
+		this._loadFinished = true;
+		this._getArrayOfArraysFromCsvFileContents(data);
+		this._arrayOfAllItems = [];
+		for(var i=0; i<this._dataArray.length; i++){
+			this._arrayOfAllItems.push(this._createItemFromIdentity(i));
+		}
+	},
+	
+	_createItemFromIdentity: function(/* String */ identity){
+		var item = {};
+		item[this._storeProp] = this;
+		item[this._idProp] = identity;
+		return item; //Object
+	},
+	
+	
+/***************************************
+     dojo.data.api.Identity API
+***************************************/
+	getIdentity: function(/* item */ item){
+		//	summary: 
+		//		See dojo.data.api.Identity.getIdentity()
+		if(this.isItem(item)){
+			return item[this._idProp]; //String
+		}
+		return null; //null
+	},
+
+	getItemByIdentity: function(/* String */ identity){
+		//	summary: 
+		//		See dojo.data.api.Identity.getItemByIdentity()
+
+		// Force a sync'ed load if it hasn't occurred yet
+		if(!this._loadFinished){
+			this._forceLoad();
+		}
+		// First create an item from the identity, then make sure
+		// that the identity is part of this datastore.
+		var item = this._createItemFromIdentity(identity);
+		if(this.isItem(item)){
+			return item; //Object
+		}
+		return null; //null
+	},
+
+	_forceLoad: function(){
+		//	summary: 
+		//		Internal function to force a load of the store if it hasn't occurred yet.  This is required
+		//		for specific functions to work properly.  See dojo.data.api.Identity.getItemByIdentity()
+		var self = this;
+		if(this._csvFileUrl){
+			var getArgs = {
+					url: self._csvFileUrl, 
+					handleAs: "text",
+					sync: true
+				};
+			var getHandler = dojo.xhrGet(getArgs);
+			getHandler.addCallback(function(data){
+				self._processData(data);
+			});
+			getHandler.addErrback(function(error){
+				throw error;
+			});
+		}else if(this._csvData){
+			self._processData(data);
+			self._csvData = null;
+		} 
+	}
+});
+//Mix in the simple fetch implementation to this class.
+dojo.extend(dojox.data.CsvStore,dojo.data.util.simpleFetch);

Added: trunk/examples/typeface/root/static/dojo/dojox/data/OpmlStore.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/OpmlStore.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/OpmlStore.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,300 @@
+dojo.provide("dojox.data.OpmlStore");
+
+dojo.require("dojo.data.util.filter");
+dojo.require("dojo.data.util.simpleFetch");
+
+dojo.declare("dojox.data.OpmlStore",
+	null,
+	function(/* Object */ keywordParameters){
+		// summary: initializer
+		// keywordParameters: {url: String}
+		this._xmlData = null;
+		this._arrayOfTopLevelItems = [];
+		this._metadataNodes = null;
+		this._loadFinished = false;
+		this._opmlFileUrl = keywordParameters.url;
+		this._opmlData = keywordParameters.data;  // XML DOM Document
+	},{
+	/* summary:
+	 *   The OpmlStore implements the dojo.data.api.Read API.  
+	 */
+	 
+	/* examples:
+	 *   var opmlStore = new dojo.data.OpmlStore({url:"geography.xml"});
+	 *   var opmlStore = new dojo.data.OpmlStore({url:"http://example.com/geography.xml"});
+	 */
+	_assertIsItem: function(/* item */ item){
+		if(!this.isItem(item)){ 
+			throw new Error("dojo.data.OpmlStore: a function was passed an item argument that was not an item");
+		}
+	},
+	
+	_assertIsAttribute: function(/* item || String */ attribute){
+		//	summary:
+		//      This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
+		//	attribute: 
+		//		The attribute to test for being contained by the store.
+		if(!dojo.isString(attribute)){
+			throw new Error("dojox.data.OpmlStore: a function was passed an attribute argument that was not an attribute object nor an attribute name string");
+		}
+	},
+	
+	_removeChildNodesThatAreNotElementNodes: function(/* node */ node, /* boolean */ recursive){
+		var childNodes = node.childNodes;
+		if(childNodes.length == 0){
+			return;
+		}
+		var nodesToRemove = [];
+		var i, childNode;
+		for(i = 0; i < childNodes.length; ++i){
+			childNode = childNodes[i];
+			if(childNode.nodeType != 1){ 
+				nodesToRemove.push(childNode); 
+			}
+		};
+		for(i = 0; i < nodesToRemove.length; ++i){
+			childNode = nodesToRemove[i];
+			node.removeChild(childNode);
+		}
+		if(recursive){
+			for(i = 0; i < childNodes.length; ++i){
+				childNode = childNodes[i];
+				this._removeChildNodesThatAreNotElementNodes(childNode, recursive);
+			}
+		}
+	},
+	
+	_processRawXmlTree: function(/* xmlDoc */ rawXmlTree){
+		this._loadFinished = true;
+		this._xmlData = rawXmlTree;
+		var headNodes = rawXmlTree.getElementsByTagName('head');
+		var headNode = headNodes[0];
+		if(headNode){
+			this._removeChildNodesThatAreNotElementNodes(headNode);
+			this._metadataNodes = headNode.childNodes;
+		}
+		var bodyNodes = rawXmlTree.getElementsByTagName('body');
+		var bodyNode = bodyNodes[0];
+		if(bodyNode){
+			this._removeChildNodesThatAreNotElementNodes(bodyNode, true);
+			
+			var bodyChildNodes = bodyNodes[0].childNodes;
+			for(var i = 0; i < bodyChildNodes.length; ++i){
+				var node = bodyChildNodes[i];
+				if(node.tagName == 'outline'){
+					this._arrayOfTopLevelItems.push(node);
+				}
+			}
+		}
+	},
+
+/***************************************
+     dojo.data.api.Read API
+***************************************/
+	getValue: function( /* item */ item,
+						/* attribute || attribute-name-string */ attribute,
+						/* value? */ defaultValue){
+		//	summary: 
+		//      See dojo.data.api.Read.getValue()
+		this._assertIsItem(item);
+		this._assertIsAttribute(attribute);
+		if(attribute == 'children'){
+			return (item.firstChild || defaultValue); //Object
+		} else {
+			var value = item.getAttribute(attribute);
+			return (value != undefined) ? value : defaultValue; //Object
+		}
+	},
+	
+	getValues: function(/* item */ item,
+						/* attribute || attribute-name-string */ attribute){
+		//	summary: 
+		//		See dojo.data.api.Read.getValues()
+		this._assertIsItem(item);
+		this._assertIsAttribute(attribute);
+		var array = [];
+		if(attribute == 'children'){
+			for(var i = 0; i < item.childNodes.length; ++i){
+				array.push(item.childNodes[i]);
+			}
+		} else if(item.getAttribute(attribute) !== null){
+				array.push(item.getAttribute(attribute));
+		}
+		return array; // Array
+	},
+	
+	getAttributes: function(/* item */ item){
+		//	summary: 
+		//		See dojo.data.api.Read.getAttributes()
+		this._assertIsItem(item);
+		var attributes = [];
+		var xmlNode = item;
+		var xmlAttributes = xmlNode.attributes;
+		for(var i = 0; i < xmlAttributes.length; ++i){
+			var xmlAttribute = xmlAttributes.item(i);
+			attributes.push(xmlAttribute.nodeName);
+		}
+		if(xmlNode.childNodes.length > 0){
+			attributes.push('children');
+		}
+		return attributes; //Array
+	},
+	
+	hasAttribute: function( /* item */ item,
+							/* attribute || attribute-name-string */ attribute){
+		//	summary: 
+		//		See dojo.data.api.Read.hasAttribute()
+		return (this.getValues(item, attribute).length > 0); //Boolean
+	},
+	
+	containsValue: function(/* item */ item, 
+							/* attribute || attribute-name-string */ attribute, 
+							/* anything */ value){
+		//	summary: 
+		//		See dojo.data.api.Read.containsValue()
+		return this._containsValue(item,attribute,value,false); //Boolean
+	},
+
+	_containsValue: function(	/* item */ item, 
+								/* attribute || attribute-name-string */ attribute, 
+								/* anything */ value,
+								/* boolean */ ignoreCase){
+		//	summary: 
+		//		Internal function for looking at the values contained by the item.
+		//	description: 
+		//		Internal function for looking at the values contained by the item.  This 
+		//		function allows for denoting if the comparison should be case sensitive for
+		//		strings or not (for handling filtering cases where string case should not matter)
+		//	
+		//	item:
+		//		The data item to examine for attribute values.
+		//	attribute:
+		//		The attribute to inspect.
+		//	value:	
+		//		The value to match, strings may contain wildcard items like * and ?.
+		//	ignoreCase:
+		//		Flag to denote that if items are a string type, should case be used for comparison or not.
+		
+		var values = this.getValues(item, attribute);
+		for(var i = 0; i < values.length; ++i){		
+			var possibleValue = values[i];
+			if(typeof value === "string" && typeof possibleValue === "string"){
+				return (possibleValue.match(dojo.data.util.filter.patternToRegExp(value, ignoreCase)) !== null); //Boolean
+			}else if(possibleValue === value){
+				return true; //Boolean
+			}
+		}
+		return false; //Boolean
+	},
+			
+	isItem: function(/* anything */ something){
+		//	summary: 
+		//		See dojo.data.api.Read.isItem()
+		//	description:
+		//		Four things are verified to ensure that "something" is an item:
+		//		something can not be null, the nodeType must be an XML Element,
+		//		the tagName must be "outline", and the node must be a member of
+		//		XML document for this datastore. 
+		return (something && 
+				something.nodeType == 1 && 
+				something.tagName == 'outline' &&
+				something.ownerDocument === this._xmlData); //Boolean
+	},
+	
+	isItemLoaded: function(/* anything */ something){
+		//	summary: 
+		//		See dojo.data.api.Read.isItemLoaded()
+		// 		OpmlStore loads every item, so if it's an item, then it's loaded.
+		return this.isItem(something); //Boolean
+	},
+	
+	loadItem: function(/* item */ item){
+		//	summary: 
+		//		See dojo.data.api.Read.loadItem()
+		//	description:
+		//		The OpmlStore always loads all items, so if it's an item, then it's loaded.
+		//		From the dojo.data.api.Read.loadItem docs:
+		//			If a call to isItemLoaded() returns true before loadItem() is even called,
+		//			then loadItem() need not do any work at all and will not even invoke the callback handlers.
+	},
+
+	// The dojo.data.api.Read.fetch() function is implemented as
+	// a mixin from dojo.data.util.simpleFetch.
+	// That mixin requires us to define _fetchItems().
+	_fetchItems: function(	/* Object */ keywordArgs, 
+							/* Function */ findCallback, 
+							/* Function */ errorCallback){
+		//	summary: 
+		//		See dojo.data.util.simpleFetch.fetch()
+		
+		var self = this;
+		var filter = function(requestArgs, arrayOfItems){
+			var items = null;
+			if(requestArgs.query){
+				items = [];
+				var ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false; 
+				for(var i = 0; i < arrayOfItems.length; ++i){
+					var match = true;
+					var candidateItem = arrayOfItems[i];
+					for(var key in requestArgs.query){
+						var value = requestArgs.query[key];
+						if(!self._containsValue(candidateItem, key, value, ignoreCase)){
+							match = false;
+						}
+					}
+					if(match){
+						items.push(candidateItem);
+					}
+				}
+			}else{
+				// We want a copy to pass back in case the parent wishes to sort the array.  We shouldn't allow resort 
+				// of the internal list so that multiple callers can get lists and sort without affecting each other.
+				if(arrayOfItems.length> 0){
+					items = arrayOfItems.slice(0,arrayOfItems.length); 
+				}
+			}
+			findCallback(items, requestArgs);
+		};
+
+		if(this._loadFinished){
+			filter(keywordArgs, this._arrayOfTopLevelItems);
+		}else{
+			if(this._opmlFileUrl){
+				var getArgs = {
+						url: self._opmlFileUrl, 
+						handleAs: "xml"
+					};
+				var getHandler = dojo.xhrGet(getArgs);
+				getHandler.addCallback(function(data){
+					self._processRawXmlTree(data);
+					filter(keywordArgs, self._arrayOfTopLevelItems);
+				});
+				getHandler.addErrback(function(error){
+					throw error;
+				});
+			}else if(this._opmlData){
+				this._processRawXmlTree(this._opmlData);
+				this._opmlData = null;
+				filter(keywordArgs, this._arrayOfTopLevelItems);
+			}else{
+				throw new Error("dojox.data.OpmlStore: No OPML source data was provided as either URL or XML data input.");
+			}
+		}
+	},
+	
+	getFeatures: function(){
+		// summary: See dojo.data.api.Read.getFeatures()
+		 var features = {
+			 'dojo.data.api.Read': true
+		 };
+		 return features; //Object
+	},
+
+	close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+		 //	summary: 
+		 //		See dojo.data.api.Read.close()
+	}
+});
+//Mix in the simple fetch implementation to this class.
+dojo.extend(dojox.data.OpmlStore,dojo.data.util.simpleFetch);
+	

Added: trunk/examples/typeface/root/static/dojo/dojox/data/README
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/README	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/README	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,42 @@
+-------------------------------------------------------------------------------
+DojoX Data
+-------------------------------------------------------------------------------
+Version 0.9
+Release date: 05/29/2007
+-------------------------------------------------------------------------------
+Project state: beta
+-------------------------------------------------------------------------------
+Project authors
+	Jared Jurkiewicz (jared.jurkiewicz at gmail.com)
+-------------------------------------------------------------------------------
+Project description
+
+The DojoX Data project is a container for extensions and extra example stores
+that implement the dojo.data APIs.  It may also contain utility functions for
+working with specific types of data.
+
+-------------------------------------------------------------------------------
+Dependencies:
+
+DojoX Data has dependencies on core dojo (dojo.data) and the D.O.H. unit test 
+framework.
+-------------------------------------------------------------------------------
+Documentation:
+
+See the Dojo API tool (http://dojotoolkit.org/api)
+-------------------------------------------------------------------------------
+Installation instructions
+
+Grab the following from the Dojo SVN Repository:
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/data/*
+
+Install into the following directory structure:
+/dojox/data/
+
+...which should be at the same level as your Dojo checkout.
+
+/dojox/data/*
+
+Require in the dojox.data stores you wish to use.
+-------------------------------------------------------------------------------
+

Added: trunk/examples/typeface/root/static/dojo/dojox/data/XmlStore.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/XmlStore.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/XmlStore.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,1051 @@
+dojo.provide("dojox.data.XmlStore");
+dojo.provide("dojox.data.XmlItem");
+
+dojo.require("dojo.data.util.simpleFetch");
+dojo.require("dojo.data.util.filter");
+dojo.require("dojox.data.dom");
+
+dojo.declare("dojox.data.XmlStore", 
+	null,
+	function(/* object */ args) {
+		//	summary:
+		//		Initializer for the XML store.  
+		//	args:
+		//		An anonymous object to initialize properties.  It expects the following values:
+		//		url:		The url to an XML document that represents the whole store.
+		//		fetchUrl:   A URL for a fetch service that returns an XML document
+		//		saveUrl:	A URL for a save service that saves an XML document
+		//		rootItem:	A tag name for root items
+		//		keyAttribute:	An attribute name for a key or an indentify
+		// 		attributeMap:   An anonymous object contains properties for attribute mapping,
+		//						{"tag_name.item_attribute_name": "@xml_attribute_name", ...}
+		console.log("XmlStore()");
+		if(args){
+			this._url = args.url;
+			this._fetchUrl = args.fetchUrl;
+			this._saveUrl = args.saveUrl;
+			this._rootItem = args.rootItem;
+			this._keyAttribute = args.keyAttribute;
+			this._attributeMap = args.attributeMap;
+		}
+		this._newItems = [];
+		this._deletedItems = [];
+		this._modifiedItems = [];
+	}, {
+	//	summary:
+	//		A data store for XML based services or documents
+	//	description:
+    //		A data store for XML based services or documents
+
+/* dojo.data.api.Read */
+
+	getValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue){
+		//	summary:
+		//		Return an attribute value
+		//	description:
+		//		'item' must be an XML element.
+		//		If 'attribute' specifies "tagName", the tag name of the element is
+		//		returned.
+		//		If 'attribute' specifies "childNodes", the first element child is
+		//		returned.
+		//		If 'attribute' specifies "text()", the value of the first text
+		//		child is returned.
+		//		For generic attributes, if '_attributeMap' is specified,
+		//		an actual attribute name is looked up with the tag name of
+		//		the element and 'attribute' (concatenated with '.').
+		//		Then, if 'attribute' starts with "@", the value of the XML
+		//		attribute is returned.
+		//		Otherwise, the first child element of the tag name specified with
+		//		'attribute' is returned.
+		//	item:
+		//		An XML element that holds the attribute
+		//	attribute:
+		//		A tag name of a child element, An XML attribute name or one of
+		// 		special names
+		//	defaultValue:
+		//		A default value
+		//	returns:
+		//		An attribute value found, otherwise 'defaultValue'
+		var element = item.element;
+		if(attribute === "tagName"){
+			return element.nodeName;
+		}else if (attribute === "childNodes"){
+			for (var i = 0; i < element.childNodes.length; i++) {
+				var node = element.childNodes[i];
+				if (node.nodeType === dojox.data.dom.OD) {
+					return this._getItem(node); //object
+				}
+			}
+			return defaultValue;
+		}else if(attribute === "text()"){
+			for(var i = 0; i < element.childNodes.length; i++){
+				var node = element.childNodes[i];
+				if(node.nodeType === 3){
+					return node.nodeValue; //string
+				}
+			}
+			return defaultValue;
+		}else{
+			attribute = this._getAttribute(element.nodeName, attribute);
+			if(attribute.charAt(0) === '@'){
+				var name = attribute.substring(1);
+				var value = element.getAttribute(name);
+				return (value !== undefined) ? value : defaultValue; //object
+			}else{
+				for(var i = 0; i < element.childNodes.length; i++){
+					var node = element.childNodes[i];
+					if(	node.nodeType === 1 /*ELEMENT_NODE*/ &&
+						node.nodeName === attribute){
+						return this._getItem(node); //object
+					}
+				}
+				return defaultValue; //object
+			}
+		}
+	},
+
+	getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute){
+		//	summary:
+		//		Return an array of attribute values
+		//	description:
+		//		'item' must be an XML element.
+		//		If 'attribute' specifies "tagName", the tag name of the element is
+		//		returned.
+		//		If 'attribute' specifies "childNodes", child elements are returned.
+		//		If 'attribute' specifies "text()", the values of child text nodes
+		//		are returned.
+		//		For generic attributes, if '_attributeMap' is specified,
+		//		an actual attribute name is looked up with the tag name of
+		//		the element and 'attribute' (concatenated with '.').
+		//		Then, if 'attribute' starts with "@", the value of the XML
+		//		attribute is returned.
+		//		Otherwise, child elements of the tag name specified with
+		//		'attribute' are returned.
+		//	item:
+		//		An XML element that holds the attribute
+		//	attribute:
+		//		A tag name of child elements, An XML attribute name or one of
+		//		special names
+		//	returns:
+		//		An array of attribute values found, otherwise an empty array
+		var element = item.element;
+		if(attribute === "tagName"){
+			return [element.nodeName];
+		}else if(attribute === "childNodes"){
+			var values = [];
+			for(var i = 0; i < element.childNodes.length; i++){
+				var node = element.childNodes[i];
+				if(node.nodeType === 1 /*ELEMENT_NODE*/){
+					values.push(this._getItem(node));
+				}
+			}
+			return values; //array
+		}else if(attribute === "text()"){
+			var values = [];
+			for(var i = 0; i < element.childNodes.length; i++){
+				var node = childNodes[i];
+				if(node.nodeType === 3){
+					values.push(node.nodeValue);
+				}
+			}
+			return values; //array
+		}else{
+			attribute = this._getAttribute(element.nodeName, attribute);
+			if(attribute.charAt(0) === '@'){
+				var name = attribute.substring(1);
+				var value = element.getAttribute(name);
+				return (value !== undefined) ? [value] : []; //array
+			}else{
+				var values = [];
+				for(var i = 0; i < element.childNodes.length; i++){
+					var node = element.childNodes[i];
+					if(	node.nodeType === 1 /*ELEMENT_NODE*/ &&
+						node.nodeName === attribute){
+						values.push(this._getItem(node));
+					}
+				}
+				return values; //array
+			}
+		}
+	},
+
+	getAttributes: function(/* item */ item) {
+		//	summary:
+		//		Return an array of attribute names
+		// 	description:
+		//		'item' must be an XML element.
+		//		tag names of child elements and XML attribute names of attributes
+		//		specified to the element are returned along with special attribute
+		//		names applicable to the element including "tagName", "childNodes"
+		//		if the element has child elements, "text()" if the element has
+		//		child text nodes, and attribute names in '_attributeMap' that match
+		//		the tag name of the element.
+		//	item:
+		//		An XML element
+		//	returns:
+		//		An array of attributes found
+		var element = item.element;
+		var attributes = [];
+		attributes.push("tagName");
+		if(element.childNodes.length > 0){
+			var names = {};
+			var childNodes = true;
+			var text = false;
+			for(var i = 0; i < element.childNodes.length; i++){
+				var node = element.childNodes[i];
+				if (node.nodeType === 1 /*ELEMENT_NODE*/) {
+					var name = node.nodeName;
+					if(!names[name]){
+						attributes.push(name);
+						names[name] = name;
+					}
+					childNodes = true;
+				}else if(node.nodeType === 3){
+					text = true;
+				}
+			}
+			if(childNodes){
+				attributes.push("childNodes");
+			}
+			if(text){
+				attributes.push("text()");
+			}
+		}
+		for(var i = 0; i < element.attributes.length; i++){
+			attributes.push("@" + element.attributes[i].nodeName);
+		}
+		if(this._attributeMap){
+			for (var key in this._attributeMap){
+				var i = key.indexOf('.');
+				if(i > 0){
+					var tagName = key.substring(0, i);
+					if (tagName === element.nodeName){
+						attributes.push(key.substring(i + 1));
+					}
+				}else{ // global attribute
+					attributes.push(key);
+				}
+			}
+		}
+		return attributes; //array
+	},
+
+	hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute){
+		//	summary:
+		//		Check whether an element has the attribute
+		//	item:
+		//		An XML element
+		//	attribute:
+		//		A tag name of a child element, An XML attribute name or one of
+		//		special names
+		//	returns:
+		//		True if the element has the attribute, otherwise false
+		return (this.getValue(item, attribute) !== undefined); //boolean
+	},
+
+	containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value){
+		//	summary:
+		//		Check whether the attribute values contain the value
+		//	item:
+		//		An XML element that holds the attribute
+		//	attribute:
+		//		A tag name of a child element, An XML attribute name or one of
+		//		special names
+		//	returns:
+		//		True if the attribute values contain the value, otherwise false
+		var values = this.getValues(item, attribute);
+		for(var i = 0; i < values.length; i++){
+			if((typeof value === "string")){
+				if(values[i].toString && values[i].toString() === value){
+					return true;
+				}
+			}else if (values[i] === value){
+				return true; //boolean
+			}
+		}
+		return false;//boolean
+	},
+
+	isItem: function(/* anything */ something){
+		//	summary:
+		//		Check whether the object is an item (XML element)
+		//	item:
+		//		An object to check
+		// 	returns:
+		//		True if the object is an XML element, otherwise false
+		if(something && something.element && something.store && something.store === this){
+			return true; //boolean
+		}
+		return false; //boolran
+	},
+
+	isItemLoaded: function(/* anything */ something){
+		//	summary:
+		//		Check whether the object is an item (XML element) and loaded
+		//	item:
+		//		An object to check
+		//	returns:
+		//		True if the object is an XML element, otherwise false
+		return this.isItem(something); //boolean
+	},
+
+	loadItem: function(/* object */ keywordArgs){
+		//	summary:
+		//		Load an item (XML element)
+		//	keywordArgs:
+		//		object containing the args for loadItem.  See dojo.data.api.Read.loadItem()
+	},
+
+	getFeatures: function() {
+		//	summary:
+		//		Return supported data APIs
+		//	returns:
+		//		"dojo.data.api.Read" and "dojo.data.api.Write"
+		var features = {
+			"dojo.data.api.Read": true,
+			"dojo.data.api.Write": true
+		};
+		return features; //array
+	},
+
+	_fetchItems: function(request, fetchHandler, errorHandler) {
+		//	summary:
+		//		Fetch items (XML elements) that match to a query
+		//	description:
+		//		If '_fetchUrl' is specified, it is used to load an XML document
+		//		with a query string.
+		//		Otherwise and if '_url' is specified, the XML document is
+		//		loaded and list XML elements that match to a query (set of element
+		//		names and their text attribute values that the items to contain).
+		//		A wildcard, "*" can be used to query values to match all
+		//		occurrences.
+		//		If '_rootItem' is specified, it is used to fetch items.
+		//	request:
+		//		A request object
+		//	fetchHandler:
+		//		A function to call for fetched items
+		//	errorHandler:
+		//		A function to call on error
+		var localRequest = null;
+		var url = this._getFetchUrl(request);
+		if(this._url){
+			url = this._url;
+			localRequest = request; // use request for _getItems()
+		}
+		console.log("XmlStore._fetchItems(): url=" + url);
+		if(!url){
+			errorHandler(new Error("No URL specified."));
+			return;
+		}
+
+		var self = this;
+		var getArgs = {
+				url: url,
+				handleAs: "xml"
+			};
+		var getHandler = dojo.xhrGet(getArgs);
+		getHandler.addCallback(function(data){
+			var items = self._getItems(data, localRequest);
+			console.log("XmlStore._fetchItems(): length=" + (items ? items.length : 0));
+			if (items && items.length > 0) {
+				fetchHandler(items, request);
+			}
+			else {
+				fetchHandler([], request);
+			}
+		});
+		getHandler.addErrback(function(data){
+			errorHandler(data, request);
+		});
+	},
+
+	_getFetchUrl: function(request){
+		//	summary:
+		//		Generate a URL for fetch
+		//	description:
+		//		This default implementation generates a query string in the form of
+		//		"?name1=value1&name2=value2..." off properties of 'query' object
+		//		specified in 'request' and appends it to '_fetchUrl'.
+		//		Sub-classes may override this method for the custom URL generation.
+		//	request:
+		//		A request object
+		//	returns:
+		//		A fetch URL
+		if(!this._fetchUrl){
+			return null;
+		}
+		var query = request.query;
+		if(!query){
+			return this._fetchUrl;
+		}
+		if(dojo.isString(query)){
+			return this._fetchUrl + query;
+		}
+		var queryString = "";
+		for(var name in query){
+			var value = query[name];
+			if(value){
+				if(queryString){
+					queryString += "&";
+				}
+				queryString += (name + "=" + value);
+			}
+		}
+		if(!queryString){
+			return this._fetchUrl;
+		}
+		return this._fetchUrl + "?" + queryString;
+	},
+
+	_getItems: function(document, request) {
+		//	summary:
+		//		Fetch items (XML elements) in an XML document based on a request
+		//	description:
+		//		This default implementation walks through child elements of
+		//		the document element to see if all properties of 'query' object
+		//		match corresponding attributes of the element (item).
+		//		If 'request' is not specified, all child elements are returned.
+		//		Sub-classes may override this method for the custom search in
+		//		an XML document.
+		//	document:
+		//		An XML document
+		//	request:
+		//		A request object
+		//	returns:
+		//		An array of items
+		var query = null;
+		if(request){
+			query = request.query;
+		}
+		var items = [];
+		var nodes = null;
+		if(this._rootItem){
+			nodes = document.getElementsByTagName(this._rootItem);
+		}
+		else{
+			nodes = document.documentElement.childNodes;
+		}
+		for(var i = 0; i < nodes.length; i++){
+			var node = nodes[i];
+			if(node.nodeType != 1 /*ELEMENT_NODE*/){
+				continue;
+			}
+            var item = this._getItem(node);
+			if(query){
+				var found = true;
+				var ignoreCase = request.queryOptions ? request.queryOptions.ignoreCase : false; 
+				for(var attribute in query){
+					var value = this.getValue(item, attribute);
+					if(value){
+						var queryValue = query[attribute];
+						if ((typeof value) === "string" && 
+							((typeof queryValue) === "string")){
+							if((value.match(dojo.data.util.filter.patternToRegExp(queryValue, ignoreCase))) !== null){
+								continue;
+							}
+						}else if((typeof value) === "object"){
+							if(	value.toString && 
+								((typeof queryValue) === "string")){
+								var stringValue = value.toString();
+								if((stringValue.match(dojo.data.util.filter.patternToRegExp(queryValue, ignoreCase))) !== null){
+									continue;
+								}
+							}else{
+								if(queryValue === "*" || queryValue === value){
+									continue;
+								}
+							}
+						}
+					}
+					found = false;
+					break;
+				}
+				if(!found){
+					continue;
+				}
+			}
+			items.push(item);
+		}
+		for(var i in items){
+			var element = items[i].element;
+			element.parentNode.removeChild(element); // make it root
+		}
+		return items;
+	},
+
+	close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
+		 //	summary: 
+		 //		See dojo.data.api.Read.close()
+	},
+
+/* dojo.data.api.Write */
+
+	newItem: function(/* object? */ keywordArgs){
+		//	summary:
+		//		Return a new XML element
+		//	description:
+		//		At least, 'keywordArgs' must contain "tagName" to be used for
+		//		the new	element.
+		//		Other attributes in 'keywordArgs' are set to the new element,
+		//		including "text()", but excluding "childNodes".
+		// 	keywordArgs:
+		//		An object containing initial attributes
+		//	returns:
+		//		An XML element
+		console.log("XmlStore.newItem()");
+		keywordArgs = (keywordArgs || {});
+		var tagName = keywordArgs.tagName;
+		if(!tagName){
+			tagName = this._rootItem;
+			if(!tagName){
+				return null;
+			}
+		}
+
+		var document = this._getDocument();
+		var element = document.createElement(tagName);
+		for(var attribute in keywordArgs){
+			if(attribute === "tagName"){
+				continue;
+			}else if(attribute === "text()"){
+				var text = document.createTextNode(keywordArgs[attribute]);
+				element.appendChild(text);
+			}else{
+				attribute = this._getAttribute(tagName, attribute);
+				if(attribute.charAt(0) === '@'){
+					var name = attribute.substring(1);
+					element.setAttribute(name, keywordArgs[attribute]);
+				}else{
+					var child = document.createElement(attribute);
+					var text = document.createTextNode(keywordArgs[attribute]);
+					child.appendChild(text);
+					element.appendChild(child);
+				}
+			}
+		}
+
+		var item = this._getItem(element);
+		this._newItems.push(item);
+		return item; //object
+	},
+	
+	deleteItem: function(/* item */ item){
+		//	summary:
+		//		Delete an XML element
+		//	item:
+		//		An XML element to delete
+		//	returns:
+		//		True
+		console.log("XmlStore.deleteItem()");
+		var element = item.element;
+		if(element.parentNode){
+			this._backupItem(item);
+			element.parentNode.removeChild(element);
+			return true;
+		}
+		this._forgetItem(item);
+		this._deletedItems.push(item);
+		return true; //boolean
+	},
+	
+	setValue: function(/* item */ item, /* attribute || string */ attribute, /* almost anything */ value){
+		//	summary:
+		//		Set an attribute value
+		//	description:
+		//		'item' must be an XML element.
+		//		If 'attribute' specifies "tagName", nothing is set and false is
+		//		returned.
+		//		If 'attribute' specifies "childNodes", the value (XML element) is
+		//		added to the element.
+		//		If 'attribute' specifies "text()", a text node is created with
+		//		the value and set it to the element as a child.
+		//		For generic attributes, if '_attributeMap' is specified,
+		//		an actual attribute name is looked up with the tag name of
+		//		the element and 'attribute' (concatenated with '.').
+		//		Then, if 'attribute' starts with "@", the value is set to the XML
+		//		attribute.
+		//		Otherwise, a text node is created with the value and set it to
+		//		the first child element of the tag name specified with 'attribute'.
+		//		If the child element does not exist, it is created.
+		//	item:
+		//		An XML element that holds the attribute
+		//	attribute:
+		//		A tag name of a child element, An XML attribute name or one of
+		//		special names
+		//	value:
+		//		A attribute value to set
+		//	returns:
+		//		False for "tagName", otherwise true
+		if(attribute === "tagName"){
+			return false; //boolean
+		}
+
+		this._backupItem(item);
+
+		var element = item.element;
+		if(attribute === "childNodes"){
+			var child = value.element;
+			element.appendChild(child);
+		}else if(attribute === "text()"){
+			while (element.firstChild){
+				element.removeChild(element.firstChild);
+			}
+			var text = this._getDocument(element).createTextNode(value);
+			element.appendChild(text);
+		}else{
+			attribute = this._getAttribute(element.nodeName, attribute);
+			if(attribute.charAt(0) === '@'){
+				var name = attribute.substring(1);
+				element.setAttribute(name, value);
+			}else{
+				var child = null;
+				for(var i = 0; i < element.childNodes.length; i++){
+					var node = element.childNodes[i];
+					if(	node.nodeType === 1 /*ELEMENT_NODE*/&&
+						node.nodeName === attribute){
+						child = node;
+						break;
+					}
+				}
+				var document = this._getDocument(element);
+				if(child){
+					while(child.firstChild){
+						child.removeChild(child.firstChild);
+					}
+				}else{
+					child = document.createElement(attribute);
+					element.appendChild(child);
+				}
+				var text = document.createTextNode(value);
+				child.appendChild(text);
+			}
+		}
+		return true; //boolean
+	},
+	
+	setValues: function(/* item */ item, /* attribute || string */ attribute, /* array */ values){
+		//	summary:
+		//		Set attribute values
+		//	description:
+		//		'item' must be an XML element.
+		//		If 'attribute' specifies "tagName", nothing is set and false is
+		//		returned.
+		//		If 'attribute' specifies "childNodes", the value (array of XML
+		//		elements) is set to the element's childNodes.
+		//		If 'attribute' specifies "text()", a text node is created with
+		//		the values and set it to the element as a child.
+		//		For generic attributes, if '_attributeMap' is specified,
+		//		an actual attribute name is looked up with the tag name of
+		//		the element and 'attribute' (concatenated with '.').
+		//		Then, if 'attribute' starts with "@", the first value is set to
+		//		the XML attribute.
+		//		Otherwise, child elements of the tag name specified with
+		//		'attribute' are replaced with new child elements and their
+		//		child text nodes of values.
+		//	item:
+		//		An XML element that holds the attribute
+		//	attribute:
+		//		A tag name of child elements, an XML attribute name or one of
+		//		special names
+		//	value:
+		//		A attribute value to set
+		//	returns:
+		//		False for "tagName", otherwise true
+		if(attribute === "tagName"){
+			return false; //boolean
+		}
+
+		this._backupItem(item);
+
+		var element = item.element;
+		if(attribute === "childNodes"){
+			while(element.firstChild){
+				element.removeChild(element.firstChild);
+			}
+			for(var i = 0; i < values.length; i++){
+				var child = values[i].element;
+				element.appendChild(child);
+			}
+		}else if(attribute === "text()"){
+			while (element.firstChild){
+				element.removeChild(element.firstChild);
+			}
+			var value = "";
+			for(var i = 0; i < values.length; i++){
+				value += values[i];
+			}
+			var text = this._getDocument(element).createTextNode(value);
+			element.appendChild(text);
+		}else{
+			attribute = this._getAttribute(element.nodeName, attribute);
+			if(attribute.charAt(0) === '@'){
+				var name = attribute.substring(1);
+				element.setAttribute(name, values[0]);
+			}else{
+				for(var i = element.childNodes.length - 1; i >= 0; i--){
+					var node = element.childNodes[i];
+					if(	node.nodeType === 1 /*ELEMENT_NODE*/ &&
+						node.nodeName === attribute){
+						element.removeChild(node);
+					}
+				}
+				var document = this._getDocument(element);
+				for(var i = 0; i < values.length; i++){
+					var child = document.createElement(attribute);
+					var text = document.createTextNode(values[i]);
+					child.appendChild(text);
+					element.appendChild(child);
+				}
+			}
+		}
+		return true; //boolean
+	},
+	
+	unsetAttribute: function(/* item */ item, /* attribute || string */ attribute){
+		//	summary:
+		//		Remove an attribute
+		//	description:
+		//		'item' must be an XML element.
+		//		'attribute' can be an XML attribute name of the element or one of
+		//		special names described below.
+		//		If 'attribute' specifies "tagName", nothing is removed and false is
+		//		returned.
+		//		If 'attribute' specifies "childNodes" or "text()", all child nodes
+		//		are removed.
+		//		For generic attributes, if '_attributeMap' is specified,
+		//		an actual attribute name is looked up with the tag name of
+		//		the element and 'attribute' (concatenated with '.').
+		//		Then, if 'attribute' starts with "@", the XML attribute is removed.
+		//		Otherwise, child elements of the tag name specified with
+		//		'attribute' are removed.
+		//	item:
+		//		An XML element that holds the attribute
+		//	attribute:
+		//		A tag name of child elements, an XML attribute name or one of
+		//		special names
+		//	returns:
+		//		False for "tagName", otherwise true
+		if(attribute === "tagName"){
+			return false; //boolean
+		}
+
+		this._backupItem(item);
+
+		var element = item.element;
+		if(attribute === "childNodes" || attribute === "text()"){
+			while(element.firstChild){
+				element.removeChild(element.firstChild);
+			}
+		}else{
+			attribute = this._getAttribute(element.nodeName, attribute);
+			if(attribute.charAt(0) === '@'){
+				var name = attribute.substring(1);
+				element.removeAttribute(name);
+			}else{
+				for(var i = element.childNodes.length - 1; i >= 0; i--){
+					var node = element.childNodes[i];
+					if(	node.nodeType === 1 /*ELEMENT_NODE*/ &&
+						node.nodeName === attribute){
+						element.removeChild(node);
+					}
+				}
+			}
+		}
+		return true; //boolean
+	},
+	
+	save: function(/* object */ keywordArgs){
+		//	summary:
+		//		Save new and/or modified items (XML elements)
+		// 	description:
+		//		If '_saveUrl' is specified, it is used to save XML documents
+		//		for new, modified and/or deleted XML elements.
+		// 	keywordArgs:
+		//		An object for callbacks
+		if(!keywordArgs){
+			keywordArgs = {};
+		}
+		for(var i in this._modifiedItems){
+			this._saveItem(this._modifiedItems[i], keywordArgs);
+		}
+		for(var i = 0; i < this._newItems.length; i++){
+			var item = this._newItems[i];
+			if(item.element.parentNode){ // reparented
+				this._newItems.splice(i, 1);
+				i--;
+				continue;
+			}
+			this._saveItem(this._newItems[i], keywordArgs);
+		}
+		for(var i in this._deletedItems){
+			this._saveItem(this._deletedItems[i], keywordArgs, "DELETE");
+		}
+	},
+
+	revert: function(){
+		// summary:
+		//	Invalidate changes (new and/or modified elements)
+		// returns:
+		//	True
+		console.log("XmlStore.revert() _newItems=" + this._newItems.length);
+		console.log("XmlStore.revert() _deletedItems=" + this._deletedItems.length);
+		console.log("XmlStore.revert() _modifiedItems=" + this._modifiedItems.length);
+		this._newItems = [];
+		this._restoreItems(this._deletedItems);
+		this._deletedItems = [];
+		this._restoreItems(this._modifiedItems);
+		this._modifiedItems = [];
+		return true; //boolean
+	},
+	
+	isDirty: function(/* item? */ item){
+		//	summary:
+		//		Check whether an item is new, modified or deleted
+		//	description:
+		//		If 'item' is specified, true is returned if the item is new,
+		//		modified or deleted.
+		//		Otherwise, true is returned if there are any new, modified
+		//		or deleted items.
+		//	item:
+		//		An item (XML element) to check
+		//	returns:
+		//		True if an item or items are new, modified or deleted, otherwise
+		//		false
+		if (item) {
+			var element = this._getRootElement(item.element);
+			return (this._getItemIndex(this._newItems, element) >= 0 ||
+				this._getItemIndex(this._deletedItems, element) >= 0 ||
+				this._getItemIndex(this._modifiedItems, element) >= 0); //boolean
+		}
+		else {
+			return (this._newItems.length > 0 ||
+				this._deletedItems.length > 0 ||
+				this._modifiedItems.length > 0); //boolean
+		}
+	},
+
+	_saveItem: function(item, keywordArgs, method){
+		var scope = (keywordArgs.scope || dj_global);
+		var url = null;
+		var method = (method || "POST");
+		var postContent = null;
+		if(method === "DELETE"){
+			url = this._getDeleteUrl(item);
+		}else{ // POST
+			url = this._getSaveUrl(item);
+			postContent = this._getPostContent(item);
+		}
+		if(!url){
+			if(keywordArgs.onError){
+				keywordArgs.onError.call(scope, new Error("No URL for saving content: " + postContent));
+			}
+			return;
+		}
+
+		//FIXME:  Add in DELETE support when xhrDelete is added to base or core.
+		var self = this;
+		var saveArgs = {
+			url: url,
+			method: method,
+			contentType: "text/xml",
+			handleAs: "text/xml",
+			postData: postContent
+		}
+		var saveHander = rawXhrPost(saveArgs);
+		saveHandler.addCallback(function(data){
+			self._forgetItem(item);
+			if(keywordArgs.onComplete){
+				keywordArgs.onComplete.call(scope);
+			}
+		});
+		saveHandler.addErrback(function(error) {
+			if(keywordArgs.onError){
+				keywordArgs.onError.call(scope, error);
+			}
+		});
+	},
+
+	_getSaveUrl: function(item){
+		//	summary:
+		//		Generate a URL for save
+		//	description:
+		//		This default implementation just returns '_saveUrl'.
+		//		Sub-classes may override this method for the custom URL based on
+		//		changes (new, deleted, or modified).
+		//	item:
+		//		An item to save
+		//	returns:
+		//		A save URL
+		return this._saveUrl;	//string
+	},
+
+	_getDeleteUrl: function(item){
+		//	summary:
+		//		Generate a URL for delete
+		// 	description:
+		//		This default implementation returns '_saveUrl' with '_keyAttribute'
+		//	as a query string
+		//		Sub-classes may override this method for the custom URL based on
+		//		changes (new, deleted, or modified).
+		// 	item:
+		//		An item to delete
+		// 	returns:
+		//		A delete URL
+		if (!this._saveUrl) {
+			return this._saveUrl; //string
+		}
+		var saveUrl = this._saveUrl;
+		if (item && this._keyAttribute) {
+			var value = this.getValue(item, this._keyAttribute);
+			if (value) {
+				saveUrl = saveUrl + '?' + this._keyAttribute + '=' + value;
+			}
+		}
+		return saveUrl;	//string
+	},
+
+	_getPostContent: function(item){
+		//	summary:
+		//		Generate a content to post
+		// 	description:
+		//		This default implementation generates an XML document for one
+		//		(the first only) new or modified element.
+		//		Sub-classes may override this method for the custom post content
+		//		generation.
+		//	item:
+		//		An item to save
+		//	returns:
+		//		A post content
+		var element = item.element;
+		var declaration = "<?xml version=\"1.0\"?>"; // FIXME: encoding?
+		return declaration + dojox.data.dom.innerXML(element); //XML string
+	},
+
+/* internal API */
+
+	_getAttribute: function(tagName, attribute){
+		if(this._attributeMap){
+			var key = tagName + "." + attribute;
+			var value = this._attributeMap[key];
+			if(value){
+				attribute = value;
+			}else{ // look for global attribute
+				value = this._attributeMap[attribute];
+				if(value){
+					attribute = value;
+				}
+			}
+		}
+		return attribute; //object
+	},
+
+	_getItem: function(element){
+		return new dojox.data.XmlItem(element, this); //object
+	},
+
+	_getItemIndex: function(items, element){
+		for(var i in items){
+			if(items[i].element === element){
+				return i; //int
+			}
+		}
+		return -1; //int
+	},
+
+	_backupItem: function(item){
+		var element = this._getRootElement(item.element);
+		if(	this._getItemIndex(this._newItems, element) >= 0 ||
+			this._getItemIndex(this._modifiedItems, element) >= 0){
+			return; // new or already modified
+		}
+		if(element != item.element){
+			item = this._getItem(element);
+		}
+		item._backup = element.cloneNode(true);
+		this._modifiedItems.push(item);
+	},
+
+	_restoreItems: function(items){
+		for(var i in items){
+			var item = items[i];
+			if(item._backup){
+				item.element = item._backup;
+				item._backup = null;
+			}
+		}
+	},
+
+	_forgetItem: function(item){
+		var element = item.element;
+		var index = this._getItemIndex(this._newItems, element);
+		if(index >= 0){
+			this._newItems.splice(index, 1);
+		}
+		index = this._getItemIndex(this._deletedItems, element);
+		if(index >= 0){
+			this._deletedItems.splice(index, 1);
+		}
+		index = this._getItemIndex(this._modifiedItems, element);
+		if(index >= 0){
+			this._modifiedItems.splice(index, 1);
+		}
+	},
+
+	_getDocument: function(element){
+		if(element){
+			return element.ownerDocument;  //DOMDocument
+		}else if(!this._document){
+			return dojox.data.dom.createDocument(); // DOMDocument
+		}
+	},
+
+	_getRootElement: function(element){
+		while(element.parentNode){
+			element = element.parentNode;
+		}
+		return element; //DOMElement
+	}
+
+});
+
+//FIXME: Is a full class here really needed for containment of the item or would
+//an anon object work fine?
+dojo.declare("dojox.data.XmlItem", null,
+	function(element, store) {
+		//	summary:
+		//		Initialize with an XML element
+		//	element:
+		//		An XML element
+		//	store:
+		//		The containing store, if any.
+		this.element = element;
+		this.store = store;
+	}, {
+	//	summary:
+	//		A data item of 'XmlStore'
+	//	description:
+	//		This class represents an item of 'XmlStore' holding an XML element.
+	//		'element'
+	//	element:
+	//		An XML element
+
+	toString: function() {
+		//	summary:
+		//		Return a value of the first text child of the element
+		// 	returns:
+		//		a value of the first text child of the element
+		var str = "";
+		if (this.element) {
+			for (var i = 0; i < this.element.childNodes.length; i++) {
+				var node = this.element.childNodes[i];
+				if (node.nodeType === 3) {
+					str = node.nodeValue;
+					break;
+				}
+			}
+		}
+		return str;	//String
+	}
+
+});
+dojo.extend(dojox.data.XmlStore,dojo.data.util.simpleFetch);

Added: trunk/examples/typeface/root/static/dojo/dojox/data/dom.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/dom.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/dom.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,261 @@
+dojo.provide("dojox.data.dom");
+
+//DOM type to int value for reference.
+//Ints make for more compact code than full constant names.
+//ELEMENT_NODE                  = 1;
+//ATTRIBUTE_NODE                = 2;
+//TEXT_NODE                     = 3;
+//CDATA_SECTION_NODE            = 4;
+//ENTITY_REFERENCE_NODE         = 5;
+//ENTITY_NODE                   = 6;
+//PROCESSING_INSTRUCTION_NODE   = 7;
+//COMMENT_NODE                  = 8;
+//DOCUMENT_NODE                 = 9;
+//DOCUMENT_TYPE_NODE            = 10;
+//DOCUMENT_FRAGMENT_NODE        = 11;
+//NOTATION_NODE                 = 12;
+
+//FIXME:  Remove this file when possible.
+//This file contains internal/helper APIs as holders until the true DOM apis of Dojo 0.9 are finalized.
+//Therefore, these should not be generally used, they are present only for the use by XmlStore and the
+//wires project until proper dojo replacements are available.  When such exist, XmlStore and the like
+//will be ported off these and this file will be deleted.
+dojo.experimental("dojox.data.dom");
+
+dojox.data.dom.createDocument = function(/*string?*/ str, /*string?*/ mimetype){
+	//	summary:
+	//		cross-browser implementation of creating an XML document object.
+	//
+	//	str:
+	//		Optional text to create the document from.  If not provided, an empty XML document will be created.
+	//	mimetype:
+	//		Optional mimetype of the text.  Typically, this is text/xml.  Will be defaulted to text/xml if not provided.
+	var _document = dojo.doc;
+
+	if(!mimetype){ mimetype = "text/xml"; }
+	if(str && (typeof dojo.global["DOMParser"]) !== "undefined"){
+		var parser = new DOMParser();
+		return parser.parseFromString(str, mimetype);	//	DOMDocument
+	}else if((typeof dojo.global["ActiveXObject"]) !== "undefined"){
+		var prefixes = [ "MSXML2", "Microsoft", "MSXML", "MSXML3" ];
+		for(var i = 0; i<prefixes.length; i++){
+			try{
+				var doc = new ActiveXObject(prefixes[i]+".XMLDOM");
+				if(str){
+					if(doc){
+						doc.async = false;
+						doc.loadXML(str);
+						return doc;	//	DOMDocument
+					}else{
+						console.log("loadXML didn't work?");
+					}
+				}else{
+					if(doc){ 
+						return doc; //DOMDocument
+					}
+				}
+			}catch(e){ /* squelch */ };
+		}
+	}else if((_document.implementation)&&
+		(_document.implementation.createDocument)){
+		if(str){
+			if(_document.createElement){
+				// FIXME: this may change all tags to uppercase!
+				var tmp = _document.createElement("xml");
+				tmp.innerHTML = str;
+				var xmlDoc = _document.implementation.createDocument("foo", "", null);
+				for(var i = 0; i < tmp.childNodes.length; i++) {
+					xmlDoc.importNode(tmp.childNodes.item(i), true);
+				}
+				return xmlDoc;	//	DOMDocument
+			}
+		}else{
+			return _document.implementation.createDocument("", "", null); // DOMDocument
+		}
+	}
+	return null;	//	DOMDocument
+}
+
+dojox.data.dom.textContent = function(/*Node*/node, /*string?*/text){
+	//	summary:
+	//		Implementation of the DOM Level 3 attribute; scan node for text
+	//	description:
+	//		Implementation of the DOM Level 3 attribute; scan node for text
+	//		This function can also update the text of a node by replacing all child 
+	//		content of the node.
+	//	node:
+	//		The node to get the text off of or set the text on.
+	//	text:
+	//		Optional argument of the text to apply to the node.
+	if(arguments.length>1){
+		var _document = node.ownerDocument || dojo.doc;  //Preference is to get the node owning doc first or it may fail
+		dojox.data.dom.replaceChildren(node, _document.createTextNode(text));
+		return text;	//	string
+	} else {
+		if(node.textContent !== undefined){ //FF 1.5
+			return node.textContent;	//	string
+		}
+		var _result = "";
+		if(node == null){
+			return _result; //empty string.
+		}
+		for(var i = 0; i < node.childNodes.length; i++){
+			switch(node.childNodes[i].nodeType){
+				case 1: // ELEMENT_NODE
+				case 5: // ENTITY_REFERENCE_NODE
+					_result += dojox.data.dom.textContent(node.childNodes[i]);
+					break;
+				case 3: // TEXT_NODE
+				case 2: // ATTRIBUTE_NODE
+				case 4: // CDATA_SECTION_NODE
+					_result += node.childNodes[i].nodeValue;
+					break;
+				default:
+					break;
+			}
+		}
+		return _result;	//	string
+	}
+}
+
+dojox.data.dom.replaceChildren = function(/*Element*/node, /*Node || array*/ newChildren){
+	//	summary:
+	//		Removes all children of node and appends newChild. All the existing
+	//		children will be destroyed.
+	//	description:
+	//		Removes all children of node and appends newChild. All the existing
+	//		children will be destroyed.
+	// 	node:
+	//		The node to modify the children on
+	//	newChildren:
+	//		The children to add to the node.  It can either be a single Node or an
+	//		array of Nodes.
+	var nodes = [];
+	
+	if(dojo.isIE){
+		for(var i=0;i<node.childNodes.length;i++){
+			nodes.push(node.childNodes[i]);
+		}
+	}
+
+	dojox.data.dom.removeChildren(node);
+	for(var i=0;i<nodes.length;i++){
+		dojox.data.dom.destroyNode(nodes[i]);
+	}
+
+	if(!dojo.isArray(newChildren)){
+		node.appendChild(newChildren);
+	}else{
+		for(var i=0;i<newChildren.length;i++){
+			node.appendChild(newChildren[i]);
+		}
+	}
+}
+
+dojox.data.dom.removeChildren = function(/*Element*/node){
+	//	summary:
+	//		removes all children from node and returns the count of children removed.
+	//		The children nodes are not destroyed. Be sure to call destroyNode on them
+	//		after they are not used anymore.
+	//	node:
+	//		The node to remove all the children from.
+	var count = node.childNodes.length;
+	while(node.hasChildNodes()){
+		node.removeChild(node.firstChild);
+	}
+	return count; // int
+}
+
+dojox.data.dom.destroyNode = function(/*Node*/node){
+	//	summary:
+	//		destroy a node (it can not be used any more). For IE, this is the
+	//		right function to call to prevent memory leaks. While for other
+	//		browsers, this is identical to node.parentNode.removeChild(node);
+	//	node:
+	//		The node to destroy.
+	if(node.parentNode){
+		node.parentNode.removeChild(node);	}
+	if(node.nodeType != 3){ // ingore TEXT_NODE
+		if(dojo.isIE && node.outerHTML){
+			node.outerHTML=''; //prevent ugly IE mem leak associated with Node.removeChild (ticket #1727)
+		}
+		dojox.data.dom.clean(node);
+	}
+}
+
+dojox.data.dom.innerXML = function(/*Node*/node){
+	//	summary:
+	//		Implementation of MS's innerXML function.
+	//	node:
+	//		The node from which to generate the XML text representation.
+	if(node.innerXML){
+		return node.innerXML;	//	string
+	}else if (node.xml){
+		return node.xml;		//	string
+	}else if(typeof XMLSerializer != "undefined"){
+		return (new XMLSerializer()).serializeToString(node);	//	string
+	}
+}
+
+dojox.data.dom.clean = function(/*DOMNode*/node){
+	// summary:
+	//		removes native event handlers so that destruction of the node
+	//		will not leak memory. On most browsers this is a no-op, but
+	//		it's critical for manual node removal on IE.
+	// node:
+	//		A DOM node. All of it's children will also be cleaned.
+	if(dojo.isIE){ 
+		dojox.data.dom._ie_clobber.clobber(node);
+	}
+}
+
+//Internal functions:
+dojox.data.dom._ie_clobber = new function(){
+	//	summary:
+	//		Internal function for handling cleanup of properties, etc, on nodes for IE.
+	//	description:
+	//		Internal function for handling cleanup of properties, etc, on nodes for IE.
+	//		This is needed to handle memory leaks in IE if cleanup isn't done manually.
+	this.clobberNodes = [];
+
+	function nukeProp(node, prop){
+		try{ node[prop] = null; 			}catch(e){ /* squelch */ }
+		try{ delete node[prop]; 			}catch(e){ /* squelch */ }
+		// FIXME: JotLive needs this, but I'm not sure if it's too slow or not
+		try{ node.removeAttribute(prop);	}catch(e){ /* squelch */ }
+	}
+
+	this.clobber = function(nodeRef){
+		var na;
+		var tna;
+		if(nodeRef){
+			tna = nodeRef.all || nodeRef.getElementsByTagName("*");
+			na = [nodeRef];
+			for(var x=0; x<tna.length; x++){
+				// if we're gonna be clobbering the thing, at least make sure
+				// we aren't trying to do it twice
+				if(tna[x]["__doClobber__"]){
+					na.push(tna[x]);
+				}
+			}
+		}else{
+			try{ window.onload = null; }catch(e){}
+			na = (this.clobberNodes.length) ? this.clobberNodes : document.all;
+		}
+		tna = null;
+		var basis = {};
+		for(var i = na.length-1; i>=0; i=i-1){
+			var el = na[i];
+			try{
+				if(el && el["__clobberAttrs__"]){
+					for(var j=0; j<el.__clobberAttrs__.length; j++){
+						nukeProp(el, el.__clobberAttrs__[j]);
+					}
+					nukeProp(el, "__clobberAttrs__");
+					nukeProp(el, "__doClobber__");
+				}
+			}catch(e){ /* squelch! */};
+		}
+		na = null;
+	}
+}

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/dom.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/dom.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/dom.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,140 @@
+dojo.provide("dojox.data.tests.dom");
+dojo.require("dojox.data.dom");
+
+tests.register("dojox.data.tests.dom", 
+	[
+		function testCreateDocument(t){
+			var document = dojox.data.dom.createDocument();
+			t.assertTrue(document !== null);
+		},
+		function testCreateDocumentFromText(t){
+			var simpleXml = "<parentNode><childNode><grandchildNode/></childNode><childNode/></parentNode>";
+			var document = dojox.data.dom.createDocument(simpleXml, "text/xml");
+			
+			var parent = document.firstChild;
+            t.assertTrue(parent !== null);
+			t.assertTrue(parent.tagName === "parentNode");
+			t.assertTrue(parent.childNodes.length == 2);
+			
+			var firstChild = parent.firstChild;
+			t.assertTrue(firstChild !== null);
+			t.assertTrue(firstChild.tagName === "childNode");
+			t.assertTrue(firstChild.childNodes.length == 1);
+			
+			var secondChild = firstChild.nextSibling;
+			t.assertTrue(secondChild !== null);
+			t.assertTrue(secondChild.tagName === "childNode");
+
+			var grandChild = firstChild.firstChild;
+			t.assertTrue(grandChild !== null);
+			t.assertTrue(grandChild.tagName === "grandchildNode");
+
+		},
+		function testDestroyNode(t){
+			var simpleXml = "<parentNode><childNode><grandchildNode/></childNode><childNode/></parentNode>";
+			var document = dojox.data.dom.createDocument(simpleXml, "text/xml");
+            
+			var topNode = document.firstChild;
+            t.assertTrue(topNode !== null);
+			t.assertTrue(topNode.tagName === "parentNode");
+			t.assertTrue(topNode.childNodes.length == 2);
+			dojox.data.dom.destroyNode(topNode);
+			t.assertTrue(document.firstChild === null);
+		},
+		function testReadTextContent(t){
+			var text = "This is a bunch of child text on the node";
+			var simpleXml = "<parentNode>" + text + "</parentNode>";
+			var document = dojox.data.dom.createDocument(simpleXml, "text/xml");
+            
+			var topNode = document.firstChild;
+            t.assertTrue(topNode !== null);
+			t.assertTrue(topNode.tagName === "parentNode");
+			t.assertTrue(text === dojox.data.dom.textContent(topNode));
+            dojox.data.dom.destroyNode(topNode);
+			t.assertTrue(document.firstChild === null);
+		},
+		function testSetTextContent(t){
+			var text = "This is a bunch of child text on the node";
+			var text2 = "This is the new text";
+			var simpleXml = "<parentNode>" + text + "</parentNode>";
+			var document = dojox.data.dom.createDocument(simpleXml, "text/xml");
+            
+			var topNode = document.firstChild;
+			t.assertTrue(topNode !== null);
+			t.assertTrue(topNode.tagName === "parentNode");
+			t.assertTrue(text === dojox.data.dom.textContent(topNode));
+			dojox.data.dom.textContent(topNode, text2);
+			t.assertTrue(text2 === dojox.data.dom.textContent(topNode));
+			dojox.data.dom.destroyNode(topNode);
+			t.assertTrue(document.firstChild === null);
+
+		},
+		function testReplaceChildrenArray(t){
+			var simpleXml1 = "<parentNode><child1/><child2/><child3/></parentNode>";
+			var simpleXml2 = "<parentNode><child4/><child5/><child6/><child7/></parentNode>";
+			var doc1 = dojox.data.dom.createDocument(simpleXml1, "text/xml");
+			var doc2 = dojox.data.dom.createDocument(simpleXml2, "text/xml");
+            
+			var topNode1 = doc1.firstChild;
+			var topNode2 = doc2.firstChild;
+            t.assertTrue(topNode1 !== null);
+			t.assertTrue(topNode1.tagName === "parentNode");
+            t.assertTrue(topNode2 !== null);
+			t.assertTrue(topNode2.tagName === "parentNode");
+			dojox.data.dom.removeChildren(topNode1);
+			var newChildren=[];
+			for(var i=0;i<topNode2.childNodes.length;i++){
+				newChildren.push(topNode2.childNodes[i]);
+			}
+			dojox.data.dom.removeChildren(topNode2);
+			dojox.data.dom.replaceChildren(topNode1,newChildren);
+			t.assertTrue(topNode1.childNodes.length === 4);
+			t.assertTrue(topNode1.firstChild.tagName === "child4");
+			t.assertTrue(topNode1.lastChild.tagName === "child7");
+
+		},
+		function testReplaceChildrenSingle(t){
+			var simpleXml1 = "<parentNode><child1/><child2/><child3/></parentNode>";
+			var simpleXml2 = "<parentNode><child4/></parentNode>";
+			var doc1 = dojox.data.dom.createDocument(simpleXml1, "text/xml");
+			var doc2 = dojox.data.dom.createDocument(simpleXml2, "text/xml");
+            
+			var topNode1 = doc1.firstChild;
+			var topNode2 = doc2.firstChild;
+            t.assertTrue(topNode1 !== null);
+			t.assertTrue(topNode1.tagName === "parentNode");
+            t.assertTrue(topNode2 !== null);
+			t.assertTrue(topNode2.tagName === "parentNode");
+			dojox.data.dom.removeChildren(topNode1);
+			
+			var newChildren = topNode2.firstChild;
+			dojox.data.dom.removeChildren(topNode2);
+			dojox.data.dom.replaceChildren(topNode1,newChildren);
+			t.assertTrue(topNode1.childNodes.length === 1);
+			t.assertTrue(topNode1.firstChild.tagName === "child4");
+			t.assertTrue(topNode1.lastChild.tagName === "child4");
+		},
+		function testRemoveChildren(t){
+			var simpleXml1 = "<parentNode><child1/><child2/><child3/></parentNode>";
+			var doc1 = dojox.data.dom.createDocument(simpleXml1, "text/xml");
+            
+			var topNode1 = doc1.firstChild;
+            t.assertTrue(topNode1 !== null);
+			t.assertTrue(topNode1.tagName === "parentNode");
+			dojox.data.dom.removeChildren(topNode1);
+			t.assertTrue(topNode1.childNodes.length === 0);
+			t.assertTrue(topNode1.firstChild === null);
+		},
+		function testInnerXML(t){
+			var simpleXml1 = "<parentNode><child1/><child2/><child3/></parentNode>";
+			var doc1 = dojox.data.dom.createDocument(simpleXml1, "text/xml");
+            
+			var topNode1 = doc1.firstChild;
+            t.assertTrue(topNode1 !== null);
+			t.assertTrue(topNode1.tagName === "parentNode");
+
+			var innerXml = dojox.data.dom.innerXML(topNode1);
+			t.assertTrue(simpleXml1 === innerXml);
+		}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/module.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/module.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/module.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,11 @@
+dojo.provide("dojox.tests.module");
+
+try{
+	dojo.require("dojox.data.tests.stores.CsvStore");
+	dojo.require("dojox.data.tests.stores.OpmlStore");
+	dojo.requireIf(dojo.isBrowser, "dojox.data.tests.stores.XmlStore");
+	dojo.requireIf(dojo.isBrowser, "dojox.data.tests.dom");
+}catch(e){
+	doh.debug(e);
+}
+

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/runTests.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/runTests.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/runTests.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+    <head>
+    <title>Dojox Unit Test Runner</title>
+    <meta http-equiv="REFRESH" content="0;url=../../../util/doh/runner.html?testModule=dojox.data.tests.module"></HEAD>
+    <BODY>
+        Redirecting to D.O.H runner.
+    </BODY>
+</HTML> 

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/CsvStore.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/CsvStore.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/CsvStore.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,792 @@
+dojo.provide("dojox.data.tests.stores.CsvStore");
+dojo.require("dojox.data.CsvStore");
+dojo.require("dojo.data.api.Read");
+dojo.require("dojo.data.api.Identity");
+
+dojox.data.tests.stores.CsvStore.getDatasource = function(filepath){
+	//  summary:
+	//		A simple helper function for getting the sample data used in each of the tests.
+	//  description:
+	//		A simple helper function for getting the sample data used in each of the tests.
+	
+	var dataSource = {};
+	if(dojo.isBrowser){
+		dataSource.url = dojo.moduleUrl("dojox.data.tests", filepath).toString();            
+	}else{
+		// When running tests in Rhino, xhrGet is not available,
+		// so we have the file data in the code below.
+		switch(filepath){
+			case "stores/movies.csv":
+				var csvData = "";
+				csvData += "Title, Year, Producer\n";
+				csvData += "City of God, 2002, Katia Lund\n";
+				csvData += "Rain,, Christine Jeffs\n";
+				csvData += "2001: A Space Odyssey, 1968, Stanley Kubrick\n";
+				csvData += '"This is a ""fake"" movie title", 1957, Sidney Lumet\n';
+				csvData += "Alien, 1979   , Ridley Scott\n";
+				csvData += '"The Sequel to ""Dances With Wolves.""", 1982, Ridley Scott\n';
+				csvData += '"Caine Mutiny, The", 1954, "Dymtryk ""the King"", Edward"\n';
+				break;
+			case "stores/books.csv":
+				var csvData = "";
+				csvData += "Title, Author\n";
+				csvData += "The Transparent Society, David Brin\n";
+				csvData += "The First Measured Century, Theodore Caplow\n";
+				csvData += "Maps in a Mirror, Orson Scott Card\n";
+				csvData += "Princess Smartypants, Babette Cole\n";
+				csvData += "Carfree Cities, Crawford J.H.\n";
+				csvData += "Down and Out in the Magic Kingdom, Cory Doctorow\n";
+				csvData += "Tax Shift, Alan Thein Durning\n";
+				csvData += "The Sneetches and other stories, Dr. Seuss\n";
+				csvData += "News from Tartary, Peter Fleming\n";
+				break;
+			case "stores/patterns.csv":
+				var csvData = "";
+				csvData += "uniqueId, value\n";
+				csvData += "9, jfq4@#!$!@Rf14r14i5u\n";
+				csvData += "6, BaBaMaSaRa***Foo\n";
+				csvData += "2, bar*foo\n";
+				csvData += "8, 123abc\n";
+				csvData += "4, bit$Bite\n";
+				csvData += "3, 123abc\n";
+				csvData += "10, 123abcdefg\n";
+				csvData += "1, foo*bar\n";
+				csvData += "7, \n";
+				csvData += "5, 123abc\n"
+				break;
+		}
+		dataSource.data = csvData;
+	}
+	return dataSource; //Object
+}
+
+dojox.data.tests.stores.CsvStore.verifyItems = function(csvStore, items, attribute, compareArray){
+	//  summary:
+	//		A helper function for validating that the items array is ordered
+	//		the same as the compareArray
+	if(items.length != compareArray.length){ return false; }
+	for(var i = 0; i < items.length; i++){
+		if(!(csvStore.getValue(items[i], attribute) === compareArray[i])){
+			return false; //Boolean
+		}
+	}
+	return true; //Boolean
+}
+
+dojox.data.tests.stores.CsvStore.error = function(t, d, errData){
+	//  summary:
+	//		The error callback function to be used for all of the tests.
+	d.errback(errData);	
+}
+
+tests.register("dojox.data.tests.stores.CsvStore", 
+	[
+		function testReadAPI_fetch_all(t){
+			//	summary: 
+			//		Simple test of a basic fetch on CsvStore.
+			//	description:
+			//		Simple test of a basic fetch on CsvStore.
+			
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			var d = new tests.Deferred();
+            function completedAll(items){
+				t.assertTrue((items.length === 7));
+				d.callback(true);
+			}
+
+			//Get everything...
+			csvStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_one(t){
+			//	summary: 
+			//		Simple test of a basic fetch on CsvStore of a single item.
+			//	description:
+			//		Simple test of a basic fetch on CsvStore of a single item.
+
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			var d = new tests.Deferred();
+			function onComplete(items, request){
+				t.is(1, items.length);
+				d.callback(true);
+			}
+			csvStore.fetch({ 	query: {Title: "*Sequel*"}, 
+								onComplete: onComplete, 
+								onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)
+							});
+			return d; //Object
+		},
+		function testReadAPI_fetch_all_streaming(t){
+			//	summary: 
+			//		Simple test of a basic fetch on CsvStore.
+			//	description:
+			//		Simple test of a basic fetch on CsvStore.
+
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+
+			var d = new tests.Deferred();
+			count = 0;
+
+			function onBegin(size, requestObj){
+				t.assertTrue(size === 7);
+			}
+			function onItem(item, requestObj){
+				t.assertTrue(csvStore.isItem(item));
+				count++;
+			}
+			function onComplete(items, request){
+				t.is(7, count);
+				t.is(null, items);
+			    d.callback(true);
+			}
+
+			//Get everything...
+			csvStore.fetch({	onBegin: onBegin,
+								onItem: onItem, 
+								onComplete: onComplete,
+								onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)
+							});
+			return d; //Object
+		},
+		function testReadAPI_fetch_paging(t){
+			 //	summary: 
+			 //		Test of multiple fetches on a single result.  Paging, if you will.
+			 //	description:
+			 //		Test of multiple fetches on a single result.  Paging, if you will.
+
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			var d = new tests.Deferred();
+			function dumpFirstFetch(items, request){
+				t.is(5, items.length);
+				request.start = 3;
+				request.count = 1;
+				request.onComplete = dumpSecondFetch;
+				csvStore.fetch(request);
+			}
+
+			function dumpSecondFetch(items, request){
+				t.is(1, items.length);
+				request.start = 0;
+				request.count = 5;
+				request.onComplete = dumpThirdFetch;
+				csvStore.fetch(request);
+			}
+
+			function dumpThirdFetch(items, request){
+				t.is(5, items.length);
+				request.start = 2;
+				request.count = 20;
+				request.onComplete = dumpFourthFetch;
+				csvStore.fetch(request);
+			}
+
+			function dumpFourthFetch(items, request){
+				t.is(5, items.length);
+                request.start = 9;
+				request.count = 100;
+				request.onComplete = dumpFifthFetch;
+				csvStore.fetch(request);
+			}
+
+			function dumpFifthFetch(items, request){
+				t.is(0, items.length);
+				request.start = 2;
+				request.count = 20;
+				request.onComplete = dumpSixthFetch;
+				csvStore.fetch(request);
+			}
+
+			function dumpSixthFetch(items, request){
+				t.is(5, items.length);
+			    d.callback(true);
+			}
+
+			function completed(items, request){
+				t.is(7, items.length);
+				request.start = 1;
+				request.count = 5;
+				request.onComplete = dumpFirstFetch;
+				csvStore.fetch(request);
+			}
+
+			csvStore.fetch({onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+
+		},
+		function testReadAPI_getValue(t){
+			//	summary: 
+			//		Simple test of the getValue function of the store.
+			//	description:
+			//		Simple test of the getValue function of the store.
+
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			         
+			t.is("City of God", 				csvStore.getValue(csvStore.getItemByIdentity("0"),"Title"));
+			t.is("Rain", 					csvStore.getValue(csvStore.getItemByIdentity("1"),"Title"));
+			t.is("2001: A Space Odyssey", 			csvStore.getValue(csvStore.getItemByIdentity("2"),"Title"));
+			t.is('This is a "fake" movie title', 		csvStore.getValue(csvStore.getItemByIdentity("3"),"Title"));
+			t.is("Alien", 					csvStore.getValue(csvStore.getItemByIdentity("4"),"Title"));
+			t.is('The Sequel to "Dances With Wolves."', 	csvStore.getValue(csvStore.getItemByIdentity("5"),"Title"));
+			t.is('Caine Mutiny, The', 			csvStore.getValue(csvStore.getItemByIdentity("6"),"Title"));
+
+			t.is("2002", 					csvStore.getValue(csvStore.getItemByIdentity("0"),"Year"));
+			t.is("1979", 					csvStore.getValue(csvStore.getItemByIdentity("4"),"Year"));
+
+			t.is("Stanley Kubrick", 			csvStore.getValue(csvStore.getItemByIdentity("2"),"Producer"));
+			t.is('Dymtryk "the King", Edward', 		csvStore.getValue(csvStore.getItemByIdentity("6"),"Producer"));
+		},	
+		function testReadAPI_getValues(t){
+			//	summary: 
+			//		Simple test of the getValues function of the store.
+			//	description:
+			//		Simple test of the getValues function of the store.
+
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+
+			var item = csvStore.getItemByIdentity("1");
+			t.assertTrue(item !== null);
+			var names = csvStore.getValues(item,"Title");
+            t.assertTrue(dojo.isArray(names));
+			t.is(1, names.length);
+			t.is("Rain", names[0]);
+		},
+		function testIdentityAPI_getItemByIdentity(t){
+			//	summary: 
+			//		Simple test of the getItemByIdentity function of the store.
+			//	description:
+			//		Simple test of the getItemByIdentity function of the store.
+			
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			for(var i=0; i<7; i++){
+				t.assertTrue(csvStore.getItemByIdentity(i) !== null);
+			}
+			t.is(null, csvStore.getItemByIdentity("7"));
+			t.is(null, csvStore.getItemByIdentity("-1"));
+			t.is(null, csvStore.getItemByIdentity("999999"));
+		},
+		function testIdentityAPI_getIdentity(t){
+			//	summary: 
+			//		Simple test of the getItemByIdentity function of the store.
+			//	description:
+			//		Simple test of the getItemByIdentity function of the store.
+			
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.is(7, items.length);
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					if(!(csvStore.getIdentity(items[i]) === i)){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				d.callback(true);
+			}
+			
+			//Get everything...
+			csvStore.fetch({ onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_isItem(t){
+			//	summary: 
+			//		Simple test of the isItem function of the store
+			//	description:
+			//		Simple test of the isItem function of the store
+
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+
+			for(var i=0; i<7; i++){
+				t.assertTrue(csvStore.isItem(csvStore.getItemByIdentity(i)));
+			}
+			
+			t.assertTrue(!csvStore.isItem({}));
+			t.assertTrue(!csvStore.isItem({ item: "not an item" }));
+			t.assertTrue(!csvStore.isItem("not an item"));
+			t.assertTrue(!csvStore.isItem(["not an item"]));
+		},
+		function testReadAPI_hasAttribute(t){
+			//	summary: 
+			//		Simple test of the hasAttribute function of the store
+			//	description:
+			//		Simple test of the hasAttribute function of the store
+
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+
+			var item = csvStore.getItemByIdentity(1);
+			t.assertTrue(item !== null);
+			t.assertTrue(csvStore.hasAttribute(item, "Title"));
+			t.assertTrue(csvStore.hasAttribute(item, "Producer"));
+			t.assertTrue(!csvStore.hasAttribute(item, "Year"));
+			t.assertTrue(!csvStore.hasAttribute(item, "Nothing"));
+			t.assertTrue(!csvStore.hasAttribute(item, "title"));
+
+			//Test that null attributes throw an exception
+			var passed = false;
+			try{
+				csvStore.hasAttribute(item, null);
+			}catch (e){
+				passed = true;
+			}
+			t.assertTrue(passed);
+		},
+		function testReadAPI_containsValue(t){
+			//	summary: 
+			//		Simple test of the containsValue function of the store
+			//	description:
+			//		Simple test of the containsValue function of the store
+
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+ 			
+			var item = csvStore.getItemByIdentity("4");
+			t.assertTrue(item !== null);
+			t.assertTrue(csvStore.containsValue(item, "Title", "Alien"));
+			t.assertTrue(csvStore.containsValue(item, "Year", "1979"));
+			t.assertTrue(csvStore.containsValue(item, "Producer", "Ridley Scott"));
+			t.assertTrue(!csvStore.containsValue(item, "Title", "Alien2"));
+			t.assertTrue(!csvStore.containsValue(item, "Year", "1979   "));
+			t.assertTrue(!csvStore.containsValue(item, "Title", null));
+
+			//Test that null attributes throw an exception
+			var passed = false;
+			try{
+				csvStore.containsValue(item, null, "foo");
+			}catch (e){
+				passed = true;
+			}
+			t.assertTrue(passed);
+		},
+		function testReadAPI_getAttributes(t){
+			//	summary: 
+			//		Simple test of the getAttributes function of the store
+			//	description:
+			//		Simple test of the getAttributes function of the store
+
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+
+			var item = csvStore.getItemByIdentity("4");
+			t.assertTrue(item !== null);
+			t.assertTrue(csvStore.isItem(item));
+
+			var attributes = csvStore.getAttributes(item);
+			t.is(3, attributes.length);
+			for(var i = 0; i < attributes.length; i++){
+				t.assertTrue((attributes[i] === "Title" || attributes[i] === "Year" || attributes[i] === "Producer"));
+			}
+			
+			// Test an item that does not have all of the attributes
+			var item = csvStore.getItemByIdentity(1);
+			t.assertTrue(item !== null);
+			t.assertTrue(csvStore.isItem(item));
+
+			var attributes = csvStore.getAttributes(item);
+			t.assertTrue(attributes.length === 2);
+			t.assertTrue(attributes[0] === "Title");
+			t.assertTrue(attributes[1] === "Producer");
+		},
+		function testReadAPI_getFeatures(t){
+			//	summary: 
+			//		Simple test of the getFeatures function of the store
+			//	description:
+			//		Simple test of the getFeatures function of the store
+
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+
+			var features = csvStore.getFeatures(); 
+			var count = 0;
+			for(i in features){
+				t.assertTrue((i === "dojo.data.api.Read" || i === "dojo.data.api.Identity"));
+				count++;
+			}
+			t.assertTrue(count === 2);
+		},
+		function testReadAPI_fetch_patternMatch0(t){
+			//	summary: 
+			//		Function to test pattern matching of everything starting with lowercase e
+			//	description:
+			//		Function to test pattern matching of everything starting with lowercase e
+
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.is(2, items.length);
+				var valueArray = [ "Alien", "The Sequel to \"Dances With Wolves.\""];
+				t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "Title", valueArray));
+				d.callback(true);
+			}
+			
+			csvStore.fetch({query: {Producer: "* Scott"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_patternMatch1(t){
+			//	summary: 
+			//		Function to test pattern matching of everything with $ in it.
+			//	description:
+			//		Function to test pattern matching of everything with $ in it.
+			
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.assertTrue(items.length === 2);
+				var valueArray = [ "jfq4@#!$!@Rf14r14i5u", "bit$Bite"];
+				t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "value", valueArray));
+				d.callback(true);
+			}
+			
+			csvStore.fetch({query: {value: "*$*"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_patternMatch2(t){
+			//	summary: 
+			//		Function to test exact pattern match
+			//	description:
+			//		Function to test exact pattern match
+			
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.is(1, items.length);
+				t.assertTrue(csvStore.getValue(items[0], "value") === "bar*foo");
+				d.callback(true);
+			}
+			
+			csvStore.fetch({query: {value: "bar\*foo"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_patternMatch_caseInsensitive(t){
+			//	summary: 
+			//		Function to test exact pattern match with case insensitivity set.
+			//	description:
+			//		Function to test exact pattern match with case insensitivity set.
+			
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.is(1, items.length);
+				t.assertTrue(csvStore.getValue(items[0], "value") === "bar*foo");
+				d.callback(true);
+			}
+			
+			csvStore.fetch({query: {value: "BAR\\*foo"}, queryOptions: {ignoreCase: true}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_patternMatch_caseSensitive(t){
+			//	summary: 
+			//		Function to test exact pattern match with case insensitivity set.
+			//	description:
+			//		Function to test exact pattern match with case insensitivity set.
+			
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.is(0, items.length);
+				d.callback(true);
+			}
+			
+			csvStore.fetch({query: {value: "BAR\\*foo"}, queryOptions: {ignoreCase: false}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_sortNumeric(t){
+			//	summary: 
+			//		Function to test sorting numerically.
+			//	description:
+			//		Function to test sorting numerically.
+			
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.assertTrue(items.length === 10);
+				// TODO: CsvStore treats everything like a string, so these numbers will be sorted lexicographically.
+				var orderedArray = [ "1", "10", "2", "3", "4", "5", "6", "7", "8", "9" ];
+				t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "uniqueId", orderedArray));
+				d.callback(true);
+			}
+
+			var sortAttributes = [{attribute: "uniqueId"}];
+			csvStore.fetch({onComplete: completed, 
+							onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d),
+							sort: sortAttributes});
+			return d; //Object
+		},
+		function testReadAPI_fetch_sortNumericDescending(t){
+			//	summary: 
+			//		Function to test sorting numerically.
+			//	description:
+			//		Function to test sorting numerically.
+
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.is(10, items.length);
+				// TODO: CsvStore treats everything like a string, so these numbers will be sorted lexicographically.
+				var orderedArray = [ "9", "8", "7", "6", "5", "4", "3", "2", "10", "1" ];
+				t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "uniqueId", orderedArray));
+				d.callback(true);
+			}
+			
+			var sortAttributes = [{attribute: "uniqueId", descending: true}];
+			csvStore.fetch({ sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_sortNumericWithCount(t){
+			//	summary: 
+			//		Function to test sorting numerically in descending order, returning only a specified number of them.
+			//	description:
+			//		Function to test sorting numerically in descending order, returning only a specified number of them.
+		
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.is(5, items.length);
+				// TODO: CsvStore treats everything like a string, so these numbers will be sorted lexicographically.
+				var orderedArray = [ "9", "8", "7", "6", "5" ];
+				t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "uniqueId", orderedArray));
+				d.callback(true);
+			}
+			
+			var sortAttributes = [{attribute: "uniqueId", descending: true}];
+			csvStore.fetch({sort: sortAttributes, 
+							count: 5,
+							onComplete: completed,
+							onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_sortAlphabetic(t){
+			//	summary: 
+			//		Function to test sorting alphabetic ordering.
+			//	description:
+			//		Function to test sorting alphabetic ordering.
+		
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				//Output should be in this order...
+				var orderedArray = [ 	"123abc",
+										"123abc",
+										"123abc",
+										"123abcdefg",
+										"BaBaMaSaRa***Foo",
+										"bar*foo",
+										"bit$Bite",
+										"foo*bar",
+										"jfq4@#!$!@Rf14r14i5u",
+										undefined
+					];
+				t.is(10, items.length);
+				t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "value", orderedArray));
+				d.callback(true);
+			}
+			
+			var sortAttributes = [{attribute: "value"}];
+			csvStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_sortAlphabeticDescending(t){
+			//	summary: 
+			//		Function to test sorting alphabetic ordering in descending mode.
+			//	description:
+			//		Function to test sorting alphabetic ordering in descending mode.
+		
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				//Output should be in this order...
+				var orderedArray = [ 	undefined,
+										"jfq4@#!$!@Rf14r14i5u",
+										"foo*bar",
+										"bit$Bite",
+										"bar*foo",
+										"BaBaMaSaRa***Foo",
+										"123abcdefg",
+										"123abc",
+										"123abc",
+										"123abc"
+					];
+				t.is(10, items.length);
+				t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "value", orderedArray));
+				d.callback(true);
+			}
+			
+			var sortAttributes = [{attribute: "value", descending: true}];
+			csvStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_sortMultiple(t){
+			//	summary: 
+			//		Function to test sorting on multiple attributes.
+			//	description:
+			//		Function to test sorting on multiple attributes.
+			
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/patterns.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+		
+			var d = new tests.Deferred();
+			function completed(items, request){
+				var orderedArray0 = [ "8", "5", "3", "10", "6", "2", "4", "1", "9", "7" ];
+				var orderedArray1 = [	"123abc",
+										"123abc",
+										"123abc",
+										"123abcdefg",
+										"BaBaMaSaRa***Foo",
+										"bar*foo",
+										"bit$Bite",
+										"foo*bar",
+										"jfq4@#!$!@Rf14r14i5u",
+										undefined
+									];
+				t.is(10, items.length);
+				t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "uniqueId", orderedArray0));
+				t.assertTrue(dojox.data.tests.stores.CsvStore.verifyItems(csvStore, items, "value", orderedArray1));
+				d.callback(true);
+			}
+			
+			var sortAttributes = [{ attribute: "value"}, { attribute: "uniqueId", descending: true}];
+			csvStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_sortMultipleSpecialComparator(t){
+			//	summary: 
+			//		Function to test sorting on multiple attributes with a custom comparator.
+			//	description:
+			//		Function to test sorting on multiple attributes with a custom comparator.
+
+			var args = dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv");
+			var csvStore = new dojox.data.CsvStore(args);
+			
+			csvStore.comparatorMap = {};
+			csvStore.comparatorMap["Producer"] = function(a,b){ 
+				var ret = 0;
+				// We want to sort authors alphabetical by their last name
+				function lastName(name){
+					if(typeof name === "undefined"){ return undefined; }
+					
+					var matches = name.match(/\s*(\S+)$/); // Grab the last word in the string.
+					return matches ? matches[1] : name; // Strings with only whitespace will not match.
+				}
+				var lastNameA = lastName(a);
+				var lastNameB = lastName(b);
+				if(lastNameA > lastNameB || typeof lastNameA === "undefined"){
+					ret = 1;
+				}else if(lastNameA < lastNameB || typeof lastNameB === "undefined"){
+					ret = -1;
+				}
+				return ret;
+			};
+		
+			var sortAttributes = [{attribute: "Producer", descending: true}, { attribute: "Title", descending: true}];
+		
+			var d = new tests.Deferred();
+			function completed(items, findResult){
+				var orderedArray = [5,4,0,3,2,1,6];
+				t.assertTrue(items.length === 7);
+				var passed = true;
+				for(var i = 0; i < items.length; i++){
+					if(!(csvStore.getIdentity(items[i]) === orderedArray[i])){
+						passed=false;
+						break;
+					}
+				}
+				t.assertTrue(passed);
+				d.callback(true);
+			}
+			
+			csvStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.CsvStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_functionConformance(t){
+			//	summary: 
+			//		Simple test read API conformance.  Checks to see all declared functions are actual functions on the instances.
+			//	description:
+			//		Simple test read API conformance.  Checks to see all declared functions are actual functions on the instances.
+
+			var testStore = new dojox.data.CsvStore(dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"));
+			var readApi = new dojo.data.api.Read();
+			var passed = true;
+
+			for(i in readApi){
+				if(i.toString().charAt(0) !== '_')
+				{
+					var member = readApi[i];
+					//Check that all the 'Read' defined functions exist on the test store.
+					if(typeof member === "function"){
+						console.log("Looking at function: [" + i + "]");
+						var testStoreMember = testStore[i];
+						if(!(typeof testStoreMember === "function")){
+							console.log("Problem with function: [" + i + "].   Got value: " + testStoreMember);
+							passed = false;
+							break;
+						}
+					}
+				}
+			}
+			t.assertTrue(passed);
+		},
+		function testIdentityAPI_functionConformance(t){
+			//	summary: 
+			//		Simple test identity API conformance.  Checks to see all declared functions are actual functions on the instances.
+			//	description:
+			//		Simple test identity API conformance.  Checks to see all declared functions are actual functions on the instances.
+
+			var testStore = new dojox.data.CsvStore(dojox.data.tests.stores.CsvStore.getDatasource("stores/movies.csv"));
+			var identityApi = new dojo.data.api.Identity();
+			var passed = true;
+
+			for(i in identityApi){
+				if(i.toString().charAt(0) !== '_')
+				{
+					var member = identityApi[i];
+					//Check that all the 'Read' defined functions exist on the test store.
+					if(typeof member === "function"){
+						console.log("Looking at function: [" + i + "]");
+						var testStoreMember = testStore[i];
+						if(!(typeof testStoreMember === "function")){
+							passed = false;
+							break;
+						}
+					}
+				}
+			}
+			t.assertTrue(passed);
+		}
+	]
+);
+

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/OpmlStore.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/OpmlStore.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/OpmlStore.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,673 @@
+dojo.provide("dojox.data.tests.stores.OpmlStore");
+dojo.require("dojox.data.OpmlStore");
+dojo.require("dojo.data.api.Read");
+
+dojox.data.tests.stores.OpmlStore.getDatasource = function(filepath){
+	//  summary:
+	//		A simple helper function for getting the sample data used in each of the tests.
+	//  description:
+	//		A simple helper function for getting the sample data used in each of the tests.
+	
+	var dataSource = {};
+	if(dojo.isBrowser){
+		dataSource.url = dojo.moduleUrl("dojox.data.tests", filepath).toString();            
+	}else{
+		// When running tests in Rhino, xhrGet is not available,
+		// so we have the file data in the code below.
+		switch(filepath){
+			case "stores/geography.xml":
+				var opmlData = "";
+				opmlData += '<?xml version="1.0" encoding="ISO-8859-1"?>\n';
+				opmlData += '	<opml version="1.0">\n';
+				opmlData += '		<head>\n';
+				opmlData += '			<title>geography.opml</title>\n';
+				opmlData += '			<dateCreated>2006-11-10</dateCreated>\n';
+				opmlData += '			<dateModified>2006-11-13</dateModified>\n';
+				opmlData += '			<ownerName>Magellan, Ferdinand</ownerName>\n';
+				opmlData += '		</head>\n';
+				opmlData += '		<body>\n';
+				opmlData += '			<outline text="Africa" type="continent">\n';
+				opmlData += '				<outline text="Egypt" type="country"/>\n';
+				opmlData += '				<outline text="Kenya" type="country">\n';
+				opmlData += '					<outline text="Nairobi" type="city"/>\n';
+				opmlData += '					<outline text="Mombasa" type="city"/>\n';
+				opmlData += '				</outline>\n';
+				opmlData += '				<outline text="Sudan" type="country">\n';
+				opmlData += '					<outline text="Khartoum" type="city"/>\n';
+				opmlData += '				</outline>\n';
+				opmlData += '			</outline>\n';
+				opmlData += '			<outline text="Asia" type="continent">\n';
+				opmlData += '				<outline text="China" type="country"/>\n';
+				opmlData += '				<outline text="India" type="country"/>\n';
+				opmlData += '				<outline text="Russia" type="country"/>\n';
+				opmlData += '				<outline text="Mongolia" type="country"/>\n';
+				opmlData += '			</outline>\n';
+				opmlData += '			<outline text="Australia" type="continent" population="21 million">\n';
+				opmlData += '				<outline text="Australia" type="country" population="21 million"/>\n';
+				opmlData += '			</outline>\n';
+				opmlData += '			<outline text="Europe" type="continent">\n';
+				opmlData += '				<outline text="Germany" type="country"/>\n';
+				opmlData += '				<outline text="France" type="country"/>\n';
+				opmlData += '				<outline text="Spain" type="country"/>\n';
+				opmlData += '				<outline text="Italy" type="country"/>\n';
+				opmlData += '			</outline>\n';
+				opmlData += '			<outline text="North America" type="continent">\n';
+				opmlData += '				<outline text="Mexico" type="country" population="108 million" area="1,972,550 sq km">\n';
+				opmlData += '					<outline text="Mexico City" type="city" population="19 million" timezone="-6 UTC"/>\n';
+				opmlData += '					<outline text="Guadalajara" type="city" population="4 million" timezone="-6 UTC"/>\n';
+				opmlData += '				</outline>\n';
+				opmlData += '				<outline text="Canada" type="country" population="33 million" area="9,984,670 sq km">\n';
+				opmlData += '					<outline text="Ottawa" type="city" population="0.9 million" timezone="-5 UTC"/>\n';
+				opmlData += '					<outline text="Toronto" type="city" population="2.5 million" timezone="-5 UTC"/>\n';
+				opmlData += '				</outline>\n';
+				opmlData += '				<outline text="United States of America" type="country"/>\n';
+				opmlData += '			</outline>\n';
+				opmlData += '			<outline text="South America" type="continent">\n';
+				opmlData += '				<outline text="Brazil" type="country" population="186 million"/>\n';
+				opmlData += '				<outline text="Argentina" type="country" population="40 million"/>\n';
+				opmlData += '			</outline>\n';
+				opmlData += '		</body>\n';
+				opmlData += '	</opml>\n';
+				break;
+		}
+		dataSource.data = opmlData;
+	}
+	return dataSource; //Object
+}
+
+dojox.data.tests.stores.OpmlStore.verifyItems = function(opmlStore, items, attribute, compareArray){
+	//  summary:
+	//		A helper function for validating that the items array is ordered
+	//		the same as the compareArray
+	if(items.length != compareArray.length){ return false; }
+	for(var i = 0; i < items.length; i++){
+		if(!(opmlStore.getValue(items[i], attribute) === compareArray[i])){
+			return false; //Boolean
+		}
+	}
+	return true; //Boolean
+}
+
+dojox.data.tests.stores.OpmlStore.error = function(t, d, errData){
+	//  summary:
+	//		The error callback function to be used for all of the tests.
+	d.errback(errData);	
+}
+
+tests.register("dojox.data.tests.stores.OpmlStore", 
+	[
+		function testReadAPI_fetch_all(t){
+			//	summary: 
+			//		Simple test of a basic fetch on OpmlStore.
+			//	description:
+			//		Simple test of a basic fetch on OpmlStore.
+			
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+			
+			var d = new tests.Deferred();
+			function completedAll(items){
+				t.is(6, items.length);
+				d.callback(true);
+			}
+
+			//Get everything...
+			opmlStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_one(t){
+			//	summary: 
+			//		Simple test of a basic fetch on OpmlStore of a single item.
+			//	description:
+			//		Simple test of a basic fetch on OpmlStore of a single item.
+
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+			
+			var d = new tests.Deferred();
+			function onComplete(items, request){
+				t.is(1, items.length);
+				d.callback(true);
+			}
+			opmlStore.fetch({ 	query: {text: "Asia"}, 
+								onComplete: onComplete, 
+								onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+							});
+			return d; //Object
+		},
+		function testReadAPI_fetch_all_streaming(t){
+			//	summary: 
+			//		Simple test of a basic fetch on OpmlStore.
+			//	description:
+			//		Simple test of a basic fetch on OpmlStore.
+
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+
+			var d = new tests.Deferred();
+			count = 0;
+
+			function onBegin(size, requestObj){
+				t.is(6, size);
+			}
+			function onItem(item, requestObj){
+				t.assertTrue(opmlStore.isItem(item));
+				count++;
+			}
+			function onComplete(items, request){
+				t.is(6, count);
+				t.is(null, items);
+				d.callback(true);
+			}
+
+			//Get everything...
+			opmlStore.fetch({	onBegin: onBegin,
+								onItem: onItem, 
+								onComplete: onComplete,
+								onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+							});
+			return d; //Object
+		},
+		function testReadAPI_fetch_paging(t){
+			 //	summary: 
+			 //		Test of multiple fetches on a single result.  Paging, if you will.
+			 //	description:
+			 //		Test of multiple fetches on a single result.  Paging, if you will.
+
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+			
+			var d = new tests.Deferred();
+			function dumpFirstFetch(items, request){
+				t.is(5, items.length);
+				request.start = 3;
+				request.count = 1;
+				request.onComplete = dumpSecondFetch;
+				opmlStore.fetch(request);
+			}
+
+			function dumpSecondFetch(items, request){
+				t.is(1, items.length);
+				request.start = 0;
+				request.count = 5;
+				request.onComplete = dumpThirdFetch;
+				opmlStore.fetch(request);
+			}
+
+			function dumpThirdFetch(items, request){
+				t.is(5, items.length);
+				request.start = 2;
+				request.count = 20;
+				request.onComplete = dumpFourthFetch;
+				opmlStore.fetch(request);
+			}
+
+			function dumpFourthFetch(items, request){
+				t.is(4, items.length);
+				request.start = 9;
+				request.count = 100;
+				request.onComplete = dumpFifthFetch;
+				opmlStore.fetch(request);
+			}
+
+			function dumpFifthFetch(items, request){
+				t.is(0, items.length);
+				request.start = 2;
+				request.count = 20;
+				request.onComplete = dumpSixthFetch;
+				opmlStore.fetch(request);
+			}
+
+			function dumpSixthFetch(items, request){
+				t.is(4, items.length);
+			    d.callback(true);
+			}
+
+			function completed(items, request){
+				t.is(6, items.length);
+				request.start = 1;
+				request.count = 5;
+				request.onComplete = dumpFirstFetch;
+				opmlStore.fetch(request);
+			}
+
+			opmlStore.fetch({onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+
+		},
+		function testReadAPI_getValue(t){
+			//	summary: 
+			//		Simple test of the getValue function of the store.
+			//	description:
+			//		Simple test of the getValue function of the store.
+
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+			
+			var d = new tests.Deferred();
+			function completedAll(items){
+				t.is(6, items.length);
+				
+				t.is("Africa", 		opmlStore.getValue(items[0],"text"));
+				t.is("Asia", 		opmlStore.getValue(items[1],"text"));
+				t.is("Australia", 	opmlStore.getValue(items[2],"text"));
+				t.is("Europe", 		opmlStore.getValue(items[3],"text"));
+				t.is("North America", 	opmlStore.getValue(items[4],"text"));
+				t.is("South America",	opmlStore.getValue(items[5],"text"));
+	
+				t.is("continent", 	opmlStore.getValue(items[1],"type"));
+				t.is("21 million", 	opmlStore.getValue(items[2],"population"));
+				
+				var firstChild = opmlStore.getValue(items[4],"children");
+				t.assertTrue(opmlStore.isItem(firstChild));
+				t.is("Mexico", 		opmlStore.getValue(firstChild,"text"));
+				t.is("country", 	opmlStore.getValue(firstChild,"type"));
+				t.is("108 million", 	opmlStore.getValue(firstChild,"population"));
+				t.is("1,972,550 sq km", opmlStore.getValue(firstChild,"area"));
+				
+				firstChild = opmlStore.getValue(firstChild,"children");
+				t.assertTrue(opmlStore.isItem(firstChild));
+				t.is("Mexico City", 	opmlStore.getValue(firstChild,"text"));
+				t.is("city", 		opmlStore.getValue(firstChild,"type"));
+				t.is("19 million", 	opmlStore.getValue(firstChild,"population"));
+				t.is("-6 UTC", 		opmlStore.getValue(firstChild,"timezone"));
+				
+				d.callback(true);
+			}
+
+			//Get everything...
+			opmlStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+		},	
+		function testReadAPI_getValues(t){
+			//	summary: 
+			//		Simple test of the getValues function of the store.
+			//	description:
+			//		Simple test of the getValues function of the store.
+
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+
+			var d = new tests.Deferred();
+			function completed(items){
+				t.is(1, items.length);
+				
+				var children = opmlStore.getValues(items[0],"children");
+				t.is(3, children.length);
+				for(var i=0; i<children.length; i++){
+					t.assertTrue(opmlStore.isItem(children[i]));
+				}
+				
+				t.is("Mexico", 		opmlStore.getValues(children[0],"text")[0]);
+				t.is("country", 	opmlStore.getValues(children[0],"type")[0]);
+				t.is("108 million", 	opmlStore.getValues(children[0],"population")[0]);
+				t.is("1,972,550 sq km", opmlStore.getValues(children[0],"area")[0]);
+				
+				t.is("Canada", 		opmlStore.getValues(children[1],"text")[0]);
+				t.is("country", 	opmlStore.getValues(children[1],"type")[0]);
+				
+				children = opmlStore.getValues(children[1],"children");
+				t.is(2, children.length);
+				for(var i=0; i<children.length; i++){
+					t.assertTrue(opmlStore.isItem(children[i]));
+				}
+				t.is("Ottawa", 	opmlStore.getValues(children[0],"text")[0]);
+				t.is("Toronto", opmlStore.getValues(children[1],"text")[0]);
+								
+				d.callback(true);
+			}
+
+			//Get one item...
+			opmlStore.fetch({	query: {text: "North America"},
+								onComplete: completed, 
+								onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_isItem(t){
+			//	summary: 
+			//		Simple test of the isItem function of the store
+			//	description:
+			//		Simple test of the isItem function of the store
+
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+
+			var d = new tests.Deferred();
+			function completedAll(items){
+				t.is(6, items.length);
+				for(var i=0; i<6; i++){
+					t.assertTrue(opmlStore.isItem(items[i]));
+				}
+				t.assertTrue(!opmlStore.isItem({}));
+				t.assertTrue(!opmlStore.isItem({ item: "not an item" }));
+				t.assertTrue(!opmlStore.isItem("not an item"));
+				t.assertTrue(!opmlStore.isItem(["not an item"]));
+				
+				d.callback(true);
+			}
+
+			//Get everything...
+			opmlStore.fetch({ onComplete: completedAll, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_hasAttribute(t){
+			//	summary: 
+			//		Simple test of the hasAttribute function of the store
+			//	description:
+			//		Simple test of the hasAttribute function of the store
+
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+
+			var d = new tests.Deferred();
+			function onComplete(items){
+				t.is(1, items.length);
+				t.assertTrue(items[0] !== null);
+				t.assertTrue(opmlStore.hasAttribute(items[0], "text"));
+				t.assertTrue(opmlStore.hasAttribute(items[0], "type"));
+				t.assertTrue(!opmlStore.hasAttribute(items[0], "population"));
+				t.assertTrue(!opmlStore.hasAttribute(items[0], "Nothing"));
+				t.assertTrue(!opmlStore.hasAttribute(items[0], "Text"));
+				
+				//Test that null attributes throw an exception
+				var passed = false;
+				try{
+					opmlStore.hasAttribute(items[0], null);
+				}catch (e){
+					passed = true;
+				}
+				t.assertTrue(passed);
+				
+				d.callback(true);
+			}
+
+			//Get one item...
+			opmlStore.fetch({ 	query: {text: "Asia"}, 
+								onComplete: onComplete, 
+								onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+							});
+			return d; //Object
+		},
+		function testReadAPI_containsValue(t){
+			//	summary: 
+			//		Simple test of the containsValue function of the store
+			//	description:
+			//		Simple test of the containsValue function of the store
+
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+ 			
+			var d = new tests.Deferred();
+			function onComplete(items){
+				t.is(1, items.length);
+				t.assertTrue(items[0] !== null);
+				t.assertTrue(opmlStore.containsValue(items[0], "text", "North America"));
+				t.assertTrue(opmlStore.containsValue(items[0], "type", "continent"));
+				t.assertTrue(!opmlStore.containsValue(items[0], "text", "America"));
+				t.assertTrue(!opmlStore.containsValue(items[0], "Type", "continent"));
+				t.assertTrue(!opmlStore.containsValue(items[0], "text", null));
+								
+				var children = opmlStore.getValues(items[0], "children");
+				t.assertTrue(opmlStore.containsValue(items[0], "children", children[0]));
+				t.assertTrue(opmlStore.containsValue(items[0], "children", children[1]));
+				t.assertTrue(opmlStore.containsValue(items[0], "children", children[2]));
+	
+				//Test that null attributes throw an exception
+				var passed = false;
+				try{
+					opmlStore.containsValue(items[0], null, "foo");
+				}catch (e){
+					passed = true;
+				}
+				t.assertTrue(passed);
+				
+				d.callback(true);
+			}
+
+			//Get one item...
+			opmlStore.fetch({ 	query: {text: "North America"}, 
+								onComplete: onComplete, 
+								onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)
+							});
+			return d; //Object
+		},
+		function testReadAPI_getAttributes(t){
+			//	summary: 
+			//		Simple test of the getAttributes function of the store
+			//	description:
+			//		Simple test of the getAttributes function of the store
+
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+
+			var d = new tests.Deferred();
+			function onComplete(items){
+				t.is(6, items.length);
+				t.assertTrue(opmlStore.isItem(items[0]));
+	
+				var attributes = opmlStore.getAttributes(items[0]);
+				t.is(3, attributes.length);
+				for(var i = 0; i < attributes.length; i++){
+					t.assertTrue((attributes[i] === "text" || attributes[i] === "type" || attributes[i] === "children"));
+				}
+				
+				d.callback(true);
+			}
+
+			//Get everything...
+			opmlStore.fetch({ onComplete: onComplete, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_getFeatures(t){
+			//	summary: 
+			//		Simple test of the getFeatures function of the store
+			//	description:
+			//		Simple test of the getFeatures function of the store
+
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+
+			var features = opmlStore.getFeatures(); 
+			var count = 0;
+			for(i in features){
+				t.assertTrue((i === "dojo.data.api.Read"));
+				count++;
+			}
+			t.assertTrue(count === 1);
+		},
+		function testReadAPI_fetch_patternMatch0(t){
+			//	summary: 
+			//		Function to test pattern matching of everything starting with Capital A
+			//	description:
+			//		Function to test pattern matching of everything starting with Capital A
+
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.is(3, items.length);
+				var valueArray = [ "Africa", "Asia", "Australia"];
+				t.assertTrue(dojox.data.tests.stores.OpmlStore.verifyItems(opmlStore, items, "text", valueArray));
+				d.callback(true);
+			}
+			
+			opmlStore.fetch({query: {text: "A*"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_patternMatch1(t){
+			//	summary: 
+			//		Function to test pattern matching of everything with America in it.
+			//	description:
+			//		Function to test pattern matching of everything with America in it.
+			
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.assertTrue(items.length === 2);
+				var valueArray = [ "North America", "South America"];
+				t.assertTrue(dojox.data.tests.stores.OpmlStore.verifyItems(opmlStore, items, "text", valueArray));
+				d.callback(true);
+			}
+			
+			opmlStore.fetch({query: {text: "*America*"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_patternMatch2(t){
+			//	summary: 
+			//		Function to test exact pattern match
+			//	description:
+			//		Function to test exact pattern match
+			
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.is(1, items.length);
+				t.assertTrue(opmlStore.getValue(items[0], "text") === "Europe");
+				d.callback(true);
+			}
+			
+			opmlStore.fetch({query: {text: "Europe"}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_patternMatch_caseInsensitive(t){
+			//	summary: 
+			//		Function to test exact pattern match with case insensitivity set.
+			//	description:
+			//		Function to test exact pattern match with case insensitivity set.
+			
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.is(1, items.length);
+				t.assertTrue(opmlStore.getValue(items[0], "text") === "Asia");
+				d.callback(true);
+			}
+			
+			opmlStore.fetch({query: {text: "asia"}, queryOptions: {ignoreCase: true}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_patternMatch_caseSensitive(t){
+			//	summary: 
+			//		Function to test exact pattern match with case sensitivity set.
+			//	description:
+			//		Function to test exact pattern match with case sensitivity set.
+			
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				t.is(0, items.length);
+				d.callback(true);
+			}
+			
+			opmlStore.fetch({query: {text: "ASIA"}, queryOptions: {ignoreCase: false}, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_sortAlphabetic(t){
+			//	summary: 
+			//		Function to test sorting alphabetic ordering.
+			//	description:
+			//		Function to test sorting alphabetic ordering.
+		
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				//Output should be in this order...
+				var orderedArray = [ "Africa", "Asia", "Australia", "Europe", "North America", "South America"];
+				t.is(6, items.length);
+				t.assertTrue(dojox.data.tests.stores.OpmlStore.verifyItems(opmlStore, items, "text", orderedArray));
+				d.callback(true);
+			}
+			
+			var sortAttributes = [{attribute: "text"}];
+			opmlStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_sortAlphabeticDescending(t){
+			//	summary: 
+			//		Function to test sorting alphabetic ordering in descending mode.
+			//	description:
+			//		Function to test sorting alphabetic ordering in descending mode.
+		
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				//Output should be in this order...
+				var orderedArray = [ "South America", "North America", "Europe", "Australia", "Asia", "Africa"
+					];
+				t.is(6, items.length);
+				t.assertTrue(dojox.data.tests.stores.OpmlStore.verifyItems(opmlStore, items, "text", orderedArray));
+				d.callback(true);
+			}
+			
+			var sortAttributes = [{attribute: "text", descending: true}];
+			opmlStore.fetch({sort: sortAttributes, onComplete: completed, onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_fetch_sortAlphabeticWithCount(t){
+			//	summary: 
+			//		Function to test sorting numerically in descending order, returning only a specified number of them.
+			//	description:
+			//		Function to test sorting numerically in descending order, returning only a specified number of them.
+		
+			var args = dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml");
+			var opmlStore = new dojox.data.OpmlStore(args);
+			
+			var d = new tests.Deferred();
+			function completed(items, request){
+				//Output should be in this order...
+				var orderedArray = [ "South America", "North America", "Europe", "Australia"
+					];
+				t.is(4, items.length);
+				t.assertTrue(dojox.data.tests.stores.OpmlStore.verifyItems(opmlStore, items, "text", orderedArray));
+				d.callback(true);
+			}
+			
+			var sortAttributes = [{attribute: "text", descending: true}];
+			opmlStore.fetch({sort: sortAttributes, 
+							count: 4,
+							onComplete: completed,
+							onError: dojo.partial(dojox.data.tests.stores.OpmlStore.error, t, d)});
+			return d; //Object
+		},
+		function testReadAPI_functionConformance(t){
+			//	summary: 
+			//		Simple test read API conformance.  Checks to see all declared functions are actual functions on the instances.
+			//	description:
+			//		Simple test read API conformance.  Checks to see all declared functions are actual functions on the instances.
+
+			var testStore = new dojox.data.OpmlStore(dojox.data.tests.stores.OpmlStore.getDatasource("stores/geography.xml"));
+			var readApi = new dojo.data.api.Read();
+			var passed = true;
+
+			for(i in readApi){
+				if(i.toString().charAt(0) !== '_')
+				{
+					var member = readApi[i];
+					//Check that all the 'Read' defined functions exist on the test store.
+					if(typeof member === "function"){
+						var testStoreMember = testStore[i];
+						if(!(typeof testStoreMember === "function")){
+							passed = false;
+							break;
+						}
+					}
+				}
+			}
+			t.assertTrue(passed);
+		}
+	]
+);
+

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/XmlStore.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/XmlStore.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/XmlStore.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,828 @@
+dojo.provide("dojox.data.tests.stores.XmlStore");
+dojo.require("dojox.data.XmlStore");
+dojo.require("dojo.data.api.Read");
+dojo.require("dojo.data.api.Write");
+
+
+dojox.data.tests.stores.XmlStore.getBooks2Store = function(){
+	return new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books2.xml").toString()});
+};
+
+dojox.data.tests.stores.XmlStore.getBooksStore = function(){
+	return new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books.xml").toString()});
+};
+
+tests.register("dojox.data.tests.stores.XmlStore", 
+	[
+		function testReadAPI_fetch_all(t){
+			//	summary: 
+			//		Simple test of fetching all xml items through an XML element called isbn
+			//	description:
+			//		Simple test of fetching all xml items through an XML element called isbn
+			var store = dojox.data.tests.stores.XmlStore.getBooksStore();
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(20, items.length);
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"*"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_fetch_one(t){
+			//	summary: 
+			//		Simple test of fetching one xml items through an XML element called isbn
+			//	description:
+			//		Simple test of fetching one xml items through an XML element called isbn
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_fetch_paging(t){
+			//	summary: 
+			//		Simple test of fetching one xml items through an XML element called isbn
+			//	description:
+			//		Simple test of fetching one xml items through an XML element called isbn
+			var store = dojox.data.tests.stores.XmlStore.getBooksStore();
+			
+			var d = new doh.Deferred();
+			function dumpFirstFetch(items, request){
+				t.assertEqual(5, items.length);
+				request.start = 3;
+				request.count = 1;
+				request.onComplete = dumpSecondFetch;
+				store.fetch(request);
+			}
+
+			function dumpSecondFetch(items, request){
+				t.assertEqual(1, items.length);
+				request.start = 0;
+				request.count = 5;
+				request.onComplete = dumpThirdFetch;
+				store.fetch(request);
+			}
+
+			function dumpThirdFetch(items, request){
+				t.assertEqual(5, items.length);
+				request.start = 2;
+				request.count = 20;
+				request.onComplete = dumpFourthFetch;
+				store.fetch(request);
+			}
+
+			function dumpFourthFetch(items, request){
+				t.assertEqual(18, items.length);
+				request.start = 9;
+				request.count = 100;
+				request.onComplete = dumpFifthFetch;
+				store.fetch(request);
+			}
+
+			function dumpFifthFetch(items, request){
+				t.assertEqual(11, items.length);
+				request.start = 2;
+				request.count = 20;
+				request.onComplete = dumpSixthFetch;
+				store.fetch(request);
+			}
+
+			function dumpSixthFetch(items, request){
+				t.assertEqual(18, items.length);
+				d.callback(true);
+			}
+
+			function completed(items, request){
+				t.assertEqual(20, items.length);
+				request.start = 1;
+				request.count = 5;
+				request.onComplete = dumpFirstFetch;
+				store.fetch(request);
+			}
+
+			function error(errData, request){
+				d.errback(errData);
+			}
+
+			store.fetch({onComplete: completed, onError: error});
+			return d; //Object
+		},
+		function testReadAPI_fetch_pattern0(t){
+			//	summary: 
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+			//	description:
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+			var d = new doh.Deferred();                                                             
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"?9B574"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_fetch_pattern1(t){
+			//	summary: 
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+			//	description:
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(4, items.length);
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"A9B57?"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_fetch_pattern2(t){
+			//	summary: 
+			//		Simple test of fetching one xml items through an XML element called isbn with * pattern match
+			//	description:
+			//		Simple test of fetching one xml items through an XML element called isbn with * pattern match
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(5, items.length);
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"A9*"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_fetch_pattern_caseInsensitive(t){
+			//	summary: 
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case insensitive mode.
+			//	description:
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case insensitive mode.
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+			var d = new doh.Deferred();                                                             
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"?9b574"}, queryOptions: {ignoreCase: true}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_fetch_pattern_caseSensitive(t){
+			//	summary: 
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case sensitive mode.
+			//	description:
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match and in case sensitive mode.
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+			var d = new doh.Deferred();                                                             
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"?9B574"}, queryOptions: {ignoreCase: false}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_fetch_all_rootItem(t){
+			//	summary: 
+			//		Simple test of fetching all xml items through an XML element called isbn
+			//	description:
+			//		Simple test of fetching all xml items through an XML element called isbn
+			var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books3.xml").toString(), 
+				rootItem:"book"});
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(5, items.length);
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"*"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_fetch_withAttrMap_all(t){
+			var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr.xml").toString(),
+				attributeMap: {"book.isbn": "@isbn"}});
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(5, items.length);
+				d.callback(true);
+			}
+			function onError(error, request) {
+				console.debug(error);
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"*"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_fetch_withAttrMap_one(t){
+			var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr.xml").toString(),
+				attributeMap: {"book.isbn": "@isbn"}});
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				d.callback(true);
+			}
+			function onError(error, request) {
+				console.debug(error);
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"2"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_fetch_withAttrMap_pattern0(t){
+			//	summary: 
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+			//	description:
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+			var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr2.xml").toString(), 
+				attributeMap: {"book.isbn": "@isbn"}});
+			var d = new doh.Deferred();                                                             
+			function onComplete(items, request) {
+				t.assertEqual(3, items.length);
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"ABC?"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_fetch_withAttrMap_pattern1(t){
+			//	summary: 
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+			//	description:
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+			var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr2.xml").toString(),
+				attributeMap: {"book.isbn": "@isbn"}});
+			var d = new doh.Deferred();                                                             
+			function onComplete(items, request) {
+				t.assertEqual(5, items.length);
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"A*"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_fetch_withAttrMap_pattern2(t){
+			//	summary: 
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+			//	description:
+			//		Simple test of fetching one xml items through an XML element called isbn with ? pattern match
+			var store = new dojox.data.XmlStore({url: dojo.moduleUrl("dojox.data.tests", "stores/books_isbnAttr2.xml").toString(), 
+				attributeMap: {"book.isbn": "@isbn"}});
+			var d = new doh.Deferred();                                                             
+			function onComplete(items, request) {
+				t.assertEqual(2, items.length);
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"?C*"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_getValue(t){
+			 //	summary: 
+			 //		Simple test of the getValue API
+			 //	description:
+			 //		Simple test of the getValue API
+			 var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			 var d = new doh.Deferred();
+			 function onComplete(items, request) {
+				 t.assertEqual(1, items.length);
+				 var item = items[0];
+				 t.assertTrue(store.hasAttribute(item,"isbn"));
+				 t.assertEqual(store.getValue(item,"isbn"), "A9B574");
+				 d.callback(true);
+			 }
+			 function onError(error, request) {
+				 d.errback(error);
+			 }
+			 store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+			 return d; //Object
+		},
+		function testReadAPI_getValues(t){
+			 //	summary: 
+			 //		Simple test of the getValues API
+			 //	description:
+			 //		Simple test of the getValues API
+			 var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			 var d = new doh.Deferred();
+			 function onComplete(items, request) {
+				 t.assertEqual(1, items.length);
+				 var item = items[0];
+				 t.assertTrue(store.hasAttribute(item,"isbn"));
+				 var values = store.getValues(item,"isbn");
+				 t.assertEqual(1,values.length);
+				 t.assertEqual("A9B574", values[0]);
+				 d.callback(true);
+			 }
+			 function onError(error, request) {
+				 d.errback(error);
+			 }
+			 store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+			 return d; //Object
+		},
+		function testReadAPI_isItem(t){
+			 //	summary: 
+			 //		Simple test of the isItem API
+			 //	description:
+			 //		Simple test of the isItem API
+			 var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			 var d = new doh.Deferred();
+			 function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				var item = items[0];
+				t.assertTrue(store.isItem(item));
+				t.assertTrue(!store.isItem({}));
+				t.assertTrue(!store.isItem("Foo"));
+				t.assertTrue(!store.isItem(1));
+				d.callback(true);
+			 }
+			 function onError(error, request) {
+				 d.errback(error);
+			 }
+			 store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+			 return d; //Object
+		},
+		function testReadAPI_isItem_multistore(t){
+			//	summary: 
+			//		Simple test of the isItem API across multiple store instances.
+			//	description:
+			//		Simple test of the isItem API across multiple store instances.
+			var store1 = dojox.data.tests.stores.XmlStore.getBooks2Store();
+			var store2 = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			var d = new doh.Deferred();
+			function onComplete1(items, request) {
+				t.assertEqual(1, items.length);
+				var item1 = items[0];
+				t.assertTrue(store1.isItem(item1));
+
+				function onComplete2(items, request) {
+					t.assertEqual(1, items.length);
+					var item2 = items[0];
+					t.assertTrue(store2.isItem(item2));
+					t.assertTrue(!store1.isItem(item2));
+					t.assertTrue(!store2.isItem(item1));
+					d.callback(true);
+				}
+				store2.fetch({query:{isbn:"A9B574"}, onComplete: onComplete2, onError: onError});
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store1.fetch({query:{isbn:"A9B574"}, onComplete: onComplete1, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_hasAttribute(t){
+			//	summary: 
+			//		Simple test of the hasAttribute API
+			//	description:
+			//		Simple test of the hasAttribute API
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				var item = items[0];
+				t.assertTrue(store.hasAttribute(item,"isbn"));
+				t.assertTrue(!store.hasAttribute(item,"bob"));
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_containsValue(t){
+			//	summary: 
+			//		Simple test of the containsValue API
+			//	description:
+			//		Simple test of the containsValue API
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				var item = items[0];
+				t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+				t.assertTrue(!store.containsValue(item,"isbn", "bob"));
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_sortDescending(t){
+			//	summary: 
+			//		Simple test of the sorting API in descending order.
+			//	description:
+			//		Simple test of the sorting API in descending order.
+			var store = dojox.data.tests.stores.XmlStore.getBooksStore();
+
+			//Comparison is done as a string type (toString comparison), so the order won't be numeric
+			//So have to compare in 'alphabetic' order.
+			var order = [9,8,7,6,5,4,3,20,2,19,18,17,16,15,14,13,12,11,10,1];
+			
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				console.log("Number of items: " + items.length);
+				t.assertEqual(20, items.length);
+
+				for(var i = 0; i < items.length; i++){
+					t.assertEqual(order[i], store.getValue(items[i],"isbn").toString());
+				}
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+
+			var sortAttributes = [{attribute: "isbn", descending: true}];
+			store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_sortAscending(t){
+			//	summary: 
+			//		Simple test of the sorting API in ascending order.
+			//	description:
+			//		Simple test of the sorting API in ascending order.
+			var store = dojox.data.tests.stores.XmlStore.getBooksStore();
+
+			//Comparison is done as a string type (toString comparison), so the order won't be numeric
+			//So have to compare in 'alphabetic' order.
+			var order = [1,10,11,12,13,14,15,16,17,18,19,2,20,3,4,5,6,7,8,9];
+						
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(20, items.length);
+				var itemId = 1;
+				for(var i = 0; i < items.length; i++){
+					t.assertEqual(order[i], store.getValue(items[i],"isbn").toString());
+				}
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+
+			var sortAttributes = [{attribute: "isbn"}];
+			store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_sortDescendingNumeric(t){
+			//	summary: 
+			//		Simple test of the sorting API in descending order using a numeric comparator.
+			//	description:
+			//		Simple test of the sorting API in descending order using a numeric comparator.
+			var store = dojox.data.tests.stores.XmlStore.getBooksStore();
+
+			//isbn should be treated as a numeric, not as a string comparison
+			store.comparatorMap = {};
+			store.comparatorMap["isbn"] = function(a, b){
+				var ret = 0;
+				if(parseInt(a.toString()) > parseInt(b.toString())){
+					ret = 1;
+				}else if(parseInt(a.toString()) < parseInt(b.toString())){
+					ret = -1;
+				}
+				return ret; //int, {-1,0,1}
+			};
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+                		t.assertEqual(20, items.length);
+                		var itemId = 20;
+				for(var i = 0; i < items.length; i++){
+					t.assertEqual(itemId, store.getValue(items[i],"isbn").toString());
+					itemId--;
+				}
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+
+			var sortAttributes = [{attribute: "isbn", descending: true}];
+			store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_sortAscendingNumeric(t){
+			//	summary: 
+			//		Simple test of the sorting API in ascending order using a numeric comparator.
+			//	description:
+			//		Simple test of the sorting API in ascending order using a numeric comparator.
+			var store = dojox.data.tests.stores.XmlStore.getBooksStore();
+
+			//isbn should be treated as a numeric, not as a string comparison
+			store.comparatorMap = {};
+			store.comparatorMap["isbn"] = function(a, b){
+				var ret = 0;
+				if(parseInt(a.toString()) > parseInt(b.toString())){
+					ret = 1;
+				}else if(parseInt(a.toString()) < parseInt(b.toString())){
+					ret = -1;
+				}
+				return ret; //int, {-1,0,1}
+			};
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(20, items.length);
+				var itemId = 1;
+				for(var i = 0; i < items.length; i++){
+					t.assertEqual(itemId, store.getValue(items[i],"isbn").toString());
+					itemId++;
+				}
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+
+			var sortAttributes = [{attribute: "isbn"}];
+			store.fetch({query:{isbn:"*"}, sort: sortAttributes, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_isItemLoaded(t){
+			//	summary: 
+			//		Simple test of the isItemLoaded API
+			//	description:
+			//		Simple test of the isItemLoaded API
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				var item = items[0];
+				t.assertTrue(store.isItemLoaded(item));
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_getFeatures(t){
+			//	summary: 
+			//		Simple test of the getFeatures function of the store
+			//	description:
+			//		Simple test of the getFeatures function of the store
+
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+			var features = store.getFeatures(); 
+			var count = 0;
+			for(i in features){
+				t.assertTrue((i === "dojo.data.api.Read" || i === "dojo.data.api.Write"));
+				count++;
+			}
+			t.assertEqual(2, count);
+		},
+		function testReadAPI_getAttributes(t){
+			//	summary: 
+			//		Simple test of the getAttributes API
+			//	description:
+			//		Simple test of the getAttributes API
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				var item = items[0];
+				var attributes = store.getAttributes(item);
+
+				//Should be six, as all items should have tagName, childNodes, and text() special attributes 
+				//in addition to any doc defined ones, which in this case are author, title, and isbn
+				//FIXME:  Figure out why IE returns 5!  Need to get firebug lite working in IE for that.
+				//Suspect it's childNodes, may not be defined if there are no child nodes.
+				for(var i = 0; i < attributes.length; i++){
+					console.log("attribute found: " + attributes[i]);
+				}
+				if(dojo.isIE){
+					t.assertEqual(5,attributes.length);
+				}else{
+					t.assertEqual(6,attributes.length);
+				}
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testWriteAPI_setValue(t){
+			//	summary: 
+			//		Simple test of the setValue API
+			//	description:
+			//		Simple test of the setValue API
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				var item = items[0];
+				t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+				store.setValue(item, "isbn", "A9B574-new");
+				t.assertEqual(store.getValue(item,"isbn").toString(), "A9B574-new");
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testWriteAPI_setValues(t){
+			//	summary: 
+			//		Simple test of the setValues API
+			//	description:
+			//		Simple test of the setValues API
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				var item = items[0];
+				t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+				store.setValues(item, "isbn", ["A9B574-new1", "A9B574-new2"]);
+				var values = store.getValues(item,"isbn");
+				t.assertEqual(values[0].toString(), "A9B574-new1");
+				t.assertEqual(values[1].toString(), "A9B574-new2");
+				store.setValues(values[0], "text()", ["A9B574", "-new3"]);
+				t.assertEqual(store.getValue(values[0],"text()").toString(), "A9B574-new3");
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testWriteAPI_unsetAttribute(t){
+			//	summary: 
+			//		Simple test of the unsetAttribute API
+			//	description:
+			//		Simple test of the unsetAttribute API
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				var item = items[0];
+				t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+				store.unsetAttribute(item,"isbn");
+				t.assertTrue(!store.hasAttribute(item,"isbn"));
+				t.assertTrue(store.isDirty(item));
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testWriteAPI_isDirty(t){
+			//	summary: 
+			//		Simple test of the isDirty API
+			//	description:
+			//		Simple test of the isDirty API
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				var item = items[0];
+				t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+				store.setValue(item, "isbn", "A9B574-new");
+				t.assertEqual(store.getValue(item,"isbn").toString(), "A9B574-new");
+				t.assertTrue(store.isDirty(item));
+				d.callback(true);
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testWriteAPI_revert(t){
+			//	summary: 
+			//		Simple test of the isDirty API
+			//	description:
+			//		Simple test of the isDirty API
+			var store = dojox.data.tests.stores.XmlStore.getBooks2Store();
+
+			var d = new doh.Deferred();
+			function onComplete(items, request) {
+				t.assertEqual(1, items.length);
+				var item = items[0];
+				t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+				t.assertTrue(!store.isDirty(item));
+				store.setValue(item, "isbn", "A9B574-new");
+				t.assertEqual(store.getValue(item,"isbn").toString(), "A9B574-new");
+				t.assertTrue(store.isDirty(item));
+				store.revert();
+				
+				//Fetch again to see if it reset the state.
+				function onComplete1(items, request) {
+					t.assertEqual(1, items.length);
+					var item = items[0];
+					t.assertTrue(store.containsValue(item,"isbn", "A9B574"));
+					d.callback(true);
+				}
+				store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete1, onError: onError});
+			}
+			function onError(error, request) {
+				d.errback(error);
+			}
+			store.fetch({query:{isbn:"A9B574"}, onComplete: onComplete, onError: onError});
+			return d; //Object
+		},
+		function testReadAPI_functionConformance(t){
+			//	summary: 
+			//		Simple test read API conformance.  Checks to see all declared functions are actual functions on the instances.
+			//	description:
+			//		Simple test read API conformance.  Checks to see all declared functions are actual functions on the instances.
+
+			var testStore = dojox.data.tests.stores.XmlStore.getBooksStore();
+			var readApi = new dojo.data.api.Read();
+			var passed = true;
+
+			for(i in readApi){
+				var member = readApi[i];
+				//Check that all the 'Read' defined functions exist on the test store.
+				if(typeof member === "function"){
+					var testStoreMember = testStore[i];
+					if(!(typeof testStoreMember === "function")){
+						console.log("Problem with function: [" + i + "]");
+						passed = false;
+						break;
+					}
+				}
+			}
+			t.assertTrue(passed);
+		},
+		function testWriteAPI_functionConformance(t){
+			//	summary: 
+			//		Simple test write API conformance.  Checks to see all declared functions are actual functions on the instances.
+			//	description:
+			//		Simple test write API conformance.  Checks to see all declared functions are actual functions on the instances.
+
+			var testStore = dojox.data.tests.stores.XmlStore.getBooksStore();
+			var writeApi = new dojo.data.api.Write();
+			var passed = true;
+
+			for(i in writeApi){
+				var member = writeApi[i];
+				//Check that all the 'Write' defined functions exist on the test store.
+				if(typeof member === "function"){
+					var testStoreMember = testStore[i];
+					if(!(typeof testStoreMember === "function")){
+						passed = false;
+						break;
+					}
+				}
+			}
+			t.assertTrue(passed);
+		}
+	]
+);
+
+
+
+

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books.xml
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books.xml	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books.xml	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<books>
+	<book>
+		<isbn>1</isbn>
+		<title>Title of 1</title>
+		<author>Author of 1</author>
+	</book>
+	<book>
+		<isbn>2</isbn>
+		<title>Title of 2</title>
+		<author>Author of 2</author>
+	</book>
+	<book>
+		<isbn>3</isbn>
+		<title>Title of 3</title>
+		<author>Author of 3</author>
+	</book>
+	<book>
+		<isbn>4</isbn>
+		<title>Title of 4</title>
+		<author>Author of 4</author>
+	</book>
+	<book>
+		<isbn>5</isbn>
+		<title>Title of 5</title>
+		<author>Author of 5</author>
+	</book>
+	<book>
+		<isbn>6</isbn>
+		<title>Title of 6</title>
+		<author>Author of 6</author>
+	</book>
+	<book>
+		<isbn>7</isbn>
+		<title>Title of 7</title>
+		<author>Author of 7</author>
+	</book>
+	<book>
+		<isbn>8</isbn>
+		<title>Title of 8</title>
+		<author>Author of 8</author>
+	</book>
+	<book>
+		<isbn>9</isbn>
+		<title>Title of 9</title>
+		<author>Author of 9</author>
+	</book>
+	<book>
+		<isbn>10</isbn>
+		<title>Title of 10</title>
+		<author>Author of 10</author>
+	</book>
+	<book>
+		<isbn>11</isbn>
+		<title>Title of 11</title>
+		<author>Author of 11</author>
+	</book>
+	<book>
+		<isbn>12</isbn>
+		<title>Title of 12</title>
+		<author>Author of 12</author>
+	</book>
+	<book>
+		<isbn>13</isbn>
+		<title>Title of 13</title>
+		<author>Author of 13</author>
+	</book>
+	<book>
+		<isbn>14</isbn>
+		<title>Title of 14</title>
+		<author>Author of 14</author>
+	</book>
+	<book>
+		<isbn>15</isbn>
+		<title>Title of 15</title>
+		<author>Author of 15</author>
+	</book>
+	<book>
+		<isbn>16</isbn>
+		<title>Title of 16</title>
+		<author>Author of 16</author>
+	</book>
+	<book>
+		<isbn>17</isbn>
+		<title>Title of 17</title>
+		<author>Author of 17</author>
+	</book>
+	<book>
+		<isbn>18</isbn>
+		<title>Title of 18</title>
+		<author>Author of 18</author>
+	</book>
+	<book>
+		<isbn>19</isbn>
+		<title>Title of 19</title>
+		<author>Author of 19</author>
+	</book>
+	<book>
+		<isbn>20</isbn>
+		<title>Title of 20</title>
+		<author>Author of 20</author>
+	</book>
+</books>

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books2.xml
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books2.xml	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books2.xml	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<books>
+	<book>
+		<isbn>A9B57C</isbn>
+		<title>Title of 1</title>
+		<author>Author of 1</author>
+	</book>
+	<book>
+		<isbn>A9B57F</isbn>
+		<title>Title of 2</title>
+		<author>Author of 2</author>
+	</book>
+	<book>
+		<isbn>A9B577</isbn>
+		<title>Title of 3</title>
+		<author>Author of 3</author>
+	</book>
+	<book>
+		<isbn>A9B574</isbn>
+		<title>Title of 4</title>
+		<author>Author of 4</author>
+	</book>
+	<book>
+		<isbn>A9B5CC</isbn>
+		<title>Title of 5</title>
+		<author>Author of 5</author>
+	</book>
+</books>

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books3.xml
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books3.xml	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books3.xml	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<books>
+	<category>
+		<name>Category 1</name>
+		<book>
+			<isbn>1</isbn>
+			<title>Title of 1</title>
+			<author>Author of 1</author>
+		</book>
+		<book>
+			<isbn>2</isbn>
+			<title>Title of 2</title>
+			<author>Author of 2</author>
+		</book>
+		<book>
+			<isbn>3</isbn>
+			<title>Title of 3</title>
+			<author>Author of 3</author>
+		</book>
+		<book>
+			<isbn>4</isbn>
+			<title>Title of 4</title>
+			<author>Author of 4</author>
+		</book>
+		<book>
+			<isbn>5</isbn>
+			<title>Title of 5</title>
+			<author>Author of 5</author>
+		</book>
+	</category>
+</books>

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books_isbnAttr.xml
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books_isbnAttr.xml	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books_isbnAttr.xml	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<books>
+	<book isbn="1">
+		<title>Title of 1</title>
+		<author>Author of 1</author>
+	</book>
+	<book isbn="2">
+		<title>Title of 2</title>
+		<author>Author of 2</author>
+	</book>
+	<book isbn="3">
+		<title>Title of 3</title>
+		<author>Author of 3</author>
+	</book>
+	<book isbn="4">
+		<title>Title of 4</title>
+		<author>Author of 4</author>
+	</book>
+	<book isbn="5">
+		<title>Title of 5</title>
+		<author>Author of 5</author>
+	</book>
+</books>

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books_isbnAttr2.xml
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books_isbnAttr2.xml	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/books_isbnAttr2.xml	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<books>
+	<book isbn="ABC1">
+		<title>Title of 1</title>
+		<author>Author of 1</author>
+	</book>
+	<book isbn="ABC2">
+		<title>Title of 2</title>
+		<author>Author of 2</author>
+	</book>
+	<book isbn="ABC3">
+		<title>Title of 3</title>
+		<author>Author of 3</author>
+	</book>
+	<book isbn="ACB4">
+		<title>Title of 4</title>
+		<author>Author of 4</author>
+	</book>
+	<book isbn="ACF5">
+		<title>Title of 5</title>
+		<author>Author of 5</author>
+	</book>
+</books>

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/geography.xml
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/geography.xml	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/geography.xml	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<opml version="1.0">
+	<head>
+		<title>geography.opml</title>
+		<dateCreated>2006-11-10</dateCreated>
+		<dateModified>2006-11-13</dateModified>
+		<ownerName>Magellan, Ferdinand</ownerName>
+	</head>
+	<body>
+		<outline text="Africa" type="continent">
+			<outline text="Egypt" type="country"/>
+			<outline text="Kenya" type="country">
+				<outline text="Nairobi" type="city"/>
+				<outline text="Mombasa" type="city"/>
+			</outline>
+			<outline text="Sudan" type="country">
+				<outline text="Khartoum" type="city"/>
+			</outline>
+		</outline>
+		<outline text="Asia" type="continent">
+			<outline text="China" type="country"/>
+			<outline text="India" type="country"/>
+			<outline text="Russia" type="country"/>
+			<outline text="Mongolia" type="country"/>
+		</outline>
+		<outline text="Australia" type="continent" population="21 million">
+			<outline text="Australia" type="country" population="21 million"/>
+		</outline>
+		<outline text="Europe" type="continent">
+			<outline text="Germany" type="country"/>
+			<outline text="France" type="country"/>
+			<outline text="Spain" type="country"/>
+			<outline text="Italy" type="country"/>
+		</outline>
+		<outline text="North America" type="continent">
+			<outline text="Mexico" type="country" population="108 million" area="1,972,550 sq km">
+				<outline text="Mexico City" type="city" population="19 million" timezone="-6 UTC"/>
+				<outline text="Guadalajara" type="city" population="4 million" timezone="-6 UTC"/>
+			</outline>
+			<outline text="Canada" type="country" population="33 million" area="9,984,670 sq km">
+				<outline text="Ottawa" type="city" population="0.9 million" timezone="-5 UTC"/>
+				<outline text="Toronto" type="city" population="2.5 million" timezone="-5 UTC"/>
+			</outline>
+			<outline text="United States of America" type="country"/>
+		</outline>
+		<outline text="South America" type="continent">
+			<outline text="Brazil" type="country" population="186 million"/>
+			<outline text="Argentina" type="country" population="40 million"/>
+		</outline>
+	</body>
+</opml>

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/movies.csv
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/movies.csv	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/movies.csv	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+Title, Year, Producer
+City of God, 2002, Katia Lund
+Rain,, Christine Jeffs
+2001: A Space Odyssey, , Stanley Kubrick
+"This is a ""fake"" movie title", 1957, Sidney Lumet
+Alien, 1979   , Ridley Scott
+"The Sequel to ""Dances With Wolves.""", 1982, Ridley Scott
+"Caine Mutiny, The", 1954, "Dymtryk ""the King"", Edward"
+

Added: trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/patterns.csv
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/patterns.csv	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/data/tests/stores/patterns.csv	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,11 @@
+uniqueId, value
+9, jfq4@#!$!@Rf14r14i5u
+6, BaBaMaSaRa***Foo
+2, bar*foo
+8, 123abc
+4, bit$Bite
+3, 123abc
+10, 123abcdefg
+1, foo*bar
+7, 
+5, 123abc

Added: trunk/examples/typeface/root/static/dojo/dojox/date/php.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/date/php.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/date/php.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,292 @@
+dojo.provide("dojox.date.php");
+dojo.require("dojo.date");
+
+dojox.date.php.format = function(/*Date*/ date, /*String*/ format, /*Object?*/ overrides){
+	// summary: Get a formatted string for a given date object
+	var df = new dojox.date.php.DateFormat(date);
+	return df.format(format, overrides);	
+}
+
+dojox.date.php.DateFormat = function(/*Date*/ date){
+	this.date = date;
+}
+dojo.extend(dojox.date.php.DateFormat, {
+	weekdays: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+	weekdays_3: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+	months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+	months_3: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+	monthdays: [31,28,31,30,31,30,31,31,30,31,30,31],
+
+	format: function(/*String*/ format, /*Object?*/ overrides){
+		// summary: Format the internal date object
+		var parts = [];
+		for(var i = 0; i < format.length; i++){
+			var chr = format.charAt(i);
+			if(overrides && typeof overrides[chr] == "function"){
+				parts.push(overrides[chr].call(this));
+			}else if(typeof this[chr] == "function"){
+				parts.push(this[chr]());
+			}else{
+				parts.push(chr);
+			}
+		}
+		return parts.join("");
+	},
+
+	// Day
+
+	d: function(){
+		// summary: Day of the month, 2 digits with leading zeros
+		var j = this.j();
+		return (j.length == 1) ? "0" + j : j;
+	},
+
+	D: function(){
+		// summary: A textual representation of a day, three letters
+		return this.weekdays_3[this.date.getDay()];
+	},
+
+	j: function(){
+		// summary: Day of the month without leading zeros
+		return this.date.getDate() + "";
+	},
+
+	l: function(){
+		// summary: A full textual representation of the day of the week
+		return this.weekdays[this.date.getDay()];
+	},
+	
+	N: function(){
+		// summary: ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0)
+		var w = this.w();
+		return (!w) ? 7 : w;
+	},
+
+	S: function(){
+		// summary: English ordinal suffix for the day of the month, 2 characters
+		switch(this.date.getDate()){
+			case 11: case 12: case 13: return "th";
+			case 1: case 21: case 31: return "st";
+			case 2: case 22: return "nd";
+			case 3: case 23: return "rd";
+			default: return "th";
+		}
+	},
+
+	w: function(){
+		// summary: Numeric representation of the day of the week
+		return this.date.getDay() + "";
+	},
+
+	z: function(){
+		// summary: The day of the year (starting from 0)
+		var millis = this.date.getTime() - new Date(this.date.getFullYear(), 0, 1).getTime();
+		return Math.floor(millis/86400000) + "";
+	},
+
+	// Week
+
+	W: function(){
+		// summary: ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0)
+		var week;
+		var jan1_w = new Date(this.date.getFullYear(), 0, 1).getDay() + 1;
+		var w = this.date.getDay() + 1;
+		var z = parseInt(this.z());
+
+		if(z <= (8 - jan1_w) && jan1_w > 4){
+			var last_year = new Date(this.date.getFullYear() - 1, this.date.getMonth(), this.date.getDate());
+			if(jan1_w == 5 || (jan1_w == 6 && dojo.date.isLeapYear(last_year))){
+				week = 53;
+			}else{
+				week = 52;
+			}
+		}else{
+			var i;
+			if(Boolean(this.L())){
+				i = 366;
+			}else{
+				i = 365;
+			}
+			if((i - z) < (4 - w)){
+				week = 1;
+			}else{
+				var j = z + (7 - w) + (jan1_w - 1);
+				week = Math.ceil(j / 7);
+				if(jan1_w > 4){
+					--week;
+				}
+			}
+		}
+		
+		return week;
+	},
+
+	// Month
+
+	F: function(){
+		// summary: A full textual representation of a month, such as January or March
+		return this.months[this.date.getMonth()];
+	},
+
+	m: function(){
+		// summary: Numeric representation of a month, with leading zeros
+		var n = this.n();
+		return (n.length == 1) ? "0" + n : n;
+	},
+
+	M: function(){
+		// summary: A short textual representation of a month, three letters
+		return months_3[this.date.getMonth()];
+	},
+
+	n: function(){
+		// summary: Numeric representation of a month, without leading zeros
+		return this.date.getMonth() + 1 + "";
+	},
+
+	t: function(){
+		// summary: Number of days in the given month
+		return (Boolean(this.L()) && this.date.getMonth() == 1) ? 29 : this.monthdays[this.getMonth()];
+	},
+
+	// Year
+
+	L: function(){
+		// summary: Whether it's a leap year
+		return (dojo.date.isLeapYear(this.date)) ? "1" : "0";
+	},
+
+	o: function(){
+		// summary:
+		//		ISO-8601 year number. This has the same value as Y, except that if
+		//		the ISO week number (W) belongs to the previous or next year, that year is used instead. (added in PHP 5.1.0)
+		// TODO: Figure out what this means
+	},
+
+	Y: function(){
+		// summary: A full numeric representation of a year, 4 digits
+		return this.date.getFullYear() + "";
+	},
+
+	y: function(){
+		// summary: A two digit representation of a year
+		return this.date.getFullYear.substsring(2, 4);
+	},
+
+	// Time
+
+	a: function(){
+		// summary: Lowercase Ante meridiem and Post meridiem
+		return this.date.getHours() >= 12 ? "pm" : "am";
+	},
+
+	b: function(){
+		// summary: Uppercase Ante meridiem and Post meridiem
+		return this.a().toUpperCase();
+	},
+
+	B: function(){
+		// summary:
+		//	Swatch Internet time
+		//	A day is 1,000 beats. All time is measured from GMT + 1
+		var off = this.date.getTimezoneOffset() + 60;
+		var secs = (this.date.getHours() * 3600) + (this.date.getMinutes() * 60) + this.getSeconds() + (off * 60);
+		var beat = Math.abs(Math.floor(secs / 86.4) % 1000) + "";
+		while(beat.length <  2) beat = "0" + beat;
+		return beat;
+	},
+
+	g: function(){
+		// summary: 12-hour format of an hour without leading zeros
+		return (this.date.getHours() > 12) ? this.date.getHours() - 12 + "" : this.date.getHours() + "";
+	},
+
+	G: function(){
+		// summary: 24-hour format of an hour without leading zeros
+		return this.date.getHours() + "";
+	},
+
+	h: function(){
+		// summary: 12-hour format of an hour with leading zeros
+		var g = this.g();
+		return (g.length == 1) ? "0" + g : g;
+	},
+
+	H: function(){
+		// summary: 24-hour format of an hour with leading zeros
+		var G = this.G();
+		return (G.length == 1) ? "0" + G : G;
+	},
+
+	i: function(){
+		// summary: Minutes with leading zeros
+		var mins = this.date.getMinutes() + "";
+		return (mins.length == 1) ? "0" + mins : mins;
+	},
+
+	s: function(){
+		// summary: Seconds, with leading zeros
+		var secs = this.date.getSeconds() + "";
+		return (secs.length == 1) ? "0" + secs : secs;
+	},
+
+	// Timezone
+
+	e: function(){
+		// summary: Timezone identifier (added in PHP 5.1.0)
+		return dojo.date.getTimezoneName(this.date);
+	},
+
+	I: function(){
+		// summary: Whether or not the date is in daylight saving time
+		// TODO: Can dojo.date do this?
+	},
+
+	O: function(){
+		// summary: Difference to Greenwich time (GMT) in hours
+		var off = Math.abs(this.date.getTimezoneOffset());
+		var hours = Math.floor(off / 60) + "";
+		var mins = (off % 60) + "";
+		if(hours.length == 1) hours = "0" + hours;
+		if(mins.length == 1) hours = "0" + mins;
+		return ((this.date.getTimezoneOffset() < 0) ? "+" : "-") + hours + mins;
+	},
+
+	P: function(){
+		// summary: Difference to Greenwich time (GMT) with colon between hours and minutes (added in PHP 5.1.3)
+		var O = this.O();
+		return O.substring(0, 2) + ":" + O.substring(2, 4);
+	},
+
+	T: function(){
+		// summary: Timezone abbreviation
+
+		// Guess...
+		return this.e().substring(0, 3);
+	},
+
+	Z: function(){
+		// summary:
+		//		Timezone offset in seconds. The offset for timezones west of UTC is always negative,
+		//		and for those east of UTC is always positive.
+		return this.date.getTimezoneOffset() * -60;
+	},
+
+	// Full Date/Time
+
+	c: function(){
+		// summary: ISO 8601 date (added in PHP 5)
+		return this.Y() + "-" + this.m() + "-" + this.d() + "T" + this.h() + ":" + this.i() + ":" + this.s() + this.P();
+	},
+
+	r: function(){
+		// summary: RFC 2822 formatted date
+		return this.D() + ", " + this.d() + " " + this.M() + " " + this.Y() + " " + this.H() + ":" + this.i() + ":" + this.s() + " " + this.O();
+	},
+
+	U: function(){
+		// summary: Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
+		return Math.floor(this.date.getTime() / 1000);
+	}
+
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/date/posix.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/date/posix.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/date/posix.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,289 @@
+dojo.provide("dojox.date.posix");
+
+dojo.require("dojo.date");
+dojo.require("dojo.date.locale");
+dojo.require("dojo.string");
+
+dojox.date.posix.strftime = function(/*Date*/dateObject, /*String*/format, /*String?*/locale){
+//
+// summary:
+//		Formats the date object using the specifications of the POSIX strftime function
+//
+// description:
+//		see <http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html>
+
+	// zero pad
+	var padChar = null;
+	var _ = function(s, n){
+		return dojo.string.pad(s, n || 2, padChar || "0");
+	};
+
+	var bundle = dojo.date.locale._getGregorianBundle(locale);
+
+	var $ = function(property){
+		switch(property){
+			case "a": // abbreviated weekday name according to the current locale
+				return dojo.date.locale.getNames('days', 'abbr', 'format', locale)[dateObject.getDay()];
+
+			case "A": // full weekday name according to the current locale
+				return dojo.date.locale.getNames('days', 'wide', 'format', locale)[dateObject.getDay()];
+
+			case "b":
+			case "h": // abbreviated month name according to the current locale
+				return dojo.date.locale.getNames('months', 'abbr', 'format', locale)[dateObject.getMonth()];
+				
+			case "B": // full month name according to the current locale
+				return dojo.date.locale.getNames('months', 'wide', 'format', locale)[dateObject.getMonth()];
+				
+			case "c": // preferred date and time representation for the current
+				      // locale
+				return dojo.date.locale.format(dateObject, {formatLength: 'full', locale: locale});
+
+			case "C": // century number (the year divided by 100 and truncated
+				      // to an integer, range 00 to 99)
+				return _(Math.floor(dateObject.getFullYear()/100));
+				
+			case "d": // day of the month as a decimal number (range 01 to 31)
+				return _(dateObject.getDate());
+				
+			case "D": // same as %m/%d/%y
+				return $("m") + "/" + $("d") + "/" + $("y");
+					
+			case "e": // day of the month as a decimal number, a single digit is
+				      // preceded by a space (range ' 1' to '31')
+				if(padChar == null){ padChar = " "; }
+				return _(dateObject.getDate());
+			
+			case "f": // month as a decimal number, a single digit is
+							// preceded by a space (range ' 1' to '12')
+				if(padChar == null){ padChar = " "; }
+				return _(dateObject.getMonth()+1);				
+			
+			case "g": // like %G, but without the century.
+				break;
+			
+			case "G": // The 4-digit year corresponding to the ISO week number
+				      // (see %V).  This has the same format and value as %Y,
+				      // except that if the ISO week number belongs to the
+				      // previous or next year, that year is used instead.
+				dojo.unimplemented("unimplemented modifier 'G'");
+				break;
+			
+			case "F": // same as %Y-%m-%d
+				return $("Y") + "-" + $("m") + "-" + $("d");
+				
+			case "H": // hour as a decimal number using a 24-hour clock (range
+				      // 00 to 23)
+				return _(dateObject.getHours());
+				
+			case "I": // hour as a decimal number using a 12-hour clock (range
+				      // 01 to 12)
+				return _(dateObject.getHours() % 12 || 12);
+
+			case "j": // day of the year as a decimal number (range 001 to 366)
+				return _(dojo.date.locale._getDayOfYear(dateObject), 3);
+
+			case "k": // Hour as a decimal number using a 24-hour clock (range
+					  // 0 to 23 (space-padded))
+				if(padChar == null){ padChar = " "; }
+				return _(dateObject.getHours());
+
+			case "l": // Hour as a decimal number using a 12-hour clock (range
+					  // 1 to 12 (space-padded))
+				if(padChar == null){ padChar = " "; }
+				return _(dateObject.getHours() % 12 || 12);
+
+			case "m": // month as a decimal number (range 01 to 12)
+				return _(dateObject.getMonth() + 1);
+
+			case "M": // minute as a decimal number
+				return _(dateObject.getMinutes());
+
+			case "n":
+				return "\n";
+
+			case "p": // either `am' or `pm' according to the given time value,
+				      // or the corresponding strings for the current locale
+				return bundle[dateObject.getHours() < 12 ? "am" : "pm"];
+				
+			case "r": // time in a.m. and p.m. notation
+				return $("I") + ":" + $("M") + ":" + $("S") + " " + $("p");
+				
+			case "R": // time in 24 hour notation
+				return $("H") + ":" + $("M");
+				
+			case "S": // second as a decimal number
+				return _(dateObject.getSeconds());
+
+			case "t":
+				return "\t";
+
+			case "T": // current time, equal to %H:%M:%S
+				return $("H") + ":" + $("M") + ":" + $("S");
+				
+			case "u": // weekday as a decimal number [1,7], with 1 representing
+				      // Monday
+				return String(dateObject.getDay() || 7);
+				
+			case "U": // week number of the current year as a decimal number,
+				      // starting with the first Sunday as the first day of the
+				      // first week
+				return _(dojo.date.locale._getWeekOfYear(dateObject));
+
+			case "V": // week number of the year (Monday as the first day of the
+				      // week) as a decimal number [01,53]. If the week containing
+				      // 1 January has four or more days in the new year, then it 
+				      // is considered week 1. Otherwise, it is the last week of 
+				      // the previous year, and the next week is week 1.
+				return _(dojox.date.posix.getIsoWeekOfYear(dateObject));
+				
+			case "W": // week number of the current year as a decimal number,
+				      // starting with the first Monday as the first day of the
+				      // first week
+				return _(dojo.date.locale._getWeekOfYear(dateObject, 1));
+				
+			case "w": // day of the week as a decimal, Sunday being 0
+				return String(dateObject.getDay());
+
+			case "x": // preferred date representation for the current locale
+				      // without the time
+				return dojo.date.locale.format(dateObject, {selector:'date', formatLength: 'full', locale:locale});
+
+			case "X": // preferred time representation for the current locale
+				      // without the date
+				return dojo.date.locale.format(dateObject, {selector:'time', formatLength: 'full', locale:locale});
+
+			case "y": // year as a decimal number without a century (range 00 to
+				      // 99)
+				return _(dateObject.getFullYear()%100);
+				
+			case "Y": // year as a decimal number including the century
+				return String(dateObject.getFullYear());
+			
+			case "z": // time zone or name or abbreviation
+				var timezoneOffset = dateObject.getTimezoneOffset();
+				return (timezoneOffset > 0 ? "-" : "+") + 
+					_(Math.floor(Math.abs(timezoneOffset)/60)) + ":" +
+					_(Math.abs(timezoneOffset)%60);
+
+			case "Z": // time zone or name or abbreviation
+				return dojo.date.getTimezoneName(dateObject);
+			
+			case "%":
+				return "%";
+		}
+	};
+
+	// parse the formatting string and construct the resulting string
+	var string = "";
+	var i = 0;
+	var index = 0;
+	var switchCase = null;
+	while ((index = format.indexOf("%", i)) != -1){
+		string += format.substring(i, index++);
+		
+		// inspect modifier flag
+		switch (format.charAt(index++)) {
+			case "_": // Pad a numeric result string with spaces.
+				padChar = " "; break;
+			case "-": // Do not pad a numeric result string.
+				padChar = ""; break;
+			case "0": // Pad a numeric result string with zeros.
+				padChar = "0"; break;
+			case "^": // Convert characters in result string to uppercase.
+				switchCase = "upper"; break;
+			case "*": // Convert characters in result string to lowercase
+				switchCase = "lower"; break;
+			case "#": // Swap the case of the result string.
+				switchCase = "swap"; break;
+			default: // no modifier flag so decrement the index
+				padChar = null; index--; break;
+		}
+
+		// toggle case if a flag is set
+		var property = $(format.charAt(index++));
+		switch (switchCase){
+			case "upper":
+				property = property.toUpperCase();
+				break;
+			case "lower":
+				property = property.toLowerCase();
+				break;
+			case "swap": // Upper to lower, and versey-vicea
+				var compareString = property.toLowerCase();
+				var swapString = '';
+				var ch = '';
+				for (var j = 0; j < property.length; j++){
+					ch = property.charAt(j);
+					swapString += (ch == compareString.charAt(j)) ?
+						ch.toUpperCase() : ch.toLowerCase();
+				}
+				property = swapString;
+				break;
+			default:
+				break;
+		}
+		switchCase = null;
+		
+		string += property;
+		i = index;
+	}
+	string += format.substring(i);
+	
+	return string; // String
+};
+
+dojox.date.posix.getStartOfWeek = function(/*Date*/dateObject, /*Number*/firstDay){
+	// summary: Return a date object representing the first day of the given
+	//   date's week.
+	if(isNaN(firstDay)){
+		firstDay = dojo.cldr.supplemental.getFirstDayOfWeek ? dojo.cldr.supplemental.getFirstDayOfWeek() : 0;
+	}
+	var offset = firstDay;
+	if(dateObject.getDay() >= firstDay){
+		offset -= dateObject.getDay();
+	}else{
+		offset -= (7 - dateObject.getDay());
+	}
+	var date = new Date(dateObject);
+	date.setHours(0, 0, 0, 0);
+	return dojo.date.add(date, "day", offset); // Date
+}
+
+dojox.date.posix.setIsoWeekOfYear = function(/*Date*/dateObject, /*Number*/week){
+	// summary: Set the ISO8601 week number of the given date.
+	//   The week containing January 4th is the first week of the year.
+	// week:
+	//   can be positive or negative: -1 is the year's last week.
+	if(!week){ return dateObject; }
+	var currentWeek = dojox.date.posix.getIsoWeekOfYear(dateObject);
+	var offset = week - currentWeek;
+	if(week < 0){
+		var weeks = dojox.date.posix.getIsoWeeksInYear(dateObject);
+		offset = (weeks + week + 1) - currentWeek;
+	}
+	return dojo.date.add(dateObject, "week", offset); // Date
+}
+
+dojox.date.posix.getIsoWeekOfYear = function(/*Date*/dateObject){
+	// summary: Get the ISO8601 week number of the given date.
+	//   The week containing January 4th is the first week of the year.
+	//   See http://en.wikipedia.org/wiki/ISO_week_date
+	var weekStart = dojox.date.posix.getStartOfWeek(dateObject, 1);
+	var yearStart = new Date(dateObject.getFullYear(), 0, 4); // January 4th
+	yearStart = dojox.date.posix.getStartOfWeek(yearStart, 1);
+	var diff = weekStart.getTime() - yearStart.getTime();
+	if(diff < 0){ return dojox.date.posix.getIsoWeeksInYear(weekStart); } // Integer
+	return Math.ceil(diff / 604800000) + 1; // Integer
+}
+
+dojox.date.posix.getIsoWeeksInYear = function(/*Date*/dateObject) {
+	// summary: Determine the number of ISO8601 weeks in the year of the given 
+	//   date. Most years have 52 but some have 53.
+	//   See http://www.phys.uu.nl/~vgent/calendar/isocalendar_text3.htm	
+	function p(y) {
+		return y + Math.floor(y/4) - Math.floor(y/100) + Math.floor(y/400);
+	}
+	var y = dateObject.getFullYear();
+	return ( p(y) % 7 == 4 || p(y-1) % 7 == 3 ) ? 53 : 52;
+}

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/_base.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/_base.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/_base.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,319 @@
+dojo.provide("dojox.gfx._base");
+
+// candidates for dojox.style (work on VML and SVG nodes)
+dojox.gfx._hasClass = function(/*HTMLElement*/node, /*String*/classStr){
+	//	summary:
+	//		Returns whether or not the specified classes are a portion of the
+	//		class list currently applied to the node. 
+	// return (new RegExp('(^|\\s+)'+classStr+'(\\s+|$)')).test(node.className)	// Boolean
+	return ((" "+node.getAttribute("className")+" ").indexOf(" "+classStr+" ") >= 0);  // Boolean
+}
+
+dojox.gfx._addClass = function(/*HTMLElement*/node, /*String*/classStr){
+	//	summary:
+	//		Adds the specified classes to the end of the class list on the
+	//		passed node.
+	var cls = node.getAttribute("className");
+	if((" "+cls+" ").indexOf(" "+classStr+" ") < 0){
+		node.setAttribute("className", cls + (cls ? ' ' : '') + classStr);
+	}
+}
+
+dojox.gfx._removeClass = function(/*HTMLElement*/node, /*String*/classStr){
+	//	summary: Removes classes from node.
+	node.setAttribute("className", node.getAttribute("className").replace(new RegExp('(^|\\s+)'+classStr+'(\\s+|$)'), "$1$2"));
+}
+
+
+// candidate for dojox.lang:
+dojox.gfx._base._copy = function(o, deep){
+	if(!o){ return o; }
+	if(dojo.isArray(o)){
+		var r = [];
+		if(deep){
+			for(var i = 0; i < o.length; ++i){
+				r.push(dojox.gfx._base._copy(o[i], true));
+			}
+		}else{
+			for(var i = 0; i < o.length; ++i){
+				r.push(o[i]);
+			}
+		}
+		return r;
+	}else if(dojo.isObject(o)){
+		var r = new o.constructor();
+		if(deep){
+			for(var i in o){
+				if(!(i in r) || r[i] != o[i]){
+					r[i] = dojox.gfx._base._copy(o[i], true);
+				}
+			}
+		}else{
+			for(var i in o){
+				if(!(i in r) || r[i] != o[i]){
+					r[i] = o[i];
+				}
+			}
+		}
+		return r;
+	}
+	return o;
+};
+
+// candidate for dojox.html.metrics (dynamic font resize handler is not implemented here)
+
+//	derived from Morris John's emResized measurer
+dojox.gfx._base._getFontMeasurements = function(){
+	//	summary
+	//	Returns an object that has pixel equivilents of standard font size values.
+	var heights = {
+		'1em':0, '1ex':0, '100%':0, '12pt':0, '16px':0, 'xx-small':0, 'x-small':0,
+		'small':0, 'medium':0, 'large':0, 'x-large':0, 'xx-large':0
+	};
+
+	if(dojo.isIE){
+		//	we do a font-size fix if and only if one isn't applied already.
+		//	NOTE: If someone set the fontSize on the HTML Element, this will kill it.
+		dojo.doc.documentElement.style.fontSize="100%";
+	}
+
+	//	set up the measuring node.
+	var div=dojo.doc.createElement("div");
+	div.style.position="absolute";
+	div.style.left="-100px";
+	div.style.top="0";
+	div.style.width="30px";
+	div.style.height="1000em";
+	div.style.border="0";
+	div.style.margin="0";
+	div.style.padding="0";
+	div.style.outline="0";
+	div.style.lineHeight="1";
+	div.style.overflow="hidden";
+	dojo.body().appendChild(div);
+
+	//	do the measurements.
+	for(var p in heights){
+		div.style.fontSize = p;
+		heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000;
+	}
+	
+	dojo.body().removeChild(div);
+	div = null;
+	return heights; 	//	object
+};
+
+dojox.gfx._base._fontMeasurements = null;
+
+dojox.gfx._base._getCachedFontMeasurements = function(recalculate){
+	if(recalculate || !dojox.gfx._base._fontMeasurements){
+		dojox.gfx._base._fontMeasurements = dojox.gfx._base._getFontMeasurements();
+	}
+	return dojox.gfx._base._fontMeasurements;
+};
+
+// candidate for dojo.dom
+
+dojox.gfx._base._uniqueId = 0;
+dojox.gfx._base._getUniqueId = function(){
+	// summary: returns a unique string for use with any DOM element
+	var id;
+	do{
+		id = "dojoUnique" + (++dojox.gfx._base._uniqueId);
+	}while(dojo.byId(id));
+	return id;
+};
+
+dojo.mixin(dojox.gfx, {
+	// summary: defines constants, prototypes, and utility functions
+	
+	// default shapes, which are used to fill in missing parameters
+	defaultPath:     {type: "path",     path: ""},
+	defaultPolyline: {type: "polyline", points: []},
+	defaultRect:     {type: "rect",     x: 0, y: 0, width: 100, height: 100, r: 0},
+	defaultEllipse:  {type: "ellipse",  cx: 0, cy: 0, rx: 200, ry: 100},
+	defaultCircle:   {type: "circle",   cx: 0, cy: 0, r: 100},
+	defaultLine:     {type: "line",     x1: 0, y1: 0, x2: 100, y2: 100},
+	defaultImage:    {type: "image",    x: 0, y: 0, width: 0, height: 0, src: ""},
+	defaultText:     {type: "text",     x: 0, y: 0, text: "",
+		align: "start", decoration: "none", rotated: false, kerning: true },
+	defaultTextPath: {type: "textpath", text: "",
+		align: "start", decoration: "none", rotated: false, kerning: true },
+
+	// default geometric attributes
+	defaultStroke: {type: "stroke", color: "black", style: "solid", width: 1, cap: "butt", join: 4},
+	defaultLinearGradient: {type: "linear", x1: 0, y1: 0, x2: 100, y2: 100, 
+		colors: [{offset: 0, color: "black"}, {offset: 1, color: "white"}]},
+	defaultRadialGradient: {type: "radial", cx: 0, cy: 0, r: 100, 
+		colors: [{offset: 0, color: "black"}, {offset: 1, color: "white"}]},
+	defaultPattern: {type: "pattern", x: 0, y: 0, width: 0, height: 0, src: ""},
+	defaultFont: {type: "font", style: "normal", variant: "normal", weight: "normal", 
+		size: "10pt", family: "serif"},
+
+	normalizeColor: function(/*Color*/ color){
+		// summary: converts any legal color representation to normalized dojo.Color object
+		return (color instanceof dojo.Color) ? color : new dojo.Color(color); // dojo.Color
+	},
+	normalizeParameters: function(existed, update){
+		// summary: updates an existing object with properties from an "update" object
+		// existed: Object: the "target" object to be updated
+		// update:  Object: the "update" object, whose properties will be used to update the existed object
+		if(update){
+			var empty = {};
+			for(var x in existed){
+				if(x in update && !(x in empty)){
+					existed[x] = update[x];
+				}
+			}
+		}
+		return existed;	// Object
+	},
+	makeParameters: function(defaults, update){
+		// summary: copies the original object, and all copied properties from the "update" object
+		// defaults: Object: the object to be cloned before updating
+		// update:   Object: the object, which properties are to be cloned during updating
+		if(!update) return dojox.gfx._base._copy(defaults, true);
+		var result = {};
+		for(var i in defaults){
+			if(!(i in result)){
+				result[i] = dojox.gfx._base._copy((i in update) ? update[i] : defaults[i], true);
+			}
+		}
+		return result; // Object
+	},
+	formatNumber: function(x, addSpace){
+		// summary: converts a number to a string using a fixed notation
+		// x:			Number:		number to be converted
+		// addSpace:	Boolean?:	if it is true, add a space before a positive number
+		var val = x.toString();
+		if(val.indexOf("e") >= 0){
+			val = x.toFixed(4);
+		}else{
+			var point = val.indexOf(".");
+			if(point >= 0 && val.length - point > 5){
+				val = x.toFixed(4);
+			}
+		}
+		if(x < 0){
+			return val; // String
+		}
+		return addSpace ? " " + val : val; // String
+	},
+	// font operations
+	makeFontString: function(font){
+		// summary: converts a font object to a CSS font string
+		// font:	Object:	font object (see dojox.gfx.defaultFont)
+		return font.style + " " + font.variant + " " + font.weight + " " + font.size + " " + font.family; // Object
+	},
+	splitFontString: function(str){
+		// summary: converts a CSS font string to a font object
+		// str:		String:	a CSS font string
+		var font = dojox.gfx._base._copy(dojox.gfx.defaultFont);
+		var t = str.split(/\s+/);
+		do{
+			if(t.length < 5){ break; }
+			font.style  = t[0];
+			font.varian = t[1];
+			font.weight = t[2];
+			var i = t[3].indexOf("/");
+			font.size = i < 0 ? t[3] : t[3].substring(0, i);
+			var j = 4;
+			if(i < 0){
+				if(t[4] == "/"){
+					j = 6;
+					break;
+				}
+				if(t[4].substr(0, 1) == "/"){
+					j = 5;
+					break;
+				}
+			}
+			if(j + 3 > t.length){ break; }
+			font.size = t[j];
+			font.family = t[j + 1];
+		}while(false);
+		return font;	// Object
+	},
+	// length operations
+	cm_in_pt: 72 / 2.54,	// Number: centimeters per inch
+	mm_in_pt: 7.2 / 2.54,	// Number: millimeters per inch
+	px_in_pt: function(){
+		// summary: returns a number of pixels per point
+		return dojox.gfx._base._getCachedFontMeasurements()["12pt"] / 12;	// Number
+	},
+	pt2px: function(len){
+		// summary: converts points to pixels
+		// len: Number: a value in points
+		return len * dojox.gfx.px_in_pt();	// Number
+	},
+	px2pt: function(len){
+		// summary: converts pixels to points
+		// len: Number: a value in pixels
+		return len / dojox.gfx.px_in_pt();	// Number
+	},
+	normalizedLength: function(len) {
+		// summary: converts any length value to pixels
+		// len: String: a length, e.g., "12pc"
+		if(len.length == 0) return 0;
+		if(len.length > 2){
+			var px_in_pt = dojox.gfx.px_in_pt();
+			var val = parseFloat(len);
+			switch(len.slice(-2)){
+				case "px": return val;
+				case "pt": return val * px_in_pt;
+				case "in": return val * 72 * px_in_pt;
+				case "pc": return val * 12 * px_in_pt;
+				case "mm": return val / dojox.gfx.mm_in_pt * px_in_pt;
+				case "cm": return val / dojox.gfx.cm_in_pt * px_in_pt;
+			}
+		}
+		return parseFloat(len);	// Number
+	},
+	
+	// a constant used to split a SVG/VML path into primitive components
+	pathVmlRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,
+	pathSvgRegExp: /([A-Za-z])|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g
+});
+
+dojo.declare("dojox.gfx.Surface", null,
+	function(){
+		// summary: a surface object to be used for drawings
+		
+		// underlying node
+		this.rawNode = null;
+	},
+{
+	getEventSource: function(){
+		// summary: returns a node, which can be used to attach event listeners
+		
+		return this.rawNode; // Node
+	},
+	createShape: function(shape){
+		// summary: creates a shape object based on its type
+		// shape: Object: a shape object
+		switch(shape.type){
+			case dojox.gfx.defaultPath.type:		return this.createPath(shape);
+			case dojox.gfx.defaultRect.type:		return this.createRect(shape);
+			case dojox.gfx.defaultCircle.type:		return this.createCircle(shape);
+			case dojox.gfx.defaultEllipse.type:		return this.createEllipse(shape);
+			case dojox.gfx.defaultLine.type:		return this.createLine(shape);
+			case dojox.gfx.defaultPolyline.type:	return this.createPolyline(shape);
+			case dojox.gfx.defaultImage.type:		return this.createImage(shape);
+			case dojox.gfx.defaultText.type:		return this.createText(shape);
+			case dojox.gfx.defaultTextPath.type:	return this.createTextPath(shape);
+		}
+		return null;
+	}
+});
+
+dojo.declare("dojox.gfx.Point", null, {
+	// summary: a hypothetical 2D point to be used for drawings - {x, y}
+	// description: This object is defined for documentation purposes.
+	//	You should use a naked object instead: {x: 1, y: 2}.
+});
+
+dojo.declare("dojox.gfx.Rectangle", null, {
+	// summary: a hypothetical rectangle - {x, y, width, height}
+	// description: This object is defined for documentation purposes.
+	//	You should use a naked object instead: {x: 1, y: 2, width: 100, height: 200}.
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/butterfly.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/butterfly.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/butterfly.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,98 @@
+<html>
+<head>
+<title>dojox.gfx: Butterfly</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx");
+
+// no sliders yet
+
+//dojo.require ("dojo.widget.*");
+//dojo.require ("dojo.widget.Slider");
+
+var rotation = 0, scaling = 1;
+var surface, g, m = dojox.gfx.matrix;
+var initial_matrix = m.translate(140, 180);
+
+var updateMatrix = function(){
+	if(g){ g.setTransform([m.rotategAt(rotation, 350, 350), m.scaleAt(scaling, 350, 350), initial_matrix]); }
+};
+
+var rotatingEvent = function(value){
+	rotation = value;
+	dojo.byId("rotationValue").innerHTML = rotation;
+	updateMatrix();
+};
+
+var scalingEvent = function(value){
+	scaling = Math.exp(Math.LN10 * (value - 1));
+	dojo.byId("scaleValue").innerHTML = scaling.toFixed(3);
+	updateMatrix();
+};
+
+var makeShapes = function(){
+	surface = dojox.gfx.createSurface(dojo.byId("gfx_holder"), 700, 700);
+	surface.createRect({x: 0, y: 0, width: 700, height: 700}).setFill("#eee");
+	g = surface.createGroup().setTransform(initial_matrix);
+    g.createPath("M204.33 139.83 C196.33 133.33 206.68 132.82 206.58 132.58 C192.33 97.08 169.35 81.41 167.58 80.58 C162.12 78.02 159.48 78.26 160.45 76.97 C161.41 75.68 167.72 79.72 168.58 80.33 C193.83 98.33 207.58 132.33 207.58 132.33 C207.58 132.33 209.33 133.33 209.58 132.58 C219.58 103.08 239.58 87.58 246.33 81.33 C253.08 75.08 256.63 74.47 247.33 81.58 C218.58 103.58 210.34 132.23 210.83 132.33 C222.33 134.83 211.33 140.33 211.83 139.83 C214.85 136.81 214.83 145.83 214.83 145.83 C214.83 145.83 231.83 110.83 298.33 66.33 C302.43 63.59 445.83 -14.67 395.83 80.83 C393.24 85.79 375.83 105.83 375.83 105.83 C375.83 105.83 377.33 114.33 371.33 121.33 C370.3 122.53 367.83 134.33 361.83 140.83 C360.14 142.67 361.81 139.25 361.83 140.83 C362.33 170.83 337.76 170.17 339.33 170.33 C348.83 171.33 350.19 183.66 350.33 183.83 C355.83 190.33 353.83 191.83 355.83 194.83 C366.63 211.02 355.24 210.05 356.83 212.83 C360.83 219.83 355.99 222.72 357.33 224.83 C360.83 230.33 354.75 233.84 354.83 235.33 C355.33 243.83 349.67 240.73 349.83 244.33 C350.33 255.33 346.33 250.83 343.83 254.83 C336.33 266.83 333.46 262.38 332.83 263.83 C329.83 270.83 325.81 269.15 324.33 270.83 C320.83 274.83 317.33 274.83 315.83 276.33 C308.83 283.33 304.86 278.39 303.83 278.83 C287.83 285.83 280.33 280.17 277.83 280.33 C270.33 280.83 271.48 279.67 269.33 277.83 C237.83 250.83 219.33 211.83 215.83 206.83 C214.4 204.79 211.35 193.12 212.33 195.83 C214.33 201.33 213.33 250.33 207.83 250.33 C202.33 250.33 201.83 204.33 205.33 195.83 C206.43 193.16 204.4 203.72 201.79 206.83 C196.33 213.33 179.5 250.83 147.59 277.83 C145.42 279.67 146.58 280.83 138.98 280.33 C136.46 280.17 128.85 285.83 112.65 278.83 C111.61 278.39 107.58 283.33 100.49 276.33 C98.97 274.83 95.43 274.83 91.88 270.83 C90.39 269.15 86.31 270.83 83.27 263.83 C82.64 262.38 79.73 266.83 72.13 254.83 C69.6 250.83 65.54 255.33 66.05 244.33 C66.22 240.73 60.48 243.83 60.99 235.33 C61.08 233.84 54.91 230.33 58.45 224.83 C59.81 222.72 54.91 219.83 58.96 212.83 C60.57 210.05 49.04 211.02 59.97 194.83 C62 191.83 59.97 190.33 65.54 183.83 C65.69 183.66 67.06 171.33 76.69 170.33 C78.28 170.17 53.39 170.83 53.9 140.83 C53.92 139.25 55.61 142.67 53.9 140.83 C47.82 134.33 45.32 122.53 44.27 121.33 C38.19 114.33 39.71 105.83 39.71 105.83 C39.71 105.83 22.08 85.79 19.46 80.83 C-31.19 -14.67 114.07 63.59 118.22 66.33 C185.58 110.83 202 145.83 202 145.83 C202 145.83 202.36 143.28 203 141.83 C203.64 140.39 204.56 140.02 204.33 139.83 z").setFill("rgb(246,127,0)");
+    g.createPath("M203.62 139.62 C195.62 133.12 205.96 132.6 205.87 132.37 C191.62 96.87 168.64 81.2 166.87 80.37 C161.41 77.81 158.77 78.05 159.73 76.76 C160.69 75.47 167.01 79.51 167.87 80.12 C193.12 98.12 206.87 132.12 206.87 132.12 C206.87 132.12 208.62 133.12 208.87 132.37 C218.87 102.87 238.87 87.37 245.62 81.12 C252.37 74.87 255.92 74.26 246.62 81.37 C217.87 103.37 209.63 132.01 210.12 132.12 C221.62 134.62 210.62 140.12 211.12 139.62 C214.14 136.6 214.12 145.62 214.12 145.62 C214.12 145.62 231.12 110.62 297.62 66.12 C301.71 63.38 445.12 -14.88 395.12 80.62 C392.53 85.57 375.12 105.62 375.12 105.62 C375.12 105.62 376.62 114.12 370.62 121.12 C369.59 122.32 367.12 134.12 361.12 140.62 C359.43 142.46 361.09 139.04 361.12 140.62 C361.62 170.62 337.05 169.96 338.62 170.12 C348.12 171.12 349.47 183.45 349.62 183.62 C355.12 190.12 353.12 191.62 355.12 194.62 C365.91 210.81 354.53 209.84 356.12 212.62 C360.12 219.62 355.28 222.51 356.62 224.62 C360.12 230.12 354.03 233.62 354.12 235.12 C354.62 243.62 348.96 240.52 349.12 244.12 C349.62 255.12 345.62 250.62 343.12 254.62 C335.62 266.62 332.74 262.17 332.12 263.62 C329.12 270.62 325.09 268.94 323.62 270.62 C320.12 274.62 316.62 274.62 315.12 276.12 C308.12 283.12 304.15 278.17 303.12 278.62 C287.12 285.62 279.62 279.95 277.12 280.12 C269.62 280.62 270.77 279.46 268.62 277.62 C237.12 250.62 218.62 211.62 215.12 206.62 C213.69 204.57 210.63 192.91 211.62 195.62 C213.62 201.12 212.62 250.12 207.12 250.12 C201.62 250.12 201.12 204.12 204.62 195.62 C205.72 192.95 203.69 203.5 201.08 206.62 C195.62 213.12 178.79 250.62 146.88 277.62 C144.71 279.46 145.87 280.62 138.27 280.12 C135.75 279.95 128.14 285.62 111.94 278.62 C110.9 278.17 106.87 283.12 99.78 276.12 C98.26 274.62 94.72 274.62 91.17 270.62 C89.68 268.94 85.6 270.62 82.56 263.62 C81.93 262.17 79.01 266.62 71.42 254.62 C68.88 250.62 64.83 255.12 65.34 244.12 C65.51 240.52 59.77 243.62 60.27 235.12 C60.36 233.62 54.2 230.12 57.74 224.62 C59.1 222.51 54.2 219.62 58.25 212.62 C59.86 209.84 48.33 210.81 59.26 194.62 C61.29 191.62 59.26 190.12 64.83 183.62 C64.98 183.45 66.35 171.12 75.98 170.12 C77.57 169.96 52.68 170.62 53.18 140.62 C53.21 139.04 54.9 142.46 53.18 140.62 C47.11 134.12 44.6 122.32 43.56 121.12 C37.48 114.12 39 105.62 39 105.62 C39 105.62 21.37 85.57 18.74 80.62 C-31.9 -14.88 113.36 63.38 117.51 66.12 C184.87 110.62 201.29 145.62 201.29 145.62 C201.29 145.62 201.65 143.07 202.29 141.62 C202.93 140.18 203.85 139.81 203.62 139.62 zM242.12 153.12 C245.16 153.02 251.35 156.17 255.12 155.12 C280.55 148.06 328.44 154.56 331.62 155.62 C343.62 159.62 351.62 131.12 326.12 131.12 C294.59 131.12 301.12 129.12 280.12 126.12 C278.34 125.87 252.6 135.42 228.62 149.12 C225.12 151.12 227.12 153.62 242.12 153.12 zM223.12 148.12 C225.66 148.4 238.12 139.62 277.12 124.12 C279.49 123.18 279.62 118.12 300.62 108.62 C301.99 108 300.12 104.62 314.62 92.62 C321.79 86.69 297.12 87.62 291.62 88.62 C286.12 89.62 272.62 100.62 272.62 100.62 C272.62 100.62 287.8 88.55 282.62 90.12 C271.12 93.62 241.12 126.62 231.12 140.62 C221.12 154.62 247.62 116.62 254.12 110.62 C260.62 104.62 204.62 146.12 223.12 148.12 zM335.62 128.62 C350.14 131.53 348.62 110.12 341.12 109.12 C329.55 107.58 307.51 108.3 301.12 110.62 C284.62 116.62 280.29 122.65 281.62 123.12 C310.12 133.12 330.62 127.62 335.62 128.62 zM335.12 106.62 C341.04 107.36 351.12 109.62 351.62 101.62 C351.87 97.6 365.62 104.62 368.62 105.12 C371.1 105.53 358.12 100.33 353.62 97.12 C350.12 94.62 349.51 91.76 349.12 91.62 C317.12 80.12 303.62 107.12 303.62 107.12 C303.62 107.12 331.12 106.12 335.12 106.62 zM400.62 62.62 C395.62 54.62 386.66 57.08 383.62 53.62 C369.12 37.12 335.54 58.28 363.12 56.12 C395.12 53.62 401.21 63.57 400.62 62.62 zM376.62 66.62 C390.13 66.62 396.12 72.62 395.12 71.62 C388.12 64.62 382.12 66.12 380.62 64.12 C371.7 52.23 345.12 64.62 347.12 67.62 C349.12 70.62 373.12 66.62 376.62 66.62 zM330.12 76.12 C309.12 81.12 318.12 88.62 320.62 88.12 C340.05 84.24 334.5 75.08 330.12 76.12 zM340.62 52.12 C331.12 53.12 330.48 70.43 335.12 67.12 C342.12 62.12 350.12 51.12 340.62 52.12 zM315.62 75.62 C329.62 70.12 319.12 67.62 314.62 68.12 C310.12 68.62 306.79 75.45 308.12 78.12 C311.12 84.12 312.91 76.69 315.62 75.62 zM359.62 121.12 C364.12 118.62 358.62 112.62 354.62 115.12 C350.62 117.62 355.12 123.62 359.62 121.12 zM350.12 78.62 C361.89 90.39 366.62 84.12 369.12 83.12 C377.24 79.87 386.12 88.62 384.62 87.12 C377.34 79.84 372.62 81.12 371.62 79.62 C364.01 68.2 352.66 75.44 350.12 75.62 C343.12 76.12 334.43 81.03 337.62 80.12 C341.12 79.12 348.62 77.12 350.12 78.62 zM383.62 44.12 C390.62 39.12 381.4 37.85 379.62 38.12 C373.12 39.12 376.62 49.12 383.62 44.12 zM224.62 181.12 C230.12 187.62 291.62 285.12 282.12 252.62 C280.83 248.2 285.62 266.12 291.12 256.12 C292.66 253.32 301.27 253.03 274.62 208.62 C273.12 206.12 252.62 198.12 232.12 175.62 C229.02 172.21 220.05 175.72 224.62 181.12 zM280.12 215.62 C284.62 222.62 295.81 246.07 296.62 249.62 C299.12 260.62 306.12 248.12 307.62 248.62 C320.78 253.01 311.12 241.12 310.12 238.12 C300.95 210.62 279.62 213.12 279.62 213.12 C279.62 213.12 275.62 208.62 280.12 215.62 zM253.62 256.12 C266.26 274.09 271.12 267.12 273.62 265.12 C281.32 258.96 232.34 196.14 229.12 192.12 C225.12 187.12 225.12 215.62 253.62 256.12 zM300.12 219.12 C306.62 224.12 313.86 245.19 317.62 244.62 C327.62 243.12 321.62 234.62 324.12 236.12 C326.62 237.62 331.62 234.95 330.12 232.12 C317.62 208.62 298.12 216.12 298.12 216.12 C298.12 216.12 293.62 214.12 300.12 219.12 zM235.62 168.62 C216.12 168.62 282.12 222.62 301.12 212.12 C305.06 209.94 296.12 208.62 297.62 197.12 C297.9 195.02 284.12 191.12 284.12 178.12 C284.12 173.88 276.2 172.12 251.12 172.12 C246.62 172.12 256.03 168.62 235.62 168.62 zM307.62 213.62 C325.89 215.65 330.23 229.8 332.62 228.12 C361.12 208.12 309.89 199.96 300.62 201.12 C296.62 201.62 303.12 213.12 307.62 213.62 zM238.62 164.12 C242.12 166.62 254.12 176.62 292.62 168.12 C294.09 167.8 263.62 167.62 259.62 166.62 C255.62 165.62 236.25 162.43 238.62 164.12 zM305.12 198.62 C342.62 207.62 332.72 201.36 334.12 200.62 C342.62 196.12 333.33 195.23 334.62 193.62 C338.83 188.36 327.62 185.12 304.12 182.62 C298.56 182.03 287.54 179.27 287.12 180.12 C283.62 187.12 300.33 197.47 305.12 198.62 zM311.12 182.12 C343.62 187.62 323.23 177.43 323.62 177.12 C335.12 168.12 297.12 168.12 297.12 168.12 C297.12 168.12 280.79 172 281.12 172.62 C285.62 181.12 307.15 181.45 311.12 182.12 zM249.62 253.62 C249.62 253.62 220.62 207.12 226.62 188.12 C227.83 184.31 213.62 165.62 220.12 197.12 C220.22 197.61 218.89 190.43 216.62 187.12 C214.35 183.81 211.18 184.9 213.12 194.62 C218.01 219.05 249.62 253.62 249.62 253.62 zM289.12 83.62 C296.62 81.62 293.12 79.12 288.62 78.12 C284.12 77.12 281.62 85.62 289.12 83.62 zM187.4 149.12 C163.12 135.42 137.04 125.87 135.23 126.12 C113.96 129.12 120.58 131.12 88.64 131.12 C62.81 131.12 70.91 159.62 83.07 155.62 C86.29 154.56 134.8 148.06 160.56 155.12 C164.37 156.17 170.65 153.02 173.73 153.12 C188.92 153.62 190.95 151.12 187.4 149.12 zM161.57 110.62 C168.15 116.62 195 154.62 184.87 140.62 C174.74 126.62 144.35 93.62 132.7 90.12 C127.46 88.55 142.83 100.62 142.83 100.62 C142.83 100.62 129.16 89.62 123.58 88.62 C118.01 87.62 93.03 86.69 100.29 92.62 C114.97 104.62 113.08 108 114.47 108.62 C135.74 118.12 135.87 123.18 138.27 124.12 C177.78 139.62 190.4 148.4 192.97 148.12 C211.71 146.12 154.99 104.62 161.57 110.62 zM133.71 123.12 C135.07 122.65 130.68 116.62 113.96 110.62 C107.49 108.3 85.16 107.58 73.44 109.12 C65.85 110.12 64.31 131.53 79.01 128.62 C84.08 127.62 104.84 133.12 133.71 123.12 zM111.43 107.12 C111.43 107.12 97.75 80.12 65.34 91.62 C64.95 91.76 64.33 94.62 60.78 97.12 C56.23 100.33 43.08 105.53 45.59 105.12 C48.63 104.62 62.55 97.6 62.81 101.62 C63.31 109.62 73.53 107.36 79.52 106.62 C83.57 106.12 111.43 107.12 111.43 107.12 zM51.16 56.12 C79.09 58.28 45.08 37.12 30.39 53.62 C27.31 57.08 18.24 54.62 13.17 62.62 C12.57 63.57 18.74 53.62 51.16 56.12 zM67.37 67.62 C69.39 64.62 42.47 52.23 33.43 64.12 C31.91 66.12 25.83 64.62 18.74 71.62 C17.73 72.62 23.8 66.62 37.48 66.62 C41.03 66.62 65.34 70.62 67.37 67.62 zM84.59 76.12 C105.86 81.12 96.74 88.62 94.21 88.12 C74.53 84.24 80.15 75.08 84.59 76.12 zM79.52 67.12 C84.22 70.43 83.57 53.12 73.95 52.12 C64.33 51.12 72.43 62.12 79.52 67.12 zM106.87 78.12 C108.22 75.45 104.84 68.62 100.29 68.12 C95.73 67.62 85.09 70.12 99.27 75.62 C102.02 76.69 103.83 84.12 106.87 78.12 zM59.77 115.12 C55.72 112.62 50.14 118.62 54.7 121.12 C59.26 123.62 63.82 117.62 59.77 115.12 zM76.99 80.12 C80.22 81.03 71.42 76.12 64.33 75.62 C61.75 75.44 50.26 68.2 42.55 79.62 C41.53 81.12 36.75 79.84 29.38 87.12 C27.86 88.62 36.85 79.87 45.08 83.12 C47.61 84.12 52.41 90.39 64.33 78.62 C65.85 77.12 73.44 79.12 76.99 80.12 zM34.44 38.12 C32.64 37.85 23.3 39.12 30.39 44.12 C37.48 49.12 41.03 39.12 34.44 38.12 zM183.86 175.62 C163.09 198.12 142.32 206.12 140.8 208.62 C113.81 253.03 122.53 253.32 124.09 256.12 C129.66 266.12 134.52 248.2 133.21 252.62 C123.58 285.12 185.88 187.62 191.45 181.12 C196.08 175.72 187 172.21 183.86 175.62 zM135.74 213.12 C135.74 213.12 114.13 210.62 104.84 238.12 C103.83 241.12 94.05 253.01 107.38 248.62 C108.9 248.12 115.99 260.62 118.52 249.62 C119.34 246.07 130.68 222.62 135.23 215.62 C139.79 208.62 135.74 213.12 135.74 213.12 zM186.89 192.12 C183.64 196.14 134.02 258.96 141.82 265.12 C144.35 267.12 149.27 274.09 162.08 256.12 C190.95 215.62 190.95 187.12 186.89 192.12 zM117 216.12 C117 216.12 97.25 208.62 84.59 232.12 C83.06 234.95 88.13 237.62 90.66 236.12 C93.2 234.62 87.12 243.12 97.25 244.62 C101.06 245.19 108.39 224.12 114.97 219.12 C121.56 214.12 117 216.12 117 216.12 zM164.61 172.12 C139.2 172.12 131.18 173.88 131.18 178.12 C131.18 191.12 117.23 195.02 117.51 197.12 C119.03 208.62 109.97 209.94 113.96 212.12 C133.21 222.62 200.06 168.62 180.31 168.62 C159.64 168.62 169.17 172.12 164.61 172.12 zM114.47 201.12 C105.08 199.96 53.18 208.12 82.05 228.12 C84.47 229.8 88.87 215.65 107.38 213.62 C111.94 213.12 118.52 201.62 114.47 201.12 zM156 166.62 C151.95 167.62 121.09 167.8 122.57 168.12 C161.57 176.62 173.73 166.62 177.27 164.12 C179.67 162.43 160.05 165.62 156 166.62 zM128.14 180.12 C127.71 179.27 116.55 182.03 110.92 182.62 C87.12 185.12 75.76 188.36 80.03 193.62 C81.33 195.23 71.92 196.12 80.53 200.62 C81.95 201.36 71.92 207.62 109.91 198.62 C114.76 197.47 131.69 187.12 128.14 180.12 zM134.22 172.62 C134.56 172 118.01 168.12 118.01 168.12 C118.01 168.12 79.52 168.12 91.17 177.12 C91.57 177.43 70.91 187.62 103.83 182.12 C107.86 181.45 129.66 181.12 134.22 172.62 zM203.1 194.62 C205.07 184.9 201.85 183.81 199.56 187.12 C197.26 190.43 195.91 197.61 196.01 197.12 C202.6 165.62 188.21 184.31 189.43 188.12 C195.5 207.12 166.13 253.62 166.13 253.62 C166.13 253.62 198.15 219.05 203.1 194.62 zM126.62 78.12 C122.06 79.12 118.52 81.62 126.12 83.62 C133.71 85.62 131.18 77.12 126.62 78.12 z").setFill("black");
+    g.createPath("M363.73 85.73 C359.27 86.29 355.23 86.73 354.23 81.23 C353.23 75.73 355.73 73.73 363.23 75.73 C370.73 77.73 375.73 84.23 363.73 85.73 zM327.23 89.23 C327.23 89.23 308.51 93.65 325.73 80.73 C333.73 74.73 334.23 79.73 334.73 82.73 C335.48 87.2 327.23 89.23 327.23 89.23 zM384.23 48.73 C375.88 47.06 376.23 42.23 385.23 40.23 C386.7 39.91 389.23 49.73 384.23 48.73 zM389.23 48.73 C391.73 48.23 395.73 49.23 396.23 52.73 C396.73 56.23 392.73 58.23 390.23 56.23 C387.73 54.23 386.73 49.23 389.23 48.73 zM383.23 59.73 C385.73 58.73 393.23 60.23 392.73 63.23 C392.23 66.23 386.23 66.73 383.73 65.23 C381.23 63.73 380.73 60.73 383.23 59.73 zM384.23 77.23 C387.23 74.73 390.73 77.23 391.73 78.73 C392.73 80.23 387.73 82.23 386.23 82.73 C384.73 83.23 381.23 79.73 384.23 77.23 zM395.73 40.23 C395.73 40.23 399.73 40.23 398.73 41.73 C397.73 43.23 394.73 43.23 394.73 43.23 zM401.73 49.23 C401.73 49.23 405.73 49.23 404.73 50.73 C403.73 52.23 400.73 52.23 400.73 52.23 zM369.23 97.23 C369.23 97.23 374.23 99.23 373.23 100.73 C372.23 102.23 370.73 104.73 367.23 101.23 C363.73 97.73 369.23 97.23 369.23 97.23 zM355.73 116.73 C358.73 114.23 362.23 116.73 363.23 118.23 C364.23 119.73 359.23 121.73 357.73 122.23 C356.23 122.73 352.73 119.23 355.73 116.73 zM357.73 106.73 C360.73 104.23 363.23 107.73 364.23 109.23 C365.23 110.73 361.23 111.73 359.73 112.23 C358.23 112.73 354.73 109.23 357.73 106.73 zM340.73 73.23 C337.16 73.43 331.23 71.73 340.23 65.73 C348.55 60.19 348.23 61.73 348.73 64.73 C349.48 69.2 344.3 73.04 340.73 73.23 zM310.23 82.23 C310.23 82.23 306.73 79.23 313.73 73.23 C321.33 66.73 320.23 69.23 320.73 72.23 C321.48 76.7 310.23 82.23 310.23 82.23 zM341.23 55.73 C341.23 55.73 347.23 54.73 346.23 56.23 C345.23 57.73 342.73 63.23 339.23 59.73 C335.73 56.23 341.23 55.73 341.23 55.73 zM374.73 86.23 C376.11 86.23 377.23 87.36 377.23 88.73 C377.23 90.11 376.11 91.23 374.73 91.23 C373.36 91.23 372.23 90.11 372.23 88.73 C372.23 87.36 373.36 86.23 374.73 86.23 zM369.73 110.73 C371.11 110.73 372.23 111.86 372.23 113.23 C372.23 114.61 371.11 115.73 369.73 115.73 C368.36 115.73 367.23 114.61 367.23 113.23 C367.23 111.86 368.36 110.73 369.73 110.73 zM365.73 120.73 C367.11 120.73 368.23 121.86 368.23 123.23 C368.23 124.61 367.11 125.73 365.73 125.73 C364.36 125.73 363.23 124.61 363.23 123.23 C363.23 121.86 364.36 120.73 365.73 120.73 zM349.73 127.23 C351.11 127.23 352.23 128.36 352.23 129.73 C352.23 131.11 351.11 132.23 349.73 132.23 C348.36 132.23 347.23 131.11 347.23 129.73 C347.23 128.36 348.36 127.23 349.73 127.23 zM358.23 128.73 C359.61 128.73 362.23 130.86 362.23 132.23 C362.23 133.61 359.61 133.73 358.23 133.73 C356.86 133.73 355.73 132.61 355.73 131.23 C355.73 129.86 356.86 128.73 358.23 128.73 zM382.23 89.73 C383.61 89.73 384.73 90.86 384.73 92.23 C384.73 93.61 383.61 94.73 382.23 94.73 C380.86 94.73 379.73 93.61 379.73 92.23 C379.73 90.86 380.86 89.73 382.23 89.73 zM395.73 66.23 C397.11 66.23 398.23 67.36 398.23 68.73 C398.23 70.11 397.11 71.23 395.73 71.23 C394.36 71.23 393.23 70.11 393.23 68.73 C393.23 67.36 394.36 66.23 395.73 66.23 zM300.73 74.23 C303.05 75.16 314.23 67.73 310.73 66.73 C307.23 65.73 298.23 73.23 300.73 74.23 zM319.73 61.23 C322.23 61.73 329.73 58.73 326.23 57.73 C322.73 56.73 317.09 60.71 319.73 61.23 zM271.73 91.73 C277.23 88.73 292.73 81.23 285.23 82.23 C277.73 83.23 267.01 94.31 271.73 91.73 zM364.23 42.23 C366.73 42.73 374.23 39.73 370.73 38.73 C367.23 37.73 361.59 41.71 364.23 42.23 zM292.23 78.73 C294.73 79.23 299.73 76.73 296.23 75.73 C292.73 74.73 289.59 78.21 292.23 78.73 zM355.23 141.23 C356.61 141.23 357.73 142.86 357.73 144.23 C357.73 145.61 357.11 145.73 355.73 145.73 C354.36 145.73 353.23 144.61 353.23 143.23 C353.23 141.86 353.86 141.23 355.23 141.23 zM347.73 140.73 C349.11 140.73 351.23 141.36 351.23 142.73 C351.23 144.11 348.61 143.73 347.23 143.73 C345.86 143.73 344.73 142.61 344.73 141.23 C344.73 139.86 346.36 140.73 347.73 140.73 zM349.73 155.23 C351.11 155.23 353.73 157.36 353.73 158.73 C353.73 160.11 351.11 160.23 349.73 160.23 C348.36 160.23 347.23 159.11 347.23 157.73 C347.23 156.36 348.36 155.23 349.73 155.23 zM337.73 175.73 C341.73 174.73 341.73 176.73 342.73 180.23 C343.73 183.73 350.8 195.11 339.23 181.23 C336.73 178.23 333.73 176.73 337.73 175.73 zM349.73 187.73 C351.11 187.73 352.23 188.86 352.23 190.23 C352.23 191.61 351.11 192.73 349.73 192.73 C348.36 192.73 347.23 191.61 347.23 190.23 C347.23 188.86 348.36 187.73 349.73 187.73 zM352.23 196.73 C353.61 196.73 354.73 197.86 354.73 199.23 C354.73 200.61 353.61 201.73 352.23 201.73 C350.86 201.73 349.73 200.61 349.73 199.23 C349.73 197.86 350.86 196.73 352.23 196.73 zM352.4 205.73 C353.77 205.73 355.73 208.86 355.73 210.23 C355.73 211.61 354.61 212.73 353.23 212.73 C351.86 212.73 349.07 211.11 349.07 209.73 C349.07 208.36 351.02 205.73 352.4 205.73 zM353.73 221.73 C355.11 221.73 354.73 221.86 354.73 223.23 C354.73 224.61 354.61 223.73 353.23 223.73 C351.86 223.73 352.23 224.61 352.23 223.23 C352.23 221.86 352.36 221.73 353.73 221.73 zM340.23 188.73 C341.61 188.73 341.23 188.86 341.23 190.23 C341.23 191.61 341.11 190.73 339.73 190.73 C338.36 190.73 338.73 191.61 338.73 190.23 C338.73 188.86 338.86 188.73 340.23 188.73 zM343.23 201.23 C344.61 201.23 344.23 201.36 344.23 202.73 C344.23 204.11 344.44 207.73 343.07 207.73 C341.69 207.73 341.73 204.11 341.73 202.73 C341.73 201.36 341.86 201.23 343.23 201.23 zM346.73 215.23 C348.11 215.23 347.73 215.36 347.73 216.73 C347.73 218.11 347.61 217.23 346.23 217.23 C344.86 217.23 345.23 218.11 345.23 216.73 C345.23 215.36 345.36 215.23 346.73 215.23 zM340.57 228.73 C341.94 228.73 341.73 228.86 341.73 230.23 C341.73 231.61 341.44 230.73 340.07 230.73 C338.69 230.73 339.23 231.61 339.23 230.23 C339.23 228.86 339.19 228.73 340.57 228.73 zM349.4 232.07 C350.77 232.07 352.07 234.02 352.07 235.4 C352.07 236.77 349.11 239.23 347.73 239.23 C346.36 239.23 346.73 240.11 346.73 238.73 C346.73 237.36 348.02 232.07 349.4 232.07 zM343.73 246.4 C345.11 246.4 347.4 246.02 347.4 247.4 C347.4 248.77 344.11 251.23 342.73 251.23 C341.36 251.23 341.73 252.11 341.73 250.73 C341.73 249.36 342.36 246.4 343.73 246.4 zM335.23 239.23 C336.61 239.23 336.23 239.36 336.23 240.73 C336.23 242.11 336.11 241.23 334.73 241.23 C333.36 241.23 333.73 242.11 333.73 240.73 C333.73 239.36 333.86 239.23 335.23 239.23 zM332.73 258.4 C334.11 258.4 335.4 260.02 335.4 261.4 C335.4 262.77 333.11 262.23 331.73 262.23 C330.36 262.23 330.73 263.11 330.73 261.73 C330.73 260.36 331.36 258.4 332.73 258.4 zM324.4 263.73 C325.77 263.73 325.07 265.36 325.07 266.73 C325.07 268.11 320.11 271.23 318.73 271.23 C317.36 271.23 317.73 272.11 317.73 270.73 C317.73 269.36 323.02 263.73 324.4 263.73 zM325.23 247.73 C326.61 247.73 326.23 247.86 326.23 249.23 C326.23 250.61 326.11 249.73 324.73 249.73 C323.36 249.73 323.73 250.61 323.73 249.23 C323.73 247.86 323.86 247.73 325.23 247.73 zM313.23 256.23 C314.61 256.23 319.07 258.02 319.07 259.4 C319.07 260.77 313.44 263.07 312.07 263.07 C310.69 263.07 309.73 260.77 309.73 259.4 C309.73 258.02 311.86 256.23 313.23 256.23 zM300.23 260.73 C301.61 260.73 301.23 260.86 301.23 262.23 C301.23 263.61 301.11 262.73 299.73 262.73 C298.36 262.73 298.73 263.61 298.73 262.23 C298.73 260.86 298.86 260.73 300.23 260.73 zM308.23 272.73 C309.61 272.73 309.23 272.86 309.23 274.23 C309.23 275.61 309.11 274.73 307.73 274.73 C306.36 274.73 306.73 275.61 306.73 274.23 C306.73 272.86 306.86 272.73 308.23 272.73 zM305.23 273.73 C306.61 273.73 306.23 273.86 306.23 275.23 C306.23 276.61 306.11 275.73 304.73 275.73 C303.36 275.73 303.73 276.61 303.73 275.23 C303.73 273.86 303.86 273.73 305.23 273.73 zM293.73 274.07 C294.65 274.07 295.73 275.48 295.73 276.4 C295.73 277.32 295.65 276.73 294.73 276.73 C293.82 276.73 291.4 277.98 291.4 277.07 C291.4 276.15 292.82 274.07 293.73 274.07 zM296.73 276.73 C297.65 276.73 297.4 276.82 297.4 277.73 C297.4 278.65 297.32 278.07 296.4 278.07 C295.48 278.07 295.73 278.65 295.73 277.73 C295.73 276.82 295.82 276.73 296.73 276.73 zM291.4 263.73 C292.32 263.73 293.73 267.15 293.73 268.07 C293.73 268.98 290.65 268.73 289.73 268.73 C288.82 268.73 287.4 265.98 287.4 265.07 C287.4 264.15 290.48 263.73 291.4 263.73 zM280.07 274.73 C281.44 274.73 281.23 274.86 281.23 276.23 C281.23 277.61 280.94 276.73 279.57 276.73 C278.19 276.73 278.73 277.61 278.73 276.23 C278.73 274.86 278.69 274.73 280.07 274.73 zM277.07 267.73 C278.44 267.73 276.4 271.02 276.4 272.4 C276.4 273.77 271.94 274.23 270.57 274.23 C269.19 274.23 271.73 272.44 271.73 271.07 C271.73 269.69 275.69 267.73 277.07 267.73 zM52.23 84.9 C56.7 85.46 60.73 85.9 61.73 80.4 C62.73 74.9 60.23 72.9 52.73 74.9 C45.23 76.9 40.23 83.4 52.23 84.9 zM88.73 88.4 C88.73 88.4 107.45 92.81 90.23 79.9 C82.23 73.9 81.73 78.9 81.23 81.9 C80.49 86.37 88.73 88.4 88.73 88.4 zM31.73 47.9 C40.08 46.23 39.73 41.4 30.73 39.4 C29.27 39.07 26.73 48.9 31.73 47.9 zM26.73 47.9 C24.23 47.4 20.23 48.4 19.73 51.9 C19.23 55.4 23.23 57.4 25.73 55.4 C28.23 53.4 29.23 48.4 26.73 47.9 zM32.73 58.9 C30.23 57.9 22.73 59.4 23.23 62.4 C23.73 65.4 29.73 65.9 32.23 64.4 C34.73 62.9 35.23 59.9 32.73 58.9 zM31.73 76.4 C28.73 73.9 25.23 76.4 24.23 77.9 C23.23 79.4 28.23 81.4 29.73 81.9 C31.23 82.4 34.73 78.9 31.73 76.4 zM20.23 39.4 C20.23 39.4 16.23 39.4 17.23 40.9 C18.23 42.4 21.23 42.4 21.23 42.4 zM14.23 48.4 C14.23 48.4 10.23 48.4 11.23 49.9 C12.23 51.4 15.23 51.4 15.23 51.4 zM46.73 96.4 C46.73 96.4 41.73 98.4 42.73 99.9 C43.73 101.4 45.23 103.9 48.73 100.4 C52.23 96.9 46.73 96.4 46.73 96.4 zM60.23 115.9 C57.23 113.4 53.73 115.9 52.73 117.4 C51.73 118.9 56.73 120.9 58.23 121.4 C59.73 121.9 63.23 118.4 60.23 115.9 zM58.23 105.9 C55.23 103.4 52.73 106.9 51.73 108.4 C50.73 109.9 54.73 110.9 56.23 111.4 C57.73 111.9 61.23 108.4 58.23 105.9 zM75.23 72.4 C78.8 72.6 84.73 70.9 75.73 64.9 C67.41 59.35 67.73 60.9 67.23 63.9 C66.49 68.37 71.66 72.2 75.23 72.4 zM105.73 81.4 C105.73 81.4 109.23 78.4 102.23 72.4 C94.64 65.89 95.73 68.4 95.23 71.4 C94.49 75.87 105.73 81.4 105.73 81.4 zM74.73 54.9 C74.73 54.9 68.73 53.9 69.73 55.4 C70.73 56.9 73.23 62.4 76.73 58.9 C80.23 55.4 74.73 54.9 74.73 54.9 zM41.23 85.4 C39.86 85.4 38.73 86.53 38.73 87.9 C38.73 89.28 39.86 90.4 41.23 90.4 C42.61 90.4 43.73 89.28 43.73 87.9 C43.73 86.53 42.61 85.4 41.23 85.4 zM46.23 109.9 C44.86 109.9 43.73 111.03 43.73 112.4 C43.73 113.78 44.86 114.9 46.23 114.9 C47.61 114.9 48.73 113.78 48.73 112.4 C48.73 111.03 47.61 109.9 46.23 109.9 zM50.23 119.9 C48.86 119.9 47.73 121.03 47.73 122.4 C47.73 123.78 48.86 124.9 50.23 124.9 C51.61 124.9 52.73 123.78 52.73 122.4 C52.73 121.03 51.61 119.9 50.23 119.9 zM66.23 126.4 C64.86 126.4 63.73 127.53 63.73 128.9 C63.73 130.28 64.86 131.4 66.23 131.4 C67.61 131.4 68.73 130.28 68.73 128.9 C68.73 127.53 67.61 126.4 66.23 126.4 zM57.73 127.9 C56.36 127.9 53.73 130.03 53.73 131.4 C53.73 132.78 56.36 132.9 57.73 132.9 C59.11 132.9 60.23 131.78 60.23 130.4 C60.23 129.03 59.11 127.9 57.73 127.9 zM33.73 88.9 C32.36 88.9 31.23 90.03 31.23 91.4 C31.23 92.78 32.36 93.9 33.73 93.9 C35.11 93.9 36.23 92.78 36.23 91.4 C36.23 90.03 35.11 88.9 33.73 88.9 zM20.23 65.4 C18.86 65.4 17.73 66.53 17.73 67.9 C17.73 69.28 18.86 70.4 20.23 70.4 C21.61 70.4 22.73 69.28 22.73 67.9 C22.73 66.53 21.61 65.4 20.23 65.4 zM115.23 73.4 C112.91 74.33 101.73 66.9 105.23 65.9 C108.73 64.9 117.73 72.4 115.23 73.4 zM96.23 60.4 C93.73 60.9 86.23 57.9 89.73 56.9 C93.23 55.9 98.87 59.87 96.23 60.4 zM144.23 90.9 C138.73 87.9 123.23 80.4 130.73 81.4 C138.23 82.4 148.96 93.48 144.23 90.9 zM51.73 41.4 C49.23 41.9 41.73 38.9 45.23 37.9 C48.73 36.9 54.37 40.87 51.73 41.4 zM123.73 77.9 C121.23 78.4 116.23 75.9 119.73 74.9 C123.23 73.9 126.37 77.37 123.73 77.9 zM60.73 140.4 C59.36 140.4 58.23 142.03 58.23 143.4 C58.23 144.78 58.86 144.9 60.23 144.9 C61.61 144.9 62.73 143.78 62.73 142.4 C62.73 141.03 62.11 140.4 60.73 140.4 zM68.23 139.9 C66.86 139.9 64.73 140.53 64.73 141.9 C64.73 143.28 67.36 142.9 68.73 142.9 C70.11 142.9 71.23 141.78 71.23 140.4 C71.23 139.03 69.61 139.9 68.23 139.9 zM66.23 154.4 C64.86 154.4 62.23 156.53 62.23 157.9 C62.23 159.28 64.86 159.4 66.23 159.4 C67.61 159.4 68.73 158.28 68.73 156.9 C68.73 155.53 67.61 154.4 66.23 154.4 zM78.23 174.9 C74.23 173.9 74.23 175.9 73.23 179.4 C72.23 182.9 65.17 194.28 76.73 180.4 C79.23 177.4 82.23 175.9 78.23 174.9 zM66.23 186.9 C64.86 186.9 63.73 188.02 63.73 189.4 C63.73 190.77 64.86 191.9 66.23 191.9 C67.61 191.9 68.73 190.77 68.73 189.4 C68.73 188.02 67.61 186.9 66.23 186.9 zM63.73 195.9 C62.36 195.9 61.23 197.02 61.23 198.4 C61.23 199.77 62.36 200.9 63.73 200.9 C65.11 200.9 66.23 199.77 66.23 198.4 C66.23 197.02 65.11 195.9 63.73 195.9 zM63.57 204.9 C62.19 204.9 60.23 208.02 60.23 209.4 C60.23 210.77 61.36 211.9 62.73 211.9 C64.11 211.9 66.9 210.27 66.9 208.9 C66.9 207.52 64.94 204.9 63.57 204.9 zM62.23 220.9 C60.86 220.9 61.23 221.02 61.23 222.4 C61.23 223.77 61.36 222.9 62.73 222.9 C64.11 222.9 63.73 223.77 63.73 222.4 C63.73 221.02 63.61 220.9 62.23 220.9 zM75.73 187.9 C74.36 187.9 74.73 188.02 74.73 189.4 C74.73 190.77 74.86 189.9 76.23 189.9 C77.61 189.9 77.23 190.77 77.23 189.4 C77.23 188.02 77.11 187.9 75.73 187.9 zM72.73 200.4 C71.36 200.4 71.73 200.52 71.73 201.9 C71.73 203.27 71.53 206.9 72.9 206.9 C74.28 206.9 74.23 203.27 74.23 201.9 C74.23 200.52 74.11 200.4 72.73 200.4 zM69.23 214.4 C67.86 214.4 68.23 214.52 68.23 215.9 C68.23 217.27 68.36 216.4 69.73 216.4 C71.11 216.4 70.73 217.27 70.73 215.9 C70.73 214.52 70.61 214.4 69.23 214.4 zM75.4 227.9 C74.03 227.9 74.23 228.02 74.23 229.4 C74.23 230.77 74.53 229.9 75.9 229.9 C77.28 229.9 76.73 230.77 76.73 229.4 C76.73 228.02 76.78 227.9 75.4 227.9 zM66.57 231.23 C65.19 231.23 63.9 233.19 63.9 234.57 C63.9 235.94 66.86 238.4 68.23 238.4 C69.61 238.4 69.23 239.27 69.23 237.9 C69.23 236.52 67.94 231.23 66.57 231.23 zM72.23 245.57 C70.86 245.57 68.57 245.19 68.57 246.57 C68.57 247.94 71.86 250.4 73.23 250.4 C74.61 250.4 74.23 251.27 74.23 249.9 C74.23 248.52 73.61 245.57 72.23 245.57 zM80.73 238.4 C79.36 238.4 79.73 238.52 79.73 239.9 C79.73 241.27 79.86 240.4 81.23 240.4 C82.61 240.4 82.23 241.27 82.23 239.9 C82.23 238.52 82.11 238.4 80.73 238.4 zM83.23 257.57 C81.86 257.57 80.57 259.19 80.57 260.57 C80.57 261.94 82.86 261.4 84.23 261.4 C85.61 261.4 85.23 262.27 85.23 260.9 C85.23 259.52 84.61 257.57 83.23 257.57 zM91.57 262.9 C90.19 262.9 90.9 264.52 90.9 265.9 C90.9 267.27 95.86 270.4 97.23 270.4 C98.61 270.4 98.23 271.27 98.23 269.9 C98.23 268.52 92.94 262.9 91.57 262.9 zM90.73 246.9 C89.36 246.9 89.73 247.02 89.73 248.4 C89.73 249.77 89.86 248.9 91.23 248.9 C92.61 248.9 92.23 249.77 92.23 248.4 C92.23 247.02 92.11 246.9 90.73 246.9 zM102.73 255.4 C101.36 255.4 96.9 257.19 96.9 258.57 C96.9 259.94 102.53 262.23 103.9 262.23 C105.28 262.23 106.23 259.94 106.23 258.57 C106.23 257.19 104.11 255.4 102.73 255.4 zM115.73 259.9 C114.36 259.9 114.73 260.02 114.73 261.4 C114.73 262.77 114.86 261.9 116.23 261.9 C117.61 261.9 117.23 262.77 117.23 261.4 C117.23 260.02 117.11 259.9 115.73 259.9 zM107.73 271.9 C106.36 271.9 106.73 272.02 106.73 273.4 C106.73 274.77 106.86 273.9 108.23 273.9 C109.61 273.9 109.23 274.77 109.23 273.4 C109.23 272.02 109.11 271.9 107.73 271.9 zM110.73 272.9 C109.36 272.9 109.73 273.02 109.73 274.4 C109.73 275.77 109.86 274.9 111.23 274.9 C112.61 274.9 112.23 275.77 112.23 274.4 C112.23 273.02 112.11 272.9 110.73 272.9 zM122.23 273.23 C121.32 273.23 120.23 274.65 120.23 275.57 C120.23 276.48 120.32 275.9 121.23 275.9 C122.15 275.9 124.57 277.15 124.57 276.23 C124.57 275.32 123.15 273.23 122.23 273.23 zM119.23 275.9 C118.32 275.9 118.57 275.98 118.57 276.9 C118.57 277.82 118.65 277.23 119.57 277.23 C120.48 277.23 120.23 277.82 120.23 276.9 C120.23 275.98 120.15 275.9 119.23 275.9 zM124.57 262.9 C123.65 262.9 122.23 266.32 122.23 267.23 C122.23 268.15 125.32 267.9 126.23 267.9 C127.15 267.9 128.57 265.15 128.57 264.23 C128.57 263.32 125.48 262.9 124.57 262.9 zM135.9 273.9 C134.53 273.9 134.73 274.02 134.73 275.4 C134.73 276.77 135.03 275.9 136.4 275.9 C137.78 275.9 137.23 276.77 137.23 275.4 C137.23 274.02 137.28 273.9 135.9 273.9 zM138.9 266.9 C137.53 266.9 139.57 270.19 139.57 271.57 C139.57 272.94 144.03 273.4 145.4 273.4 C146.78 273.4 144.23 271.61 144.23 270.23 C144.23 268.86 140.28 266.9 138.9 266.9 zM211 134.8 C209.63 134.8 209.83 134.93 209.83 136.3 C209.83 137.68 210.13 136.8 211.5 136.8 C212.88 136.8 212.33 137.68 212.33 136.3 C212.33 134.93 212.38 134.8 211 134.8 zM205.5 134.8 C204.13 134.8 204.33 134.93 204.33 136.3 C204.33 137.68 204.63 136.8 206 136.8 C207.38 136.8 206.83 137.68 206.83 136.3 C206.83 134.93 206.88 134.8 205.5 134.8 zM211 143.8 C209.63 143.8 209.83 143.93 209.83 145.3 C209.83 146.68 210.13 145.8 211.5 145.8 C212.88 145.8 212.33 146.68 212.33 145.3 C212.33 143.93 212.38 143.8 211 143.8 zM204.9 143.7 C203.53 143.7 203.73 143.83 203.73 145.2 C203.73 146.58 204.03 145.7 205.4 145.7 C206.78 145.7 206.23 146.58 206.23 145.2 C206.23 143.83 206.28 143.7 204.9 143.7 zM213 154.3 C211.63 154.3 212 155.43 212 156.8 C212 158.18 212.42 161.3 213.8 161.3 C215.17 161.3 214.33 157.18 214.33 155.8 C214.33 154.43 214.38 154.3 213 154.3 zM204 154.3 C202.63 154.3 202.6 155.53 202.6 156.9 C202.6 158.28 201.63 161.5 203 161.5 C204.38 161.5 204.8 157.68 204.8 156.3 C204.8 154.93 205.38 154.3 204 154.3 z").setFill("rgb(255,246,227)");
+	//surface.createLine({x1: 0, y1: 350, x2: 700, y2: 350}).setStroke("green");
+	//surface.createLine({y1: 0, x1: 350, y2: 700, x2: 350}).setStroke("green");
+    //dojo.event.connect(dojo.widget.byId("rotatingSlider"), "onValueChanged", rotatingEvent);
+    //dojo.event.connect(dojo.widget.byId("scalingSlider"), "onValueChanged", scalingEvent);
+    //dojo.byId("sliders").style.visibility = "visible";
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+<style type="text/css">
+td.pad { padding: 0px 5px 0px 5px; }
+</style>
+</head>
+<body>
+	<h1>dojox.gfx: Butterfly</h1>
+	<p>This example was directly converted from SVG file.</p>
+	<p>This is a slightly modified version of a sample that shipped with JASC's WebDraw (www.jasc.com). Generated by Jasc WebDraw PR4(tm) on 06/07/01 12:18:39.</p>
+	<!--
+	<table id="sliders" style="visibility: hidden;">
+		<tr>
+			<td align="center" class="pad">Rotation (<span id="rotationValue">0</span>)</td>
+			<td align="center" class="pad">Scaling (<span id="scaleValue">1.000</span>)</td>
+		</tr>
+		<tr>
+			<td class="pad">
+				<div id="rotatingSlider" dojoType="SliderHorizontal" 
+					initialValue="0" minimum="-180" maximum="180" snapValues="73"
+					activeDrag="true"
+					buttonStyle="top: 1px;"
+					backgroundStyle="padding: 8px 4px; border: 1px solid black;"
+					backgroundSize="width:100px; height:5px;"
+					backgroundSrc="src/widget/templates/images/blank.gif"
+					progressBackgroundSrc="src/widget/templates/images/slider-bg.gif"
+					handleStyle="top: 0px; width: 13px; height: 18px;"
+					handleSrc="src/widget/templates/images/slider.gif">
+				</div>
+			</td>
+			<td class="pad">
+				<div id="scalingSlider" dojoType="SliderHorizontal" 
+					initialValue="1" minimum="0" maximum="1" snapValues="10"
+					activeDrag="true"
+					buttonStyle="top: 1px;"
+					backgroundStyle="padding: 8px 4px; border: 1px solid black;"
+					backgroundSize="width:100px; height:5px;"
+					backgroundSrc="src/widget/templates/images/blank.gif"
+					progressBackgroundSrc="src/widget/templates/images/slider-bg.gif"
+					handleStyle="top: 0px; width: 13px; height: 18px;"
+					handleSrc="src/widget/templates/images/slider.gif">
+				</div>
+			</td>
+		</tr>
+	</table>
+	-->
+	<div id="gfx_holder" style="width: 700px; height: 700px;"></div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/circles.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/circles.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/circles.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,149 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
+<head>
+<title>dojox.gfx: 100 draggable circles</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx");
+
+var container = null;
+var container_position = null;
+var surface = null;
+var surface_size = null;
+
+function getRand(from, to)
+{
+	return Math.random() * (to - from) + from;
+}
+
+var skew_stat_factor = 15;
+
+function getRandSkewed(from, to)
+{
+	// let skew stats to smaller values
+	var seed = 0;
+	for(var i = 0; i < skew_stat_factor; ++i){
+		seed += Math.random();
+	}
+	seed = 2 * Math.abs(seed / skew_stat_factor - 0.5);
+	return seed * (to - from) + from;
+}
+
+function randColor(alpha)
+{
+	var red   = Math.floor(getRand(0, 255));
+	var green = Math.floor(getRand(0, 255));
+	var blue  = Math.floor(getRand(0, 255));
+	var opacity = 1;
+	if (alpha) {
+		opacity = getRand(0.1, 1);
+	}
+	return [red, green, blue, opacity];
+}
+
+var gShapes = {}
+var gShapeCounter = 0;
+
+function makeCircleGrid(itemCount)
+{
+	var minR = 10, maxR = surface_size.width / 3;
+	for (var j = 0; j < itemCount; ++j) {
+		var r = getRandSkewed(minR, maxR);
+		var cx = getRand(r, surface_size.width  - r);
+		var cy = getRand(r, surface_size.height - r);
+		var id = "shape_" + (gShapeCounter++);
+		var aShape = surface.createCircle({cx: cx, cy: cy, r: r})
+			.setFill(randColor(true))
+			.setStroke({color: randColor(1), width: getRand(3)})
+			;
+		aShape.getEventSource().setAttribute('shapeid', id);
+		dojox.gfx._addClass(aShape.getEventSource(), "movable");
+		gShapes[id] = aShape;
+	}
+}
+
+var current_shape = null;
+var current_shape_window = null;
+var last_position = null;
+
+function getShape(event)
+{
+	var id = event.target.getAttribute('shapeid');
+	var s  = id ? gShapes[id] : null;
+	return s;
+}
+
+function handleMouseDown(event)
+{
+	var shape = getShape(event);
+	if (shape) {
+		current_shape = shape;
+		last_position = {
+			x: event.clientX - container_position.x,
+			y: event.clientY - container_position.y
+		};
+		var params = shape.getShape();
+		var center = dojox.gfx.matrix.multiplyPoint(shape.getTransform(), params.cx, params.cy);
+		var dx = last_position.x - center.x;
+		var dy = last_position.y - center.y;
+		var r  = params.r;
+		current_shape_window = {
+			x1: r + dx,
+			y1: r + dy,
+			x2: surface_size.width  - r + dx,
+			y2: surface_size.height - r + dy
+		};
+	}
+	dojo.stopEvent(event);
+}
+
+function handleMouseMove(event)
+{
+	if(!current_shape) return;
+	var x = Math.min(Math.max(event.clientX - container_position.x, current_shape_window.x1), current_shape_window.x2);
+	var y = Math.min(Math.max(event.clientY - container_position.y, current_shape_window.y1), current_shape_window.y2);
+	current_shape.applyTransform({dx: x - last_position.x, dy: y - last_position.y});
+	last_position = {x: x, y: y};
+	dojo.stopEvent(event);
+}
+
+function handleMouseUp(event)
+{
+	current_shape = null;
+	dojo.stopEvent(event);
+}
+
+function initGfx() {
+	container = dojo.byId("gfx_holder");
+	container_position = dojo.coords(container, true);
+	surface = dojox.gfx.createSurface(container, 500, 500);
+	surface_size = surface.getDimensions();
+	surface_size.width  = parseInt(surface_size.width);
+	surface_size.height = parseInt(surface_size.height);
+
+	makeCircleGrid(100);
+
+	dojo.connect(container, 'onmousedown', handleMouseDown);
+	dojo.connect(container, 'onmousemove', handleMouseMove);
+	dojo.connect(container, 'onmouseup',   handleMouseUp);
+	
+	// cancel text selection and text dragging
+	dojo.connect(container, "ondragstart",   dojo, "stopEvent");
+	dojo.connect(container, "onselectstart", dojo, "stopEvent");
+}
+
+dojo.addOnLoad(initGfx);
+
+</script>
+
+<style type="text/css">
+.movable { cursor: pointer; }
+</style>
+
+</head>
+<body>
+	<h1>dojox.gfx: 100 draggable circles</h1>
+	<div id="gfx_holder" style="width: 500px; height: 500px;"></div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/clock.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/clock.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/clock.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,241 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
+<head>
+<title>dojox.gfx: interactive analog clock</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx");
+dojo.require("dojo.date.locale");
+
+var current_time = new Date();
+
+var hour_hand   = null;
+var minute_hand = null;
+var second_hand = null;
+
+var hour_shadow   = null;
+var minute_shadow = null;
+var second_shadow = null;
+
+var center = {x: 385 / 2, y: 385 / 2};
+
+var hour_shadow_shift   = {dx: 2, dy: 2};
+var minute_shadow_shift = {dx: 3, dy: 3};
+var second_shadow_shift = {dx: 4, dy: 4};
+
+var selected_hand = null;
+var container = null;
+var container_position = null;
+var text_time = null;
+var diff_time = new Date();
+
+placeHand = function(shape, angle, shift) {
+	var move = {dx: center.x + (shift ? shift.dx : 0), dy: center.y + (shift ? shift.dy : 0)};
+	return shape.setTransform([move, dojox.gfx.matrix.rotateg(-angle)]);
+};
+
+placeHourHand = function(h, m, s) {
+	var angle = 30 * (h % 12 + m / 60 + s / 3600);
+	placeHand(hour_hand, angle);
+	placeHand(hour_shadow, angle, hour_shadow_shift);
+};
+
+placeMinuteHand = function(m, s) {
+	var angle = 6 * (m + s / 60);
+	placeHand(minute_hand, angle);
+	placeHand(minute_shadow, angle, minute_shadow_shift);
+};
+
+placeSecondHand = function(s) {
+	var angle = 6 * s;
+	placeHand(second_hand, angle);
+	placeHand(second_shadow, angle, second_shadow_shift);
+};
+
+reflectTime = function(time, hold_second_hand, hold_minute_hand, hold_hour_hand) {
+	if(!time) time = current_time;
+	var h = time.getHours();
+	var m = time.getMinutes();
+	var s = time.getSeconds();
+	if(!hold_hour_hand) placeHourHand(h, m, s);
+	if(!hold_minute_hand) placeMinuteHand(m, s);
+	if(!hold_second_hand) placeSecondHand(s);
+	text_time.innerHTML = dojo.date.locale.format(
+		time, {selector: "time", timePattern: "h:mm:ss a"});
+};
+
+resetTime = function() {
+	current_time = new Date();
+	reflectTime();
+};
+
+tick = function() {
+	current_time.setSeconds(current_time.getSeconds() + 1);
+	reflectTime();
+};
+
+advanceTime = function() {
+	if(!selected_hand) {
+		tick();
+	}
+};
+
+normalizeAngle = function(angle) {
+	if(angle > Math.PI) {
+		angle -= 2 * Math.PI;
+	} else if(angle < -Math.PI) {
+		angle += 2 * Math.PI;
+	}
+	return angle;
+};
+
+calculateAngle = function(x, y, handAngle) {
+	try {
+		return normalizeAngle(Math.atan2(y - center.y, x - center.x) - handAngle);
+	} catch(e) {
+		// supress
+	}
+	return 0;
+};
+
+getSecondAngle = function(time) {
+	if(!time) time = current_time;
+	return (6 * time.getSeconds() - 90) / 180 * Math.PI;
+};
+
+getMinuteAngle = function(time) {
+	if(!time) time = current_time;
+	return (6 * (time.getMinutes() + time.getSeconds() / 60) - 90) / 180 * Math.PI;
+};
+
+getHourAngle = function(time) {
+	if(!time) time = current_time;
+	return (30 * (time.getHours() + (time.getMinutes() + time.getSeconds() / 60) / 60) - 90) / 180 * Math.PI;
+};
+
+onMouseDown = function(event) {
+	selected_hand = event.target;
+	diff_time.setTime(current_time.getTime());
+	dojo.stopEvent(event);
+};
+
+onMouseMove = function(event) {
+	if(!selected_hand) return;
+	if(event.target == second_hand.getEventSource() || 
+			event.target == minute_hand.getEventSource() || 
+			event.target == hour_hand.getEventSource()) {
+		dojo.stopEvent(event);
+		return;
+	}
+	if(selected_hand == second_hand.getEventSource() ) {
+		var angle = calculateAngle(
+			event.clientX - container_position.x, 
+			event.clientY - container_position.y, 
+			normalizeAngle(getSecondAngle())
+		);
+		var diff = Math.round(angle / Math.PI * 180 / 6); // in whole seconds
+		current_time.setSeconds(current_time.getSeconds() + Math.round(diff));
+		reflectTime();
+	} else if(selected_hand == minute_hand.getEventSource() ) {
+		var angle = calculateAngle(
+			event.clientX - container_position.x, 
+			event.clientY - container_position.y, 
+			normalizeAngle(getMinuteAngle(diff_time))
+		);
+		var diff = Math.round(angle / Math.PI * 180 / 6 * 60); // in whole seconds
+		diff_time.setTime(diff_time.getTime() + 1000 * diff);
+		reflectTime(diff_time, true);
+		
+	} else if(selected_hand == hour_hand.getEventSource() ) {
+		var angle = calculateAngle(
+			event.clientX - container_position.x, 
+			event.clientY - container_position.y, 
+			normalizeAngle(getHourAngle(diff_time))
+		);
+		var diff = Math.round(angle / Math.PI * 180 / 30 * 60 * 60); // in whole seconds
+		diff_time.setTime(diff_time.getTime() + 1000 * diff);
+		reflectTime(diff_time, true, true);
+	} else {
+		return;
+	}
+	dojo.stopEvent(event);
+};
+
+onMouseUp = function(event) {
+	if(selected_hand != second_hand.getEventSource()) {
+		current_time.setTime(diff_time.getTime());
+		reflectTime();
+	}
+	selected_hand = null;
+	dojo.stopEvent(event);
+};
+
+makeShapes = function(){
+	// prerequisites
+	container = dojo.byId("gfx_holder");
+	container_position = dojo.coords(container, true);
+	text_time = dojo.byId("time");
+	var surface = dojox.gfx.createSurface(container, 385, 385);
+    surface.createImage({width: 385, height: 385, src: "images/clock_face.jpg"});
+    
+    // hand shapes
+    var hour_hand_points = [{x: -7, y: 15}, {x: 7, y: 15}, {x: 0, y: -60}, {x: -7, y: 15}];
+    var minute_hand_points = [{x: -5, y: 15}, {x: 5, y: 15}, {x: 0, y: -100}, {x: -5, y: 15}];
+    var second_hand_points = [{x: -2, y: 15}, {x: 2, y: 15}, {x: 2, y: -105}, {x: 6, y: -105}, {x: 0, y: -116}, {x: -6, y: -105}, {x: -2, y: -105}, {x: -2, y: 15}];
+    
+    // create shapes
+    hour_shadow = surface.createPolyline(hour_hand_points)
+		.setFill([0, 0, 0, 0.1])
+		;
+    hour_hand = surface.createPolyline(hour_hand_points)
+		.setStroke({color: "black", width: 2})
+		.setFill("#889")
+		;
+    minute_shadow = surface.createPolyline(minute_hand_points)
+		.setFill([0, 0, 0, 0.1])
+		;
+    minute_hand = surface.createPolyline(minute_hand_points)
+		.setStroke({color: "black", width: 2})
+		.setFill("#ccd")
+		;
+    second_shadow = surface.createPolyline(second_hand_points)
+		.setFill([0, 0, 0, 0.1])
+		;
+    second_hand = surface.createPolyline(second_hand_points)
+		.setStroke({color: "#800", width: 1})
+		.setFill("#d00")
+		;
+	dojox.gfx._addClass(hour_hand  .getEventSource(), "movable");
+	dojox.gfx._addClass(minute_hand.getEventSource(), "movable");
+	dojox.gfx._addClass(second_hand.getEventSource(), "movable");
+	surface.createCircle({r: 1}).setFill("black").setTransform({dx: 192.5, dy: 192.5});
+	
+	// attach events
+	dojo.connect(hour_hand  .getEventSource(), "onmousedown", onMouseDown);
+	dojo.connect(minute_hand.getEventSource(), "onmousedown", onMouseDown);
+	dojo.connect(second_hand.getEventSource(), "onmousedown", onMouseDown);
+	dojo.connect(container, "onmousemove", onMouseMove);
+	dojo.connect(container, "onmouseup",   onMouseUp);
+	dojo.connect(dojo.byId("reset"), "onclick", resetTime);
+
+	// start the clock		
+	resetTime();
+	window.setInterval(advanceTime, 1000);
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+<style type="text/css">
+.movable { cursor: hand; }
+</style>
+</head>
+<body>
+	<h1>dojox.gfx: interactive analog clock</h1>
+	<p>Grab hands and set your own time.</p>
+	<div id="gfx_holder" style="width: 385px; height: 385px;"></div>
+	<p>Current time: <span id="time"></span>.</p>
+	<p><button id="reset">Reset</button></p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/images/clock_face.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/images/clock_face.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/lion.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/lion.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/lion.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,234 @@
+<html>
+<head>
+<title>dojox.gfx: Lion</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx");
+
+// no sliders yet
+
+//dojo.require ("dojo.widget.*");
+//dojo.require ("dojo.widget.Slider");
+
+var rotation = 0, scaling = 1;
+var surface, g, m = dojox.gfx.matrix;
+var initial_matrix = m.normalize([m.rotateg(-10), m.translate(300, 100)]);
+
+var updateMatrix = function(){
+	if(g){ g.setTransform([m.rotategAt(rotation, 350, 350), m.scaleAt(scaling, 350, 350), initial_matrix]); }
+};
+
+var rotatingEvent = function(value){
+	rotation = value;
+	dojo.byId("rotationValue").innerHTML = rotation;
+	updateMatrix();
+};
+
+var scalingEvent = function(value){
+	scaling = Math.exp(Math.LN10 * (value - 1));
+	dojo.byId("scaleValue").innerHTML = scaling.toFixed(3);
+	updateMatrix();
+};
+
+makeShapes = function(){
+	surface = dojox.gfx.createSurface(dojo.byId("gfx_holder"), 700, 700);
+	surface.createRect({x: 0, y: 0, width: 700, height: 700}).setFill("#eee");
+	g = surface.createGroup().setTransform(initial_matrix);
+	g.createPolyline([69,18,82,8,99,3,118,5,135,12,149,21,156,13,165,9,177,13,183,28,180,50,164,91,155,107,154,114,151,121,141,127,139,136,155,206,157,251,126,342,133,357,128,376,83,376,75,368,67,350,61,350,53,369,4,369,2,361,5,354,12,342,16,321,4,257,4,244,7,218,9,179,26,127,43,93,32,77,30,70,24,67,16,49,17,35,18,23,30,12,40,7,53,7,62,12]).setFill("#f2cc99");
+	g.createPolyline([142,79,136,74,138,82,133,78,133,84,127,78,128,85,124,80,125,87,119,82,119,90,125,99,125,96,128,100,128,94,131,98,132,93,135,97,136,93,138,97,139,94,141,98,143,94,144,85]).setFill("#e5b27f");
+	g.createPolyline([127,101,132,100,137,99,144,101,143,105,135,110]).setFill("#eb8080");
+	g.createPolyline([178,229,157,248,139,296,126,349,137,356,158,357,183,342,212,332,235,288,235,261,228,252,212,250,188,251]).setFill("#f2cc99");
+	var c = new dojo.Color("#9c826b");
+	g.createPolyline([56,229,48,241,48,250,57,281,63,325,71,338,81,315,76,321,79,311,83,301,75,308,80,298,73,303,76,296,71,298,74,292,69,293,74,284,78,278,71,278,74,274,68,273,70,268,66,267,68,261,60,266,62,259,65,253,57,258,59,251,55,254,55,248,60,237,54,240,58,234,54,236]).setFill(c);
+	g.createPolyline([74,363,79,368,81,368,85,362,89,363,92,370,96,373,101,372,108,361,110,371,113,373,116,371,120,358,122,363,123,371,126,371,129,367,132,357,135,361,130,376,127,377,94,378,84,376,76,371]).setFill(c);
+	g.createPolyline([212,250,219,251,228,258,236,270,235,287,225,304,205,332,177,343,171,352,158,357,166,352,168,346,168,339,165,333,155,327,155,323,161,320,165,316,169,316,167,312,171,313,168,308,173,309,170,306,177,306,175,308,177,311,174,311,176,316,171,315,174,319,168,320,168,323,175,327,179,332,183,326,184,332,189,323,190,328,194,320,194,325,199,316,201,320,204,313,206,316,208,310,211,305,219,298,226,288,229,279,228,266,224,259,217,253]).setFill(c);
+	g.createPolyline([151,205,151,238,149,252,141,268,128,282,121,301,130,300,126,313,118,324,116,337,120,346,133,352,133,340,137,333,145,329,156,327,153,319,153,291,157,271,170,259,178,277,193,250,174,216]).setFill(c);
+	g.createPolyline([78,127,90,142,95,155,108,164,125,167,139,175,150,206,152,191,141,140,121,148,100,136]).setFill(c);
+	g.createPolyline([21,58,35,63,38,68,32,69,42,74,40,79,47,80,54,83,45,94,34,81,32,73,24,66]).setFill(c);
+	g.createPolyline([71,34,67,34,66,27,59,24,54,17,48,17,39,22,30,26,28,31,31,39,38,46,29,45,36,54,41,61,41,70,50,69,54,71,55,58,67,52,76,43,76,39,68,44]).setFill(c);
+	g.createPolyline([139,74,141,83,143,89,144,104,148,104,155,106,154,86,157,77,155,72,150,77,144,77]).setFill(c);
+	g.createPolyline([105,44,102,53,108,58,111,62,112,55]).setFill(c);
+	g.createPolyline([141,48,141,54,144,58,139,62,137,66,136,59,137,52]).setFill(c);
+	g.createPolyline([98,135,104,130,105,134,108,132,108,135,112,134,113,137,116,136,116,139,119,139,124,141,128,140,133,138,140,133,139,140,126,146,104,144]).setFill(c);
+	g.createPolyline([97,116,103,119,103,116,111,118,116,117,122,114,127,107,135,111,142,107,141,114,145,118,149,121,145,125,140,124,127,121,113,125,100,124]).setFill(c);
+	g.createPolyline([147,33,152,35,157,34,153,31,160,31,156,28,161,28,159,24,163,25,163,21,165,22,170,23,167,17,172,21,174,18,175,23,176,22,177,28,177,33,174,37,176,39,174,44,171,49,168,53,164,57,159,68,156,70,154,60,150,51,146,43,144,35]).setFill(c);
+	g.createPolyline([85,72,89,74,93,75,100,76,105,75,102,79,94,79,88,76]).setFill(c);
+	g.createPolyline([86,214,79,221,76,232,82,225,78,239,82,234,78,245,81,243,79,255,84,250,84,267,87,254,90,271,90,257,95,271,93,256,95,249,92,252,93,243,89,253,89,241,86,250,87,236,83,245,87,231,82,231,90,219,84,221]).setFill(c);
+	c = new dojo.Color("#ffcc7f");
+	g.createPolyline([93,68,96,72,100,73,106,72,108,66,105,63,100,62]).setFill(c);
+	g.createPolyline([144,64,142,68,142,73,146,74,150,73,154,64,149,62]).setFill(c);
+	c = new dojo.Color("#9c826b");
+	g.createPolyline([57,91,42,111,52,105,41,117,53,112,46,120,53,116,50,124,57,119,55,127,61,122,60,130,67,126,66,134,71,129,72,136,77,130,76,137,80,133,82,138,86,135,96,135,94,129,86,124,83,117,77,123,79,117,73,120,75,112,68,116,71,111,65,114,69,107,63,110,68,102,61,107,66,98,61,103,63,97,57,99]).setFill(c);
+	g.createPolyline([83,79,76,79,67,82,75,83,65,88,76,87,65,92,76,91,68,96,77,95,70,99,80,98,72,104,80,102,76,108,85,103,92,101,87,98,93,96,86,94,91,93,85,91,93,89,99,89,105,93,107,85,102,82,92,80]).setFill(c);
+	g.createPolyline([109,77,111,83,109,89,113,94,117,90,117,81,114,78]).setFill(c);
+	g.createPolyline([122,128,127,126,134,127,136,129,134,130,130,128,124,129]).setFill(c);
+	g.createPolyline([78,27,82,32,80,33,82,36,78,37,82,40,78,42,81,46,76,47,78,49,74,50,82,52,87,50,83,48,91,46,86,45,91,42,88,40,92,37,86,34,90,31,86,29,89,26]).setFill(c);
+	g.createPolyline([82,17,92,20,79,21,90,25,81,25,94,28,93,26,101,30,101,26,107,33,108,28,111,40,113,34,115,45,117,39,119,54,121,46,124,58,126,47,129,59,130,49,134,58,133,44,137,48,133,37,137,40,133,32,126,20,135,26,132,19,138,23,135,17,142,18,132,11,116,6,94,6,78,11,92,12,80,14,90,16]).setFill(c);
+	g.createPolyline([142,234,132,227,124,223,115,220,110,225,118,224,127,229,135,236,122,234,115,237,113,242,121,238,139,243,121,245,111,254,95,254,102,244,104,235,110,229,100,231,104,224,113,216,122,215,132,217,141,224,145,230,149,240]).setFill(c);
+	g.createPolyline([115,252,125,248,137,249,143,258,134,255,125,254]).setFill(c);
+	g.createPolyline([114,212,130,213,140,219,147,225,144,214,137,209,128,207]).setFill(c);
+	g.createPolyline([102,263,108,258,117,257,131,258,116,260,109,265]).setFill(c);
+	g.createPolyline([51,241,35,224,40,238,23,224,31,242,19,239,28,247,17,246,25,250,37,254,39,263,44,271,47,294,48,317,51,328,60,351,60,323,53,262,47,246]).setFill(c);
+	g.createPolyline([2,364,9,367,14,366,18,355,20,364,26,366,31,357,35,364,39,364,42,357,47,363,53,360,59,357,54,369,7,373]).setFill(c);
+	g.createPolyline([7,349,19,345,25,339,18,341,23,333,28,326,23,326,27,320,23,316,25,311,20,298,15,277,12,264,9,249,10,223,3,248,5,261,15,307,17,326,11,343]).setFill(c);
+	g.createPolyline([11,226,15,231,25,236,18,227]).setFill(c);
+	g.createPolyline([13,214,19,217,32,227,23,214,16,208,15,190,24,148,31,121,24,137,14,170,8,189]).setFill(c);
+	g.createPolyline([202,254,195,258,199,260,193,263,197,263,190,268,196,268,191,273,188,282,200,272,194,272,201,266,197,265,204,262,200,258,204,256]).setFill(c);
+	c = new dojo.Color("#845433");
+	g.createPolyline([151,213,165,212,179,225,189,246,187,262,179,275,176,263,177,247,171,233,163,230,165,251,157,264,146,298,145,321,133,326,143,285,154,260,153,240]).setFill(c);
+	g.createPolyline([91,132,95,145,97,154,104,148,107,155,109,150,111,158,115,152,118,159,120,153,125,161,126,155,133,164,132,154,137,163,137,152,142,163,147,186,152,192,148,167,141,143,124,145,105,143]).setFill(c);
+	c = new dojo.Color("#9c826b");
+	g.createPolyline([31,57,23,52,26,51,20,44,23,42,21,36,22,29,25,23,24,32,30,43,26,41,30,50,26,48]).setFill(c);
+	g.createPolyline([147,21,149,28,155,21,161,16,167,14,175,15,173,11,161,9]).setFill(c);
+	g.createPolyline([181,39,175,51,169,57,171,65,165,68,165,75,160,76,162,91,171,71,180,51]).setFill(c);
+	g.createPolyline([132,346,139,348,141,346,142,341,147,342,143,355,133,350]).setFill(c);
+	g.createPolyline([146,355,151,352,155,348,157,343,160,349,151,356,147,357]).setFill(c);
+	g.createPolyline([99,266,100,281,94,305,86,322,78,332,72,346,73,331,91,291]).setFill(c);
+	g.createPolyline([20,347,32,342,45,340,54,345,45,350,42,353,38,350,31,353,29,356,23,350,19,353,15,349]).setFill(c);
+	g.createPolyline([78,344,86,344,92,349,88,358,84,352]).setFill(c);
+	g.createPolyline([93,347,104,344,117,345,124,354,121,357,116,351,112,351,108,355,102,351]).setFill(c);
+	c = new dojo.Color("black");
+	g.createPolyline([105,12,111,18,113,24,113,29,119,34,116,23,112,16]).setFill(c);
+	g.createPolyline([122,27,125,34,127,43,128,34,125,29]).setFill(c);
+	g.createPolyline([115,13,122,19,122,15,113,10]).setFill(c);
+	c = new dojo.Color("#ffe5b2");
+	g.createPolyline([116,172,107,182,98,193,98,183,90,199,89,189,84,207,88,206,87,215,95,206,93,219,91,230,98,216,97,226,104,214,112,209,104,208,113,202,126,200,139,207,132,198,142,203,134,192,142,195,134,187,140,185,130,181,136,177,126,177,125,171,116,180]).setFill(c);
+	g.createPolyline([74,220,67,230,67,221,59,235,63,233,60,248,70,232,65,249,71,243,67,256,73,250,69,262,73,259,71,267,76,262,72,271,78,270,76,275,82,274,78,290,86,279,86,289,92,274,88,275,87,264,82,270,82,258,77,257,78,247,73,246,77,233,72,236]).setFill(c);
+	g.createPolyline([133,230,147,242,148,250,145,254,138,247,129,246,142,245,138,241,128,237,137,238]).setFill(c);
+	g.createPolyline([133,261,125,261,116,263,111,267,125,265]).setFill(c);
+	g.createPolyline([121,271,109,273,103,279,99,305,92,316,85,327,83,335,89,340,97,341,94,336,101,336,96,331,103,330,97,327,108,325,99,322,109,321,100,318,110,317,105,314,110,312,107,310,113,308,105,306,114,303,105,301,115,298,107,295,115,294,108,293,117,291,109,289,117,286,109,286,118,283,112,281,118,279,114,278,119,276,115,274]).setFill(c);
+	g.createPolyline([79,364,74,359,74,353,76,347,80,351,83,356,82,360]).setFill(c);
+	g.createPolyline([91,363,93,356,97,353,103,355,105,360,103,366,99,371,94,368]).setFill(c);
+	g.createPolyline([110,355,114,353,118,357,117,363,113,369,111,362]).setFill(c);
+	g.createPolyline([126,354,123,358,124,367,126,369,129,361,129,357]).setFill(c);
+	g.createPolyline([30,154,24,166,20,182,23,194,29,208,37,218,41,210,41,223,46,214,46,227,52,216,52,227,61,216,59,225,68,213,73,219,70,207,77,212,69,200,77,202,70,194,78,197,68,187,76,182,64,182,58,175,58,185,53,177,50,186,46,171,44,182,39,167,36,172,36,162,30,166]).setFill(c);
+	g.createPolyline([44,130,41,137,45,136,43,150,48,142,48,157,53,150,52,164,60,156,61,169,64,165,66,175,70,167,74,176,77,168,80,183,85,172,90,182,93,174,98,181,99,173,104,175,105,169,114,168,102,163,95,157,94,166,90,154,87,162,82,149,75,159,72,148,68,155,67,143,62,148,62,138,58,145,56,133,52,142,52,128,49,134,47,125]).setFill(c);
+	g.createPolyline([13,216,19,219,36,231,22,223,16,222,22,227,12,224,13,220,16,220]).setFill(c);
+	g.createPolyline([10,231,14,236,25,239,27,237,19,234]).setFill(c);
+	g.createPolyline([9,245,14,242,25,245,13,245]).setFill(c);
+	g.createPolyline([33,255,26,253,18,254,25,256,18,258,27,260,18,263,27,265,19,267,29,270,21,272,29,276,21,278,30,281,22,283,31,287,24,288,32,292,23,293,34,298,26,299,37,303,32,305,39,309,33,309,39,314,34,314,40,318,34,317,40,321,34,321,41,326,33,326,40,330,33,332,39,333,33,337,42,337,54,341,49,337,52,335,47,330,50,330,45,325,49,325,45,321,48,321,45,316,46,306,45,286,43,274,36,261]).setFill(c);
+	g.createPolyline([7,358,9,351,14,351,17,359,11,364]).setFill(c);
+	g.createPolyline([44,354,49,351,52,355,49,361]).setFill(c);
+	g.createPolyline([32,357,37,353,40,358,36,361]).setFill(c);
+	g.createPolyline([139,334,145,330,154,330,158,334,154,341,152,348,145,350,149,340,147,336,141,339,139,345,136,342,136,339]).setFill(c);
+	g.createPolyline([208,259,215,259,212,255,220,259,224,263,225,274,224,283,220,292,208,300,206,308,203,304,199,315,197,309,195,318,193,313,190,322,190,316,185,325,182,318,180,325,172,321,178,320,176,313,186,312,180,307,188,307,184,303,191,302,186,299,195,294,187,290,197,288,192,286,201,283,194,280,203,277,198,275,207,271,200,269,209,265,204,265,212,262]).setFill(c);
+	g.createPolyline([106,126,106,131,109,132,111,134,115,132,115,135,119,133,118,137,123,137,128,137,133,134,136,130,136,127,132,124,118,128,112,128,106,126,106,126,106,126]).setFill(c);
+	g.createPolyline([107,114,101,110,98,102,105,97,111,98,119,102,121,108,118,112,113,115]).setFill(c);
+	g.createPolyline([148,106,145,110,146,116,150,118,152,111,151,107]).setFill(c);
+	g.createPolyline([80,55,70,52,75,58,63,57,72,61,57,61,67,66,57,67,62,69,54,71,61,73,54,77,63,78,53,85,60,84,56,90,69,84,63,82,75,76,70,75,77,72,72,71,78,69,72,66,81,67,78,64,82,63,80,60,86,62]).setFill(c);
+	g.createPolyline([87,56,91,52,96,50,102,56,98,56,92,60]).setFill(c);
+	g.createPolyline([85,68,89,73,98,76,106,74,96,73,91,70]).setFill(c);
+	g.createPolyline([115,57,114,64,111,64,115,75,122,81,122,74,126,79,126,74,131,78,130,72,133,77,131,68,126,61,119,57]).setFill(c);
+	g.createPolyline([145,48,143,53,147,59,151,59,150,55]).setFill(c);
+	g.createPolyline([26,22,34,15,43,10,52,10,59,16,47,15,32,22]).setFill(c);
+	g.createPolyline([160,19,152,26,149,34,154,33,152,30,157,30,155,26,158,27,157,23,161,23]).setFill(c);
+	c = new dojo.Color("black");
+	g.createPolyline([98,117,105,122,109,122,105,117,113,120,121,120,130,112,128,108,123,103,123,99,128,101,132,106,135,109,142,105,142,101,145,101,145,91,148,101,145,105,136,112,135,116,143,124,148,120,150,122,142,128,133,122,121,125,112,126,103,125,100,129,96,124]).setFill(c);
+	g.createPolyline([146,118,152,118,152,115,149,115]).setFill(c);
+	g.createPolyline([148,112,154,111,154,109,149,109]).setFill(c);
+	g.createPolyline([106,112,108,115,114,116,118,114]).setFill(c);
+	g.createPolyline([108,108,111,110,116,110,119,108]).setFill(c);
+	g.createPolyline([106,104,109,105,117,106,115,104]).setFill(c);
+	g.createPolyline([50,25,41,26,34,33,39,43,49,58,36,51,47,68,55,69,54,59,61,57,74,46,60,52,67,42,57,48,61,40,54,45,60,36,59,29,48,38,52,30,47,32]).setFill(c);
+	g.createPolyline([147,34,152,41,155,49,161,53,157,47,164,47,158,43,168,44,159,40,164,37,169,37,164,33,169,34,165,28,170,30,170,25,173,29,175,27,176,32,173,36,175,39,172,42,172,46,168,49,170,55,162,57,158,63,155,58,153,50,149,46]).setFill(c);
+	g.createPolyline([155,71,159,80,157,93,157,102,155,108,150,101,149,93,154,101,152,91,151,83,155,79]).setFill(c);
+	g.createPolyline([112,78,115,81,114,91,112,87,113,82]).setFill(c);
+	g.createPolyline([78,28,64,17,58,11,47,9,36,10,28,16,21,26,18,41,20,51,23,61,33,65,28,68,37,74,36,81,43,87,48,90,43,100,40,98,39,90,31,80,30,72,22,71,17,61,14,46,16,28,23,17,33,9,45,6,54,6,65,12]).setFill(c);
+	g.createPolyline([67,18,76,9,87,5,101,2,118,3,135,8,149,20,149,26,144,19,132,12,121,9,105,7,89,8,76,14,70,20]).setFill(c);
+	g.createPolyline([56,98,48,106,56,103,47,112,56,110,52,115,57,113,52,121,62,115,58,123,65,119,63,125,69,121,68,127,74,125,74,129,79,128,83,132,94,135,93,129,85,127,81,122,76,126,75,121,71,124,71,117,66,121,66,117,62,117,64,112,60,113,60,110,57,111,61,105,57,107,60,101,55,102]).setFill(c);
+	g.createPolyline([101,132,103,138,106,134,106,139,112,136,111,142,115,139,114,143,119,142,125,145,131,142,135,138,140,134,140,129,143,135,145,149,150,171,149,184,145,165,141,150,136,147,132,151,131,149,126,152,125,150,121,152,117,148,111,152,110,148,105,149,104,145,98,150,96,138,94,132,94,130,98,132]).setFill(c);
+	g.createPolyline([41,94,32,110,23,132,12,163,6,190,7,217,5,236,3,247,9,230,12,211,12,185,18,160,26,134,35,110,43,99]).setFill(c);
+	g.createPolyline([32,246,41,250,50,257,52,267,53,295,53,323,59,350,54,363,51,365,44,366,42,360,40,372,54,372,59,366,62,353,71,352,75,335,73,330,66,318,68,302,64,294,67,288,63,286,63,279,59,275,58,267,56,262,50,247,42,235,44,246,32,236,35,244]).setFill(c);
+	g.createPolyline([134,324,146,320,159,322,173,327,179,337,179,349,172,355,158,357,170,350,174,343,170,333,163,328,152,326,134,329]).setFill(c);
+	g.createPolyline([173,339,183,334,184,338,191,329,194,332,199,323,202,325,206,318,209,320,213,309,221,303,228,296,232,289,234,279,233,269,230,262,225,256,219,253,208,252,198,252,210,249,223,250,232,257,237,265,238,277,238,291,232,305,221,323,218,335,212,342,200,349,178,348]).setFill(c);
+	g.createPolyline([165,296,158,301,156,310,156,323,162,324,159,318,162,308,162,304]).setFill(c);
+	g.createPolyline([99,252,105,244,107,234,115,228,121,228,131,235,122,233,113,235,109,246,121,239,133,243,121,243,110,251]).setFill(c);
+	g.createPolyline([117,252,124,247,134,249,136,253,126,252]).setFill(c);
+	g.createPolyline([117,218,132,224,144,233,140,225,132,219,117,218,117,218,117,218]).setFill(c);
+	g.createPolyline([122,212,134,214,143,221,141,213,132,210]).setFill(c);
+	g.createPolyline([69,352,70,363,76,373,86,378,97,379,108,379,120,377,128,378,132,373,135,361,133,358,132,366,127,375,121,374,121,362,119,367,117,374,110,376,110,362,107,357,106,371,104,375,97,376,90,375,90,368,86,362,83,364,86,369,85,373,78,370,73,362,71,351]).setFill(c);
+	g.createPolyline([100,360,96,363,99,369,102,364]).setFill(c);
+	g.createPolyline([115,360,112,363,114,369,117,364]).setFill(c);
+	g.createPolyline([127,362,125,364,126,369,128,365]).setFill(c);
+	g.createPolyline([5,255,7,276,11,304,15,320,13,334,6,348,2,353,0,363,5,372,12,374,25,372,38,372,44,369,42,367,36,368,31,369,30,360,27,368,20,370,16,361,15,368,10,369,3,366,3,359,6,352,11,348,17,331,19,316,12,291,9,274]).setFill(c);
+	g.createPolyline([10,358,7,362,10,366,11,362]).setFill(c);
+	g.createPolyline([25,357,22,360,24,366,27,360]).setFill(c);
+	g.createPolyline([37,357,34,361,36,365,38,361]).setFill(c);
+	g.createPolyline([49,356,46,359,47,364,50,360]).setFill(c);
+	g.createPolyline([130,101,132,102,135,101,139,102,143,103,142,101,137,100,133,100]).setFill(c);
+	g.createPolyline([106,48,105,52,108,56,109,52]).setFill(c);
+	g.createPolyline([139,52,139,56,140,60,142,58,141,56]).setFill(c);
+	g.createPolyline([25,349,29,351,30,355,33,350,37,348,42,351,45,347,49,345,44,343,36,345]).setFill(c);
+	g.createPolyline([98,347,105,351,107,354,109,349,115,349,120,353,118,349,113,346,104,346]).setFill(c);
+	g.createPolyline([83,348,87,352,87,357,89,351,87,348]).setFill(c);
+	g.createPolyline([155,107,163,107,170,107,186,108,175,109,155,109]).setFill(c);
+	g.createPolyline([153,114,162,113,175,112,192,114,173,114,154,115]).setFill(c);
+	g.createPolyline([152,118,164,120,180,123,197,129,169,123,151,120]).setFill(c);
+	g.createPolyline([68,109,87,106,107,106,106,108,88,108]).setFill(c);
+	g.createPolyline([105,111,95,112,79,114,71,116,85,115,102,113]).setFill(c);
+	g.createPolyline([108,101,98,99,87,99,78,99,93,100,105,102]).setFill(c);
+	g.createPolyline([85,63,91,63,97,60,104,60,108,62,111,69,112,75,110,74,108,71,103,73,106,69,105,65,103,64,103,67,102,70,99,70,97,66,94,67,97,72,88,67,84,66]).setFill(c);
+	g.createPolyline([140,74,141,66,144,61,150,61,156,62,153,70,150,73,152,65,150,65,151,68,149,71,146,71,144,66,143,70,143,74]).setFill(c);
+	g.createPolyline([146,20,156,11,163,9,172,9,178,14,182,18,184,32,182,42,182,52,177,58,176,67,171,76,165,90,157,105,160,92,164,85,168,78,167,73,173,66,172,62,175,59,174,55,177,53,180,46,181,29,179,21,173,13,166,11,159,13,153,18,148,23]).setFill(c);
+	g.createPolyline([150,187,148,211,150,233,153,247,148,267,135,283,125,299,136,292,131,313,122,328,122,345,129,352,133,359,133,367,137,359,148,356,140,350,131,347,129,340,132,332,140,328,137,322,140,304,154,265,157,244,155,223,161,220,175,229,186,247,185,260,176,275,178,287,185,277,188,261,196,253,189,236,174,213]).setFill(c);
+	g.createPolyline([147,338,142,341,143,345,141,354,147,343]).setFill(c);
+	g.createPolyline([157,342,156,349,150,356,157,353,163,346,162,342]).setFill(c);
+	g.createPolyline([99,265,96,284,92,299,73,339,73,333,87,300]).setFill(c);
+	//surface.createLine({x1: 0, y1: 350, x2: 700, y2: 350}).setStroke("green");
+	//surface.createLine({y1: 0, x1: 350, y2: 700, x2: 350}).setStroke("green");
+    //dojo.event.connect(dojo.widget.byId("rotatingSlider"), "onValueChanged", rotatingEvent);
+    //dojo.event.connect(dojo.widget.byId("scalingSlider"), "onValueChanged", scalingEvent);
+    //dojo.byId("sliders").style.visibility = "visible";
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+<style type="text/css">
+td.pad { padding: 0px 5px 0px 5px; }
+</style>
+</head>
+<body>
+	<h1>dojox.gfx: Lion</h1>
+	<p>This example was directly converted from SVG file.</p>
+	<!--
+	<table id="sliders" style="visibility: hidden;">
+		<tr>
+			<td align="center" class="pad">Rotation (<span id="rotationValue">0</span>)</td>
+			<td align="center" class="pad">Scaling (<span id="scaleValue">1.000</span>)</td>
+		</tr>
+		<tr>
+			<td class="pad">
+				<div id="rotatingSlider" dojoType="SliderHorizontal" 
+					initialValue="0" minimum="-180" maximum="180" snapValues="73"
+					activeDrag="true"
+					buttonStyle="top: 1px;"
+					backgroundStyle="padding: 8px 4px; border: 1px solid black;"
+					backgroundSize="width:100px; height:5px;"
+					backgroundSrc="src/widget/templates/images/blank.gif"
+					progressBackgroundSrc="src/widget/templates/images/slider-bg.gif"
+					handleStyle="top: 0px; width: 13px; height: 18px;"
+					handleSrc="src/widget/templates/images/slider.gif">
+				</div>
+			</td>
+			<td class="pad">
+				<div id="scalingSlider" dojoType="SliderHorizontal" 
+					initialValue="1" minimum="0" maximum="1" snapValues="10"
+					activeDrag="true"
+					buttonStyle="top: 1px;"
+					backgroundStyle="padding: 8px 4px; border: 1px solid black;"
+					backgroundSize="width:100px; height:5px;"
+					backgroundSrc="src/widget/templates/images/blank.gif"
+					progressBackgroundSrc="src/widget/templates/images/slider-bg.gif"
+					handleStyle="top: 0px; width: 13px; height: 18px;"
+					handleSrc="src/widget/templates/images/slider.gif">
+				</div>
+			</td>
+		</tr>
+	</table>
+	-->
+	<div id="gfx_holder" style="width: 700px; height: 700px;"></div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/tiger.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/tiger.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/demos/tiger.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,575 @@
+<html>
+<head>
+<title>dojox.gfx: Tiger</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx");
+
+// no sliders yet
+
+//dojo.require ("dojo.widget.*");
+//dojo.require ("dojo.widget.Slider");
+
+var rotation = 0, scaling = 1;
+var surface, g, m = dojox.gfx.matrix;
+var initial_matrix = m.translate(250, 250);
+
+var updateMatrix = function(){
+	if(g){ g.setTransform([m.rotategAt(rotation, 350, 350), m.scaleAt(scaling, 350, 350), initial_matrix]); }
+};
+
+var rotatingEvent = function(value){
+	rotation = value;
+	dojo.byId("rotationValue").innerHTML = rotation;
+	updateMatrix();
+};
+
+var scalingEvent = function(value){
+	scaling = Math.exp(Math.LN10 * (value - 1));
+	dojo.byId("scaleValue").innerHTML = scaling.toFixed(3);
+	updateMatrix();
+};
+
+makeShapes = function(){
+	surface = dojox.gfx.createSurface(dojo.byId("gfx_holder"), 700, 700);
+	surface.createRect({x: 0, y: 0, width: 700, height: 700}).setFill("#eee");
+	g = surface.createGroup().setTransform(initial_matrix);
+	var f, s = {color: "black", width: 1};
+	f = "#ffffff"; s = {color: "#000000", width: 0.172};
+	g.createPath("M-122.304 84.285C-122.304 84.285 -122.203 86.179 -123.027 86.16C-123.851 86.141 -140.305 38.066 -160.833 40.309C-160.833 40.309 -143.05 32.956 -122.304 84.285z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.172};
+	g.createPath("M-118.774 81.262C-118.774 81.262 -119.323 83.078 -120.092 82.779C-120.86 82.481 -119.977 31.675 -140.043 26.801C-140.043 26.801 -120.82 25.937 -118.774 81.262z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.172};
+	g.createPath("M-91.284 123.59C-91.284 123.59 -89.648 124.55 -90.118 125.227C-90.589 125.904 -139.763 113.102 -149.218 131.459C-149.218 131.459 -145.539 112.572 -91.284 123.59z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.172};
+	g.createPath("M-94.093 133.801C-94.093 133.801 -92.237 134.197 -92.471 134.988C-92.704 135.779 -143.407 139.121 -146.597 159.522C-146.597 159.522 -149.055 140.437 -94.093 133.801z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.172};
+	g.createPath("M-98.304 128.276C-98.304 128.276 -96.526 128.939 -96.872 129.687C-97.218 130.435 -147.866 126.346 -153.998 146.064C-153.998 146.064 -153.646 126.825 -98.304 128.276z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.172};
+	g.createPath("M-109.009 110.072C-109.009 110.072 -107.701 111.446 -108.34 111.967C-108.979 112.488 -152.722 86.634 -166.869 101.676C-166.869 101.676 -158.128 84.533 -109.009 110.072z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.172};
+	g.createPath("M-116.554 114.263C-116.554 114.263 -115.098 115.48 -115.674 116.071C-116.25 116.661 -162.638 95.922 -174.992 112.469C-174.992 112.469 -168.247 94.447 -116.554 114.263z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.172};
+	g.createPath("M-119.154 118.335C-119.154 118.335 -117.546 119.343 -118.036 120.006C-118.526 120.669 -167.308 106.446 -177.291 124.522C-177.291 124.522 -173.066 105.749 -119.154 118.335z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.172};
+	g.createPath("M-108.42 118.949C-108.42 118.949 -107.298 120.48 -107.999 120.915C-108.7 121.35 -148.769 90.102 -164.727 103.207C-164.727 103.207 -153.862 87.326 -108.42 118.949z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.172};
+	g.createPath("M-128.2 90C-128.2 90 -127.6 91.8 -128.4 92C-129.2 92.2 -157.8 50.2 -177.001 57.8C-177.001 57.8 -161.8 46 -128.2 90z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.172};
+	g.createPath("M-127.505 96.979C-127.505 96.979 -126.53 98.608 -127.269 98.975C-128.007 99.343 -164.992 64.499 -182.101 76.061C-182.101 76.061 -169.804 61.261 -127.505 96.979z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.172};
+	g.createPath("M-127.62 101.349C-127.62 101.349 -126.498 102.88 -127.199 103.315C-127.9 103.749 -167.969 72.502 -183.927 85.607C-183.927 85.607 -173.062 69.726 -127.62 101.349z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = "#000000";
+	g.createPath("M-129.83 103.065C-129.327 109.113 -128.339 115.682 -126.6 118.801C-126.6 118.801 -130.2 131.201 -121.4 144.401C-121.4 144.401 -121.8 151.601 -120.2 154.801C-120.2 154.801 -116.2 163.201 -111.4 164.001C-107.516 164.648 -98.793 167.717 -88.932 169.121C-88.932 169.121 -71.8 183.201 -75 196.001C-75 196.001 -75.4 212.401 -79 214.001C-79 214.001 -67.4 202.801 -77 219.601L-81.4 238.401C-81.4 238.401 -55.8 216.801 -71.4 235.201L-81.4 261.201C-81.4 261.201 -61.8 242.801 -69 251.201L-72.2 260.001C-72.2 260.001 -29 232.801 -59.8 262.401C-59.8 262.401 -51.8 258.801 -47.4 261.601C-47.4 261.601 -40.6 260.401 -41.4 262.001C-41.4 262.001 -62.2 272.401 -65.8 290.801C-65.8 290.801 -57.4 280.801 -60.6 291.601L-60.2 303.201C-60.2 303.201 -56.2 281.601 -56.6 319.201C-56.6 319.201 -37.4 301.201 -49 322.001L-49 338.801C-49 338.801 -33.8 322.401 -40.2 335.201C-40.2 335.201 -30.2 326.401 -34.2 341.601C-34.2 341.601 -35 352.001 -30.6 340.801C-30.6 340.801 -14.6 310.201 -20.6 336.401C-20.6 336.401 -21.4 355.601 -16.6 340.801C-16.6 340.801 -16.2 351.201 -7 358.401C-7 358.401 -8.2 307.601 4.6 343.601L8.6 360.001C8.6 360.001 11.4 350.801 11 345.601C11 345.601 25.8 329.201 19 353.601C19 353.601 34.2 330.801 31 344.001C31 344.001 23.4 360.001 25 364.801C25 364.801 41.8 330.001 43 328.401C43 328.401 41 370.802 51.8 334.801C51.8 334.801 57.4 346.801 54.6 351.201C54.6 351.201 62.6 343.201 61.8 340.001C61.8 340.001 66.4 331.801 69.2 345.401C69.2 345.401 71 354.801 72.6 351.601C72.6 351.601 76.6 375.602 77.8 352.801C77.8 352.801 79.4 339.201 72.2 327.601C72.2 327.601 73 324.401 70.2 320.401C70.2 320.401 83.8 342.001 76.6 313.201C76.6 313.201 87.801 321.201 89.001 321.201C89.001 321.201 75.4 298.001 84.2 302.801C84.2 302.801 79 292.401 97.001 304.401C97.001 304.401 81 288.401 98.601 298.001C98.601 298.001 106.601 304.401 99.001 294.401C99.001 294.401 84.6 278.401 106.601 296.401C106.601 296.401 118.201 312.801 119.001 315.601C119.001 315.601 109.001 286.401 104.601 283.601C104.601 283.601 113.001 247.201 154.201 262.801C154.201 262.801 161.001 280.001 165.401 261.601C165.401 261.601 178.201 255.201 189.401 282.801C189.401 282.801 193.401 269.201 192.601 266.401C192.601 266.401 199.401 267.601 198.601 266.401C198.601 266.401 211.801 270.801 213.001 270.001C213.001 270.001 219.801 276.801 220.201 273.201C220.201 273.201 229.401 276.001 227.401 272.401C227.401 272.401 236.201 288.001 236.601 291.601L239.001 277.601L241.001 280.401C241.001 280.401 242.601 272.801 241.801 271.601C241.001 270.401 261.801 278.401 266.601 299.201L268.601 307.601C268.601 307.601 274.601 292.801 273.001 288.801C273.001 288.801 278.201 289.601 278.601 294.001C278.601 294.001 282.601 270.801 277.801 264.801C277.801 264.801 282.201 264.001 283.401 267.601L283.401 260.401C283.401 260.401 290.601 261.201 290.601 258.801C290.601 258.801 295.001 254.801 297.001 259.601C297.001 259.601 284.601 224.401 303.001 243.601C303.001 243.601 310.201 254.401 306.601 235.601C303.001 216.801 299.001 215.201 303.801 214.801C303.801 214.801 304.601 211.201 302.601 209.601C300.601 208.001 303.801 209.601 303.801 209.601C303.801 209.601 308.601 213.601 303.401 191.601C303.401 191.601 309.801 193.201 297.801 164.001C297.801 164.001 300.601 161.601 296.601 153.201C296.601 153.201 304.601 157.601 307.401 156.001C307.401 156.001 307.001 154.401 303.801 150.401C303.801 150.401 282.201 95.6 302.601 117.601C302.601 117.601 314.451 131.151 308.051 108.351C308.051 108.351 298.94 84.341 299.717 80.045L-129.83 103.065z").setFill(f).setStroke(s);
+	f = "#cc7226"; s = "#000000";
+	g.createPath("M299.717 80.245C300.345 80.426 302.551 81.55 303.801 83.2C303.801 83.2 310.601 94 305.401 75.6C305.401 75.6 296.201 46.8 305.001 58C305.001 58 311.001 65.2 307.801 51.6C303.936 35.173 301.401 28.8 301.401 28.8C301.401 28.8 313.001 33.6 286.201 -6L295.001 -2.4C295.001 -2.4 275.401 -42 253.801 -47.2L245.801 -53.2C245.801 -53.2 284.201 -91.2 271.401 -128C271.401 -128 264.601 -133.2 255.001 -124C255.001 -124 248.601 -119.2 242.601 -120.8C242.601 -120.8 211.801 -119.6 209.801 -119.6C207.801 -119.6 173.001 -156.8 107.401 -139.2C107.401 -139.2 102.201 -137.2 97.801 -138.4C97.801 -138.4 79.4 -154.4 30.6 -131.6C30.6 -131.6 20.6 -129.6 19 -129.6C17.4 -129.6 14.6 -129.6 6.6 -123.2C-1.4 -116.8 -1.8 -116 -3.8 -114.4C-3.8 -114.4 -20.2 -103.2 -25 -102.4C-25 -102.4 -36.6 -96 -41 -86L-44.6 -84.8C-44.6 -84.8 -46.2 -77.6 -46.6 -76.4C-46.6 -76.4 -51.4 -72.8 -52.2 -67.2C-52.2 -67.2 -61 -61.2 -60.6 -56.8C-60.6 -56.8 -62.2 -51.6 -63 -46.8C-63 -46.8 -70.2 -42 -69.4 -39.2C-69.4 -39.2 -77 -25.2 -75.8 -18.4C-75.8 -18.4 -82.2 -18.8 -85 -16.4C-85 -16.4 -85.8 -11.6 -87.4 -11.2C-87.4 -11.2 -90.2 -10 -87.8 -6C-87.8 -6 -89.4 -3.2 -89.8 -1.6C-89.8 -1.6 -89 1.2 -93.4 6.8C-93.4 6.8 -99.8 25.6 -97.8 30.8C-97.8 30.8 -97.4 35.6 -100.2 37.2C-100.2 37.2 -103.8 36.8 -95.4 48.8C-95.4 48.8 -94.6 50 -97.8 52.4C-97.8 52.4 -115 56 -117.4 72.4C-117.4 72.4 -131 87.2 -131 92.4C-131 94.705 -130.729 97.852 -130.03 102.465C-130.03 102.465 -130.6 110.801 -103 111.601C-75.4 112.401 299.717 80.245 299.717 80.245z").setFill(f).setStroke(s);
+	f = "#cc7226"; s = null;
+	g.createPath("M-115.6 102.6C-140.6 63.2 -126.2 119.601 -126.2 119.601C-117.4 154.001 12.2 116.401 12.2 116.401C12.2 116.401 181.001 86 192.201 82C203.401 78 298.601 84.4 298.601 84.4L293.001 67.6C228.201 21.2 209.001 44.4 195.401 40.4C181.801 36.4 184.201 46 181.001 46.8C177.801 47.6 138.601 22.8 132.201 23.6C125.801 24.4 100.459 0.649 115.401 32.4C131.401 66.4 57 71.6 40.2 60.4C23.4 49.2 47.4 78.8 47.4 78.8C65.8 98.8 31.4 82 31.4 82C-3 69.2 -27 94.8 -30.2 95.6C-33.4 96.4 -38.2 99.6 -39 93.2C-39.8 86.8 -47.31 70.099 -79 96.4C-99 113.001 -112.8 91 -112.8 91L-115.6 102.6z").setFill(f).setStroke(s);
+	f = "#e87f3a";
+	g.createPath("M133.51 25.346C127.11 26.146 101.743 2.407 116.71 34.146C133.31 69.346 58.31 73.346 41.51 62.146C24.709 50.946 48.71 80.546 48.71 80.546C67.11 100.546 32.709 83.746 32.709 83.746C-1.691 70.946 -25.691 96.546 -28.891 97.346C-32.091 98.146 -36.891 101.346 -37.691 94.946C-38.491 88.546 -45.87 72.012 -77.691 98.146C-98.927 115.492 -112.418 94.037 -112.418 94.037L-115.618 104.146C-140.618 64.346 -125.546 122.655 -125.546 122.655C-116.745 157.056 13.509 118.146 13.509 118.146C13.509 118.146 182.31 87.746 193.51 83.746C204.71 79.746 299.038 86.073 299.038 86.073L293.51 68.764C228.71 22.364 210.31 46.146 196.71 42.146C183.11 38.146 185.51 47.746 182.31 48.546C179.11 49.346 139.91 24.546 133.51 25.346z").setFill(f).setStroke(s);
+	f = "#ea8c4d";
+	g.createPath("M134.819 27.091C128.419 27.891 103.685 3.862 118.019 35.891C134.219 72.092 59.619 75.092 42.819 63.892C26.019 52.692 50.019 82.292 50.019 82.292C68.419 102.292 34.019 85.492 34.019 85.492C-0.381 72.692 -24.382 98.292 -27.582 99.092C-30.782 99.892 -35.582 103.092 -36.382 96.692C-37.182 90.292 -44.43 73.925 -76.382 99.892C-98.855 117.983 -112.036 97.074 -112.036 97.074L-115.636 105.692C-139.436 66.692 -124.891 125.71 -124.891 125.71C-116.091 160.11 14.819 119.892 14.819 119.892C14.819 119.892 183.619 89.492 194.819 85.492C206.019 81.492 299.474 87.746 299.474 87.746L294.02 69.928C229.219 23.528 211.619 47.891 198.019 43.891C184.419 39.891 186.819 49.491 183.619 50.292C180.419 51.092 141.219 26.291 134.819 27.091z").setFill(f).setStroke(s);
+	f = "#ec9961";
+	g.createPath("M136.128 28.837C129.728 29.637 104.999 5.605 119.328 37.637C136.128 75.193 60.394 76.482 44.128 65.637C27.328 54.437 51.328 84.037 51.328 84.037C69.728 104.037 35.328 87.237 35.328 87.237C0.928 74.437 -23.072 100.037 -26.272 100.837C-29.472 101.637 -34.272 104.837 -35.072 98.437C-35.872 92.037 -42.989 75.839 -75.073 101.637C-98.782 120.474 -111.655 100.11 -111.655 100.11L-115.655 107.237C-137.455 70.437 -124.236 128.765 -124.236 128.765C-115.436 163.165 16.128 121.637 16.128 121.637C16.128 121.637 184.928 91.237 196.129 87.237C207.329 83.237 299.911 89.419 299.911 89.419L294.529 71.092C229.729 24.691 212.929 49.637 199.329 45.637C185.728 41.637 188.128 51.237 184.928 52.037C181.728 52.837 142.528 28.037 136.128 28.837z").setFill(f).setStroke(s);
+	f = "#eea575";
+	g.createPath("M137.438 30.583C131.037 31.383 106.814 7.129 120.637 39.383C137.438 78.583 62.237 78.583 45.437 67.383C28.637 56.183 52.637 85.783 52.637 85.783C71.037 105.783 36.637 88.983 36.637 88.983C2.237 76.183 -21.763 101.783 -24.963 102.583C-28.163 103.383 -32.963 106.583 -33.763 100.183C-34.563 93.783 -41.548 77.752 -73.763 103.383C-98.709 122.965 -111.273 103.146 -111.273 103.146L-115.673 108.783C-135.473 73.982 -123.582 131.819 -123.582 131.819C-114.782 166.22 17.437 123.383 17.437 123.383C17.437 123.383 186.238 92.983 197.438 88.983C208.638 84.983 300.347 91.092 300.347 91.092L295.038 72.255C230.238 25.855 214.238 51.383 200.638 47.383C187.038 43.383 189.438 52.983 186.238 53.783C183.038 54.583 143.838 29.783 137.438 30.583z").setFill(f).setStroke(s);
+	f = "#f1b288";
+	g.createPath("M138.747 32.328C132.347 33.128 106.383 9.677 121.947 41.128C141.147 79.928 63.546 80.328 46.746 69.128C29.946 57.928 53.946 87.528 53.946 87.528C72.346 107.528 37.946 90.728 37.946 90.728C3.546 77.928 -20.454 103.528 -23.654 104.328C-26.854 105.128 -31.654 108.328 -32.454 101.928C-33.254 95.528 -40.108 79.665 -72.454 105.128C-98.636 125.456 -110.891 106.183 -110.891 106.183L-115.691 110.328C-133.691 77.128 -122.927 134.874 -122.927 134.874C-114.127 169.274 18.746 125.128 18.746 125.128C18.746 125.128 187.547 94.728 198.747 90.728C209.947 86.728 300.783 92.764 300.783 92.764L295.547 73.419C230.747 27.019 215.547 53.128 201.947 49.128C188.347 45.128 190.747 54.728 187.547 55.528C184.347 56.328 145.147 31.528 138.747 32.328z").setFill(f).setStroke(s);
+	f = "#f3bf9c";
+	g.createPath("M140.056 34.073C133.655 34.873 107.313 11.613 123.255 42.873C143.656 82.874 64.855 82.074 48.055 70.874C31.255 59.674 55.255 89.274 55.255 89.274C73.655 109.274 39.255 92.474 39.255 92.474C4.855 79.674 -19.145 105.274 -22.345 106.074C-25.545 106.874 -30.345 110.074 -31.145 103.674C-31.945 97.274 -38.668 81.578 -71.145 106.874C-98.564 127.947 -110.509 109.219 -110.509 109.219L-115.709 111.874C-131.709 81.674 -122.273 137.929 -122.273 137.929C-113.473 172.329 20.055 126.874 20.055 126.874C20.055 126.874 188.856 96.474 200.056 92.474C211.256 88.474 301.22 94.437 301.22 94.437L296.056 74.583C231.256 28.183 216.856 54.874 203.256 50.874C189.656 46.873 192.056 56.474 188.856 57.274C185.656 58.074 146.456 33.273 140.056 34.073z").setFill(f).setStroke(s);
+	f = "#f5ccb0";
+	g.createPath("M141.365 35.819C134.965 36.619 107.523 13.944 124.565 44.619C146.565 84.219 66.164 83.819 49.364 72.619C32.564 61.419 56.564 91.019 56.564 91.019C74.964 111.019 40.564 94.219 40.564 94.219C6.164 81.419 -17.836 107.019 -21.036 107.819C-24.236 108.619 -29.036 111.819 -29.836 105.419C-30.636 99.019 -37.227 83.492 -69.836 108.619C-98.491 130.438 -110.127 112.256 -110.127 112.256L-115.727 113.419C-130.128 85.019 -121.618 140.983 -121.618 140.983C-112.818 175.384 21.364 128.619 21.364 128.619C21.364 128.619 190.165 98.219 201.365 94.219C212.565 90.219 301.656 96.11 301.656 96.11L296.565 75.746C231.765 29.346 218.165 56.619 204.565 52.619C190.965 48.619 193.365 58.219 190.165 59.019C186.965 59.819 147.765 35.019 141.365 35.819z").setFill(f).setStroke(s);
+	f = "#f8d8c4";
+	g.createPath("M142.674 37.565C136.274 38.365 108.832 15.689 125.874 46.365C147.874 85.965 67.474 85.565 50.674 74.365C33.874 63.165 57.874 92.765 57.874 92.765C76.274 112.765 41.874 95.965 41.874 95.965C7.473 83.165 -16.527 108.765 -19.727 109.565C-22.927 110.365 -27.727 113.565 -28.527 107.165C-29.327 100.765 -35.786 85.405 -68.527 110.365C-98.418 132.929 -109.745 115.293 -109.745 115.293L-115.745 114.965C-129.346 88.564 -120.963 144.038 -120.963 144.038C-112.163 178.438 22.673 130.365 22.673 130.365C22.673 130.365 191.474 99.965 202.674 95.965C213.874 91.965 302.093 97.783 302.093 97.783L297.075 76.91C232.274 30.51 219.474 58.365 205.874 54.365C192.274 50.365 194.674 59.965 191.474 60.765C188.274 61.565 149.074 36.765 142.674 37.565z").setFill(f).setStroke(s);
+	f = "#fae5d7";
+	g.createPath("M143.983 39.31C137.583 40.11 110.529 17.223 127.183 48.11C149.183 88.91 68.783 87.31 51.983 76.11C35.183 64.91 59.183 94.51 59.183 94.51C77.583 114.51 43.183 97.71 43.183 97.71C8.783 84.91 -15.217 110.51 -18.417 111.31C-21.618 112.11 -26.418 115.31 -27.218 108.91C-28.018 102.51 -34.346 87.318 -67.218 112.11C-98.345 135.42 -109.363 118.329 -109.363 118.329L-115.764 116.51C-128.764 92.51 -120.309 147.093 -120.309 147.093C-111.509 181.493 23.983 132.11 23.983 132.11C23.983 132.11 192.783 101.71 203.983 97.71C215.183 93.71 302.529 99.456 302.529 99.456L297.583 78.074C232.783 31.673 220.783 60.11 207.183 56.11C193.583 52.11 195.983 61.71 192.783 62.51C189.583 63.31 150.383 38.51 143.983 39.31z").setFill(f).setStroke(s);
+	f = "#fcf2eb";
+	g.createPath("M145.292 41.055C138.892 41.855 112.917 18.411 128.492 49.855C149.692 92.656 70.092 89.056 53.292 77.856C36.492 66.656 60.492 96.256 60.492 96.256C78.892 116.256 44.492 99.456 44.492 99.456C10.092 86.656 -13.908 112.256 -17.108 113.056C-20.308 113.856 -25.108 117.056 -25.908 110.656C-26.708 104.256 -32.905 89.232 -65.908 113.856C-98.273 137.911 -108.982 121.365 -108.982 121.365L-115.782 118.056C-128.582 94.856 -119.654 150.147 -119.654 150.147C-110.854 184.547 25.292 133.856 25.292 133.856C25.292 133.856 194.093 103.456 205.293 99.456C216.493 95.456 302.965 101.128 302.965 101.128L298.093 79.237C233.292 32.837 222.093 61.856 208.493 57.856C194.893 53.855 197.293 63.456 194.093 64.256C190.892 65.056 151.692 40.255 145.292 41.055z").setFill(f).setStroke(s);
+	f = "#ffffff";
+	g.createPath("M-115.8 119.601C-128.6 97.6 -119 153.201 -119 153.201C-110.2 187.601 26.6 135.601 26.6 135.601C26.6 135.601 195.401 105.2 206.601 101.2C217.801 97.2 303.401 102.8 303.401 102.8L298.601 80.4C233.801 34 223.401 63.6 209.801 59.6C196.201 55.6 198.601 65.2 195.401 66C192.201 66.8 153.001 42 146.601 42.8C140.201 43.6 114.981 19.793 129.801 51.6C152.028 99.307 69.041 89.227 54.6 79.6C37.8 68.4 61.8 98 61.8 98C80.2 118.001 45.8 101.2 45.8 101.2C11.4 88.4 -12.6 114.001 -15.8 114.801C-19 115.601 -23.8 118.801 -24.6 112.401C-25.4 106 -31.465 91.144 -64.6 115.601C-98.2 140.401 -108.6 124.401 -108.6 124.401L-115.8 119.601z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-74.2 149.601C-74.2 149.601 -81.4 161.201 -60.6 174.401C-60.6 174.401 -59.2 175.801 -77.2 171.601C-77.2 171.601 -83.4 169.601 -85 159.201C-85 159.201 -89.8 154.801 -94.6 149.201C-99.4 143.601 -74.2 149.601 -74.2 149.601z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M65.8 102C65.8 102 83.498 128.821 82.9 133.601C81.6 144.001 81.4 153.601 84.6 157.601C87.801 161.601 96.601 194.801 96.601 194.801C96.601 194.801 96.201 196.001 108.601 158.001C108.601 158.001 120.201 142.001 100.201 123.601C100.201 123.601 65 94.8 65.8 102z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-54.2 176.401C-54.2 176.401 -43 183.601 -57.4 214.801L-51 212.401C-51 212.401 -51.8 223.601 -55 226.001L-47.8 222.801C-47.8 222.801 -43 230.801 -47 235.601C-47 235.601 -30.2 243.601 -31 250.001C-31 250.001 -24.6 242.001 -28.6 235.601C-32.6 229.201 -39.8 233.201 -39 214.801L-47.8 218.001C-47.8 218.001 -42.2 209.201 -42.2 202.801L-50.2 205.201C-50.2 205.201 -34.731 178.623 -45.4 177.201C-51.4 176.401 -54.2 176.401 -54.2 176.401z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-21.8 193.201C-21.8 193.201 -19 188.801 -21.8 189.601C-24.6 190.401 -55.8 205.201 -61.8 214.801C-61.8 214.801 -27.4 190.401 -21.8 193.201z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-11.4 201.201C-11.4 201.201 -8.6 196.801 -11.4 197.601C-14.2 198.401 -45.4 213.201 -51.4 222.801C-51.4 222.801 -17 198.401 -11.4 201.201z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M1.8 186.001C1.8 186.001 4.6 181.601 1.8 182.401C-1 183.201 -32.2 198.001 -38.2 207.601C-38.2 207.601 -3.8 183.201 1.8 186.001z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-21.4 229.601C-21.4 229.601 -21.4 223.601 -24.2 224.401C-27 225.201 -63 242.801 -69 252.401C-69 252.401 -27 226.801 -21.4 229.601z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-20.2 218.801C-20.2 218.801 -19 214.001 -21.8 214.801C-23.8 214.801 -50.2 226.401 -56.2 236.001C-56.2 236.001 -26.6 214.401 -20.2 218.801z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-34.6 266.401L-44.6 274.001C-44.6 274.001 -34.2 266.401 -30.6 267.601C-30.6 267.601 -37.4 278.801 -38.2 284.001C-38.2 284.001 -27.8 271.201 -22.2 271.601C-22.2 271.601 -14.6 272.001 -14.6 282.801C-14.6 282.801 -9 272.401 -5.8 272.801C-5.8 272.801 -4.6 279.201 -5.8 286.001C-5.8 286.001 -1.8 278.401 2.2 280.001C2.2 280.001 8.6 278.001 7.8 289.601C7.8 289.601 7.8 300.001 7 302.801C7 302.801 12.6 276.401 15 276.001C15 276.001 23 274.801 27.8 283.601C27.8 283.601 23.8 276.001 28.6 278.001C28.6 278.001 39.4 279.601 42.6 286.401C42.6 286.401 35.8 274.401 41.4 277.601C41.4 277.601 48.2 277.601 49.4 284.001C49.4 284.001 57.8 305.201 59.8 306.801C59.8 306.801 52.2 285.201 53.8 285.201C53.8 285.201 51.8 273.201 57 288.001C57 288.001 53.8 274.001 59.4 274.801C65 275.601 69.4 285.601 77.8 283.201C77.8 283.201 87.401 288.801 89.401 219.601L-34.6 266.401z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-29.8 173.601C-29.8 173.601 -15 167.601 25 173.601C25 173.601 32.2 174.001 39 165.201C45.8 156.401 72.6 149.201 79 151.201L88.601 157.601L89.401 158.801C89.401 158.801 101.801 169.201 102.201 176.801C102.601 184.401 87.801 232.401 78.2 248.401C68.6 264.401 59 276.801 39.8 274.401C39.8 274.401 19 270.401 -6.6 274.401C-6.6 274.401 -35.8 272.801 -38.6 264.801C-41.4 256.801 -27.4 241.601 -27.4 241.601C-27.4 241.601 -23 233.201 -24.2 218.801C-25.4 204.401 -25 176.401 -29.8 173.601z").setFill(f).setStroke(s);
+	f = "#e5668c";
+	g.createPath("M-7.8 175.601C0.6 194.001 -29 259.201 -29 259.201C-31 260.801 -16.34 266.846 -6.2 264.401C4.746 261.763 45 266.001 45 266.001C68.6 250.401 81.4 206.001 81.4 206.001C81.4 206.001 91.801 182.001 74.2 178.801C56.6 175.601 -7.8 175.601 -7.8 175.601z").setFill(f).setStroke(s);
+	f = "#b23259";
+	g.createPath("M-9.831 206.497C-6.505 193.707 -4.921 181.906 -7.8 175.601C-7.8 175.601 54.6 182.001 65.8 161.201C70.041 153.326 84.801 184.001 84.4 193.601C84.4 193.601 21.4 208.001 6.6 196.801L-9.831 206.497z").setFill(f).setStroke(s);
+	f = "#a5264c";
+	g.createPath("M-5.4 222.801C-5.4 222.801 -3.4 230.001 -5.8 234.001C-5.8 234.001 -7.4 234.801 -8.6 235.201C-8.6 235.201 -7.4 238.801 -1.4 240.401C-1.4 240.401 0.6 244.801 3 245.201C5.4 245.601 10.2 251.201 14.2 250.001C18.2 248.801 29.4 244.801 29.4 244.801C29.4 244.801 35 241.601 43.8 245.201C43.8 245.201 46.175 244.399 46.6 240.401C47.1 235.701 50.2 232.001 52.2 230.001C54.2 228.001 63.8 215.201 62.6 214.801C61.4 214.401 -5.4 222.801 -5.4 222.801z").setFill(f).setStroke(s);
+	f = "#ff727f"; s = "#000000";
+	g.createPath("M-9.8 174.401C-9.8 174.401 -12.6 196.801 -9.4 205.201C-6.2 213.601 -7 215.601 -7.8 219.601C-8.6 223.601 -4.2 233.601 1.4 239.601L13.4 241.201C13.4 241.201 28.6 237.601 37.8 240.401C37.8 240.401 46.794 241.744 50.2 226.801C50.2 226.801 55 220.401 62.2 217.601C69.4 214.801 76.6 173.201 72.6 165.201C68.6 157.201 54.2 152.801 38.2 168.401C22.2 184.001 20.2 167.201 -9.8 174.401z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M-8.2 249.201C-8.2 249.201 -9 247.201 -13.4 246.801C-13.4 246.801 -35.8 243.201 -44.2 230.801C-44.2 230.801 -51 225.201 -46.6 236.801C-46.6 236.801 -36.2 257.201 -29.4 260.001C-29.4 260.001 -13 264.001 -8.2 249.201z").setFill(f).setStroke(s);
+	f = "#cc3f4c"; s = null;
+	g.createPath("M71.742 185.229C72.401 177.323 74.354 168.709 72.6 165.201C66.154 152.307 49.181 157.695 38.2 168.401C22.2 184.001 20.2 167.201 -9.8 174.401C-9.8 174.401 -11.545 188.364 -10.705 198.376C-10.705 198.376 26.6 186.801 27.4 192.401C27.4 192.401 29 189.201 38.2 189.201C47.4 189.201 70.142 188.029 71.742 185.229z").setFill(f).setStroke(s);
+	s = {color: "#a51926", width: 2}; f = null;
+	g.createPath("M28.6 175.201C28.6 175.201 33.4 180.001 29.8 189.601C29.8 189.601 15.4 205.601 17.4 219.601").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M-19.4 260.001C-19.4 260.001 -23.8 247.201 -15 254.001C-15 254.001 -10.2 256.001 -11.4 257.601C-12.6 259.201 -18.2 263.201 -19.4 260.001z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M-14.36 261.201C-14.36 261.201 -17.88 250.961 -10.84 256.401C-10.84 256.401 -6.419 258.849 -7.96 259.281C-12.52 260.561 -7.96 263.121 -14.36 261.201z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M-9.56 261.201C-9.56 261.201 -13.08 250.961 -6.04 256.401C-6.04 256.401 -1.665 258.711 -3.16 259.281C-6.52 260.561 -3.16 263.121 -9.56 261.201z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M-2.96 261.401C-2.96 261.401 -6.48 251.161 0.56 256.601C0.56 256.601 4.943 258.933 3.441 259.481C0.48 260.561 3.441 263.321 -2.96 261.401z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M3.52 261.321C3.52 261.321 0 251.081 7.041 256.521C7.041 256.521 10.881 258.121 9.921 259.401C8.961 260.681 9.921 263.241 3.52 261.321z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M10.2 262.001C10.2 262.001 5.4 249.601 14.6 256.001C14.6 256.001 19.4 258.001 18.2 259.601C17 261.201 18.2 264.401 10.2 262.001z").setFill(f).setStroke(s);
+	s = {color: "#a5264c", width: 2}; f = null;
+	g.createPath("M-18.2 244.801C-18.2 244.801 -5 242.001 1 245.201C1 245.201 7 246.401 8.2 246.001C9.4 245.601 12.6 245.201 12.6 245.201").setFill(f).setStroke(s);
+	s = {color: "#a5264c", width: 2};
+	g.createPath("M15.8 253.601C15.8 253.601 27.8 240.001 39.8 244.401C46.816 246.974 45.8 243.601 46.6 240.801C47.4 238.001 47.6 233.801 52.6 230.801").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M33 237.601C33 237.601 29 226.801 26.2 239.601C23.4 252.401 20.2 256.001 18.6 258.801C18.6 258.801 18.6 264.001 27 263.601C27 263.601 37.8 263.201 38.2 260.401C38.6 257.601 37 246.001 33 237.601z").setFill(f).setStroke(s);
+	s = {color: "#a5264c", width: 2}; f = null;
+	g.createPath("M47 244.801C47 244.801 50.6 242.401 53 243.601").setFill(f).setStroke(s);
+	s = {color: "#a5264c", width: 2};
+	g.createPath("M53.5 228.401C53.5 228.401 56.4 223.501 61.2 222.701").setFill(f).setStroke(s);
+	f = "#b2b2b2"; s = null;
+	g.createPath("M-25.8 265.201C-25.8 265.201 -7.8 268.401 -3.4 266.801C-3.4 266.801 5.4 266.801 -3 268.801C-3 268.801 -15.8 268.801 -23.8 267.601C-23.8 267.601 -35.4 262.001 -25.8 265.201z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M-11.8 172.001C-11.8 172.001 5.8 172.001 7.8 172.801C7.8 172.801 15 203.601 11.4 211.201C11.4 211.201 10.2 214.001 7.4 208.401C7.4 208.401 -11 175.601 -14.2 173.601C-17.4 171.601 -13 172.001 -11.8 172.001z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M-88.9 169.301C-88.9 169.301 -80 171.001 -67.4 173.601C-67.4 173.601 -62.6 196.001 -59.4 200.801C-56.2 205.601 -59.8 205.601 -63.4 202.801C-67 200.001 -81.8 186.001 -83.8 181.601C-85.8 177.201 -88.9 169.301 -88.9 169.301z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M-67.039 173.818C-67.039 173.818 -61.239 175.366 -60.23 177.581C-59.222 179.795 -61.432 183.092 -61.432 183.092C-61.432 183.092 -62.432 186.397 -63.634 184.235C-64.836 182.072 -67.708 174.412 -67.039 173.818z").setFill(f).setStroke(s);
+	f = "#000000"; s = null;
+	g.createPath("M-67 173.601C-67 173.601 -63.4 178.801 -59.8 178.801C-56.2 178.801 -55.818 178.388 -53 179.001C-48.4 180.001 -48.8 178.001 -42.2 179.201C-39.56 179.681 -37 178.801 -34.2 180.001C-31.4 181.201 -28.2 180.401 -27 178.401C-25.8 176.401 -21 172.201 -21 172.201C-21 172.201 -33.8 174.001 -36.6 174.801C-36.6 174.801 -59 176.001 -67 173.601z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M-22.4 173.801C-22.4 173.801 -28.85 177.301 -29.25 179.701C-29.65 182.101 -24 185.801 -24 185.801C-24 185.801 -21.25 190.401 -20.65 188.001C-20.05 185.601 -21.6 174.201 -22.4 173.801z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M-59.885 179.265C-59.885 179.265 -52.878 190.453 -52.661 179.242C-52.661 179.242 -52.104 177.984 -53.864 177.962C-59.939 177.886 -58.418 173.784 -59.885 179.265z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M-52.707 179.514C-52.707 179.514 -44.786 190.701 -45.422 179.421C-45.422 179.421 -45.415 179.089 -47.168 178.936C-51.915 178.522 -51.57 174.004 -52.707 179.514z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M-45.494 179.522C-45.494 179.522 -37.534 190.15 -38.203 180.484C-38.203 180.484 -38.084 179.251 -39.738 178.95C-43.63 178.244 -43.841 174.995 -45.494 179.522z").setFill(f).setStroke(s);
+	f = "#ffffcc"; s = {color: "#000000", width: 0.5};
+	g.createPath("M-38.618 179.602C-38.618 179.602 -30.718 191.163 -30.37 181.382C-30.37 181.382 -28.726 180.004 -30.472 179.782C-36.29 179.042 -35.492 174.588 -38.618 179.602z").setFill(f).setStroke(s);
+	f = "#e5e5b2"; s = null;
+	g.createPath("M-74.792 183.132L-82.45 181.601C-85.05 176.601 -87.15 170.451 -87.15 170.451C-87.15 170.451 -80.8 171.451 -68.3 174.251C-68.3 174.251 -67.424 177.569 -65.952 183.364L-74.792 183.132z").setFill(f).setStroke(s);
+	f = "#e5e5b2";
+	g.createPath("M-9.724 178.47C-11.39 175.964 -12.707 174.206 -13.357 173.8C-16.37 171.917 -12.227 172.294 -11.098 172.294C-11.098 172.294 5.473 172.294 7.356 173.047C7.356 173.047 7.88 175.289 8.564 178.68C8.564 178.68 -1.524 176.67 -9.724 178.47z").setFill(f).setStroke(s);
+	f = "#cc7226";
+	g.createPath("M43.88 40.321C71.601 44.281 97.121 8.641 98.881 -1.04C100.641 -10.72 90.521 -22.6 90.521 -22.6C91.841 -25.68 87.001 -39.76 81.721 -49C76.441 -58.24 60.54 -57.266 43 -58.24C27.16 -59.12 8.68 -35.8 7.36 -34.04C6.04 -32.28 12.2 6.001 13.52 11.721C14.84 17.441 12.2 43.841 12.2 43.841C46.44 34.741 16.16 36.361 43.88 40.321z").setFill(f).setStroke(s);
+	f = "#ea8e51";
+	g.createPath("M8.088 -33.392C6.792 -31.664 12.84 5.921 14.136 11.537C15.432 17.153 12.84 43.073 12.84 43.073C45.512 34.193 16.728 35.729 43.944 39.617C71.161 43.505 96.217 8.513 97.945 -0.992C99.673 -10.496 89.737 -22.16 89.737 -22.16C91.033 -25.184 86.281 -39.008 81.097 -48.08C75.913 -57.152 60.302 -56.195 43.08 -57.152C27.528 -58.016 9.384 -35.12 8.088 -33.392z").setFill(f).setStroke(s);
+	f = "#efaa7c";
+	g.createPath("M8.816 -32.744C7.544 -31.048 13.48 5.841 14.752 11.353C16.024 16.865 13.48 42.305 13.48 42.305C44.884 33.145 17.296 35.097 44.008 38.913C70.721 42.729 95.313 8.385 97.009 -0.944C98.705 -10.272 88.953 -21.72 88.953 -21.72C90.225 -24.688 85.561 -38.256 80.473 -47.16C75.385 -56.064 60.063 -55.125 43.16 -56.064C27.896 -56.912 10.088 -34.44 8.816 -32.744z").setFill(f).setStroke(s);
+	f = "#f4c6a8";
+	g.createPath("M9.544 -32.096C8.296 -30.432 14.12 5.761 15.368 11.169C16.616 16.577 14.12 41.537 14.12 41.537C43.556 32.497 17.864 34.465 44.072 38.209C70.281 41.953 94.409 8.257 96.073 -0.895C97.737 -10.048 88.169 -21.28 88.169 -21.28C89.417 -24.192 84.841 -37.504 79.849 -46.24C74.857 -54.976 59.824 -54.055 43.24 -54.976C28.264 -55.808 10.792 -33.76 9.544 -32.096z").setFill(f).setStroke(s);
+	f = "#f9e2d3";
+	g.createPath("M10.272 -31.448C9.048 -29.816 14.76 5.681 15.984 10.985C17.208 16.289 14.76 40.769 14.76 40.769C42.628 31.849 18.432 33.833 44.136 37.505C69.841 41.177 93.505 8.129 95.137 -0.848C96.769 -9.824 87.385 -20.84 87.385 -20.84C88.609 -23.696 84.121 -36.752 79.225 -45.32C74.329 -53.888 59.585 -52.985 43.32 -53.888C28.632 -54.704 11.496 -33.08 10.272 -31.448z").setFill(f).setStroke(s);
+	f = "#ffffff";
+	g.createPath("M44.2 36.8C69.4 40.4 92.601 8 94.201 -0.8C95.801 -9.6 86.601 -20.4 86.601 -20.4C87.801 -23.2 83.4 -36 78.6 -44.4C73.8 -52.8 59.346 -51.914 43.4 -52.8C29 -53.6 12.2 -32.4 11 -30.8C9.8 -29.2 15.4 5.6 16.6 10.8C17.8 16 15.4 40 15.4 40C40.9 31.4 19 33.2 44.2 36.8z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M90.601 2.8C90.601 2.8 62.8 10.4 51.2 8.8C51.2 8.8 35.4 2.2 26.6 24C26.6 24 23 31.2 21 33.2C19 35.2 90.601 2.8 90.601 2.8z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M94.401 0.6C94.401 0.6 65.4 12.8 55.4 12.4C55.4 12.4 39 7.8 30.6 22.4C30.6 22.4 22.2 31.6 19 33.2C19 33.2 18.6 34.8 25 30.8L35.4 36C35.4 36 50.2 45.6 59.8 29.6C59.8 29.6 63.8 18.4 63.8 16.4C63.8 14.4 85 8.8 86.601 8.4C88.201 8 94.801 3.8 94.401 0.6z").setFill(f).setStroke(s);
+	f = "#99cc32";
+	g.createPath("M47 36.514C40.128 36.514 31.755 32.649 31.755 26.4C31.755 20.152 40.128 13.887 47 13.887C53.874 13.887 59.446 18.952 59.446 25.2C59.446 31.449 53.874 36.514 47 36.514z").setFill(f).setStroke(s);
+	f = "#659900";
+	g.createPath("M43.377 19.83C38.531 20.552 33.442 22.055 33.514 21.839C35.054 17.22 41.415 13.887 47 13.887C51.296 13.887 55.084 15.865 57.32 18.875C57.32 18.875 52.004 18.545 43.377 19.83z").setFill(f).setStroke(s);
+	f = "#ffffff";
+	g.createPath("M55.4 19.6C55.4 19.6 51 16.4 51 18.6C51 18.6 54.6 23 55.4 19.6z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M45.4 27.726C42.901 27.726 40.875 25.7 40.875 23.2C40.875 20.701 42.901 18.675 45.4 18.675C47.9 18.675 49.926 20.701 49.926 23.2C49.926 25.7 47.9 27.726 45.4 27.726z").setFill(f).setStroke(s);
+	f = "#cc7226";
+	g.createPath("M-58.6 14.4C-58.6 14.4 -61.8 -6.8 -59.4 -11.2C-59.4 -11.2 -48.6 -21.2 -49 -24.8C-49 -24.8 -49.4 -42.8 -50.6 -43.6C-51.8 -44.4 -59.4 -50.4 -65.4 -44C-65.4 -44 -75.8 -26 -75 -19.6L-75 -17.6C-75 -17.6 -82.6 -18 -84.2 -16C-84.2 -16 -85.4 -10.8 -86.6 -10.4C-86.6 -10.4 -89.4 -8 -87.4 -5.2C-87.4 -5.2 -89.4 -2.8 -89 1.2L-81.4 5.2C-81.4 5.2 -79.4 19.6 -68.6 24.8C-63.764 27.129 -60.6 20.4 -58.6 14.4z").setFill(f).setStroke(s);
+	f = "#ffffff";
+	g.createPath("M-59.6 12.56C-59.6 12.56 -62.48 -6.52 -60.32 -10.48C-60.32 -10.48 -50.6 -19.48 -50.96 -22.72C-50.96 -22.72 -51.32 -38.92 -52.4 -39.64C-53.48 -40.36 -60.32 -45.76 -65.72 -40C-65.72 -40 -75.08 -23.8 -74.36 -18.04L-74.36 -16.24C-74.36 -16.24 -81.2 -16.6 -82.64 -14.8C-82.64 -14.8 -83.72 -10.12 -84.8 -9.76C-84.8 -9.76 -87.32 -7.6 -85.52 -5.08C-85.52 -5.08 -87.32 -2.92 -86.96 0.68L-80.12 4.28C-80.12 4.28 -78.32 17.24 -68.6 21.92C-64.248 24.015 -61.4 17.96 -59.6 12.56z").setFill(f).setStroke(s);
+	f = "#eb955c";
+	g.createPath("M-51.05 -42.61C-52.14 -43.47 -59.63 -49.24 -65.48 -43C-65.48 -43 -75.62 -25.45 -74.84 -19.21L-74.84 -17.26C-74.84 -17.26 -82.25 -17.65 -83.81 -15.7C-83.81 -15.7 -84.98 -10.63 -86.15 -10.24C-86.15 -10.24 -88.88 -7.9 -86.93 -5.17C-86.93 -5.17 -88.88 -2.83 -88.49 1.07L-81.08 4.97C-81.08 4.97 -79.13 19.01 -68.6 24.08C-63.886 26.35 -60.8 19.79 -58.85 13.94C-58.85 13.94 -61.97 -6.73 -59.63 -11.02C-59.63 -11.02 -49.1 -20.77 -49.49 -24.28C-49.49 -24.28 -49.88 -41.83 -51.05 -42.61z").setFill(f).setStroke(s);
+	f = "#f2b892";
+	g.createPath("M-51.5 -41.62C-52.48 -42.54 -59.86 -48.08 -65.56 -42C-65.56 -42 -75.44 -24.9 -74.68 -18.82L-74.68 -16.92C-74.68 -16.92 -81.9 -17.3 -83.42 -15.4C-83.42 -15.4 -84.56 -10.46 -85.7 -10.08C-85.7 -10.08 -88.36 -7.8 -86.46 -5.14C-86.46 -5.14 -88.36 -2.86 -87.98 0.94L-80.76 4.74C-80.76 4.74 -78.86 18.42 -68.6 23.36C-64.006 25.572 -61 19.18 -59.1 13.48C-59.1 13.48 -62.14 -6.66 -59.86 -10.84C-59.86 -10.84 -49.6 -20.34 -49.98 -23.76C-49.98 -23.76 -50.36 -40.86 -51.5 -41.62z").setFill(f).setStroke(s);
+	f = "#f8dcc8";
+	g.createPath("M-51.95 -40.63C-52.82 -41.61 -60.09 -46.92 -65.64 -41C-65.64 -41 -75.26 -24.35 -74.52 -18.43L-74.52 -16.58C-74.52 -16.58 -81.55 -16.95 -83.03 -15.1C-83.03 -15.1 -84.14 -10.29 -85.25 -9.92C-85.25 -9.92 -87.84 -7.7 -85.99 -5.11C-85.99 -5.11 -87.84 -2.89 -87.47 0.81L-80.44 4.51C-80.44 4.51 -78.59 17.83 -68.6 22.64C-64.127 24.794 -61.2 18.57 -59.35 13.02C-59.35 13.02 -62.31 -6.59 -60.09 -10.66C-60.09 -10.66 -50.1 -19.91 -50.47 -23.24C-50.47 -23.24 -50.84 -39.89 -51.95 -40.63z").setFill(f).setStroke(s);
+	f = "#ffffff";
+	g.createPath("M-59.6 12.46C-59.6 12.46 -62.48 -6.52 -60.32 -10.48C-60.32 -10.48 -50.6 -19.48 -50.96 -22.72C-50.96 -22.72 -51.32 -38.92 -52.4 -39.64C-53.16 -40.68 -60.32 -45.76 -65.72 -40C-65.72 -40 -75.08 -23.8 -74.36 -18.04L-74.36 -16.24C-74.36 -16.24 -81.2 -16.6 -82.64 -14.8C-82.64 -14.8 -83.72 -10.12 -84.8 -9.76C-84.8 -9.76 -87.32 -7.6 -85.52 -5.08C-85.52 -5.08 -87.32 -2.92 -86.96 0.68L-80.12 4.28C-80.12 4.28 -78.32 17.24 -68.6 21.92C-64.248 24.015 -61.4 17.86 -59.6 12.46z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-62.7 6.2C-62.7 6.2 -84.3 -4 -85.2 -4.8C-85.2 -4.8 -76.1 3.4 -75.3 3.4C-74.5 3.4 -62.7 6.2 -62.7 6.2z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-79.8 0C-79.8 0 -61.4 3.6 -61.4 8C-61.4 10.912 -61.643 24.331 -67 22.8C-75.4 20.4 -71.8 6 -79.8 0z").setFill(f).setStroke(s);
+	f = "#99cc32";
+	g.createPath("M-71.4 3.8C-71.4 3.8 -62.422 5.274 -61.4 8C-60.8 9.6 -60.137 17.908 -65.6 19C-70.152 19.911 -72.382 9.69 -71.4 3.8z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M14.595 46.349C14.098 44.607 15.409 44.738 17.2 44.2C19.2 43.6 31.4 39.8 32.2 37.2C33 34.6 46.2 39 46.2 39C48 39.8 52.4 42.4 52.4 42.4C57.2 43.6 63.8 44 63.8 44C66.2 45 69.6 47.8 69.6 47.8C84.2 58 96.601 50.8 96.601 50.8C116.601 44.2 110.601 27 110.601 27C107.601 18 110.801 14.6 110.801 14.6C111.001 10.8 118.201 17.2 118.201 17.2C120.801 21.4 121.601 26.4 121.601 26.4C129.601 37.6 126.201 19.8 126.201 19.8C126.401 18.8 123.601 15.2 123.601 14C123.601 12.8 121.801 9.4 121.801 9.4C118.801 6 121.201 -1 121.201 -1C123.001 -14.8 120.801 -13 120.801 -13C119.601 -14.8 110.401 -4.8 110.401 -4.8C108.201 -1.4 102.201 0.2 102.201 0.2C99.401 2 96.001 0.6 96.001 0.6C93.401 0.2 87.801 7.2 87.801 7.2C90.601 7 93.001 11.4 95.401 11.6C97.801 11.8 99.601 9.2 101.201 8.6C102.801 8 105.601 13.8 105.601 13.8C106.001 16.4 100.401 21.2 100.401 21.2C100.001 25.8 98.401 24.2 98.401 24.2C95.401 23.6 94.201 27.4 93.201 32C92.201 36.6 88.001 37 88.001 37C86.401 44.4 85.2 41.4 85.2 41.4C85 35.8 79 41.6 79 41.6C77.8 43.6 73.2 41.4 73.2 41.4C66.4 39.4 68.8 37.4 68.8 37.4C70.6 35.2 81.8 37.4 81.8 37.4C84 35.8 76 31.8 76 31.8C75.4 30 76.4 25.6 76.4 25.6C77.6 22.4 84.4 16.8 84.4 16.8C93.801 15.6 91.001 14 91.001 14C84.801 8.8 79 16.4 79 16.4C76.8 22.6 59.4 37.6 59.4 37.6C54.6 41 57.2 34.2 53.2 37.6C49.2 41 28.6 32 28.6 32C17.038 30.807 14.306 46.549 10.777 43.429C10.777 43.429 16.195 51.949 14.595 46.349z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M209.401 -120C209.401 -120 183.801 -112 181.001 -93.2C181.001 -93.2 178.601 -70.4 199.001 -52.8C199.001 -52.8 199.401 -46.4 201.401 -43.2C201.401 -43.2 199.801 -38.4 218.601 -46L245.801 -54.4C245.801 -54.4 252.201 -56.8 257.401 -65.6C262.601 -74.4 277.801 -93.2 274.201 -118.4C274.201 -118.4 275.401 -129.6 269.401 -130C269.401 -130 261.001 -131.6 253.801 -124C253.801 -124 247.001 -120.8 244.601 -121.2L209.401 -120z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M264.022 -120.99C264.022 -120.99 266.122 -129.92 261.282 -125.08C261.282 -125.08 254.242 -119.36 246.761 -119.36C246.761 -119.36 232.241 -117.16 227.841 -103.96C227.841 -103.96 223.881 -77.12 231.801 -71.4C231.801 -71.4 236.641 -63.92 243.681 -70.52C250.722 -77.12 266.222 -107.35 264.022 -120.99z").setFill(f).setStroke(s);
+	f = "#323232";
+	g.createPath("M263.648 -120.632C263.648 -120.632 265.738 -129.376 260.986 -124.624C260.986 -124.624 254.074 -119.008 246.729 -119.008C246.729 -119.008 232.473 -116.848 228.153 -103.888C228.153 -103.888 224.265 -77.536 232.041 -71.92C232.041 -71.92 236.793 -64.576 243.705 -71.056C250.618 -77.536 265.808 -107.24 263.648 -120.632z").setFill(f).setStroke(s);
+	f = "#666666";
+	g.createPath("M263.274 -120.274C263.274 -120.274 265.354 -128.832 260.69 -124.168C260.69 -124.168 253.906 -118.656 246.697 -118.656C246.697 -118.656 232.705 -116.536 228.465 -103.816C228.465 -103.816 224.649 -77.952 232.281 -72.44C232.281 -72.44 236.945 -65.232 243.729 -71.592C250.514 -77.952 265.394 -107.13 263.274 -120.274z").setFill(f).setStroke(s);
+	f = "#999999";
+	g.createPath("M262.9 -119.916C262.9 -119.916 264.97 -128.288 260.394 -123.712C260.394 -123.712 253.738 -118.304 246.665 -118.304C246.665 -118.304 232.937 -116.224 228.777 -103.744C228.777 -103.744 225.033 -78.368 232.521 -72.96C232.521 -72.96 237.097 -65.888 243.753 -72.128C250.41 -78.368 264.98 -107.02 262.9 -119.916z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M262.526 -119.558C262.526 -119.558 264.586 -127.744 260.098 -123.256C260.098 -123.256 253.569 -117.952 246.633 -117.952C246.633 -117.952 233.169 -115.912 229.089 -103.672C229.089 -103.672 225.417 -78.784 232.761 -73.48C232.761 -73.48 237.249 -66.544 243.777 -72.664C250.305 -78.784 264.566 -106.91 262.526 -119.558z").setFill(f).setStroke(s);
+	f = "#ffffff";
+	g.createPath("M262.151 -119.2C262.151 -119.2 264.201 -127.2 259.801 -122.8C259.801 -122.8 253.401 -117.6 246.601 -117.6C246.601 -117.6 233.401 -115.6 229.401 -103.6C229.401 -103.6 225.801 -79.2 233.001 -74C233.001 -74 237.401 -67.2 243.801 -73.2C250.201 -79.2 264.151 -106.8 262.151 -119.2z").setFill(f).setStroke(s);
+	f = "#992600";
+	g.createPath("M50.6 84C50.6 84 30.2 64.8 22.2 64C22.2 64 -12.2 60 -27 78C-27 78 -9.4 57.6 18.2 63.2C18.2 63.2 -3.4 58.8 -15.8 62C-15.8 62 -32.6 62 -42.2 76L-45 80.8C-45 80.8 -41 66 -22.6 60C-22.6 60 0.2 55.2 11 60C11 60 -10.6 53.2 -20.6 55.2C-20.6 55.2 -51 52.8 -63.8 79.2C-63.8 79.2 -59.8 64.8 -45 57.6C-45 57.6 -31.4 48.8 -11 51.6C-11 51.6 3.4 54.8 8.6 57.2C13.8 59.6 12.6 56.8 4.2 52C4.2 52 -1.4 42 -15.4 42.4C-15.4 42.4 -58.2 46 -68.6 58C-68.6 58 -55 46.8 -44.6 44C-44.6 44 -22.2 36 -13.8 36.8C-13.8 36.8 11 37.8 18.6 33.8C18.6 33.8 7.4 38.8 10.6 42C13.8 45.2 20.6 52.8 20.6 54C20.6 55.2 44.8 77.3 48.4 81.7L50.6 84z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M189 278C189 278 173.5 241.5 161 232C161 232 187 248 190.5 266C190.5 266 190.5 276 189 278z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M236 285.5C236 285.5 209.5 230.5 191 206.5C191 206.5 234.5 244 239.5 270.5L240 276L237 273.5C237 273.5 236.5 282.5 236 285.5z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M292.5 237C292.5 237 230 177.5 228.5 175C228.5 175 289 241 292 248.5C292 248.5 290 239.5 292.5 237z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M104 280.5C104 280.5 123.5 228.5 142.5 251C142.5 251 157.5 261 157 264C157 264 153 257.5 135 258C135 258 116 255 104 280.5z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M294.5 153C294.5 153 249.5 124.5 242 123C230.193 120.639 291.5 152 296.5 162.5C296.5 162.5 298.5 160 294.5 153z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M143.801 259.601C143.801 259.601 164.201 257.601 171.001 250.801L175.401 254.401L193.001 216.001L196.601 221.201C196.601 221.201 211.001 206.401 210.201 198.401C209.401 190.401 223.001 204.401 223.001 204.401C223.001 204.401 222.201 192.801 229.401 199.601C229.401 199.601 227.001 184.001 235.401 192.001C235.401 192.001 224.864 161.844 247.401 187.601C253.001 194.001 248.601 187.201 248.601 187.201C248.601 187.201 222.601 139.201 244.201 153.601C244.201 153.601 246.201 130.801 245.001 126.401C243.801 122.001 241.801 99.6 237.001 94.4C232.201 89.2 237.401 87.6 243.001 92.8C243.001 92.8 231.801 68.8 245.001 80.8C245.001 80.8 241.401 65.6 237.001 62.8C237.001 62.8 231.401 45.6 246.601 56.4C246.601 56.4 242.201 44 239.001 40.8C239.001 40.8 227.401 13.2 234.601 18L239.001 21.6C239.001 21.6 232.201 7.6 238.601 12C245.001 16.4 245.001 16 245.001 16C245.001 16 223.801 -17.2 244.201 0.4C244.201 0.4 236.042 -13.518 232.601 -20.4C232.601 -20.4 213.801 -40.8 228.201 -34.4L233.001 -32.8C233.001 -32.8 224.201 -42.8 216.201 -44.4C208.201 -46 218.601 -52.4 225.001 -50.4C231.401 -48.4 247.001 -40.8 247.001 -40.8C247.001 -40.8 259.801 -22 263.801 -21.6C263.801 -21.6 243.801 -29.2 249.801 -21.2C249.801 -21.2 264.201 -7.2 257.001 -7.6C257.001 -7.6 251.001 -0.4 255.801 8.4C255.801 8.4 237.342 -9.991 252.201 15.6L259.001 32C259.001 32 234.601 7.2 245.801 29.2C245.801 29.2 263.001 52.8 265.001 53.2C267.001 53.6 271.401 62.4 271.401 62.4L267.001 60.4L272.201 69.2C272.201 69.2 261.001 57.2 267.001 70.4L272.601 84.8C272.601 84.8 252.201 62.8 265.801 92.4C265.801 92.4 249.401 87.2 258.201 104.4C258.201 104.4 256.601 120.401 257.001 125.601C257.401 130.801 258.601 159.201 254.201 167.201C249.801 175.201 260.201 194.401 262.201 198.401C264.201 202.401 267.801 213.201 259.001 204.001C250.201 194.801 254.601 200.401 256.601 209.201C258.601 218.001 264.601 233.601 263.801 239.201C263.801 239.201 262.601 240.401 259.401 236.801C259.401 236.801 244.601 214.001 246.201 228.401C246.201 228.401 245.001 236.401 241.801 245.201C241.801 245.201 238.601 256.001 238.601 247.201C238.601 247.201 235.401 230.401 232.601 238.001C229.801 245.601 226.201 251.601 223.401 254.001C220.601 256.401 215.401 233.601 214.201 244.001C214.201 244.001 202.201 231.601 197.401 248.001L185.801 264.401C185.801 264.401 185.401 252.001 184.201 258.001C184.201 258.001 154.201 264.001 143.801 259.601z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M109.401 -97.2C109.401 -97.2 97.801 -105.2 93.801 -104.8C89.801 -104.4 121.401 -113.6 162.601 -86C162.601 -86 167.401 -83.2 171.001 -83.6C171.001 -83.6 174.201 -81.2 171.401 -77.6C171.401 -77.6 162.601 -68 173.801 -56.8C173.801 -56.8 192.201 -50 186.601 -58.8C186.601 -58.8 197.401 -54.8 199.801 -50.8C202.201 -46.8 201.001 -50.8 201.001 -50.8C201.001 -50.8 194.601 -58 188.601 -63.2C188.601 -63.2 183.401 -65.2 180.601 -73.6C177.801 -82 175.401 -92 179.801 -95.2C179.801 -95.2 175.801 -90.8 176.601 -94.8C177.401 -98.8 181.001 -102.4 182.601 -102.8C184.201 -103.2 200.601 -119 207.401 -119.4C207.401 -119.4 198.201 -118 195.201 -119C192.201 -120 165.601 -131.4 159.601 -132.6C159.601 -132.6 142.801 -139.2 154.801 -137.2C154.801 -137.2 190.601 -133.4 208.801 -120.2C208.801 -120.2 201.601 -128.6 183.201 -135.6C183.201 -135.6 161.001 -148.2 125.801 -143.2C125.801 -143.2 108.001 -140 100.201 -138.2C100.201 -138.2 97.601 -138.8 97.001 -139.2C96.401 -139.6 84.6 -148.6 57 -141.6C57 -141.6 40 -137 31.4 -132.2C31.4 -132.2 16.2 -131 12.6 -127.8C12.6 -127.8 -6 -113.2 -8 -112.4C-10 -111.6 -21.4 -104 -22.2 -103.6C-22.2 -103.6 2.4 -110.2 4.8 -112.6C7.2 -115 24.6 -117.6 27 -116.2C29.4 -114.8 37.8 -115.4 28.2 -114.8C28.2 -114.8 103.801 -100 104.601 -98C105.401 -96 109.401 -97.2 109.401 -97.2z").setFill(f).setStroke(s);
+	f = "#cc7226";
+	g.createPath("M180.801 -106.4C180.801 -106.4 170.601 -113.8 168.601 -113.8C166.601 -113.8 154.201 -124 150.001 -123.6C145.801 -123.2 133.601 -133.2 106.201 -125C106.201 -125 105.601 -127 109.201 -127.8C109.201 -127.8 115.601 -130 116.001 -130.6C116.001 -130.6 136.201 -134.8 143.401 -131.2C143.401 -131.2 152.601 -128.6 158.801 -122.4C158.801 -122.4 170.001 -119.2 173.201 -120.2C173.201 -120.2 182.001 -118 182.401 -116.2C182.401 -116.2 188.201 -113.2 186.401 -110.6C186.401 -110.6 186.801 -109 180.801 -106.4z").setFill(f).setStroke(s);
+	f = "#cc7226";
+	g.createPath("M168.33 -108.509C169.137 -107.877 170.156 -107.779 170.761 -106.97C170.995 -106.656 170.706 -106.33 170.391 -106.233C169.348 -105.916 168.292 -106.486 167.15 -105.898C166.748 -105.691 166.106 -105.873 165.553 -106.022C163.921 -106.463 162.092 -106.488 160.401 -105.8C158.416 -106.929 156.056 -106.345 153.975 -107.346C153.917 -107.373 153.695 -107.027 153.621 -107.054C150.575 -108.199 146.832 -107.916 144.401 -110.2C141.973 -110.612 139.616 -111.074 137.188 -111.754C135.37 -112.263 133.961 -113.252 132.341 -114.084C130.964 -114.792 129.507 -115.314 127.973 -115.686C126.11 -116.138 124.279 -116.026 122.386 -116.546C122.293 -116.571 122.101 -116.227 122.019 -116.254C121.695 -116.362 121.405 -116.945 121.234 -116.892C119.553 -116.37 118.065 -117.342 116.401 -117C115.223 -118.224 113.495 -117.979 111.949 -118.421C108.985 -119.269 105.831 -117.999 102.801 -119C106.914 -120.842 111.601 -119.61 115.663 -121.679C117.991 -122.865 120.653 -121.763 123.223 -122.523C123.71 -122.667 124.401 -122.869 124.801 -122.2C124.935 -122.335 125.117 -122.574 125.175 -122.546C127.625 -121.389 129.94 -120.115 132.422 -119.049C132.763 -118.903 133.295 -119.135 133.547 -118.933C135.067 -117.717 137.01 -117.82 138.401 -116.6C140.099 -117.102 141.892 -116.722 143.621 -117.346C143.698 -117.373 143.932 -117.032 143.965 -117.054C145.095 -117.802 146.25 -117.531 147.142 -117.227C147.48 -117.112 148.143 -116.865 148.448 -116.791C149.574 -116.515 150.43 -116.035 151.609 -115.852C151.723 -115.834 151.908 -116.174 151.98 -116.146C153.103 -115.708 154.145 -115.764 154.801 -114.6C154.936 -114.735 155.101 -114.973 155.183 -114.946C156.21 -114.608 156.859 -113.853 157.96 -113.612C158.445 -113.506 159.057 -112.88 159.633 -112.704C162.025 -111.973 163.868 -110.444 166.062 -109.549C166.821 -109.239 167.697 -109.005 168.33 -108.509z").setFill(f).setStroke(s);
+	f = "#cc7226";
+	g.createPath("M91.696 -122.739C89.178 -124.464 86.81 -125.57 84.368 -127.356C84.187 -127.489 83.827 -127.319 83.625 -127.441C82.618 -128.05 81.73 -128.631 80.748 -129.327C80.209 -129.709 79.388 -129.698 78.88 -129.956C76.336 -131.248 73.707 -131.806 71.2 -133C71.882 -133.638 73.004 -133.394 73.6 -134.2C73.795 -133.92 74.033 -133.636 74.386 -133.827C76.064 -134.731 77.914 -134.884 79.59 -134.794C81.294 -134.702 83.014 -134.397 84.789 -134.125C85.096 -134.078 85.295 -133.555 85.618 -133.458C87.846 -132.795 90.235 -133.32 92.354 -132.482C93.945 -131.853 95.515 -131.03 96.754 -129.755C97.006 -129.495 96.681 -129.194 96.401 -129C96.789 -129.109 97.062 -128.903 97.173 -128.59C97.257 -128.351 97.257 -128.049 97.173 -127.81C97.061 -127.498 96.782 -127.397 96.408 -127.346C95.001 -127.156 96.773 -128.536 96.073 -128.088C94.8 -127.274 95.546 -125.868 94.801 -124.6C94.521 -124.794 94.291 -125.012 94.401 -125.4C94.635 -124.878 94.033 -124.588 93.865 -124.272C93.48 -123.547 92.581 -122.132 91.696 -122.739z").setFill(f).setStroke(s);
+	f = "#cc7226";
+	g.createPath("M59.198 -115.391C56.044 -116.185 52.994 -116.07 49.978 -117.346C49.911 -117.374 49.688 -117.027 49.624 -117.054C48.258 -117.648 47.34 -118.614 46.264 -119.66C45.351 -120.548 43.693 -120.161 42.419 -120.648C42.095 -120.772 41.892 -121.284 41.591 -121.323C40.372 -121.48 39.445 -122.429 38.4 -123C40.736 -123.795 43.147 -123.764 45.609 -124.148C45.722 -124.166 45.867 -123.845 46 -123.845C46.136 -123.845 46.266 -124.066 46.4 -124.2C46.595 -123.92 46.897 -123.594 47.154 -123.848C47.702 -124.388 48.258 -124.198 48.798 -124.158C48.942 -124.148 49.067 -123.845 49.2 -123.845C49.336 -123.845 49.467 -124.156 49.6 -124.156C49.736 -124.155 49.867 -123.845 50 -123.845C50.136 -123.845 50.266 -124.066 50.4 -124.2C51.092 -123.418 51.977 -123.972 52.799 -123.793C53.837 -123.566 54.104 -122.418 55.178 -122.12C59.893 -120.816 64.03 -118.671 68.393 -116.584C68.7 -116.437 68.91 -116.189 68.8 -115.8C69.067 -115.8 69.38 -115.888 69.57 -115.756C70.628 -115.024 71.669 -114.476 72.366 -113.378C72.582 -113.039 72.253 -112.632 72.02 -112.684C67.591 -113.679 63.585 -114.287 59.198 -115.391z").setFill(f).setStroke(s);
+	f = "#cc7226";
+	g.createPath("M45.338 -71.179C43.746 -72.398 43.162 -74.429 42.034 -76.221C41.82 -76.561 42.094 -76.875 42.411 -76.964C42.971 -77.123 43.514 -76.645 43.923 -76.443C45.668 -75.581 47.203 -74.339 49.2 -74.2C51.19 -71.966 55.45 -71.581 55.457 -68.2C55.458 -67.341 54.03 -68.259 53.6 -67.4C51.149 -68.403 48.76 -68.3 46.38 -69.767C45.763 -70.148 46.093 -70.601 45.338 -71.179z").setFill(f).setStroke(s);
+	f = "#cc7226";
+	g.createPath("M17.8 -123.756C17.935 -123.755 24.966 -123.522 24.949 -123.408C24.904 -123.099 17.174 -122.05 16.81 -122.22C16.646 -122.296 9.134 -119.866 9 -120C9.268 -120.135 17.534 -123.756 17.8 -123.756z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M33.2 -114C33.2 -114 18.4 -112.2 14 -111C9.6 -109.8 -9 -102.2 -12 -100.2C-12 -100.2 -25.4 -94.8 -42.4 -74.8C-42.4 -74.8 -34.8 -78.2 -32.6 -81C-32.6 -81 -19 -93.6 -19.2 -91C-19.2 -91 -7 -99.6 -7.6 -97.4C-7.6 -97.4 16.8 -108.6 14.8 -105.4C14.8 -105.4 36.4 -110 35.4 -108C35.4 -108 54.2 -103.6 51.4 -103.4C51.4 -103.4 45.6 -102.2 52 -98.6C52 -98.6 48.6 -94.2 43.2 -98.2C37.8 -102.2 40.8 -100 35.8 -99C35.8 -99 33.2 -98.2 28.6 -102.2C28.6 -102.2 23 -106.8 14.2 -103.2C14.2 -103.2 -16.4 -90.6 -18.4 -90C-18.4 -90 -22 -87.2 -24.4 -83.6C-24.4 -83.6 -30.2 -79.2 -33.2 -77.8C-33.2 -77.8 -46 -66.2 -47.2 -64.8C-47.2 -64.8 -50.6 -59.6 -51.4 -59.2C-51.4 -59.2 -45 -63 -43 -65C-43 -65 -29 -75 -23.6 -75.8C-23.6 -75.8 -19.2 -78.8 -18.4 -80.2C-18.4 -80.2 -4 -89.4 0.2 -89.4C0.2 -89.4 9.4 -84.2 11.8 -91.2C11.8 -91.2 17.6 -93 23.2 -91.8C23.2 -91.8 26.4 -94.4 25.6 -96.6C25.6 -96.6 27.2 -98.4 28.2 -94.6C28.2 -94.6 31.6 -91 36.4 -93C36.4 -93 40.4 -93.2 38.4 -90.8C38.4 -90.8 34 -87 22.2 -86.8C22.2 -86.8 9.8 -86.2 -6.6 -78.6C-6.6 -78.6 -36.4 -68.2 -45.6 -57.8C-45.6 -57.8 -52 -49 -57.4 -47.8C-57.4 -47.8 -63.2 -47 -69.2 -39.6C-69.2 -39.6 -59.4 -45.4 -50.4 -45.4C-50.4 -45.4 -46.4 -47.8 -50.2 -44.2C-50.2 -44.2 -53.8 -36.6 -52.2 -31.2C-52.2 -31.2 -52.8 -26 -53.6 -24.4C-53.6 -24.4 -61.4 -11.6 -61.4 -9.2C-61.4 -6.8 -60.2 3 -59.8 3.6C-59.4 4.2 -60.8 2 -57 4.4C-53.2 6.8 -50.4 8.4 -49.6 11.2C-48.8 14 -51.6 5.8 -51.8 4C-52 2.2 -56.2 -5 -55.4 -7.4C-55.4 -7.4 -54.4 -6.4 -53.6 -5C-53.6 -5 -54.2 -5.6 -53.6 -9.2C-53.6 -9.2 -52.8 -14.4 -51.4 -17.6C-50 -20.8 -48 -24.6 -47.6 -25.4C-47.2 -26.2 -47.2 -32 -45.8 -29.4L-42.4 -26.8C-42.4 -26.8 -45.2 -29.4 -43 -31.6C-43 -31.6 -44 -37.2 -42.2 -39.8C-42.2 -39.8 -35.2 -48.2 -33.6 -49.2C-32 -50.2 -33.4 -49.8 -33.4 -49.8C-33.4 -49.8 -27.4 -54 -33.2 -52.4C-33.2 -52.4 -37.2 -50.8 -40.2 -50.8C-40.2 -50.8 -47.8 -48.8 -43.8 -53C-39.8 -57.2 -29.8 -62.6 -26 -62.4L-25.2 -60.8L-14 -63.2L-15.2 -62.4C-15.2 -62.4 -15.4 -62.6 -11.2 -63C-7 -63.4 -1.2 -62 0.2 -63.8C1.6 -65.6 5 -66.6 4.6 -65.2C4.2 -63.8 4 -61.8 4 -61.8C4 -61.8 9 -67.6 8.4 -65.4C7.8 -63.2 -0.4 -58 -1.8 -51.8L8.6 -60L12.2 -63C12.2 -63 15.8 -60.8 16 -62.4C16.2 -64 20.8 -69.8 22 -69.6C23.2 -69.4 25.2 -72.2 25 -69.6C24.8 -67 32.4 -61.6 32.4 -61.6C32.4 -61.6 35.6 -63.4 37 -62C38.4 -60.6 42.6 -81.8 42.6 -81.8L67.6 -92.4L111.201 -95.8L94.201 -102.6L33.2 -114z").setFill(f).setStroke(s);
+	s = {color: "#4c0000", width: 2}; f = null;
+	g.createPath("M51.4 85C51.4 85 36.4 68.2 28 65.6C28 65.6 14.6 58.8 -10 66.6").setFill(f).setStroke(s);
+	s = {color: "#4c0000", width: 2};
+	g.createPath("M24.8 64.2C24.8 64.2 -0.4 56.2 -15.8 60.4C-15.8 60.4 -34.2 62.4 -42.6 76.2").setFill(f).setStroke(s);
+	s = {color: "#4c0000", width: 2};
+	g.createPath("M21.2 63C21.2 63 4.2 55.8 -10.6 53.6C-10.6 53.6 -27.2 51 -43.8 58.2C-43.8 58.2 -56 64.2 -61.4 74.4").setFill(f).setStroke(s);
+	s = {color: "#4c0000", width: 2};
+	g.createPath("M22.2 63.4C22.2 63.4 6.8 52.4 5.8 51C5.8 51 -1.2 40 -14.2 39.6C-14.2 39.6 -35.6 40.4 -52.8 48.4").setFill(f).setStroke(s);
+	f = "#000000"; s = null;
+	g.createPath("M20.895 54.407C22.437 55.87 49.4 84.8 49.4 84.8C84.6 121.401 56.6 87.2 56.6 87.2C49 82.4 39.8 63.6 39.8 63.6C38.6 60.8 53.8 70.8 53.8 70.8C57.8 71.6 71.4 90.8 71.4 90.8C64.6 88.4 69.4 95.6 69.4 95.6C72.2 97.6 92.601 113.201 92.601 113.201C96.201 117.201 100.201 118.801 100.201 118.801C114.201 113.601 107.801 126.801 107.801 126.801C110.201 133.601 115.801 122.001 115.801 122.001C127.001 105.2 110.601 107.601 110.601 107.601C80.6 110.401 73.8 94.4 73.8 94.4C71.4 92 80.2 94.4 80.2 94.4C88.601 96.4 73 82 73 82C75.4 82 84.6 88.8 84.6 88.8C95.001 98 97.001 96 97.001 96C115.001 87.2 125.401 94.8 125.401 94.8C127.401 96.4 121.801 103.2 123.401 108.401C125.001 113.601 129.801 126.001 129.801 126.001C127.401 127.601 127.801 138.401 127.801 138.401C144.601 161.601 135.001 159.601 135.001 159.601C119.401 159.201 134.201 166.801 134.201 166.801C137.401 168.801 146.201 176.001 146.201 176.001C143.401 174.801 141.801 180.001 141.801 180.001C146.601 184.001 143.801 188.801 143.801 188.801C137.801 190.001 136.601 194.001 136.601 194.001C143.401 202.001 133.401 202.401 133.401 202.401C137.001 206.801 132.201 218.801 132.201 218.801C127.401 218.801 121.001 224.401 121.001 224.401C123.401 229.201 113.001 234.801 113.001 234.801C104.601 236.401 107.401 243.201 107.401 243.201C99.401 249.201 97.001 265.201 97.001 265.201C96.201 275.601 93.801 278.801 99.001 276.801C104.201 274.801 103.401 262.401 103.401 262.401C98.601 246.801 141.401 230.801 141.401 230.801C145.401 229.201 146.201 224.001 146.201 224.001C148.201 224.401 157.001 232.001 157.001 232.001C164.601 243.201 165.001 234.001 165.001 234.001C166.201 230.401 164.601 224.401 164.601 224.401C170.601 202.801 156.601 196.401 156.601 196.401C146.601 162.801 160.601 171.201 160.601 171.201C163.401 176.801 174.201 182.001 174.201 182.001L177.801 179.601C176.201 174.801 184.601 168.801 184.601 168.801C187.401 175.201 193.401 167.201 193.401 167.201C197.001 142.801 209.401 157.201 209.401 157.201C213.401 158.401 214.601 151.601 214.601 151.601C218.201 141.201 214.601 127.601 214.601 127.601C218.201 127.201 227.801 133.201 227.801 133.201C230.601 129.601 221.401 112.801 225.401 115.201C229.401 117.601 233.801 119.201 233.801 119.201C234.601 117.201 224.601 104.801 224.601 104.801C220.201 102 215.001 81.6 215.001 81.6C222.201 85.2 212.201 70 212.201 70C212.201 66.8 218.201 55.6 218.201 55.6C217.401 48.8 218.201 49.2 218.201 49.2C221.001 50.4 229.001 52 222.201 45.6C215.401 39.2 223.001 34.4 223.001 34.4C227.401 31.6 213.801 32 213.801 32C208.601 27.6 209.001 23.6 209.001 23.6C217.001 25.6 202.601 11.2 200.201 7.6C197.801 4 207.401 -1.2 207.401 -1.2C220.601 -4.8 209.001 -8 209.001 -8C189.401 -7.6 200.201 -18.4 200.201 -18.4C206.201 -18 204.601 -20.4 204.601 -20.4C199.401 -21.6 189.801 -28 189.801 -28C185.801 -31.6 189.401 -30.8 189.401 -30.8C206.201 -29.6 177.401 -40.8 177.401 -40.8C185.401 -40.8 167.401 -51.2 167.401 -51.2C165.401 -52.8 162.201 -60.4 162.201 -60.4C156.201 -65.6 151.401 -72.4 151.401 -72.4C151.001 -76.8 146.201 -81.6 146.201 -81.6C134.601 -95.2 129.001 -94.8 129.001 -94.8C114.201 -98.4 109.001 -97.6 109.001 -97.6L56.2 -93.2C29.8 -80.4 37.6 -59.4 37.6 -59.4C44 -51 53.2 -54.8 53.2 -54.8C57.8 -61 69.4 -58.8 69.4 -58.8C89.801 -55.6 87.201 -59.2 87.201 -59.2C84.801 -63.8 68.6 -70 68.4 -70.6C68.2 -71.2 59.4 -74.6 59.4 -74.6C56.4 -75.8 52 -85 52 -85C48.8 -88.4 64.6 -82.6 64.6 -82.6C63.4 -81.6 70.8 -77.6 70.8 -77.6C88.201 -78.6 98.801 -67.8 98.801 -67.8C109.601 -51.2 109.801 -59.4 109.801 -59.4C112.601 -68.8 100.801 -90 100.801 -90C101.201 -92 109.401 -85.4 109.401 -85.4C110.801 -87.4 111.601 -81.6 111.601 -81.6C111.801 -79.2 115.601 -71.2 115.601 -71.2C118.401 -58.2 122.001 -65.6 122.001 -65.6L126.601 -56.2C128.001 -53.6 122.001 -46 122.001 -46C121.801 -43.2 122.601 -43.4 117.001 -35.8C111.401 -28.2 114.801 -23.8 114.801 -23.8C113.401 -17.2 122.201 -17.6 122.201 -17.6C124.801 -15.4 128.201 -15.4 128.201 -15.4C130.001 -13.4 132.401 -14 132.401 -14C134.001 -17.8 140.201 -15.8 140.201 -15.8C141.601 -18.2 149.801 -18.6 149.801 -18.6C150.801 -21.2 151.201 -22.8 154.601 -23.4C158.001 -24 133.401 -67 133.401 -67C139.801 -67.8 131.601 -80.2 131.601 -80.2C129.401 -86.8 140.801 -72.2 143.001 -70.8C145.201 -69.4 146.201 -67.2 144.601 -67.4C143.001 -67.6 141.201 -65.4 142.601 -65.2C144.001 -65 157.001 -50 160.401 -39.8C163.801 -29.6 169.801 -25.6 176.001 -19.6C182.201 -13.6 181.401 10.6 181.401 10.6C181.001 19.4 187.001 30 187.001 30C189.001 33.8 184.801 52 184.801 52C182.801 54.2 184.201 55 184.201 55C185.201 56.2 192.001 69.4 192.001 69.4C190.201 69.2 193.801 72.8 193.801 72.8C199.001 78.8 192.601 75.8 192.601 75.8C186.601 74.2 193.601 84 193.601 84C194.801 85.8 185.801 81.2 185.801 81.2C176.601 80.6 188.201 87.8 188.201 87.8C196.801 95 185.401 90.6 185.401 90.6C180.801 88.8 184.001 95.6 184.001 95.6C187.201 97.2 204.401 104.2 204.401 104.2C204.801 108.001 201.801 113.001 201.801 113.001C202.201 117.001 200.001 120.401 200.001 120.401C198.801 128.601 198.201 129.401 198.201 129.401C194.001 129.601 186.601 143.401 186.601 143.401C184.801 146.001 174.601 158.001 174.601 158.001C172.601 165.001 154.601 157.801 154.601 157.801C148.001 161.201 150.001 157.801 150.001 157.801C149.601 155.601 154.401 149.601 154.401 149.601C161.401 147.001 158.801 136.201 158.801 136.201C162.801 134.801 151.601 132.001 151.801 130.801C152.001 129.601 157.801 128.201 157.801 128.201C165.801 126.201 161.401 123.801 161.401 123.801C160.801 119.801 163.801 114.201 163.801 114.201C175.401 113.401 163.801 97.2 163.801 97.2C153.001 89.6 152.001 83.8 152.001 83.8C164.601 75.6 156.401 63.2 156.601 59.6C156.801 56 158.001 34.4 158.001 34.4C156.001 28.2 153.001 14.6 153.001 14.6C155.201 9.4 162.601 -3.2 162.601 -3.2C165.401 -7.4 174.201 -12.2 172.001 -15.2C169.801 -18.2 162.001 -16.4 162.001 -16.4C154.201 -17.8 154.801 -12.6 154.801 -12.6C153.201 -11.6 152.401 -6.6 152.401 -6.6C151.68 1.333 142.801 7.6 142.801 7.6C131.601 13.8 140.801 17.8 140.801 17.8C146.801 24.4 137.001 24.6 137.001 24.6C126.001 22.8 134.201 33 134.201 33C145.001 45.8 142.001 48.6 142.001 48.6C131.801 49.6 144.401 58.8 144.401 58.8C144.401 58.8 143.601 56.8 143.801 58.6C144.001 60.4 147.001 64.6 147.801 66.6C148.601 68.6 144.601 68.8 144.601 68.8C145.201 78.4 129.801 74.2 129.801 74.2C129.801 74.2 129.801 74.2 128.201 74.4C126.601 74.6 115.401 73.8 109.601 71.6C103.801 69.4 97.001 69.4 97.001 69.4C97.001 69.4 93.001 71.2 85.4 71C77.8 70.8 69.8 73.6 69.8 73.6C65.4 73.2 74 68.8 74.2 69C74.4 69.2 80 63.6 72 64.2C50.203 65.835 39.4 55.6 39.4 55.6C37.4 54.2 34.8 51.4 34.8 51.4C24.8 49.4 36.2 63.8 36.2 63.8C37.4 65.2 36 66.2 36 66.2C35.2 64.6 27.4 59.2 27.4 59.2C24.589 58.227 23.226 56.893 20.895 54.407z").setFill(f).setStroke(s);
+	f = "#4c0000";
+	g.createPath("M-3 42.8C-3 42.8 8.6 48.4 11.2 51.2C13.8 54 27.8 65.4 27.8 65.4C27.8 65.4 22.4 63.4 19.8 61.6C17.2 59.8 6.4 51.6 6.4 51.6C6.4 51.6 2.6 45.6 -3 42.8z").setFill(f).setStroke(s);
+	f = "#99cc32";
+	g.createPath("M-61.009 11.603C-60.672 11.455 -61.196 8.743 -61.4 8.2C-62.422 5.474 -71.4 4 -71.4 4C-71.627 5.365 -71.682 6.961 -71.576 8.599C-71.576 8.599 -66.708 14.118 -61.009 11.603z").setFill(f).setStroke(s);
+	f = "#659900";
+	g.createPath("M-61.009 11.403C-61.458 11.561 -61.024 8.669 -61.2 8.2C-62.222 5.474 -71.4 3.9 -71.4 3.9C-71.627 5.265 -71.682 6.861 -71.576 8.499C-71.576 8.499 -67.308 13.618 -61.009 11.403z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-65.4 11.546C-66.025 11.546 -66.531 10.406 -66.531 9C-66.531 7.595 -66.025 6.455 -65.4 6.455C-64.775 6.455 -64.268 7.595 -64.268 9C-64.268 10.406 -64.775 11.546 -65.4 11.546z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-65.4 9z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-111 109.601C-111 109.601 -116.6 119.601 -91.8 113.601C-91.8 113.601 -77.8 112.401 -75.4 110.001C-74.2 110.801 -65.834 113.734 -63 114.401C-56.2 116.001 -47.8 106 -47.8 106C-47.8 106 -43.2 95.5 -40.4 95.5C-37.6 95.5 -40.8 97.1 -40.8 97.1C-40.8 97.1 -47.4 107.201 -47 108.801C-47 108.801 -52.2 128.801 -68.2 129.601C-68.2 129.601 -84.35 130.551 -83 136.401C-83 136.401 -74.2 134.001 -71.8 136.401C-71.8 136.401 -61 136.001 -69 142.401L-75.8 154.001C-75.8 154.001 -75.66 157.919 -85.8 154.401C-95.6 151.001 -105.9 138.101 -105.9 138.101C-105.9 138.101 -121.85 123.551 -111 109.601z").setFill(f).setStroke(s);
+	f = "#e59999";
+	g.createPath("M-112.2 113.601C-112.2 113.601 -114.2 123.201 -77.4 112.801C-77.4 112.801 -73 112.801 -70.6 113.601C-68.2 114.401 -56.2 117.201 -54.2 116.001C-54.2 116.001 -61.4 129.601 -73 128.001C-73 128.001 -86.2 129.601 -85.8 134.401C-85.8 134.401 -81.8 141.601 -77 144.001C-77 144.001 -74.2 146.401 -74.6 149.601C-75 152.801 -77.8 154.401 -79.8 155.201C-81.8 156.001 -85 152.801 -86.6 152.801C-88.2 152.801 -96.6 146.401 -101 141.601C-105.4 136.801 -113.8 124.801 -113.4 122.001C-113 119.201 -112.2 113.601 -112.2 113.601z").setFill(f).setStroke(s);
+	f = "#b26565";
+	g.createPath("M-109 131.051C-106.4 135.001 -103.2 139.201 -101 141.601C-96.6 146.401 -88.2 152.801 -86.6 152.801C-85 152.801 -81.8 156.001 -79.8 155.201C-77.8 154.401 -75 152.801 -74.6 149.601C-74.2 146.401 -77 144.001 -77 144.001C-80.066 142.468 -82.806 138.976 -84.385 136.653C-84.385 136.653 -84.2 139.201 -89.4 138.401C-94.6 137.601 -99.8 134.801 -101.4 131.601C-103 128.401 -105.4 126.001 -103.8 129.601C-102.2 133.201 -99.8 136.801 -98.2 137.201C-96.6 137.601 -97 138.801 -99.4 138.401C-101.8 138.001 -104.6 137.601 -109 132.401z").setFill(f).setStroke(s);
+	f = "#992600";
+	g.createPath("M-111.6 110.001C-111.6 110.001 -109.8 96.4 -108.6 92.4C-108.6 92.4 -109.4 85.6 -107 81.4C-104.6 77.2 -102.6 71 -99.6 65.6C-96.6 60.2 -96.4 56.2 -92.4 54.6C-88.4 53 -82.4 44.4 -79.6 43.4C-76.8 42.4 -77 43.2 -77 43.2C-77 43.2 -70.2 28.4 -56.6 32.4C-56.6 32.4 -72.8 29.6 -57 20.2C-57 20.2 -61.8 21.3 -58.5 14.3C-56.299 9.632 -56.8 16.4 -67.8 28.2C-67.8 28.2 -72.8 36.8 -78 39.8C-83.2 42.8 -95.2 49.8 -96.4 53.6C-97.6 57.4 -100.8 63.2 -102.8 64.8C-104.8 66.4 -107.6 70.6 -108 74C-108 74 -109.2 78 -110.6 79.2C-112 80.4 -112.2 83.6 -112.2 85.6C-112.2 87.6 -114.2 90.4 -114 92.8C-114 92.8 -113.2 111.801 -113.6 113.801L-111.6 110.001z").setFill(f).setStroke(s);
+	f = "#ffffff";
+	g.createPath("M-120.2 114.601C-120.2 114.601 -122.2 113.201 -126.6 119.201C-126.6 119.201 -119.3 152.201 -119.3 153.601C-119.3 153.601 -118.2 151.501 -119.5 144.301C-120.8 137.101 -121.7 124.401 -121.7 124.401L-120.2 114.601z").setFill(f).setStroke(s);
+	f = "#992600";
+	g.createPath("M-98.6 54C-98.6 54 -116.2 57.2 -115.8 86.4L-116.6 111.201C-116.6 111.201 -117.8 85.6 -119 84C-120.2 82.4 -116.2 71.2 -119.4 77.2C-119.4 77.2 -133.4 91.2 -125.4 112.401C-125.4 112.401 -123.9 115.701 -126.9 111.101C-126.9 111.101 -131.5 98.5 -130.4 92.1C-130.4 92.1 -130.2 89.9 -128.3 87.1C-128.3 87.1 -119.7 75.4 -117 73.1C-117 73.1 -115.2 58.7 -99.8 53.5C-99.8 53.5 -94.1 51.2 -98.6 54z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M40.8 -12.2C41.46 -12.554 41.451 -13.524 42.031 -13.697C43.18 -14.041 43.344 -15.108 43.862 -15.892C44.735 -17.211 44.928 -18.744 45.51 -20.235C45.782 -20.935 45.809 -21.89 45.496 -22.55C44.322 -25.031 43.62 -27.48 42.178 -29.906C41.91 -30.356 41.648 -31.15 41.447 -31.748C40.984 -33.132 39.727 -34.123 38.867 -35.443C38.579 -35.884 39.104 -36.809 38.388 -36.893C37.491 -36.998 36.042 -37.578 35.809 -36.552C35.221 -33.965 36.232 -31.442 37.2 -29C36.418 -28.308 36.752 -27.387 36.904 -26.62C37.614 -23.014 36.416 -19.662 35.655 -16.188C35.632 -16.084 35.974 -15.886 35.946 -15.824C34.724 -13.138 33.272 -10.693 31.453 -8.312C30.695 -7.32 29.823 -6.404 29.326 -5.341C28.958 -4.554 28.55 -3.588 28.8 -2.6C25.365 0.18 23.115 4.025 20.504 7.871C20.042 8.551 20.333 9.76 20.884 10.029C21.697 10.427 22.653 9.403 23.123 8.557C23.512 7.859 23.865 7.209 24.356 6.566C24.489 6.391 24.31 5.972 24.445 5.851C27.078 3.504 28.747 0.568 31.2 -1.8C33.15 -2.129 34.687 -3.127 36.435 -4.14C36.743 -4.319 37.267 -4.07 37.557 -4.265C39.31 -5.442 39.308 -7.478 39.414 -9.388C39.464 -10.272 39.66 -11.589 40.8 -12.2z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M31.959 -16.666C32.083 -16.743 31.928 -17.166 32.037 -17.382C32.199 -17.706 32.602 -17.894 32.764 -18.218C32.873 -18.434 32.71 -18.814 32.846 -18.956C35.179 -21.403 35.436 -24.427 34.4 -27.4C35.424 -28.02 35.485 -29.282 35.06 -30.129C34.207 -31.829 34.014 -33.755 33.039 -35.298C32.237 -36.567 30.659 -37.811 29.288 -36.508C28.867 -36.108 28.546 -35.321 28.824 -34.609C28.888 -34.446 29.173 -34.3 29.146 -34.218C29.039 -33.894 28.493 -33.67 28.487 -33.398C28.457 -31.902 27.503 -30.391 28.133 -29.062C28.905 -27.433 29.724 -25.576 30.4 -23.8C29.166 -21.684 30.199 -19.235 28.446 -17.358C28.31 -17.212 28.319 -16.826 28.441 -16.624C28.733 -16.138 29.139 -15.732 29.625 -15.44C29.827 -15.319 30.175 -15.317 30.375 -15.441C30.953 -15.803 31.351 -16.29 31.959 -16.666z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M94.771 -26.977C96.16 -25.185 96.45 -22.39 94.401 -21C94.951 -17.691 98.302 -19.67 100.401 -20.2C100.292 -20.588 100.519 -20.932 100.802 -20.937C101.859 -20.952 102.539 -21.984 103.601 -21.8C104.035 -23.357 105.673 -24.059 106.317 -25.439C108.043 -29.134 107.452 -33.407 104.868 -36.653C104.666 -36.907 104.883 -37.424 104.759 -37.786C104.003 -39.997 101.935 -40.312 100.001 -41C98.824 -44.875 98.163 -48.906 96.401 -52.6C94.787 -52.85 94.089 -54.589 92.752 -55.309C91.419 -56.028 90.851 -54.449 90.892 -53.403C90.899 -53.198 91.351 -52.974 91.181 -52.609C91.105 -52.445 90.845 -52.334 90.845 -52.2C90.846 -52.065 91.067 -51.934 91.201 -51.8C90.283 -50.98 88.86 -50.503 88.565 -49.358C87.611 -45.648 90.184 -42.523 91.852 -39.322C92.443 -38.187 91.707 -36.916 90.947 -35.708C90.509 -35.013 90.617 -33.886 90.893 -33.03C91.645 -30.699 93.236 -28.96 94.771 -26.977z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M57.611 -8.591C56.124 -6.74 52.712 -4.171 55.629 -2.243C55.823 -2.114 56.193 -2.11 56.366 -2.244C58.387 -3.809 60.39 -4.712 62.826 -5.294C62.95 -5.323 63.224 -4.856 63.593 -5.017C65.206 -5.72 67.216 -5.662 68.4 -7C72.167 -6.776 75.732 -7.892 79.123 -9.2C80.284 -9.648 81.554 -10.207 82.755 -10.709C84.131 -11.285 85.335 -12.213 86.447 -13.354C86.58 -13.49 86.934 -13.4 87.201 -13.4C87.161 -14.263 88.123 -14.39 88.37 -15.012C88.462 -15.244 88.312 -15.64 88.445 -15.742C90.583 -17.372 91.503 -19.39 90.334 -21.767C90.049 -22.345 89.8 -22.963 89.234 -23.439C88.149 -24.35 87.047 -23.496 86 -23.8C85.841 -23.172 85.112 -23.344 84.726 -23.146C83.867 -22.707 82.534 -23.292 81.675 -22.854C80.313 -22.159 79.072 -21.99 77.65 -21.613C77.338 -21.531 76.56 -21.627 76.4 -21C76.266 -21.134 76.118 -21.368 76.012 -21.346C74.104 -20.95 72.844 -20.736 71.543 -19.044C71.44 -18.911 70.998 -19.09 70.839 -18.955C69.882 -18.147 69.477 -16.913 68.376 -16.241C68.175 -16.118 67.823 -16.286 67.629 -16.157C66.983 -15.726 66.616 -15.085 65.974 -14.638C65.645 -14.409 65.245 -14.734 65.277 -14.99C65.522 -16.937 66.175 -18.724 65.6 -20.6C67.677 -23.12 70.194 -25.069 72 -27.8C72.015 -29.966 72.707 -32.112 72.594 -34.189C72.584 -34.382 72.296 -35.115 72.17 -35.462C71.858 -36.316 72.764 -37.382 71.92 -38.106C70.516 -39.309 69.224 -38.433 68.4 -37C66.562 -36.61 64.496 -35.917 62.918 -37.151C61.911 -37.938 61.333 -38.844 60.534 -39.9C59.549 -41.202 59.884 -42.638 59.954 -44.202C59.96 -44.33 59.645 -44.466 59.645 -44.6C59.646 -44.735 59.866 -44.866 60 -45C59.294 -45.626 59.019 -46.684 58 -47C58.305 -48.092 57.629 -48.976 56.758 -49.278C54.763 -49.969 53.086 -48.057 51.194 -47.984C50.68 -47.965 50.213 -49.003 49.564 -49.328C49.132 -49.544 48.428 -49.577 48.066 -49.311C47.378 -48.807 46.789 -48.693 46.031 -48.488C44.414 -48.052 43.136 -46.958 41.656 -46.103C40.171 -45.246 39.216 -43.809 38.136 -42.489C37.195 -41.337 37.059 -38.923 38.479 -38.423C40.322 -37.773 41.626 -40.476 43.592 -40.15C43.904 -40.099 44.11 -39.788 44 -39.4C44.389 -39.291 44.607 -39.52 44.8 -39.8C45.658 -38.781 46.822 -38.444 47.76 -37.571C48.73 -36.667 50.476 -37.085 51.491 -36.088C53.02 -34.586 52.461 -31.905 54.4 -30.6C53.814 -29.287 53.207 -28.01 52.872 -26.583C52.59 -25.377 53.584 -24.18 54.795 -24.271C56.053 -24.365 56.315 -25.124 56.8 -26.2C57.067 -25.933 57.536 -25.636 57.495 -25.42C57.038 -23.033 56.011 -21.04 55.553 -18.609C55.494 -18.292 55.189 -18.09 54.8 -18.2C54.332 -14.051 50.28 -11.657 47.735 -8.492C47.332 -7.99 47.328 -6.741 47.737 -6.338C49.14 -4.951 51.1 -6.497 52.8 -7C53.013 -8.206 53.872 -9.148 55.204 -9.092C55.46 -9.082 55.695 -9.624 56.019 -9.754C56.367 -9.892 56.869 -9.668 57.155 -9.866C58.884 -11.061 60.292 -12.167 62.03 -13.356C62.222 -13.487 62.566 -13.328 62.782 -13.436C63.107 -13.598 63.294 -13.985 63.617 -14.17C63.965 -14.37 64.207 -14.08 64.4 -13.8C63.754 -13.451 63.75 -12.494 63.168 -12.292C62.393 -12.024 61.832 -11.511 61.158 -11.064C60.866 -10.871 60.207 -11.119 60.103 -10.94C59.505 -9.912 58.321 -9.474 57.611 -8.591z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M2.2 -58C2.2 -58 -7.038 -60.872 -18.2 -35.2C-18.2 -35.2 -20.6 -30 -23 -28C-25.4 -26 -36.6 -22.4 -38.6 -18.4L-49 -2.4C-49 -2.4 -34.2 -18.4 -31 -20.8C-31 -20.8 -23 -29.2 -26.2 -22.4C-26.2 -22.4 -40.2 -11.6 -39 -2.4C-39 -2.4 -44.6 12 -45.4 14C-45.4 14 -29.4 -18 -27 -19.2C-24.6 -20.4 -23.4 -20.4 -24.6 -16.8C-25.8 -13.2 -26.2 3.2 -29 5.2C-29 5.2 -21 -15.2 -21.8 -18.4C-21.8 -18.4 -18.6 -22 -16.2 -16.8L-17.4 -0.8L-13 11.2C-13 11.2 -15.4 0 -13.8 -15.6C-13.8 -15.6 -15.8 -26 -11.8 -20.4C-7.8 -14.8 1.8 -8.8 1.8 -4C1.8 -4 -3.4 -21.6 -12.6 -26.4L-16.6 -20.4L-17.8 -22.4C-17.8 -22.4 -21.4 -23.2 -17 -30C-12.6 -36.8 -13 -37.6 -13 -37.6C-13 -37.6 -6.6 -30.4 -5 -30.4C-5 -30.4 8.2 -38 9.4 -13.6C9.4 -13.6 16.2 -28 7 -34.8C7 -34.8 -7.8 -36.8 -6.6 -42L0.6 -54.4C4.2 -59.6 2.6 -56.8 2.6 -56.8z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-17.8 -41.6C-17.8 -41.6 -30.6 -41.6 -33.8 -36.4L-41 -26.8C-41 -26.8 -23.8 -36.8 -19.8 -38C-15.8 -39.2 -17.8 -41.6 -17.8 -41.6z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-57.8 -35.2C-57.8 -35.2 -59.8 -34 -60.2 -31.2C-60.6 -28.4 -63 -28 -62.2 -25.2C-61.4 -22.4 -59.4 -20 -59.4 -24C-59.4 -28 -57.8 -30 -57 -31.2C-56.2 -32.4 -54.6 -36.8 -57.8 -35.2z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-66.6 26C-66.6 26 -75 22 -78.2 18.4C-81.4 14.8 -80.948 19.966 -85.8 19.6C-91.647 19.159 -90.6 3.2 -90.6 3.2L-94.6 10.8C-94.6 10.8 -95.8 25.2 -87.8 22.8C-83.893 21.628 -82.6 23.2 -84.2 24C-85.8 24.8 -78.6 25.2 -81.4 26.8C-84.2 28.4 -69.8 23.2 -72.2 33.6L-66.6 26z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-79.2 40.4C-79.2 40.4 -94.6 44.8 -98.2 35.2C-98.2 35.2 -103 37.6 -100.8 40.6C-98.6 43.6 -97.4 44 -97.4 44C-97.4 44 -92 45.2 -92.6 46C-93.2 46.8 -95.6 50.2 -95.6 50.2C-95.6 50.2 -85.4 44.2 -79.2 40.4z").setFill(f).setStroke(s);
+	f = "#ffffff";
+	g.createPath("M149.201 118.601C148.774 120.735 147.103 121.536 145.201 122.201C143.284 121.243 140.686 118.137 138.801 120.201C138.327 119.721 137.548 119.661 137.204 118.999C136.739 118.101 137.011 117.055 136.669 116.257C136.124 114.985 135.415 113.619 135.601 112.201C137.407 111.489 138.002 109.583 137.528 107.82C137.459 107.563 137.03 107.366 137.23 107.017C137.416 106.694 137.734 106.467 138.001 106.2C137.866 106.335 137.721 106.568 137.61 106.548C137 106.442 137.124 105.805 137.254 105.418C137.839 103.672 139.853 103.408 141.201 104.6C141.457 104.035 141.966 104.229 142.401 104.2C142.351 103.621 142.759 103.094 142.957 102.674C143.475 101.576 145.104 102.682 145.901 102.07C146.977 101.245 148.04 100.546 149.118 101.149C150.927 102.162 152.636 103.374 153.835 105.115C154.41 105.949 154.65 107.23 154.592 108.188C154.554 108.835 153.173 108.483 152.83 109.412C152.185 111.16 154.016 111.679 154.772 113.017C154.97 113.366 154.706 113.67 154.391 113.768C153.98 113.896 153.196 113.707 153.334 114.16C154.306 117.353 151.55 118.031 149.201 118.601z").setFill(f).setStroke(s);
+	f = "#ffffff";
+	g.createPath("M139.6 138.201C139.593 136.463 137.992 134.707 139.201 133.001C139.336 133.135 139.467 133.356 139.601 133.356C139.736 133.356 139.867 133.135 140.001 133.001C141.496 135.217 145.148 136.145 145.006 138.991C144.984 139.438 143.897 140.356 144.801 141.001C142.988 142.349 142.933 144.719 142.001 146.601C140.763 146.315 139.551 145.952 138.401 145.401C138.753 143.915 138.636 142.231 139.456 140.911C139.89 140.213 139.603 139.134 139.6 138.201z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-26.6 129.201C-26.6 129.201 -43.458 139.337 -29.4 124.001C-20.6 114.401 -10.6 108.801 -10.6 108.801C-10.6 108.801 -0.2 104.4 3.4 103.2C7 102 22.2 96.8 25.4 96.4C28.6 96 38.2 92 45 96C51.8 100 59.8 104.4 59.8 104.4C59.8 104.4 43.4 96 39.8 98.4C36.2 100.8 29 100.4 23 103.6C23 103.6 8.2 108.001 5 110.001C1.8 112.001 -8.6 123.601 -10.2 122.801C-11.8 122.001 -9.8 121.601 -8.6 118.801C-7.4 116.001 -9.4 114.401 -17.4 120.801C-25.4 127.201 -26.6 129.201 -26.6 129.201z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-19.195 123.234C-19.195 123.234 -17.785 110.194 -9.307 111.859C-9.307 111.859 -1.081 107.689 1.641 105.721C1.641 105.721 9.78 104.019 11.09 103.402C29.569 94.702 44.288 99.221 44.835 98.101C45.381 96.982 65.006 104.099 68.615 108.185C69.006 108.628 58.384 102.588 48.686 100.697C40.413 99.083 18.811 100.944 7.905 106.48C4.932 107.989 -4.013 113.773 -6.544 113.662C-9.075 113.55 -19.195 123.234 -19.195 123.234z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-23 148.801C-23 148.801 -38.2 146.401 -21.4 144.801C-21.4 144.801 -3.4 142.801 0.6 137.601C0.6 137.601 14.2 128.401 17 128.001C19.8 127.601 49.8 120.401 50.2 118.001C50.6 115.601 56.2 115.601 57.8 116.401C59.4 117.201 58.6 118.401 55.8 119.201C53 120.001 21.8 136.401 15.4 137.601C9 138.801 -2.6 146.401 -7.4 147.601C-12.2 148.801 -23 148.801 -23 148.801z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-3.48 141.403C-3.48 141.403 -12.062 140.574 -3.461 139.755C-3.461 139.755 5.355 136.331 7.403 133.668C7.403 133.668 14.367 128.957 15.8 128.753C17.234 128.548 31.194 124.861 31.399 123.633C31.604 122.404 65.67 109.823 70.09 113.013C73.001 115.114 63.1 113.437 53.466 117.847C52.111 118.467 18.258 133.054 14.981 133.668C11.704 134.283 5.765 138.174 3.307 138.788C0.85 139.403 -3.48 141.403 -3.48 141.403z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-11.4 143.601C-11.4 143.601 -6.2 143.201 -7.4 144.801C-8.6 146.401 -11 145.601 -11 145.601L-11.4 143.601z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-18.6 145.201C-18.6 145.201 -13.4 144.801 -14.6 146.401C-15.8 148.001 -18.2 147.201 -18.2 147.201L-18.6 145.201z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-29 146.801C-29 146.801 -23.8 146.401 -25 148.001C-26.2 149.601 -28.6 148.801 -28.6 148.801L-29 146.801z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-36.6 147.601C-36.6 147.601 -31.4 147.201 -32.6 148.801C-33.8 150.401 -36.2 149.601 -36.2 149.601L-36.6 147.601z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M1.8 108.001C1.8 108.001 6.2 108.001 5 109.601C3.8 111.201 0.6 110.801 0.6 110.801L1.8 108.001z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-8.2 113.601C-8.2 113.601 -1.694 111.46 -4.2 114.801C-5.4 116.401 -7.8 115.601 -7.8 115.601L-8.2 113.601z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-19.4 118.401C-19.4 118.401 -14.2 118.001 -15.4 119.601C-16.6 121.201 -19 120.401 -19 120.401L-19.4 118.401z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-27 124.401C-27 124.401 -21.8 124.001 -23 125.601C-24.2 127.201 -26.6 126.401 -26.6 126.401L-27 124.401z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-33.8 129.201C-33.8 129.201 -28.6 128.801 -29.8 130.401C-31 132.001 -33.4 131.201 -33.4 131.201L-33.8 129.201z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M5.282 135.598C5.282 135.598 12.203 135.066 10.606 137.195C9.009 139.325 5.814 138.26 5.814 138.26L5.282 135.598z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M15.682 130.798C15.682 130.798 22.603 130.266 21.006 132.395C19.409 134.525 16.214 133.46 16.214 133.46L15.682 130.798z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M26.482 126.398C26.482 126.398 33.403 125.866 31.806 127.995C30.209 130.125 27.014 129.06 27.014 129.06L26.482 126.398z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M36.882 121.598C36.882 121.598 43.803 121.066 42.206 123.195C40.609 125.325 37.414 124.26 37.414 124.26L36.882 121.598z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M9.282 103.598C9.282 103.598 16.203 103.066 14.606 105.195C13.009 107.325 9.014 107.06 9.014 107.06L9.282 103.598z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M19.282 100.398C19.282 100.398 26.203 99.866 24.606 101.995C23.009 104.125 18.614 103.86 18.614 103.86L19.282 100.398z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-3.4 140.401C-3.4 140.401 1.8 140.001 0.6 141.601C-0.6 143.201 -3 142.401 -3 142.401L-3.4 140.401z").setFill(f).setStroke(s);
+	f = "#992600";
+	g.createPath("M-76.6 41.2C-76.6 41.2 -81 50 -81.4 53.2C-81.4 53.2 -80.6 44.4 -79.4 42.4C-78.2 40.4 -76.6 41.2 -76.6 41.2z").setFill(f).setStroke(s);
+	f = "#992600";
+	g.createPath("M-95 55.2C-95 55.2 -98.2 69.6 -97.8 72.4C-97.8 72.4 -99 60.8 -98.6 59.6C-98.2 58.4 -95 55.2 -95 55.2z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-74.2 -19.4L-74.4 -16.2L-76.6 -16C-76.6 -16 -62.4 -3.4 -61.8 4.2C-61.8 4.2 -61 -4 -74.2 -19.4z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-70.216 -18.135C-70.647 -18.551 -70.428 -19.296 -70.836 -19.556C-71.645 -20.072 -69.538 -20.129 -69.766 -20.845C-70.149 -22.051 -69.962 -22.072 -70.084 -23.348C-70.141 -23.946 -69.553 -25.486 -69.168 -25.926C-67.722 -27.578 -69.046 -30.51 -67.406 -32.061C-67.102 -32.35 -66.726 -32.902 -66.441 -33.32C-65.782 -34.283 -64.598 -34.771 -63.648 -35.599C-63.33 -35.875 -63.531 -36.702 -62.962 -36.61C-62.248 -36.495 -61.007 -36.625 -61.052 -35.784C-61.165 -33.664 -62.494 -31.944 -63.774 -30.276C-63.323 -29.572 -63.781 -28.937 -64.065 -28.38C-65.4 -25.76 -65.211 -22.919 -65.385 -20.079C-65.39 -19.994 -65.697 -19.916 -65.689 -19.863C-65.336 -17.528 -64.752 -15.329 -63.873 -13.1C-63.507 -12.17 -63.036 -11.275 -62.886 -10.348C-62.775 -9.662 -62.672 -8.829 -63.08 -8.124C-61.045 -5.234 -62.354 -2.583 -61.185 0.948C-60.978 1.573 -59.286 3.487 -59.749 3.326C-62.262 2.455 -62.374 2.057 -62.551 1.304C-62.697 0.681 -63.027 -0.696 -63.264 -1.298C-63.328 -1.462 -63.499 -3.346 -63.577 -3.468C-65.09 -5.85 -63.732 -5.674 -65.102 -8.032C-66.53 -8.712 -67.496 -9.816 -68.619 -10.978C-68.817 -11.182 -67.674 -11.906 -67.855 -12.119C-68.947 -13.408 -70.1 -14.175 -69.764 -15.668C-69.609 -16.358 -69.472 -17.415 -70.216 -18.135z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-73.8 -16.4C-73.8 -16.4 -73.4 -9.6 -71 -8C-68.6 -6.4 -69.8 -7.2 -73 -8.4C-76.2 -9.6 -75 -10.4 -75 -10.4C-75 -10.4 -77.8 -10 -75.4 -8C-73 -6 -69.4 -3.6 -71 -3.6C-72.6 -3.6 -80.2 -7.6 -80.2 -10.4C-80.2 -13.2 -81.2 -17.3 -81.2 -17.3C-81.2 -17.3 -80.1 -18.1 -75.3 -18C-75.3 -18 -73.9 -17.3 -73.8 -16.4z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M-74.6 2.2C-74.6 2.2 -83.12 -0.591 -101.6 2.8C-101.6 2.8 -92.569 0.722 -73.8 3C-63.5 4.25 -74.6 2.2 -74.6 2.2z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M-72.502 2.129C-72.502 2.129 -80.748 -1.389 -99.453 0.392C-99.453 0.392 -90.275 -0.897 -71.774 2.995C-61.62 5.131 -72.502 2.129 -72.502 2.129z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M-70.714 2.222C-70.714 2.222 -78.676 -1.899 -97.461 -1.514C-97.461 -1.514 -88.213 -2.118 -70.052 3.14C-60.086 6.025 -70.714 2.222 -70.714 2.222z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M-69.444 2.445C-69.444 2.445 -76.268 -1.862 -93.142 -2.96C-93.142 -2.96 -84.803 -2.79 -68.922 3.319C-60.206 6.672 -69.444 2.445 -69.444 2.445z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M45.84 12.961C45.84 12.961 44.91 13.605 45.124 12.424C45.339 11.243 73.547 -1.927 77.161 -1.677C77.161 -1.677 46.913 11.529 45.84 12.961z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M42.446 13.6C42.446 13.6 41.57 14.315 41.691 13.121C41.812 11.927 68.899 -3.418 72.521 -3.452C72.521 -3.452 43.404 12.089 42.446 13.6z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M39.16 14.975C39.16 14.975 38.332 15.747 38.374 14.547C38.416 13.348 58.233 -2.149 68.045 -4.023C68.045 -4.023 50.015 4.104 39.16 14.975z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M36.284 16.838C36.284 16.838 35.539 17.532 35.577 16.453C35.615 15.373 53.449 1.426 62.28 -0.26C62.28 -0.26 46.054 7.054 36.284 16.838z").setFill(f).setStroke(s);
+	f = "#cccccc"; s = null;
+	g.createPath("M4.6 164.801C4.6 164.801 -10.6 162.401 6.2 160.801C6.2 160.801 24.2 158.801 28.2 153.601C28.2 153.601 41.8 144.401 44.6 144.001C47.4 143.601 63.8 140.001 64.2 137.601C64.6 135.201 70.6 132.801 72.2 133.601C73.8 134.401 73.8 143.601 71 144.401C68.2 145.201 49.4 152.401 43 153.601C36.6 154.801 25 162.401 20.2 163.601C15.4 164.801 4.6 164.801 4.6 164.801z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M77.6 127.401C77.6 127.401 74.6 129.001 73.4 131.601C73.4 131.601 67 142.201 52.8 145.401C52.8 145.401 29.8 154.401 22 156.401C22 156.401 8.6 161.401 1.2 160.601C1.2 160.601 -5.8 160.801 0.4 162.401C0.4 162.401 20.6 160.401 24 158.601C24 158.601 39.6 153.401 42.6 150.801C45.6 148.201 63.8 143.201 66 141.201C68.2 139.201 78 130.801 77.6 127.401z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M18.882 158.911C18.882 158.911 24.111 158.685 22.958 160.234C21.805 161.784 19.357 160.91 19.357 160.91L18.882 158.911z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M11.68 160.263C11.68 160.263 16.908 160.037 15.756 161.586C14.603 163.136 12.155 162.263 12.155 162.263L11.68 160.263z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M1.251 161.511C1.251 161.511 6.48 161.284 5.327 162.834C4.174 164.383 1.726 163.51 1.726 163.51L1.251 161.511z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-6.383 162.055C-6.383 162.055 -1.154 161.829 -2.307 163.378C-3.46 164.928 -5.908 164.054 -5.908 164.054L-6.383 162.055z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M35.415 151.513C35.415 151.513 42.375 151.212 40.84 153.274C39.306 155.336 36.047 154.174 36.047 154.174L35.415 151.513z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M45.73 147.088C45.73 147.088 51.689 143.787 51.155 148.849C50.885 151.405 46.362 149.749 46.362 149.749L45.73 147.088z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M54.862 144.274C54.862 144.274 62.021 140.573 60.287 146.035C59.509 148.485 55.493 146.935 55.493 146.935L54.862 144.274z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M64.376 139.449C64.376 139.449 68.735 134.548 69.801 141.21C70.207 143.748 65.008 142.11 65.008 142.11L64.376 139.449z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M26.834 155.997C26.834 155.997 32.062 155.77 30.91 157.32C29.757 158.869 27.308 157.996 27.308 157.996L26.834 155.997z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M62.434 34.603C62.434 34.603 61.708 35.268 61.707 34.197C61.707 33.127 79.191 19.863 88.034 18.479C88.034 18.479 71.935 25.208 62.434 34.603z").setFill(f).setStroke(s);
+	f = "#000000"; s = null;
+	g.createPath("M65.4 98.4C65.4 98.4 87.401 120.801 96.601 124.401C96.601 124.401 105.801 135.601 101.801 161.601C101.801 161.601 98.601 169.201 95.401 148.401C95.401 148.401 98.601 123.201 87.401 139.201C87.401 139.201 79 129.301 85.4 129.601C85.4 129.601 88.601 131.601 89.001 130.001C89.401 128.401 81.4 114.801 64.2 100.4C47 86 65.4 98.4 65.4 98.4z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M7 137.201C7 137.201 6.8 135.401 8.6 136.201C10.4 137.001 104.601 143.201 136.201 167.201C136.201 167.201 91.001 144.001 7 137.201z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M17.4 132.801C17.4 132.801 17.2 131.001 19 131.801C20.8 132.601 157.401 131.601 181.001 164.001C181.001 164.001 159.001 138.801 17.4 132.801z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M29 128.801C29 128.801 28.8 127.001 30.6 127.801C32.4 128.601 205.801 115.601 229.401 148.001C229.401 148.001 219.801 122.401 29 128.801z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M39 124.001C39 124.001 38.8 122.201 40.6 123.001C42.4 123.801 164.601 85.2 188.201 117.601C188.201 117.601 174.801 93 39 124.001z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M-19 146.801C-19 146.801 -19.2 145.001 -17.4 145.801C-15.6 146.601 2.2 148.801 4.2 187.601C4.2 187.601 -3 145.601 -19 146.801z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M-27.8 148.401C-27.8 148.401 -28 146.601 -26.2 147.401C-24.4 148.201 -10.2 143.601 -13 182.401C-13 182.401 -11.8 147.201 -27.8 148.401z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M-35.8 148.801C-35.8 148.801 -36 147.001 -34.2 147.801C-32.4 148.601 -17 149.201 -29.4 171.601C-29.4 171.601 -19.8 147.601 -35.8 148.801z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M11.526 104.465C11.526 104.465 11.082 106.464 12.631 105.247C28.699 92.622 61.141 33.72 116.826 28.086C116.826 28.086 78.518 15.976 11.526 104.465z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M22.726 102.665C22.726 102.665 21.363 101.472 23.231 100.847C25.099 100.222 137.541 27.72 176.826 35.686C176.826 35.686 149.719 28.176 22.726 102.665z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M1.885 108.767C1.885 108.767 1.376 110.366 3.087 109.39C12.062 104.27 15.677 47.059 59.254 45.804C59.254 45.804 26.843 31.09 1.885 108.767z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M-18.038 119.793C-18.038 119.793 -19.115 121.079 -17.162 120.825C-6.916 119.493 14.489 78.222 58.928 83.301C58.928 83.301 26.962 68.955 -18.038 119.793z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M-6.8 113.667C-6.8 113.667 -7.611 115.136 -5.742 114.511C4.057 111.237 17.141 66.625 61.729 63.078C61.729 63.078 27.603 55.135 -6.8 113.667z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M-25.078 124.912C-25.078 124.912 -25.951 125.954 -24.369 125.748C-16.07 124.669 1.268 91.24 37.264 95.354C37.264 95.354 11.371 83.734 -25.078 124.912z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M-32.677 130.821C-32.677 130.821 -33.682 131.866 -32.091 131.748C-27.923 131.439 2.715 98.36 21.183 113.862C21.183 113.862 9.168 95.139 -32.677 130.821z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M36.855 98.898C36.855 98.898 35.654 97.543 37.586 97.158C39.518 96.774 160.221 39.061 198.184 51.927C198.184 51.927 172.243 41.053 36.855 98.898z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M3.4 163.201C3.4 163.201 3.2 161.401 5 162.201C6.8 163.001 22.2 163.601 9.8 186.001C9.8 186.001 19.4 162.001 3.4 163.201z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M13.8 161.601C13.8 161.601 13.6 159.801 15.4 160.601C17.2 161.401 35 163.601 37 202.401C37 202.401 29.8 160.401 13.8 161.601z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M20.6 160.001C20.6 160.001 20.4 158.201 22.2 159.001C24 159.801 48.6 163.201 72.2 195.601C72.2 195.601 36.6 158.801 20.6 160.001z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M28.225 157.972C28.225 157.972 27.788 156.214 29.678 156.768C31.568 157.322 52.002 155.423 90.099 189.599C90.099 189.599 43.924 154.656 28.225 157.972z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M38.625 153.572C38.625 153.572 38.188 151.814 40.078 152.368C41.968 152.922 76.802 157.423 128.499 192.399C128.499 192.399 54.324 150.256 38.625 153.572z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M-1.8 142.001C-1.8 142.001 -2 140.201 -0.2 141.001C1.6 141.801 55 144.401 85.4 171.201C85.4 171.201 50.499 146.426 -1.8 142.001z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M-11.8 146.001C-11.8 146.001 -12 144.201 -10.2 145.001C-8.4 145.801 16.2 149.201 39.8 181.601C39.8 181.601 4.2 144.801 -11.8 146.001z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M49.503 148.962C49.503 148.962 48.938 147.241 50.864 147.655C52.79 148.068 87.86 150.004 141.981 181.098C141.981 181.098 64.317 146.704 49.503 148.962z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M57.903 146.562C57.903 146.562 57.338 144.841 59.264 145.255C61.19 145.668 96.26 147.604 150.381 178.698C150.381 178.698 73.317 143.904 57.903 146.562z").setFill(f).setStroke(s);
+	f = "#ffffff"; s = {color: "#000000", width: 0.1};
+	g.createPath("M67.503 141.562C67.503 141.562 66.938 139.841 68.864 140.255C70.79 140.668 113.86 145.004 203.582 179.298C203.582 179.298 82.917 138.904 67.503 141.562z").setFill(f).setStroke(s);
+	f = "#000000"; s = null;
+	g.createPath("M-43.8 148.401C-43.8 148.401 -38.6 148.001 -39.8 149.601C-41 151.201 -43.4 150.401 -43.4 150.401L-43.8 148.401z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-13 162.401C-13 162.401 -7.8 162.001 -9 163.601C-10.2 165.201 -12.6 164.401 -12.6 164.401L-13 162.401z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-21.8 162.001C-21.8 162.001 -16.6 161.601 -17.8 163.201C-19 164.801 -21.4 164.001 -21.4 164.001L-21.8 162.001z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-117.169 150.182C-117.169 150.182 -112.124 151.505 -113.782 152.624C-115.439 153.744 -117.446 152.202 -117.446 152.202L-117.169 150.182z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-115.169 140.582C-115.169 140.582 -110.124 141.905 -111.782 143.024C-113.439 144.144 -115.446 142.602 -115.446 142.602L-115.169 140.582z").setFill(f).setStroke(s);
+	f = "#000000";
+	g.createPath("M-122.369 136.182C-122.369 136.182 -117.324 137.505 -118.982 138.624C-120.639 139.744 -122.646 138.202 -122.646 138.202L-122.369 136.182z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-42.6 211.201C-42.6 211.201 -44.2 211.201 -48.2 213.201C-50.2 213.201 -61.4 216.801 -67 226.801C-67 226.801 -54.6 217.201 -42.6 211.201z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M45.116 303.847C45.257 304.105 45.312 304.525 45.604 304.542C46.262 304.582 47.495 304.883 47.37 304.247C46.522 299.941 45.648 295.004 41.515 293.197C40.876 292.918 39.434 293.331 39.36 294.215C39.233 295.739 39.116 297.088 39.425 298.554C39.725 299.975 41.883 299.985 42.8 298.601C43.736 300.273 44.168 302.116 45.116 303.847z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M34.038 308.581C34.786 309.994 34.659 311.853 36.074 312.416C36.814 312.71 38.664 311.735 38.246 310.661C37.444 308.6 37.056 306.361 35.667 304.55C35.467 304.288 35.707 303.755 35.547 303.427C34.953 302.207 33.808 301.472 32.4 301.801C31.285 304.004 32.433 306.133 33.955 307.842C34.091 307.994 33.925 308.37 34.038 308.581z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-5.564 303.391C-5.672 303.014 -5.71 302.551 -5.545 302.23C-5.014 301.197 -4.221 300.075 -4.558 299.053C-4.906 297.997 -6.022 298.179 -6.672 298.748C-7.807 299.742 -7.856 301.568 -8.547 302.927C-8.743 303.313 -8.692 303.886 -9.133 304.277C-9.607 304.698 -10.047 306.222 -9.951 306.793C-9.898 307.106 -10.081 317.014 -9.859 316.751C-9.24 316.018 -6.19 306.284 -6.121 305.392C-6.064 304.661 -5.332 304.196 -5.564 303.391z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-31.202 296.599C-28.568 294.1 -25.778 291.139 -26.22 287.427C-26.336 286.451 -28.111 286.978 -28.298 287.824C-29.1 291.449 -31.139 294.11 -33.707 296.502C-35.903 298.549 -37.765 304.893 -38 305.401C-34.303 300.145 -32.046 297.399 -31.202 296.599z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-44.776 290.635C-44.253 290.265 -44.555 289.774 -44.338 289.442C-43.385 287.984 -42.084 286.738 -42.066 285C-42.063 284.723 -42.441 284.414 -42.776 284.638C-43.053 284.822 -43.395 284.952 -43.503 285.082C-45.533 287.531 -46.933 290.202 -48.376 293.014C-48.559 293.371 -49.703 297.862 -49.39 297.973C-49.151 298.058 -47.431 293.877 -47.221 293.763C-45.958 293.077 -45.946 291.462 -44.776 290.635z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-28.043 310.179C-27.599 309.31 -26.023 308.108 -26.136 307.219C-26.254 306.291 -25.786 304.848 -26.698 305.536C-27.955 306.484 -31.404 307.833 -31.674 313.641C-31.7 314.212 -28.726 311.519 -28.043 310.179z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-13.6 293.001C-13.2 292.333 -12.492 292.806 -12.033 292.543C-11.385 292.171 -10.774 291.613 -10.482 290.964C-9.512 288.815 -7.743 286.995 -7.6 284.601C-9.091 283.196 -9.77 285.236 -10.4 286.201C-11.723 284.554 -12.722 286.428 -14.022 286.947C-14.092 286.975 -14.305 286.628 -14.38 286.655C-15.557 287.095 -16.237 288.176 -17.235 288.957C-17.406 289.091 -17.811 288.911 -17.958 289.047C-18.61 289.65 -19.583 289.975 -19.863 290.657C-20.973 293.364 -24.113 295.459 -26 303.001C-25.619 303.91 -21.488 296.359 -21.001 295.661C-20.165 294.465 -20.047 297.322 -18.771 296.656C-18.72 296.629 -18.534 296.867 -18.4 297.001C-18.206 296.721 -17.988 296.492 -17.6 296.601C-17.6 296.201 -17.734 295.645 -17.533 295.486C-16.296 294.509 -16.38 293.441 -15.6 292.201C-15.142 292.99 -14.081 292.271 -13.6 293.001z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M46.2 347.401C46.2 347.401 53.6 327.001 49.2 315.801C49.2 315.801 60.6 337.401 56 348.601C56 348.601 55.6 338.201 51.6 333.201C51.6 333.201 47.6 346.001 46.2 347.401z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M31.4 344.801C31.4 344.801 36.8 336.001 28.8 317.601C28.8 317.601 28 338.001 21.2 349.001C21.2 349.001 35.4 328.801 31.4 344.801z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M21.4 342.801C21.4 342.801 21.2 322.801 21.6 319.801C21.6 319.801 17.8 336.401 7.6 346.001C7.6 346.001 22 334.001 21.4 342.801z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M11.8 310.801C11.8 310.801 17.8 324.401 7.8 342.801C7.8 342.801 14.2 330.601 9.4 323.601C9.4 323.601 12 320.201 11.8 310.801z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-7.4 342.401C-7.4 342.401 -8.4 326.801 -6.6 324.601C-6.6 324.601 -6.4 318.201 -6.8 317.201C-6.8 317.201 -2.8 311.001 -2.6 318.401C-2.6 318.401 -1.2 326.201 1.6 330.801C1.6 330.801 5.2 336.201 5 342.601C5 342.601 -5 312.401 -7.4 342.401z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-11 314.801C-11 314.801 -17.6 325.601 -19.4 344.601C-19.4 344.601 -20.8 338.401 -17 324.001C-17 324.001 -12.8 308.601 -11 314.801z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-32.8 334.601C-32.8 334.601 -27.8 329.201 -26.4 324.201C-26.4 324.201 -22.8 308.401 -29.2 317.001C-29.2 317.001 -29 325.001 -37.2 332.401C-37.2 332.401 -32.4 330.001 -32.8 334.601z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-38.6 329.601C-38.6 329.601 -35.2 312.201 -34.4 311.401C-34.4 311.401 -32.6 308.001 -35.4 311.201C-35.4 311.201 -44.2 330.401 -48.2 337.001C-48.2 337.001 -40.2 327.801 -38.6 329.601z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-44.4 313.001C-44.4 313.001 -32.8 290.601 -54.6 316.401C-54.6 316.401 -43.6 306.601 -44.4 313.001z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M-59.8 298.401C-59.8 298.401 -55 279.601 -52.4 279.801C-52.4 279.801 -44.2 270.801 -50.8 281.401C-50.8 281.401 -56.8 291.001 -56.2 300.801C-56.2 300.801 -56.8 291.201 -59.8 298.401z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M270.5 287C270.5 287 258.5 277 256 273.5C256 273.5 269.5 292 269.5 299C269.5 299 272 291.5 270.5 287z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M276 265C276 265 255 250 251.5 242.5C251.5 242.5 278 272 278 276.5C278 276.5 278.5 267.5 276 265z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M293 111C293 111 281 103 279.5 105C279.5 105 290 111.5 292.5 120C292.5 120 291 111 293 111z").setFill(f).setStroke(s);
+	f = "#cccccc";
+	g.createPath("M301.5 191.5L284 179.5C284 179.5 303 196.5 303.5 200.5L301.5 191.5z").setFill(f).setStroke(s);
+	s = "#000000"; f = null;
+	g.createPath("M-89.25 169L-67.25 173.75").setFill(f).setStroke(s);
+	s = "#000000";
+	g.createPath("M-39 331C-39 331 -39.5 327.5 -48.5 338").setFill(f).setStroke(s);
+	s = "#000000";
+	g.createPath("M-33.5 336C-33.5 336 -31.5 329.5 -38 334").setFill(f).setStroke(s);
+	s = "#000000";
+	g.createPath("M20.5 344.5C20.5 344.5 22 333.5 10.5 346.5").setFill(f).setStroke(s);
+	//surface.createLine({x1: 0, y1: 350, x2: 700, y2: 350}).setStroke("green");
+	//surface.createLine({y1: 0, x1: 350, y2: 700, x2: 350}).setStroke("green");
+    //dojo.event.connect(dojo.widget.byId("rotatingSlider"), "onValueChanged", rotatingEvent);
+    //dojo.event.connect(dojo.widget.byId("scalingSlider"), "onValueChanged", scalingEvent);
+    //dojo.byId("sliders").style.visibility = "visible";
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+<style type="text/css">
+td.pad { padding: 0px 5px 0px 5px; }
+</style>
+</head>
+<body>
+	<h1>dojox.gfx: Tiger</h1>
+	<p>This example was directly converted from SVG file.</p>
+	<!--
+	<table id="sliders" style="visibility: hidden;">
+		<tr>
+			<td align="center" class="pad">Rotation (<span id="rotationValue">0</span>)</td>
+			<td align="center" class="pad">Scaling (<span id="scaleValue">1.000</span>)</td>
+		</tr>
+		<tr>
+			<td class="pad">
+				<div id="rotatingSlider" dojoType="SliderHorizontal" 
+					initialValue="0" minimum="-180" maximum="180" snapValues="73"
+					activeDrag="true"
+					buttonStyle="top: 1px;"
+					backgroundStyle="padding: 8px 4px; border: 1px solid black;"
+					backgroundSize="width:100px; height:5px;"
+					backgroundSrc="src/widget/templates/images/blank.gif"
+					progressBackgroundSrc="src/widget/templates/images/slider-bg.gif"
+					handleStyle="top: 0px; width: 13px; height: 18px;"
+					handleSrc="src/widget/templates/images/slider.gif">
+				</div>
+			</td>
+			<td class="pad">
+				<div id="scalingSlider" dojoType="SliderHorizontal" 
+					initialValue="1" minimum="0" maximum="1" snapValues="10"
+					activeDrag="true"
+					buttonStyle="top: 1px;"
+					backgroundStyle="padding: 8px 4px; border: 1px solid black;"
+					backgroundSize="width:100px; height:5px;"
+					backgroundSrc="src/widget/templates/images/blank.gif"
+					progressBackgroundSrc="src/widget/templates/images/slider-bg.gif"
+					handleStyle="top: 0px; width: 13px; height: 18px;"
+					handleSrc="src/widget/templates/images/slider.gif">
+				</div>
+			</td>
+		</tr>
+	</table>
+	-->
+	<div id="gfx_holder" style="width: 700px; height: 700px;"></div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/matrix.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/matrix.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/matrix.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,440 @@
+dojo.provide("dojox.gfx.matrix");
+
+// candidates for dojox.math:
+dojox.gfx.matrix._degToRad = function(degree){ return Math.PI * degree / 180; };
+dojox.gfx.matrix._radToDeg = function(radian){ return radian / Math.PI * 180; };
+
+dojox.gfx.matrix.Matrix2D = function(arg){
+	// summary: a 2D matrix object
+	// description: Normalizes a 2D matrix-like object. If arrays is passed, 
+	//		all objects of the array are normalized and multiplied sequentially.
+	// arg: Object
+	//		a 2D matrix-like object, a number, or an array of such objects
+	if(arg){
+		if(typeof arg == "number"){
+			this.xx = this.yy = arg;
+		}else if(arg instanceof Array){
+			if(arg.length > 0){
+				var m = dojox.gfx.matrix.normalize(arg[0]);
+				// combine matrices
+				for(var i = 1; i < arg.length; ++i){
+					var l = m;
+					var r = dojox.gfx.matrix.normalize(arg[i]);
+					m = new dojox.gfx.matrix.Matrix2D();
+					m.xx = l.xx * r.xx + l.xy * r.yx;
+					m.xy = l.xx * r.xy + l.xy * r.yy;
+					m.yx = l.yx * r.xx + l.yy * r.yx;
+					m.yy = l.yx * r.xy + l.yy * r.yy;
+					m.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
+					m.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
+				}
+				dojo.mixin(this, m);
+			}
+		}else{
+			dojo.mixin(this, arg);
+		}
+	}
+};
+
+// the default (identity) matrix, which is used to fill in missing values
+dojo.extend(dojox.gfx.matrix.Matrix2D, {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 0});
+
+dojo.mixin(dojox.gfx.matrix, {
+	// summary: class constants, and methods of dojox.gfx.matrix
+	
+	// matrix constants
+	
+	// identity: dojox.gfx.matrix.Matrix2D
+	//		an identity matrix constant: identity * (x, y) == (x, y)
+	identity: new dojox.gfx.matrix.Matrix2D(),
+	
+	// flipX: dojox.gfx.matrix.Matrix2D
+	//		a matrix, which reflects points at x = 0 line: flipX * (x, y) == (-x, y)
+	flipX:    new dojox.gfx.matrix.Matrix2D({xx: -1}),
+	
+	// flipY: dojox.gfx.matrix.Matrix2D
+	//		a matrix, which reflects points at y = 0 line: flipY * (x, y) == (x, -y)
+	flipY:    new dojox.gfx.matrix.Matrix2D({yy: -1}),
+	
+	// flipXY: dojox.gfx.matrix.Matrix2D
+	//		a matrix, which reflects points at the origin of coordinates: flipXY * (x, y) == (-x, -y)
+	flipXY:   new dojox.gfx.matrix.Matrix2D({xx: -1, yy: -1}),
+	
+	// matrix creators
+	
+	translate: function(a, b){
+		// summary: forms a translation matrix
+		// description: The resulting matrix is used to translate (move) points by specified offsets.
+		// a: Number: an x coordinate value
+		// b: Number: a y coordinate value
+		if(arguments.length > 1){
+			return new dojox.gfx.matrix.Matrix2D({dx: a, dy: b}); // dojox.gfx.matrix.Matrix2D
+		}
+		// branch
+		// a: dojox.gfx.Point: a point-like object, which specifies offsets for both dimensions
+		// b: null
+		return new dojox.gfx.matrix.Matrix2D({dx: a.x, dy: a.y}); // dojox.gfx.matrix.Matrix2D
+	},
+	scale: function(a, b){
+		// summary: forms a scaling matrix
+		// description: The resulting matrix is used to scale (magnify) points by specified offsets.
+		// a: Number: a scaling factor used for the x coordinate
+		// b: Number: a scaling factor used for the y coordinate
+		if(arguments.length > 1){
+			return new dojox.gfx.matrix.Matrix2D({xx: a, yy: b}); // dojox.gfx.matrix.Matrix2D
+		}
+		if(typeof a == "number"){
+			// branch
+			// a: Number: a uniform scaling factor used for the both coordinates
+			// b: null
+			return new dojox.gfx.matrix.Matrix2D({xx: a, yy: a}); // dojox.gfx.matrix.Matrix2D
+		}
+		// branch
+		// a: dojox.gfx.Point: a point-like object, which specifies scale factors for both dimensions
+		// b: null
+		return new dojox.gfx.matrix.Matrix2D({xx: a.x, yy: a.y}); // dojox.gfx.matrix.Matrix2D
+	},
+	rotate: function(angle){
+		// summary: forms a rotating matrix
+		// description: The resulting matrix is used to rotate points 
+		//		around the origin of coordinates (0, 0) by specified angle.
+		// angle: Number: an angle of rotation in radians (>0 for CCW)
+		var c = Math.cos(angle);
+		var s = Math.sin(angle);
+		return new dojox.gfx.matrix.Matrix2D({xx: c, xy: s, yx: -s, yy: c}); // dojox.gfx.matrix.Matrix2D
+	},
+	rotateg: function(degree){
+		// summary: forms a rotating matrix
+		// description: The resulting matrix is used to rotate points
+		//		around the origin of coordinates (0, 0) by specified degree.
+		//		See dojox.gfx.matrix.rotate() for comparison.
+		// degree: Number: an angle of rotation in degrees (>0 for CCW)
+		return dojox.gfx.matrix.rotate(dojox.gfx.matrix._degToRad(degree)); // dojox.gfx.matrix.Matrix2D
+	},
+	skewX: function(angle) {
+		// summary: forms an x skewing matrix
+		// description: The resulting matrix is used to skew points in the x dimension
+		//		around the origin of coordinates (0, 0) by specified angle.
+		// angle: Number: an skewing angle in radians
+		return new dojox.gfx.matrix.Matrix2D({xy: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D
+	},
+	skewXg: function(degree){
+		// summary: forms an x skewing matrix
+		// description: The resulting matrix is used to skew points in the x dimension
+		//		around the origin of coordinates (0, 0) by specified degree.
+		//		See dojox.gfx.matrix.skewX() for comparison.
+		// degree: Number: an skewing angle in degrees
+		return dojox.gfx.matrix.skewX(dojox.gfx.matrix._degToRad(degree)); // dojox.gfx.matrix.Matrix2D
+	},
+	skewY: function(angle){
+		// summary: forms a y skewing matrix
+		// description: The resulting matrix is used to skew points in the y dimension
+		//		around the origin of coordinates (0, 0) by specified angle.
+		// angle: Number: an skewing angle in radians
+		return new dojox.gfx.matrix.Matrix2D({yx: -Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D
+	},
+	skewYg: function(degree){
+		// summary: forms a y skewing matrix
+		// description: The resulting matrix is used to skew points in the y dimension
+		//		around the origin of coordinates (0, 0) by specified degree.
+		//		See dojox.gfx.matrix.skewY() for comparison.
+		// degree: Number: an skewing angle in degrees
+		return dojox.gfx.matrix.skewY(dojox.gfx.matrix._degToRad(degree)); // dojox.gfx.matrix.Matrix2D
+	},
+	reflect: function(a, b){
+		// summary: forms a reflection matrix
+		// description: The resulting matrix is used to reflect points around a vector, 
+		//		which goes through the origin.
+		// a: dojox.gfx.Point: a point-like object, which specifies a vector of reflection
+		// b: null
+		if(arguments.length == 1){
+			b = a.y;
+			a = a.x;
+		}
+		// branch
+		// a: Number: an x coordinate value
+		// b: Number: a y coordinate value
+		
+		// make a unit vector
+		var n2 = a * a + b * b;
+		var xy = 2 * a * b / n2;
+		return new dojox.gfx.matrix.Matrix2D({xx: 2 * a * a / n2 - 1, xy: xy, yx: xy, yy: 2 * b * b / n2 - 1}); // dojox.gfx.matrix.Matrix2D
+	},
+	project: function(a, b){
+		// summary: forms an orthogonal projection matrix
+		// description: The resulting matrix is used to project points orthogonally on a vector, 
+		//		which goes through the origin.
+		// a: dojox.gfx.Point: a point-like object, which specifies a vector of projection
+		// b: null
+		if(arguments.length == 1){
+			b = a.y;
+			a = a.x;
+		}
+		// branch
+		// a: Number: an x coordinate value
+		// b: Number: a y coordinate value
+		
+		// make a unit vector
+		var n2 = a * a + b * b;
+		var xy = a * b / n2;
+		return new dojox.gfx.matrix.Matrix2D({xx: a * a / n2, xy: xy, yx: xy, yy: b * b / n2}); // dojox.gfx.matrix.Matrix2D
+	},
+	
+	// ensure matrix 2D conformance
+	normalize: function(matrix){
+		// summary: converts an object to a matrix, if necessary
+		// description: Converts any 2D matrix-like object or an array of
+		//		such objects to a valid dojox.gfx.matrix.Matrix2D object.
+		// matrix: Object: an object, which is converted to a matrix, if necessary
+		return (matrix instanceof dojox.gfx.matrix.Matrix2D) ? matrix : new dojox.gfx.matrix.Matrix2D(matrix); // dojox.gfx.matrix.Matrix2D
+	},
+	
+	// common operations
+	
+	clone: function(matrix){
+		// summary: creates a copy of a 2D matrix
+		// matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be cloned
+		var obj = new dojox.gfx.matrix.Matrix2D();
+		for(var i in matrix){
+			if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i];
+		}
+		return obj; // dojox.gfx.matrix.Matrix2D
+	},
+	invert: function(matrix){
+		// summary: inverts a 2D matrix
+		// matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be inverted
+		var m = dojox.gfx.matrix.normalize(matrix);
+		var D = m.xx * m.yy - m.xy * m.yx;
+		var M = new dojox.gfx.matrix.Matrix2D({
+			xx: m.yy/D, xy: -m.xy/D, 
+			yx: -m.yx/D, yy: m.xx/D, 
+			dx: (m.yx * m.dy - m.yy * m.dx) / D, 
+			dy: (m.xy * m.dx - m.xx * m.dy) / D
+		});
+		return M; // dojox.gfx.matrix.Matrix2D
+	},
+	_multiplyPoint: function(m, x, y){
+		// summary: applies a matrix to a point
+		// matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
+		// x: Number: an x coordinate of a point
+		// y: Number: a y coordinate of a point
+		return {x: m.xx * x + m.xy * y + m.dx, y: m.yx * x + m.yy * y + m.dy}; // dojox.gfx.Point
+	},
+	multiplyPoint: function(matrix, /* Number||Point */ a, /* Number, optional */ b){
+		// summary: applies a matrix to a point
+		// matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
+		// a: Number: an x coordinate of a point
+		// b: Number: a y coordinate of a point
+		var m = dojox.gfx.matrix.normalize(matrix);
+		if(typeof a == "number" && typeof b == "number"){
+			return dojox.gfx.matrix._multiplyPoint(m, a, b); // dojox.gfx.Point
+		}
+		// branch
+		// matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
+		// a: dojox.gfx.Point: a point
+		// b: null
+		return dojox.gfx.matrix._multiplyPoint(m, a.x, a.y); // dojox.gfx.Point
+	},
+	multiply: function(matrix){
+		// summary: combines matrices by multiplying them sequentially in the given order
+		// matrix: dojox.gfx.matrix.Matrix2D...: a 2D matrix-like object, 
+		//		all subsequent arguments are matrix-like objects too
+		var m = dojox.gfx.matrix.normalize(matrix);
+		// combine matrices
+		for(var i = 1; i < arguments.length; ++i){
+			var l = m;
+			var r = dojox.gfx.matrix.normalize(arguments[i]);
+			m = new dojox.gfx.matrix.Matrix2D();
+			m.xx = l.xx * r.xx + l.xy * r.yx;
+			m.xy = l.xx * r.xy + l.xy * r.yy;
+			m.yx = l.yx * r.xx + l.yy * r.yx;
+			m.yy = l.yx * r.xy + l.yy * r.yy;
+			m.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
+			m.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
+		}
+		return m; // dojox.gfx.matrix.Matrix2D
+	},
+	
+	// high level operations
+	
+	_sandwich: function(m, x, y){
+		// summary: applies a matrix at a centrtal point
+		// m: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object, which is applied at a central point
+		// x: Number: an x component of the central point
+		// y: Number: a y component of the central point
+		return dojox.gfx.matrix.multiply(dojox.gfx.matrix.translate(x, y), m, dojox.gfx.matrix.translate(-x, -y)); // dojox.gfx.matrix.Matrix2D
+	},
+	scaleAt: function(a, b, c, d){
+		// summary: scales a picture using a specified point as a center of scaling
+		// description: Compare with dojox.gfx.matrix.scale().
+		// a: Number: a scaling factor used for the x coordinate
+		// b: Number: a scaling factor used for the y coordinate
+		// c: Number: an x component of a central point
+		// d: Number: a y component of a central point
+		
+		// accepts several signatures:
+		//	1) uniform scale factor, Point
+		//	2) uniform scale factor, x, y
+		//	3) x scale, y scale, Point
+		//	4) x scale, y scale, x, y
+		
+		switch(arguments.length){
+			case 4:
+				// a and b are scale factor components, c and d are components of a point
+				return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.scale(a, b), c, d); // dojox.gfx.matrix.Matrix2D
+			case 3:
+				if(typeof c == "number"){
+					// branch
+					// a: Number: a uniform scaling factor used for both coordinates
+					// b: Number: an x component of a central point
+					// c: Number: a y component of a central point
+					// d: null
+					return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.scale(a), b, c); // dojox.gfx.matrix.Matrix2D
+				}
+				// branch
+				// a: Number: a scaling factor used for the x coordinate
+				// b: Number: a scaling factor used for the y coordinate
+				// c: dojox.gfx.Point: a central point
+				// d: null
+				return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.scale(a, b), c.x, c.y); // dojox.gfx.matrix.Matrix2D
+		}
+		// branch
+		// a: Number: a uniform scaling factor used for both coordinates
+		// b: dojox.gfx.Point: a central point
+		// c: null
+		// d: null
+		return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.scale(a), b.x, b.y); // dojox.gfx.matrix.Matrix2D
+	},
+	rotateAt: function(angle, a, b){
+		// summary: rotates a picture using a specified point as a center of rotation
+		// description: Compare with dojox.gfx.matrix.rotate().
+		// angle: Number: an angle of rotation in radians (>0 for CCW)
+		// a: Number: an x component of a central point
+		// b: Number: a y component of a central point
+		
+		// accepts several signatures:
+		//	1) rotation angle in radians, Point
+		//	2) rotation angle in radians, x, y
+		
+		if(arguments.length > 2){
+			return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.rotate(angle), a, b); // dojox.gfx.matrix.Matrix2D
+		}
+		
+		// branch
+		// angle: Number: an angle of rotation in radians (>0 for CCW)
+		// a: dojox.gfx.Point: a central point
+		// b: null
+		return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.rotate(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D
+	},
+	rotategAt: function(degree, a, b){
+		// summary: rotates a picture using a specified point as a center of rotation
+		// description: Compare with dojox.gfx.matrix.rotateg().
+		// degree: Number: an angle of rotation in degrees (>0 for CCW)
+		// a: Number: an x component of a central point
+		// b: Number: a y component of a central point
+		
+		// accepts several signatures:
+		//	1) rotation angle in degrees, Point
+		//	2) rotation angle in degrees, x, y
+		
+		if(arguments.length > 2){
+			return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.rotateg(degree), a, b); // dojox.gfx.matrix.Matrix2D
+		}
+
+		// branch
+		// degree: Number: an angle of rotation in degrees (>0 for CCW)
+		// a: dojox.gfx.Point: a central point
+		// b: null
+		return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.rotateg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D
+	},
+	skewXAt: function(angle, a, b){
+		// summary: skews a picture along the x axis using a specified point as a center of skewing
+		// description: Compare with dojox.gfx.matrix.skewX().
+		// angle: Number: an skewing angle in radians
+		// a: Number: an x component of a central point
+		// b: Number: a y component of a central point
+		
+		// accepts several signatures:
+		//	1) skew angle in radians, Point
+		//	2) skew angle in radians, x, y
+		
+		if(arguments.length > 2){
+			return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.skewX(angle), a, b); // dojox.gfx.matrix.Matrix2D
+		}
+
+		// branch
+		// angle: Number: an skewing angle in radians
+		// a: dojox.gfx.Point: a central point
+		// b: null
+		return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.skewX(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D
+	},
+	skewXgAt: function(degree, a, b){
+		// summary: skews a picture along the x axis using a specified point as a center of skewing
+		// description: Compare with dojox.gfx.matrix.skewXg().
+		// degree: Number: an skewing angle in degrees
+		// a: Number: an x component of a central point
+		// b: Number: a y component of a central point
+		
+		// accepts several signatures:
+		//	1) skew angle in degrees, Point
+		//	2) skew angle in degrees, x, y
+
+		if(arguments.length > 2){
+			return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.skewXg(degree), a, b); // dojox.gfx.matrix.Matrix2D
+		}
+
+		// branch
+		// degree: Number: an skewing angle in degrees
+		// a: dojox.gfx.Point: a central point
+		// b: null
+		return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.skewXg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D
+	},
+	skewYAt: function(angle, a, b){
+		// summary: skews a picture along the y axis using a specified point as a center of skewing
+		// description: Compare with dojox.gfx.matrix.skewY().
+		// angle: Number: an skewing angle in radians
+		// a: Number: an x component of a central point
+		// b: Number: a y component of a central point
+		
+		// accepts several signatures:
+		//	1) skew angle in radians, Point
+		//	2) skew angle in radians, x, y
+		
+		if(arguments.length > 2){
+			return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.skewY(angle), a, b); // dojox.gfx.matrix.Matrix2D
+		}
+
+		// branch
+		// angle: Number: an skewing angle in radians
+		// a: dojox.gfx.Point: a central point
+		// b: null
+		return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.skewY(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D
+	},
+	skewYgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number, optional */ b){
+		// summary: skews a picture along the y axis using a specified point as a center of skewing
+		// description: Compare with dojox.gfx.matrix.skewYg().
+		// degree: Number: an skewing angle in degrees
+		// a: Number: an x component of a central point
+		// b: Number: a y component of a central point
+		
+		// accepts several signatures:
+		//	1) skew angle in degrees, Point
+		//	2) skew angle in degrees, x, y
+
+		if(arguments.length > 2){
+			return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.skewYg(degree), a, b); // dojox.gfx.matrix.Matrix2D
+		}
+
+		// branch
+		// degree: Number: an skewing angle in degrees
+		// a: dojox.gfx.Point: a central point
+		// b: null
+		return dojox.gfx.matrix._sandwich(dojox.gfx.matrix.skewYg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D
+	}
+	
+	// TODO: rect-to-rect mapping, scale-to-fit (isotropic and anisotropic versions)
+	
+});
+
+// propagate Matrix2D up
+dojox.gfx.Matrix2D = dojox.gfx.matrix.Matrix2D;

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/path.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/path.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/path.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,352 @@
+dojo.provide("dojox.gfx.path");
+
+dojo.require("dojox.gfx.shape");
+
+dojo.declare("dojox.gfx.path.Path", dojox.gfx.Shape,
+	function(rawNode){
+		// summary: a generalized path shape
+		// rawNode: Node: a DOM node to be used by this path object
+		this.shape = dojox.gfx._base._copy(dojox.gfx.defaultPath, true);
+		this.segments = [];
+		this.absolute = true;
+		this.last = {};
+		this.attach(rawNode);
+	}, {	
+	// mode manipulations
+	setAbsoluteMode: function(mode){
+		// summary: sets an absolute or relative mode for path points
+		// mode: Boolean: true/false or "absolute"/"relative" to specify the mode
+		this.absolute = typeof(mode) == "string" ? (mode == "absolute") : mode;
+		return this; // self
+	},
+	getAbsoluteMode: function(){
+		// summary: returns a current value of the absolute mode
+		return this.absolute; // Boolean
+	},
+	
+	getBoundingBox: function(){
+		// summary: returns the bounding box {x, y, width, height} or null
+		return (this.bbox && ("l" in this.bbox)) ? {x: this.bbox.l, y: this.bbox.t, width: this.bbox.r - this.bbox.l, height: this.bbox.b - this.bbox.t} : null; // dojox.gfx.Rectangle
+	},
+	
+	getLastPosition: function(){
+		// summary: returns the last point in the path, or null
+		return "x" in this.last ? this.last : null; // Object
+	},
+	
+	// segment interpretation
+	_updateBBox: function(x, y){
+		// summary: updates the bounding box of path with new point
+		// x: Number: an x coordinate
+		// y: Number: a y coordinate
+		
+		// we use {l, b, r, t} representation of a bbox
+		if(this.bbox && ("l" in this.bbox)){
+			if(this.bbox.l > x) this.bbox.l = x;
+			if(this.bbox.r < x) this.bbox.r = x;
+			if(this.bbox.t > y) this.bbox.t = y;
+			if(this.bbox.b < y) this.bbox.b = y;
+		}else{
+			this.bbox = {l: x, b: y, r: x, t: y};
+		}
+	},
+	_updateWithSegment: function(segment){
+		// summary: updates the bounding box of path with new segment
+		// segment: Object: a segment
+		var n = segment.args;
+		var l = n.length;
+		// update internal variables: bbox, absolute, last
+		switch(segment.action){
+			case "M":
+			case "L":
+			case "C":
+			case "S":
+			case "Q":
+			case "T":
+				for(var i = 0; i < l; i += 2){
+					this._updateBBox(n[i], n[i + 1]);
+				}
+				this.last.x = n[l - 2];
+				this.last.y = n[l - 1];
+				this.absolute = true;
+				break;
+			case "H":
+				for(var i = 0; i < l; ++i){
+					this._updateBBox(n[i], this.last.y);
+				}
+				this.last.x = n[l - 1];
+				this.absolute = true;
+				break;
+			case "V":
+				for(var i = 0; i < l; ++i){
+					this._updateBBox(this.last.x, n[i]);
+				}
+				this.last.y = n[l - 1];
+				this.absolute = true;
+				break;
+			case "m":
+				var start = 0;
+				if(!("x" in this.last)){
+					this._updateBBox(this.last.x = n[0], this.last.y = n[1]);
+					start = 2;
+				}
+				for(var i = start; i < l; i += 2){
+					this._updateBBox(this.last.x += n[i], this.last.y += n[i + 1]);
+				}
+				this.absolute = false;
+				break;
+			case "l":
+			case "t":
+				for(var i = 0; i < l; i += 2){
+					this._updateBBox(this.last.x += n[i], this.last.y += n[i + 1]);
+				}
+				this.absolute = false;
+				break;
+			case "h":
+				for(var i = 0; i < l; ++i){
+					this._updateBBox(this.last.x += n[i], this.last.y);
+				}
+				this.absolute = false;
+				break;
+			case "v":
+				for(var i = 0; i < l; ++i){
+					this._updateBBox(this.last.x, this.last.y += n[i]);
+				}
+				this.absolute = false;
+				break;
+			case "c":
+				for(var i = 0; i < l; i += 6){
+					this._updateBBox(this.last.x + n[i], this.last.y + n[i + 1]);
+					this._updateBBox(this.last.x + n[i + 2], this.last.y + n[i + 3]);
+					this._updateBBox(this.last.x += n[i + 4], this.last.y += n[i + 5]);
+				}
+				this.absolute = false;
+				break;
+			case "s":
+			case "q":
+				for(var i = 0; i < l; i += 4){
+					this._updateBBox(this.last.x + n[i], this.last.y + n[i + 1]);
+					this._updateBBox(this.last.x += n[i + 2], this.last.y += n[i + 3]);
+				}
+				this.absolute = false;
+				break;
+			case "A":
+				for(var i = 0; i < l; i += 7){
+					this._updateBBox(n[i + 5], n[i + 6]);
+				}
+				this.last.x = n[l - 2];
+				this.last.y = n[l - 1];
+				this.absolute = true;
+				break;
+			case "a":
+				for(var i = 0; i < l; i += 7){
+					this._updateBBox(this.last.x += n[i + 5], this.last.y += n[i + 6]);
+				}
+				this.absolute = false;
+				break;
+		}
+		// add an SVG path segment
+		var path = [segment.action];
+		for(var i = 0; i < l; ++i){
+			path.push(dojox.gfx.formatNumber(n[i], true));
+		}
+		if(typeof(this.shape.path) == "string"){
+			this.shape.path += path.join("");
+		}else{
+			var l = path.length;
+			var a = this.shape.path;
+			for(var i = 0; i < l; ++i){
+				a.push(path[i]);
+			}
+		}
+	},
+	
+	// a dictionary, which maps segment type codes to a number of their argemnts
+	_validSegments: {m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0},
+	
+	_pushSegment: function(action, args){
+		// summary: adds a segment
+		// action: String: valid SVG code for a segment's type
+		// args: Array: a list of parameters for this segment
+		var group = this._validSegments[action.toLowerCase()];
+		if(typeof(group) == "number"){
+			if(group){
+				if(args.length >= group){
+					var segment = {action: action, args: args.slice(0, args.length - args.length % group)};
+					this.segments.push(segment);
+					this._updateWithSegment(segment);
+				}
+			}else{
+				var segment = {action: action, args: []};
+				this.segments.push(segment);
+				this._updateWithSegment(segment);
+			}
+		}
+	},
+	
+	_collectArgs: function(array, args){
+		// summary: converts an array of arguments to plain numeric values
+		// array: Array: an output argument (array of numbers)
+		// args: Array: an input argument (can be values of Boolean, Number, dojox.gfx.Point, or an embedded array of them)
+		for(var i = 0; i < args.length; ++i){
+			var t = args[i];
+			if(typeof(t) == "boolean"){
+				array.push(t ? 1 : 0);
+			}else if(typeof(t) == "number"){
+				array.push(t);
+			}else if(t instanceof Array){
+				this._collectArgs(array, t);
+			}else if("x" in t && "y" in t){
+				array.push(t.x);
+				array.push(t.y);
+			}
+		}
+	},
+
+	// segments	
+	moveTo: function(){
+		// summary: formes a move segment
+		var args = [];
+		this._collectArgs(args, arguments);
+		this._pushSegment(this.absolute ? "M" : "m", args);
+		return this; // self
+	},
+	lineTo: function(){
+		// summary: formes a line segment
+		var args = [];
+		this._collectArgs(args, arguments);
+		this._pushSegment(this.absolute ? "L" : "l", args);
+		return this; // self
+	},
+	hLineTo: function(){
+		// summary: formes a horizontal line segment
+		var args = [];
+		this._collectArgs(args, arguments);
+		this._pushSegment(this.absolute ? "H" : "h", args);
+		return this; // self
+	},
+	vLineTo: function(){
+		// summary: formes a vertical line segment
+		var args = [];
+		this._collectArgs(args, arguments);
+		this._pushSegment(this.absolute ? "V" : "v", args);
+		return this; // self
+	},
+	curveTo: function(){
+		// summary: formes a curve segment
+		var args = [];
+		this._collectArgs(args, arguments);
+		this._pushSegment(this.absolute ? "C" : "c", args);
+		return this; // self
+	},
+	smoothCurveTo: function(){
+		// summary: formes a smooth curve segment
+		var args = [];
+		this._collectArgs(args, arguments);
+		this._pushSegment(this.absolute ? "S" : "s", args);
+		return this; // self
+	},
+	qCurveTo: function(){
+		// summary: formes a quadratic curve segment
+		var args = [];
+		this._collectArgs(args, arguments);
+		this._pushSegment(this.absolute ? "Q" : "q", args);
+		return this; // self
+	},
+	qSmoothCurveTo: function(){
+		// summary: formes a quadratic smooth curve segment
+		var args = [];
+		this._collectArgs(args, arguments);
+		this._pushSegment(this.absolute ? "T" : "t", args);
+		return this; // self
+	},
+	arcTo: function(){
+		// summary: formes an elliptic arc segment
+		var args = [];
+		this._collectArgs(args, arguments);
+		for(var i = 2; i < args.length; i += 7){
+			args[i] = -args[i];
+		}
+		this._pushSegment(this.absolute ? "A" : "a", args);
+		return this; // self
+	},
+	closePath: function(){
+		// summary: closes a path
+		this._pushSegment("Z", []);
+		return this; // self
+	},
+	
+	// setShape
+	_setPath: function(path){
+		// summary: forms a path using an SVG path string
+		// path: String: an SVG path string
+		var p = dojo.isArray(path) ? path : path.match(dojox.gfx.pathSvgRegExp);
+		this.segments = [];
+		this.absolute = true;
+		this.bbox = {};
+		this.last = {};
+		if(!p) return;
+		// create segments
+		var action = "";	// current action
+		var args = [];		// current arguments
+		var l = p.length;
+		for(var i = 0; i < l; ++i){
+			var t = p[i];
+			var x = parseFloat(t);
+			if(isNaN(x)){
+				if(action){
+					this._pushSegment(action, args);
+				}
+				args = [];
+				action = t;
+			}else{
+				args.push(x);
+			}
+		}
+		this._pushSegment(action, args);
+	},
+	setShape: function(newShape){
+		// summary: forms a path using a shape
+		// newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath)
+		this.shape = dojox.gfx.makeParameters(this.shape, typeof(newShape) == "string" ? {path: newShape} : newShape);
+		var path = this.shape.path;
+		// switch to non-updating version of path building
+		this.shape.path = [];
+		this._setPath(path);
+		// switch back to the string path
+		this.shape.path = this.shape.path.join("");
+		return this; // self
+	},
+	
+	// useful constant for descendants
+	_2PI: Math.PI * 2
+});
+
+dojo.declare("dojox.gfx.path.TextPath", dojox.gfx.path.Path,
+	function(rawNode){
+		// summary: a generalized TextPath shape
+		// rawNode: Node: a DOM node to be used by this TextPath object
+		if(!("text" in this)){
+			this.text = dojox.gfx._base._copy(dojox.gfx.defaultTextPath, true);
+		}
+		if(!("fontStyle" in this)){
+			this.fontStyle = dojox.gfx._base._copy(dojox.gfx.defaultFont, true);
+		}
+	},
+{
+	setText: function(newText){
+		// summary: sets a text to be drawn along the path
+		this.text = dojox.gfx.makeParameters(this.text, 
+			typeof(newText) == "string" ? {text: newText} : newText);
+		this._setText();
+		return this;	// self
+	},
+	setFont: function(newFont){
+		// summary: sets a font for text
+		this.fontStyle = typeof newFont == "string" ? 
+			dojox.gfx.splitFontString(newFont) :
+			dojox.gfx.makeParameters(dojox.gfx.defaultFont, newFont);
+		this._setFont();
+		return this;	// self
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/shape.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/shape.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/shape.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,439 @@
+dojo.provide("dojox.gfx.shape");
+
+dojo.require("dojox.gfx._base");
+
+dojo.declare("dojox.gfx.Shape", null,
+	function(){
+		// summary: a Shape object, which knows how to apply 
+		// graphical attributes and transformations
+	
+		// rawNode: Node: underlying node
+		this.rawNode = null;
+		
+		// shape: Object: an abstract shape object
+		//	(see dojox.gfx.defaultPath,
+		//	dojox.gfx.defaultPolyline,
+		//	dojox.gfx.defaultRect,
+		//	dojox.gfx.defaultEllipse,
+		//	dojox.gfx.defaultCircle,
+		//	dojox.gfx.defaultLine,
+		//	or dojox.gfx.defaultImage)
+		this.shape = null;
+		
+		// matrix: dojox.gfx.matrix.Matrix: a transformation matrix
+		this.matrix = null;
+		
+		// fillStyle: Object: a fill object 
+		//	(see dojox.gfx.defaultLinearGradient, 
+		//	dojox.gfx.defaultRadialGradient, 
+		//	dojox.gfx.defaultPattern, 
+		//	or dojo.Color)
+		this.fillStyle = null;
+		
+		// strokeStyle: Object: a stroke object 
+		//	(see dojox.gfx.defaultStroke) 
+		this.strokeStyle = null;
+		
+		// bbox: dojox.gfx.Rectangle: a bounding box of this shape
+		//	(see dojox.gfx.defaultRect)
+		this.bbox = null;
+		
+		// virtual group structure
+		
+		// parent: Object: a parent or null
+		//	(see dojox.gfx.Surface,
+		//	dojox.gfx.shape.VirtualGroup,
+		//	or dojox.gfx.Group)
+		this.parent = null;
+		
+		// parentMatrix: dojox.gfx.matrix.Matrix
+		//	a transformation matrix inherited from the parent
+		this.parentMatrix = null;
+	},
+{
+	// trivial getters
+	
+	getNode: function(){
+		// summary: returns the current DOM Node or null
+		return this.rawNode; // Node
+	},
+	getShape: function(){
+		// summary: returns the current shape object or null
+		//	(see dojox.gfx.defaultPath,
+		//	dojox.gfx.defaultPolyline,
+		//	dojox.gfx.defaultRect,
+		//	dojox.gfx.defaultEllipse,
+		//	dojox.gfx.defaultCircle,
+		//	dojox.gfx.defaultLine,
+		//	or dojox.gfx.defaultImage)
+		return this.shape; // Object
+	},
+	getTransform: function(){
+		// summary: returns the current transformation matrix or null
+		return this.matrix;	// dojox.gfx.matrix.Matrix
+	},
+	getFill: function(){
+		// summary: returns the current fill object or null
+		//	(see dojox.gfx.defaultLinearGradient, 
+		//	dojox.gfx.defaultRadialGradient, 
+		//	dojox.gfx.defaultPattern, 
+		//	or dojox.gfx.color.Color)
+		return this.fillStyle;	// Object
+	},
+	getStroke: function(){
+		// summary: returns the current stroke object or null
+		//	(see dojox.gfx.defaultStroke) 
+		return this.strokeStyle;	// Object
+	},
+	getParent: function(){
+		// summary: returns the parent or null
+		//	(see dojox.gfx.Surface,
+		//	dojox.gfx.shape.VirtualGroup,
+		//	or dojox.gfx.Group)
+		return this.parent;	// Object
+	},
+	getBoundingBox: function(){
+		// summary: returns the bounding box or null
+		//	(see dojox.gfx.defaultRect)
+		return this.bbox;	// dojox.gfx.Rectangle
+	},
+	getTransformedBoundingBox: function(){
+		// summary: returns an array of four points or null
+		//	four points represent four corners of the untransformed bounding box
+		var b = this.getBoundingBox();
+		if(!b){
+			return null;	// null
+		}
+		var m = this._getRealMatrix();
+		var r = [];
+		var g = dojox.gfx.matrix;
+		r.push(g.multiplyPoint(m, b.x, b.y));
+		r.push(g.multiplyPoint(m, b.x + b.width, b.y));
+		r.push(g.multiplyPoint(m, b.x + b.width, b.y + b.height));
+		r.push(g.multiplyPoint(m, b.x, b.y + b.height));
+		return r;	// Array
+	},
+	getEventSource: function(){
+		// summary: returns a Node, which is used as 
+		//	a source of events for this shape
+		return this.rawNode;	// Node
+	},
+	
+	// empty settings
+	
+	setShape: function(shape){
+		// summary: sets a shape object
+		//	(the default implementation simply ignores it)
+		// shape: Object: a shape object
+		//	(see dojox.gfx.defaultPath,
+		//	dojox.gfx.defaultPolyline,
+		//	dojox.gfx.defaultRect,
+		//	dojox.gfx.defaultEllipse,
+		//	dojox.gfx.defaultCircle,
+		//	dojox.gfx.defaultLine,
+		//	or dojox.gfx.defaultImage)
+		return this;	// self
+	},
+	setFill: function(fill){
+		// summary: sets a fill object
+		//	(the default implementation simply ignores it)
+		// fill: Object: a fill object
+		//	(see dojox.gfx.defaultLinearGradient, 
+		//	dojox.gfx.defaultRadialGradient, 
+		//	dojox.gfx.defaultPattern, 
+		//	or dojo.Color)
+		return this;	// self
+	},
+	setStroke: function(stroke){
+		// summary: sets a stroke object
+		//	(the default implementation simply ignores it)
+		// stroke: Object: a stroke object
+		//	(see dojox.gfx.defaultStroke) 
+		return this;	// self
+	},
+	
+	// z-index
+	
+	moveToFront: function(){
+		// summary: moves a shape to front of its parent's list of shapes
+		//	(the default implementation does nothing)
+		return this;	// self
+	},
+	moveToBack: function(){
+		// summary: moves a shape to back of its parent's list of shapes
+		//	(the default implementation does nothing)
+		return this;
+	},
+
+	setTransform: function(matrix){
+		// summary: sets a transformation matrix
+		// matrix: dojox.gfx.matrix.Matrix: a matrix or a matrix-like object
+		//	(see an argument of dojox.gfx.matrix.Matrix 
+		//	constructor for a list of acceptable arguments)
+		this.matrix = dojox.gfx.matrix.clone(matrix ? dojox.gfx.matrix.normalize(matrix) : dojox.gfx.identity, true);
+		return this._applyTransform();	// self
+	},
+	
+	// apply left & right transformation
+	
+	applyRightTransform: function(matrix){
+		// summary: multiplies the existing matrix with an argument on right side
+		//	(this.matrix * matrix)
+		// matrix: dojox.gfx.matrix.Matrix: a matrix or a matrix-like object
+		//	(see an argument of dojox.gfx.matrix.Matrix 
+		//	constructor for a list of acceptable arguments)
+		return matrix ? this.setTransform([this.matrix, matrix]) : this;	// self
+	},
+	applyLeftTransform: function(matrix){
+		// summary: multiplies the existing matrix with an argument on left side
+		//	(matrix * this.matrix)
+		// matrix: dojox.gfx.matrix.Matrix: a matrix or a matrix-like object
+		//	(see an argument of dojox.gfx.matrix.Matrix 
+		//	constructor for a list of acceptable arguments)
+		return matrix ? this.setTransform([matrix, this.matrix]) : this;	// self
+	},
+
+	applyTransform: function(matrix){
+		// summary: a shortcut for dojox.gfx.Shape.applyRightTransform
+		// matrix: dojox.gfx.matrix.Matrix: a matrix or a matrix-like object
+		//	(see an argument of dojox.gfx.matrix.Matrix 
+		//	constructor for a list of acceptable arguments)
+		return matrix ? this.setTransform([this.matrix, matrix]) : this;	// self
+	},
+	
+	// virtual group methods
+	
+	removeShape: function(silently){
+		// summary: removes the shape from its parent's list of shapes
+		// silently: Boolean?: if true, do not redraw a picture yet
+		if(this.parent){
+			this.parent.remove(this, silently);
+		}
+		return this;	// self
+	},
+	_setParent: function(parent, matrix){
+		// summary: sets a parent
+		// parent: Object: a parent or null
+		//	(see dojox.gfx.Surface,
+		//	dojox.gfx.shape.VirtualGroup,
+		//	or dojox.gfx.Group)
+		// matrix: dojox.gfx.matrix.Matrix:
+		//	a 2D matrix or a matrix-like object
+		this.parent = parent;
+		return this._updateParentMatrix(matrix);	// self
+	},
+	_updateParentMatrix: function(matrix){
+		// summary: updates the parent matrix with new matrix
+		// matrix: dojox.gfx.matrix.Matrix:
+		//	a 2D matrix or a matrix-like object
+		this.parentMatrix = matrix ? dojox.gfx.matrix.clone(matrix) : null;
+		return this._applyTransform();	// self
+	},
+	_getRealMatrix: function(){
+		// summary: returns the cumulative ("real") transformation matrix
+		//	by combining the shape's matrix with its parent's matrix
+		return this.parentMatrix ? new dojox.gfx.matrix.Matrix2D([this.parentMatrix, this.matrix]) : this.matrix;	// dojox.gfx.Matrix2D
+	}
+});
+
+dojo.declare("dojox.gfx.shape.VirtualGroup", dojox.gfx.Shape,
+	function() {
+		// summary: a virtual group of shapes, which can be used 
+		//	as a foundation for renderer-specific groups, or as a way 
+		//	to logically group shapes (e.g, to propagate matricies)
+	
+		// children: Array: a list of children
+		this.children = [];
+	},
+
+{
+	// group management
+	
+	add: function(shape){
+		// summary: adds a shape to the list
+		// shape: dojox.gfx.Shape: a shape
+		var oldParent = shape.getParent();
+		if(oldParent){
+			oldParent.remove(shape, true);
+		}
+		this.children.push(shape);
+		return shape._setParent(this, this._getRealMatrix());	// self
+	},
+	remove: function(shape, silently){
+		// summary: removes a shape from the list
+		// silently: Boolean?: if true, do not redraw a picture yet
+		for(var i = 0; i < this.children.length; ++i){
+			if(this.children[i] == shape){
+				if(silently){
+					// skip for now
+				}else{
+					shape._setParent(null, null);
+				}
+				this.children.splice(i, 1);
+				break;
+			}
+		}
+		return this;	// self
+	},
+	clear: function(){
+		// summary: removes all shapes from a group/surface
+		this.children = [];
+		return this;
+	},
+	
+	// apply transformation
+	
+	_applyTransform: function(){
+		// summary: applies a transformation matrix to a group
+		var matrix = this._getRealMatrix();
+		for(var i = 0; i < this.children.length; ++i){
+			this.children[i]._updateParentMatrix(matrix);
+		}
+		return this;	// self
+	}
+});
+
+dojo.declare("dojox.gfx.shape.Rect", dojox.gfx.Shape,
+	function(rawNode) {
+		// summary: a generic rectangle
+		// rawNode: Node: a DOM Node
+		this.shape = dojox.gfx._base._copy(dojox.gfx.defaultRect, true);
+		this.attach(rawNode);
+	},
+{
+	getBoundingBox: function(){
+		// summary: returns the bounding box (its shape in this case)
+		return this.shape;	// dojox.gfx.Rectangle
+	}
+});
+
+dojo.declare("dojox.gfx.shape.Ellipse", dojox.gfx.Shape,
+	function(rawNode) {
+		// summary: a generic ellipse
+		// rawNode: Node: a DOM Node
+		this.shape = dojox.gfx._base._copy(dojox.gfx.defaultEllipse, true);
+		this.attach(rawNode);
+	},
+{
+	getBoundingBox: function(){
+		// summary: returns the bounding box
+		if(!this.bbox){
+			var shape = this.shape;
+			this.bbox = {x: shape.cx - shape.rx, y: shape.cy - shape.ry, 
+				width: 2 * shape.rx, height: 2 * shape.ry};
+		}
+		return this.bbox;	// dojox.gfx.Rectangle
+	}
+});
+
+dojo.declare("dojox.gfx.shape.Circle", dojox.gfx.Shape,
+	function(rawNode) {
+		// summary: a generic circle
+		//	(this is a helper object, which is defined for convenience)
+		// rawNode: Node: a DOM Node
+		this.shape = dojox.gfx._base._copy(dojox.gfx.defaultCircle, true);
+		this.attach(rawNode);
+	},
+{
+	getBoundingBox: function(){
+		// summary: returns the bounding box
+		if(!this.bbox){
+			var shape = this.shape;
+			this.bbox = {x: shape.cx - shape.r, y: shape.cy - shape.r, 
+				width: 2 * shape.r, height: 2 * shape.r};
+		}
+		return this.bbox;	// dojox.gfx.Rectangle
+	}
+});
+
+dojo.declare("dojox.gfx.shape.Line", dojox.gfx.Shape,
+	function(rawNode) {
+		// summary: a generic line
+		//	(this is a helper object, which is defined for convenience)
+		// rawNode: Node: a DOM Node
+		this.shape = dojox.gfx._base._copy(dojox.gfx.defaultLine, true);
+		this.attach(rawNode);
+	},
+{
+	getBoundingBox: function(){
+		// summary: returns the bounding box
+		if(!this.bbox){
+			var shape = this.shape;
+			this.bbox = {
+				x:		Math.min(shape.x1, shape.x2),
+				y:		Math.min(shape.y1, shape.y2),
+				width:	Math.abs(shape.x2 - shape.x1),
+				height:	Math.abs(shape.y2 - shape.y1)
+			};
+		}
+		return this.bbox;	// dojox.gfx.Rectangle
+	}
+});
+
+dojo.declare("dojox.gfx.shape.Polyline", dojox.gfx.Shape,
+	function(rawNode) {
+		// summary: a generic polyline/polygon
+		//	(this is a helper object, which is defined for convenience)
+		// rawNode: Node: a DOM Node
+		this.shape = dojox.gfx._base._copy(dojox.gfx.defaultPolyline, true);
+		this.attach(rawNode);
+	},
+{
+	getBoundingBox: function(){
+		// summary: returns the bounding box
+		if(!this.bbox && this.shape.points.length){
+			var p = this.shape.points;
+			var l = p.length;
+			var t = p[0];
+			var bbox = {l: t.x, t: t.y, r: t.x, b: t.y};
+			for(var i = 1; i < l; ++i){
+				t = p[i];
+				if(bbox.l > t.x) bbox.l = t.x;
+				if(bbox.r < t.x) bbox.r = t.x;
+				if(bbox.t > t.y) bbox.t = t.y;
+				if(bbox.b < t.y) bbox.b = t.y;
+			}
+			this.bbox = {
+				x:		bbox.l, 
+				y:		bbox.t, 
+				width:	bbox.r - bbox.l, 
+				height:	bbox.b - bbox.t
+			};
+		}
+		return this.bbox;	// dojox.gfx.Rectangle
+	}
+});
+
+dojo.declare("dojox.gfx.shape.Image", dojox.gfx.Shape,
+	function(rawNode) {
+		// summary: a generic image
+		//	(this is a helper object, which is defined for convenience)
+		// rawNode: Node: a DOM Node
+		this.shape = dojox.gfx._base._copy(dojox.gfx.defaultImage, true);
+		this.attach(rawNode);
+	},
+{
+	getBoundingBox: function(){
+		// summary: returns the bounding box (its shape in this case)
+		return this.shape;	// dojox.gfx.Rectangle
+	}
+});
+
+dojo.declare("dojox.gfx.shape.Text", dojox.gfx.Shape,
+	function(rawNode) {
+		// summary: a generic text
+		// rawNode: Node: a DOM Node
+		this.fontStyle = null;
+		this.shape = dojox.gfx._base._copy(dojox.gfx.defaultText, true);
+		this.attach(rawNode);
+	},
+{
+	setFont: function(newFont){
+		// summary: sets a font for text
+		// newFont: Object: a font object (see dojox.gfx.defaultFont) or a font string
+		this.fontStyle = typeof newFont == "string" ? dojox.gfx.splitFontString(newFont) :
+			dojox.gfx.makeParameters(dojox.gfx.defaultFont, newFont);
+		this._setFont();
+		return this;	// self
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/svg.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/svg.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/svg.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,922 @@
+dojo.provide("dojox.gfx.svg");
+
+dojo.require("dojox.gfx._base");
+dojo.require("dojox.gfx.shape");
+dojo.require("dojox.gfx.path");
+
+dojo.experimental("dojox.gfx.svg");
+
+dojox.gfx.svg.xmlns = {
+	xlink: "http://www.w3.org/1999/xlink",
+	svg:   "http://www.w3.org/2000/svg"
+};
+
+dojox.gfx.svg.getRef = function(name){
+	// summary: returns a DOM Node specified by the name argument or null
+	// name: String: an SVG external reference 
+	if(!name || name == "none") return null;
+	if(name.match(/^url\(#.+\)$/)){
+		return dojo.byId(name.slice(5, -1));	// Node
+	}
+	// alternative representation of a reference
+	if(name.match(/^#dj_unique_.+$/)){
+		// we assume here that a reference was generated by dojox.gfx
+		return dojo.byId(name.slice(1));	// Node
+	}
+	return null;	// Node
+};
+
+dojox.gfx.svg.dasharray = {
+	solid:				"none",
+	shortdash:			[4, 1],
+	shortdot:			[1, 1],
+	shortdashdot:		[4, 1, 1, 1],
+	shortdashdotdot:	[4, 1, 1, 1, 1, 1],
+	dot:				[1, 3],
+	dash:				[4, 3],
+	longdash:			[8, 3],
+	dashdot:			[4, 3, 1, 3],
+	longdashdot:		[8, 3, 1, 3],
+	longdashdotdot:		[8, 3, 1, 3, 1, 3]
+};
+
+dojo.extend(dojox.gfx.Shape, {
+	// summary: SVG-specific implementation of dojox.gfx.Shape methods
+	
+	setFill: function(fill){
+		// summary: sets a fill object (SVG)
+		// fill: Object: a fill object
+		//	(see dojox.gfx.defaultLinearGradient, 
+		//	dojox.gfx.defaultRadialGradient, 
+		//	dojox.gfx.defaultPattern, 
+		//	or dojo.Color)
+
+		if(!fill){
+			// don't fill
+			this.fillStyle = null;
+			this.rawNode.setAttribute("fill", "none");
+			this.rawNode.setAttribute("fill-opacity", 0);
+			return this;
+		}
+		if(typeof(fill) == "object" && "type" in fill){
+			// gradient
+			switch(fill.type){
+				case "linear":
+					var f = dojox.gfx.makeParameters(dojox.gfx.defaultLinearGradient, fill);
+					var gradient = this._setFillObject(f, "linearGradient");
+					dojo.forEach(["x1", "y1", "x2", "y2"], function(x){
+						gradient.setAttribute(x, f[x].toFixed(8));
+					});
+					break;
+				case "radial":
+					var f = dojox.gfx.makeParameters(dojox.gfx.defaultRadialGradient, fill);
+					var gradient = this._setFillObject(f, "radialGradient");
+					dojo.forEach(["cx", "cy", "r"], function(x){
+						gradient.setAttribute(x, f[x].toFixed(8));
+					});
+					break;
+				case "pattern":
+					var f = dojox.gfx.makeParameters(dojox.gfx.defaultPattern, fill);
+					var pattern = this._setFillObject(f, "pattern");
+					dojo.forEach(["x", "y", "width", "height"], function(x){
+						pattern.setAttribute(x, f[x].toFixed(8));
+					});
+					break;
+			}
+			return this;
+		}
+		// color object
+		var f = dojox.gfx.normalizeColor(fill);
+		this.fillStyle = f;
+		this.rawNode.setAttribute("fill", f.toCss());
+		this.rawNode.setAttribute("fill-opacity", f.a);
+		return this;	// self
+	},
+
+	setStroke: function(stroke){
+		// summary: sets a stroke object (SVG)
+		// stroke: Object: a stroke object
+		//	(see dojox.gfx.defaultStroke) 
+	
+		if(!stroke){
+			// don't stroke
+			this.strokeStyle = null;
+			this.rawNode.setAttribute("stroke", "none");
+			this.rawNode.setAttribute("stroke-opacity", 0);
+			return this;
+		}
+		// normalize the stroke
+		if(typeof stroke == "string"){
+			stroke = {color: stroke};
+		}
+		var s = this.strokeStyle = dojox.gfx.makeParameters(dojox.gfx.defaultStroke, stroke);
+		s.color = dojox.gfx.normalizeColor(s.color);
+		// generate attributes
+		var rn = this.rawNode;
+		if(s){
+			rn.setAttribute("stroke", s.color.toCss());
+			rn.setAttribute("stroke-opacity", s.color.a);
+			rn.setAttribute("stroke-width",   s.width);
+			rn.setAttribute("stroke-linecap", s.cap);
+			if(typeof(s.join) == "number"){
+				rn.setAttribute("stroke-linejoin",   "miter");
+				rn.setAttribute("stroke-miterlimit", s.join);
+			}else{
+				rn.setAttribute("stroke-linejoin",   s.join);
+			}
+			var da = s.style.toLowerCase();
+			if(da in dojox.gfx.svg.dasharray){ da = dojox.gfx.svg.dasharray[da]; }
+			if(da instanceof Array){
+				for(var i = 0; i < da.length; ++i){
+					da[i] *= s.width;
+				}
+				if(s.cap != "butt"){
+					for(var i = 0; i < da.length; i += 2){
+						da[i] -= s.width;
+						if(da[i] < 1){ da[i] = 1; }
+					}
+					for(var i = 1; i < da.length; i += 2){
+						da[i] += s.width;
+					}
+				}
+				da = da.join(",");
+			}
+			rn.setAttribute("stroke-dasharray", da);
+			rn.setAttribute("dojoGfxStrokeStyle", s.style);
+		}
+		return this;	// self
+	},
+	
+	_getParentSurface: function(){
+		var surface = this.parent;
+		for(; surface && !(surface instanceof dojox.gfx.Surface); surface = surface.parent);
+		return surface;
+	},
+
+	_setFillObject: function(f, nodeType){
+		this.fillStyle = f;
+		var surface = this._getParentSurface();
+		var defs = surface.defNode;
+		var fill = this.rawNode.getAttribute("fill");
+		var ref  = dojox.gfx.svg.getRef(fill);
+		if(ref){
+			fill = ref;
+			if(fill.tagName.toLowerCase() != nodeType.toLowerCase()){
+				var id = fill.id;
+				fill.parentNode.removeChild(fill);
+				fill = document.createElementNS(dojox.gfx.svg.xmlns.svg, nodeType);
+				fill.setAttribute("id", id);
+				defs.appendChild(fill);
+			}else{
+				while(fill.childNodes.length){
+					fill.removeChild(fill.lastChild);
+				}
+			}
+		}else{
+			fill = document.createElementNS(dojox.gfx.svg.xmlns.svg, nodeType);
+			fill.setAttribute("id", dojox.gfx._base._getUniqueId());
+			defs.appendChild(fill);
+		}
+		if(nodeType == "pattern"){
+			fill.setAttribute("patternUnits", "userSpaceOnUse");
+			var img = document.createElementNS(dojox.gfx.svg.xmlns.svg, "image");
+			img.setAttribute("x", 0);
+			img.setAttribute("y", 0);
+			img.setAttribute("width",  f.width .toFixed(8));
+			img.setAttribute("height", f.height.toFixed(8));
+			img.setAttributeNS(dojox.gfx.svg.xmlns.xlink, "href", f.src);
+			fill.appendChild(img);
+		}else{
+			fill.setAttribute("gradientUnits", "userSpaceOnUse");
+			for(var i = 0; i < f.colors.length; ++i){
+				f.colors[i].color = dojox.gfx.normalizeColor(f.colors[i].color);
+				var t = document.createElementNS(dojox.gfx.svg.xmlns.svg, "stop");
+				t.setAttribute("offset",     f.colors[i].offset.toFixed(8));
+				t.setAttribute("stop-color", f.colors[i].color.toCss());
+				fill.appendChild(t);
+			}
+		}
+		this.rawNode.setAttribute("fill", "url(#" + fill.getAttribute("id") +")");
+		this.rawNode.removeAttribute("fill-opacity");
+		return fill;
+	},
+	
+	_applyTransform: function() {
+		var matrix = this.matrix;
+		if(matrix){
+			var tm = this.matrix;
+			this.rawNode.setAttribute("transform", "matrix(" +
+				tm.xx.toFixed(8) + "," + tm.yx.toFixed(8) + "," +
+				tm.xy.toFixed(8) + "," + tm.yy.toFixed(8) + "," +
+				tm.dx.toFixed(8) + "," + tm.dy.toFixed(8) + ")");
+		}else{
+			this.rawNode.removeAttribute("transform");
+		}
+		return this;
+	},
+
+	setRawNode: function(rawNode){
+		// summary:
+		//	assigns and clears the underlying node that will represent this
+		//	shape. Once set, transforms, gradients, etc, can be applied.
+		//	(no fill & stroke by default)
+		with(rawNode){
+			setAttribute("fill", "none");
+			setAttribute("fill-opacity", 0);
+			setAttribute("stroke", "none");
+			setAttribute("stroke-opacity", 0);
+			setAttribute("stroke-width", 1);
+			setAttribute("stroke-linecap", "butt");
+			setAttribute("stroke-linejoin", "miter");
+			setAttribute("stroke-miterlimit", 4);
+		}
+		this.rawNode = rawNode;
+	},
+
+	moveToFront: function(){
+		// summary: moves a shape to front of its parent's list of shapes (SVG)
+		this.rawNode.parentNode.appendChild(this.rawNode);
+		return this;	// self
+	},
+	moveToBack: function(){
+		// summary: moves a shape to back of its parent's list of shapes (SVG)
+		this.rawNode.parentNode.insertBefore(this.rawNode, this.rawNode.parentNode.firstChild);
+		return this;	// self
+	},
+	
+	setShape: function(newShape){
+		// summary: sets a shape object (SVG)
+		// newShape: Object: a shape object
+		//	(see dojox.gfx.defaultPath,
+		//	dojox.gfx.defaultPolyline,
+		//	dojox.gfx.defaultRect,
+		//	dojox.gfx.defaultEllipse,
+		//	dojox.gfx.defaultCircle,
+		//	dojox.gfx.defaultLine,
+		//	or dojox.gfx.defaultImage)
+		this.shape = dojox.gfx.makeParameters(this.shape, newShape);
+		for(var i in this.shape){
+			if(i != "type"){ this.rawNode.setAttribute(i, this.shape[i]); }
+		}
+		return this;	// self
+	},
+	
+	attachFill: function(rawNode){
+		// summary: deduces a fill style from a Node.
+		// rawNode: Node: an SVG node
+		var fillStyle = null;
+		if(rawNode){
+			var fill = rawNode.getAttribute("fill");
+			if(fill == "none"){ return null; }
+			var ref  = dojox.gfx.svg.getRef(fill);
+			if(ref){
+				var gradient = ref;
+				switch(gradient.tagName.toLowerCase()){
+					case "lineargradient":
+						fillStyle = this._getGradient(dojox.gfx.defaultLinearGradient, gradient);
+						dojo.forEach(["x1", "y1", "x2", "y2"], function(x){
+							fillStyle[x] = gradient.getAttribute(x);
+						});
+						break;
+					case "radialgradient":
+						fillStyle = this._getGradient(dojox.gfx.defaultRadialGradient, gradient);
+						dojo.forEach(["cx", "cy", "r"], function(x){
+							fillStyle[x] = gradient.getAttribute(x);
+						});
+						fillStyle.cx = gradient.getAttribute("cx");
+						fillStyle.cy = gradient.getAttribute("cy");
+						fillStyle.r  = gradient.getAttribute("r");
+						break;
+					case "pattern":
+						fillStyle = dojo.lang.shallowCopy(dojox.gfx.defaultPattern, true);
+						dojo.forEach(["x", "y", "width", "height"], function(x){
+							fillStyle[x] = gradient.getAttribute(x);
+						});
+						fillStyle.src = gradient.firstChild.getAttributeNS(dojox.gfx.svg.xmlns.xlink, "href");
+						break;
+				}
+			}else{
+				fillStyle = new dojo.Color(fill);
+				var opacity = rawNode.getAttribute("fill-opacity");
+				if(opacity != null) fillStyle.a = opacity;
+			}
+		}
+		return fillStyle;	// Object
+	},
+	
+	_getGradient: function(defaultGradient, gradient){
+		var fillStyle = dojox.gfx._base._copy(defaultGradient, true);
+		fillStyle.colors = [];
+		for(var i = 0; i < gradient.childNodes.length; ++i){
+			fillStyle.colors.push({
+				offset: gradient.childNodes[i].getAttribute("offset"),
+				color:  new dojo.Color(gradient.childNodes[i].getAttribute("stop-color"))
+			});
+		}
+		return fillStyle;
+	},
+
+	attachStroke: function(rawNode){
+		// summary: deduces a stroke style from a Node.
+		// rawNode: Node: an SVG node
+		if(!rawNode){ return null; }
+		var stroke = rawNode.getAttribute("stroke");
+		if(stroke == null || stroke == "none") return null;
+		var strokeStyle = dojox.gfx._base._copy(dojox.gfx.defaultStroke, true);
+		var color = new dojo.Color(stroke);
+		if(color){
+			strokeStyle.color = color;
+			strokeStyle.color.a = rawNode.getAttribute("stroke-opacity");
+			strokeStyle.width = rawNode.getAttribute("stroke-width");
+			strokeStyle.cap = rawNode.getAttribute("stroke-linecap");
+			strokeStyle.join = rawNode.getAttribute("stroke-linejoin");
+			if(strokeStyle.join == "miter"){
+				strokeStyle.join = rawNode.getAttribute("stroke-miterlimit");
+			}
+			strokeStyle.style = rawNode.getAttribute("dojoGfxStrokeStyle");
+		}
+		return strokeStyle;	// Object
+	},
+
+	attachTransform: function(rawNode){
+		// summary: deduces a transformation matrix from a Node.
+		// rawNode: Node: an SVG node
+		var matrix = null;
+		if(rawNode){
+			matrix = rawNode.getAttribute("transform");
+			if(matrix.match(/^matrix\(.+\)$/)){
+				var t = matrix.slice(7, -1).split(",");
+				matrix = dojox.gfx.matrix.normalize({
+					xx: parseFloat(t[0]), xy: parseFloat(t[2]), 
+					yx: parseFloat(t[1]), yy: parseFloat(t[3]), 
+					dx: parseFloat(t[4]), dy: parseFloat(t[5])
+				});
+			}
+		}
+		return matrix;	// dojox.gfx.matrix.Matrix
+	},
+	
+	attachShape: function(rawNode){
+		// summary: builds a shape from a Node.
+		// rawNode: Node: an SVG node
+		var shape = null;
+		if(rawNode){
+			shape = dojox.gfx._base._copy(this.shape, true);
+			for(var i in shape) {
+				shape[i] = rawNode.getAttribute(i);
+			}
+		}
+		return shape;	// dojox.gfx.Shape
+	},
+
+	attach: function(rawNode){
+		// summary: reconstructs all shape parameters from a Node.
+		// rawNode: Node: an SVG node
+		if(rawNode) {
+			this.rawNode = rawNode;
+			this.fillStyle = this.attachFill(rawNode);
+			this.strokeStyle = this.attachStroke(rawNode);
+			this.matrix = this.attachTransform(rawNode);
+			this.shape = this.attachShape(rawNode);
+		}
+	},
+	
+	_getRealMatrix: function(){
+		var m = this.matrix;
+		var p = this.parent;
+		while(p){
+			if(p.matrix){
+				m = dojox.gfx.matrix.multiply(p.matrix, m);
+			}
+			p = p.parent;
+		}
+		return m;
+	}
+});
+
+dojo.declare("dojox.gfx.Group", dojox.gfx.Shape, {
+	// summary: a group shape (SVG), which can be used 
+	//	to logically group shapes (e.g, to propagate matricies)
+
+	setRawNode: function(rawNode){
+		// summary: sets a raw SVG node to be used by this shape
+		// rawNode: Node: an SVG node
+		this.rawNode = rawNode;
+	}
+});
+dojox.gfx.Group.nodeType = "g";
+
+dojo.declare("dojox.gfx.Rect", dojox.gfx.shape.Rect, {
+	// summary: a rectangle shape (SVG)
+
+	attachShape: function(rawNode){
+		// summary: builds a rectangle shape from a Node.
+		// rawNode: Node: an SVG node
+		var shape = null;
+		if(rawNode){
+			shape = dojox.gfx.Rect.superclass.attachShape.apply(this, arguments);
+			shape.r = Math.min(rawNode.getAttribute("rx"), rawNode.getAttribute("ry"));
+		}
+		return shape;	// dojox.gfx.shape.Rect
+	},
+	setShape: function(newShape){
+		// summary: sets a rectangle shape object (SVG)
+		// newShape: Object: a rectangle shape object
+		this.shape = dojox.gfx.makeParameters(this.shape, newShape);
+		this.bbox = null;
+		for(var i in this.shape){
+			if(i != "type" && i != "r"){ this.rawNode.setAttribute(i, this.shape[i]); }
+		}
+		if(this.shape.r){
+			this.rawNode.setAttribute("ry", this.shape.r);
+			this.rawNode.setAttribute("rx", this.shape.r);
+		}
+		return this;	// self
+	}
+});
+dojox.gfx.Rect.nodeType = "rect";
+
+dojox.gfx.Ellipse = dojox.gfx.shape.Ellipse;
+dojox.gfx.Ellipse.nodeType = "ellipse";
+
+dojox.gfx.Circle = dojox.gfx.shape.Circle;
+dojox.gfx.Circle.nodeType = "circle";
+
+dojox.gfx.Line = dojox.gfx.shape.Line;
+dojox.gfx.Line.nodeType = "line";
+
+dojo.declare("dojox.gfx.Polyline", dojox.gfx.shape.Polyline, {
+	// summary: a polyline/polygon shape (SVG)
+	
+	setShape: function(points, closed){
+		// summary: sets a polyline/polygon shape object (SVG)
+		// points: Object: a polyline/polygon shape object
+		if(points && points instanceof Array){
+			// branch
+			// points: Array: an array of points
+			this.shape = dojox.gfx.makeParameters(this.shape, { points: points });
+			if(closed && this.shape.points.length){ 
+				this.shape.points.push(this.shape.points[0]);
+			}
+		}else{
+			this.shape = dojox.gfx.makeParameters(this.shape, points);
+		}
+		this.box = null;
+		var attr = [];
+		var p = this.shape.points;
+		for(var i = 0; i < p.length; ++i){
+			if(typeof p[i] == "number"){
+				attr.push(p[i].toFixed(8));
+			}else{
+				attr.push(p[i].x.toFixed(8));
+				attr.push(p[i].y.toFixed(8));
+			}
+		}
+		this.rawNode.setAttribute("points", attr.join(" "));
+		return this;	// self
+	}
+});
+dojox.gfx.Polyline.nodeType = "polyline";
+
+dojo.declare("dojox.gfx.Image", dojox.gfx.shape.Image, {
+	// summary: an image (SVG)
+
+	setShape: function(newShape){
+		// summary: sets an image shape object (SVG)
+		// newShape: Object: an image shape object
+		this.shape = dojox.gfx.makeParameters(this.shape, newShape);
+		this.bbox = null;
+		var rawNode = this.rawNode;
+		for(var i in this.shape){
+			if(i != "type" && i != "src"){ rawNode.setAttribute(i, this.shape[i]); }
+		}
+		rawNode.setAttributeNS(dojox.gfx.svg.xmlns.xlink, "href", this.shape.src);
+		return this;	// self
+	},
+	setStroke: function(){
+		// summary: ignore setting a stroke style
+		return this;	// self
+	},
+	setFill: function(){
+		// summary: ignore setting a fill style
+		return this;	// self
+	},
+	attachStroke: function(rawNode){
+		// summary: ignore attaching a stroke style
+		return null;
+	},
+	attachFill: function(rawNode){
+		// summary: ignore attaching a fill style
+		return null;
+	}
+});
+dojox.gfx.Image.nodeType = "image";
+
+dojo.declare("dojox.gfx.Text", dojox.gfx.shape.Text, {
+	// summary: an anchored text (SVG)
+
+	attachShape: function(rawNode){
+		// summary: builds a text shape from a Node.
+		// rawNode: Node: an SVG node
+		var shape = null;
+		if(rawNode){
+			shape = dojox.gfx._base._copy(dojox.gfx.defaultText, true);
+			shape.x = rawNode.getAttribute("x");
+			shape.y = rawNode.getAttribute("y");
+			shape.align = rawNode.getAttribute("text-anchor");
+			shape.decoration = rawNode.getAttribute("text-decoration");
+			shape.rotated = parseFloat(rawNode.getAttribute("rotate")) != 0;
+			shape.kerning = rawNode.getAttribute("kerning") == "auto";
+			shape.text = rawNode.firstChild.nodeValue;
+		}
+		return shape;	// dojox.gfx.shape.Text
+	},
+	setShape: function(newShape){
+		// summary: sets a text shape object (SVG)
+		// newShape: Object: a text shape object
+		this.shape = dojox.gfx.makeParameters(this.shape, newShape);
+		this.bbox = null;
+		var r = this.rawNode;
+		var s = this.shape;
+		r.setAttribute("x", s.x);
+		r.setAttribute("y", s.y);
+		r.setAttribute("text-anchor", s.align);
+		r.setAttribute("text-decoration", s.decoration);
+		r.setAttribute("rotate", s.rotated ? 90 : 0);
+		r.setAttribute("kerning", s.kerning ? "auto" : 0);
+		r.textContent = s.text;
+		return this;	// self
+	},
+	attach: function(rawNode){
+		// summary: reconstructs all shape parameters from a Node.
+		// rawNode: Node: an SVG node
+		dojox.gfx.Shape.prototype.attach.call(this, rawNode);
+		if(rawNode) {
+			this.fontStyle = this.attachFont(rawNode);
+		}
+	}
+});
+dojox.gfx.Text.nodeType = "text";
+
+dojo.declare("dojox.gfx.Path", dojox.gfx.path.Path, {
+	// summary: a path shape (SVG)
+
+	_updateWithSegment: function(segment){
+		// summary: updates the bounding box of path with new segment
+		// segment: Object: a segment
+		dojox.gfx.Path.superclass._updateWithSegment.apply(this, arguments);
+		if(typeof(this.shape.path) == "string"){
+			this.rawNode.setAttribute("d", this.shape.path);
+		}
+	},
+	setShape: function(newShape){
+		// summary: forms a path using a shape (SVG)
+		// newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath)
+		dojox.gfx.Path.superclass.setShape.apply(this, arguments);
+		this.rawNode.setAttribute("d", this.shape.path);
+		return this;	// self
+	}
+});
+dojox.gfx.Path.nodeType = "path";
+
+dojo.declare("dojox.gfx.TextPath", dojox.gfx.path.TextPath, {
+	// summary: a textpath shape (SVG)
+
+	_updateWithSegment: function(segment){
+		// summary: updates the bounding box of path with new segment
+		// segment: Object: a segment
+		dojox.gfx.Path.superclass._updateWithSegment.apply(this, arguments);
+		this._setTextPath();
+	},
+	setShape: function(newShape){
+		// summary: forms a path using a shape (SVG)
+		// newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath)
+		dojox.gfx.Path.superclass.setShape.apply(this, arguments);
+		this._setTextPath();
+		return this;	// self
+	},
+	_setTextPath: function(){
+		if(typeof this.shape.path != "string"){ return; }
+		var r = this.rawNode;
+		if(!r.firstChild){
+			var tp = document.createElementNS(dojox.gfx.svg.xmlns.svg, "textPath");
+			var tx = document.createTextNode("");
+			tp.appendChild(tx);
+			r.appendChild(tp);
+		}
+		var ref  = r.firstChild.getAttributeNS(dojox.gfx.svg.xmlns.xlink, "href");
+		var path = ref && dojox.gfx.svg.getRef(ref);
+		if(!path){
+			var surface = this._getParentSurface();
+			if(surface){
+				var defs = surface.defNode;
+				path = document.createElementNS(dojox.gfx.svg.xmlns.svg, "path");
+				var id = dojox.gfx._base._getUniqueId();
+				path.setAttribute("id", id);
+				defs.appendChild(path);
+				r.firstChild.setAttributeNS(dojox.gfx.svg.xmlns.xlink, "href", "#" + id);
+			}
+		}
+		if(path){
+			path.setAttribute("d", this.shape.path);
+		}
+	},
+	_setText: function(){
+		var r = this.rawNode;
+		if(!r.firstChild){
+			var tp = document.createElementNS(dojox.gfx.svg.xmlns.svg, "textPath");
+			var tx = document.createTextNode("");
+			tp.appendChild(tx);
+			r.appendChild(tp);
+		}
+		r = r.firstChild;
+		var t = this.text;
+		r.setAttribute("alignment-baseline", "middle");
+		switch(t.align){
+			case "middle":
+				r.setAttribute("text-anchor", "middle");
+				r.setAttribute("startOffset", "50%");
+				break;
+			case "end":
+				r.setAttribute("text-anchor", "end");
+				r.setAttribute("startOffset", "100%");
+				break;
+			default:
+				r.setAttribute("text-anchor", "start");
+				r.setAttribute("startOffset", "0%");
+				break;
+		}
+		//r.parentNode.setAttribute("alignment-baseline", "central");
+		//r.setAttribute("dominant-baseline", "central");
+		r.setAttribute("baseline-shift", "0.5ex");
+		r.setAttribute("text-decoration", t.decoration);
+		r.setAttribute("rotate", t.rotated ? 90 : 0);
+		r.setAttribute("kerning", t.kerning ? "auto" : 0);
+		r.firstChild.data = t.text;
+	},
+	attachText: function(rawNode){
+		// summary: builds a textpath shape from a Node.
+		// rawNode: Node: an SVG node
+		var shape = null;
+		if(rawNode){
+			shape = dojox.gfx._base._copy(dojox.gfx.defaultTextPath, true);
+			shape.align = rawNode.getAttribute("text-anchor");
+			shape.decoration = rawNode.getAttribute("text-decoration");
+			shape.rotated = parseFloat(rawNode.getAttribute("rotate")) != 0;
+			shape.kerning = rawNode.getAttribute("kerning") == "auto";
+			shape.text = rawNode.firstChild.nodeValue;
+		}
+		return shape;	// dojox.gfx.shape.TextPath
+	},
+	attach: function(rawNode){
+		// summary: reconstructs all shape parameters from a Node.
+		// rawNode: Node: an SVG node
+		dojox.gfx.Shape.prototype.attach.call(this, rawNode);
+		if(rawNode) {
+			this.fontStyle = this.attachFont(rawNode);
+			this.text = this.attachText(rawNode);
+		}
+	}
+});
+dojox.gfx.TextPath.nodeType = "text";
+
+
+dojox.gfx.svg._font = {
+	_setFont: function(){
+		// summary: sets a font object (SVG)
+		var f = this.fontStyle;
+		// next line doesn't work in Firefox 2 or Opera 9
+		//this.rawNode.setAttribute("font", dojox.gfx.makeFontString(this.fontStyle));
+		this.rawNode.setAttribute("font-style", f.style);
+		this.rawNode.setAttribute("font-variant", f.variant);
+		this.rawNode.setAttribute("font-weight", f.weight);
+		this.rawNode.setAttribute("font-size", f.size);
+		this.rawNode.setAttribute("font-family", f.family);
+	},
+	attachFont: function(rawNode){
+		// summary: deduces a font style from a Node.
+		// rawNode: Node: an SVG node
+		if(!rawNode){ return null; }
+		var fontStyle = dojox.gfx._base._copy(dojox.gfx.defaultFont, true);
+		fontStyle.style = rawNode.getAttribute("font-style");
+		fontStyle.variant = rawNode.getAttribute("font-variant");
+		fontStyle.weight = rawNode.getAttribute("font-weight");
+		fontStyle.size = rawNode.getAttribute("font-size");
+		fontStyle.family = rawNode.getAttribute("font-family");
+		return fontStyle;	// Object
+	}
+};
+
+dojo.extend(dojox.gfx.Text, dojox.gfx.svg._font);
+dojo.extend(dojox.gfx.TextPath, dojox.gfx.svg._font);
+
+delete dojox.gfx.svg._font;
+
+dojox.gfx.svg._creators = {
+	// summary: SVG shape creators
+	createPath: function(path){
+		// summary: creates an SVG path shape
+		// path: Object: a path object (see dojox.gfx.defaultPath)
+		return this.createObject(dojox.gfx.Path, path);	// dojox.gfx.Path
+	},
+	createRect: function(rect){
+		// summary: creates an SVG rectangle shape
+		// rect: Object: a path object (see dojox.gfx.defaultRect)
+		return this.createObject(dojox.gfx.Rect, rect);	// dojox.gfx.Rect
+	},
+	createCircle: function(circle){
+		// summary: creates an SVG circle shape
+		// circle: Object: a circle object (see dojox.gfx.defaultCircle)
+		return this.createObject(dojox.gfx.Circle, circle);	// dojox.gfx.Circle
+	},
+	createEllipse: function(ellipse){
+		// summary: creates an SVG ellipse shape
+		// ellipse: Object: an ellipse object (see dojox.gfx.defaultEllipse)
+		return this.createObject(dojox.gfx.Ellipse, ellipse);	// dojox.gfx.Ellipse
+	},
+	createLine: function(line){
+		// summary: creates an SVG line shape
+		// line: Object: a line object (see dojox.gfx.defaultLine)
+		return this.createObject(dojox.gfx.Line, line);	// dojox.gfx.Line
+	},
+	createPolyline: function(points){
+		// summary: creates an SVG polyline/polygon shape
+		// points: Object: a points object (see dojox.gfx.defaultPolyline)
+		//	or an Array of points
+		return this.createObject(dojox.gfx.Polyline, points);	// dojox.gfx.Polyline
+	},
+	createImage: function(image){
+		// summary: creates an SVG image shape
+		// image: Object: an image object (see dojox.gfx.defaultImage)
+		return this.createObject(dojox.gfx.Image, image);	// dojox.gfx.Image
+	},
+	createText: function(text){
+		// summary: creates an SVG text shape
+		// text: Object: a text object (see dojox.gfx.defaultText)
+		return this.createObject(dojox.gfx.Text, text);	// dojox.gfx.Text
+	},
+	createTextPath: function(text){
+		// summary: creates an SVG text shape
+		// text: Object: a textpath object (see dojox.gfx.defaultTextPath)
+		return this.createObject(dojox.gfx.TextPath, {}).setText(text);	// dojox.gfx.TextPath
+	},
+	createGroup: function(){
+		// summary: creates an SVG group shape
+		return this.createObject(dojox.gfx.Group);	// dojox.gfx.Group
+	},
+	createObject: function(shapeType, rawShape){
+		// summary: creates an instance of the passed shapeType class
+		// shapeType: Function: a class constructor to create an instance of
+		// rawShape: Object: properties to be passed in to the classes "setShape" method
+		if(!this.rawNode){ return null; }
+		var shape = new shapeType();
+		var node = document.createElementNS(dojox.gfx.svg.xmlns.svg, shapeType.nodeType); 
+		shape.setRawNode(node);
+		this.rawNode.appendChild(node);
+		shape.setShape(rawShape);
+		this.add(shape);
+		return shape;	// dojox.gfx.Shape
+	},
+	// group control
+	add: function(shape){
+		// summary: adds a shape to a group/surface
+		// shape: dojox.gfx.Shape: an SVG shape object
+		var oldParent = shape.getParent();
+		if(oldParent){
+			oldParent.remove(shape, true);
+		}
+		shape._setParent(this, null);
+		this.rawNode.appendChild(shape.rawNode);
+		return this;	// self
+	},
+	remove: function(shape, silently){
+		// summary: remove a shape from a group/surface
+		// shape: dojox.gfx.Shape: an SVG shape object
+		// silently: Boolean?: if true, regenerate a picture
+		if(this.rawNode == shape.rawNode.parentNode){
+			this.rawNode.removeChild(shape.rawNode);
+		}
+		shape._setParent(null, null);
+		return this;	// self
+	},
+	clear: function(){
+		// summary: removes all shapes from a group/surface
+		var r = this.rawNode;
+		while(r.lastChild && r.firstChild != r.lastChild){
+			r.removeChild(r.lastChild);
+		}
+		return this;	// self
+	}
+};
+
+dojox.gfx.attachNode = function(node){
+	// summary: creates a shape from a Node
+	// node: Node: an SVG node
+	if(!node) return null;
+	var s = null;
+	switch(node.tagName.toLowerCase()){
+		case dojox.gfx.Rect.nodeType:
+			s = new dojox.gfx.Rect();
+			break;
+		case dojox.gfx.Ellipse.nodeType:
+			s = new dojox.gfx.Ellipse();
+			break;
+		case dojox.gfx.Polyline.nodeType:
+			s = new dojox.gfx.Polyline();
+			break;
+		case dojox.gfx.Path.nodeType:
+			s = new dojox.gfx.Path();
+			break;
+		case dojox.gfx.Circle.nodeType:
+			s = new dojox.gfx.Circle();
+			break;
+		case dojox.gfx.Line.nodeType:
+			s = new dojox.gfx.Line();
+			break;
+		case dojox.gfx.Image.nodeType:
+			s = new dojox.gfx.Image();
+			break;
+		case dojox.gfx.Text.nodeType:
+			var t = node.getElementsByTagName("textPath");
+			if(t && t.length){
+				s = new dojox.gfx.TextPath();
+			}else{
+				s = new dojox.gfx.Text();
+			}
+			break;
+		default:
+			console.debug("FATAL ERROR! tagName = " + node.tagName);
+			return null;
+	}
+	s.attach(node);
+	return s;	// dojox.gfx.Shape
+};
+
+dojo.extend(dojox.gfx.Surface, {
+	// summary: a surface object to be used for drawings (SVG)
+
+	setDimensions: function(width, height){
+		// summary: sets the width and height of the rawNode
+		// width: String: width of surface, e.g., "100px"
+		// height: String: height of surface, e.g., "100px"
+		if(!this.rawNode){ return this; }
+		this.rawNode.setAttribute("width",  width);
+		this.rawNode.setAttribute("height", height);
+		return this;	// self
+	},
+	getDimensions: function(){
+		// summary: returns an object with properties "width" and "height"
+		return this.rawNode ? {width: this.rawNode.getAttribute("width"), height: this.rawNode.getAttribute("height")} : null; // Object
+	}
+});
+
+dojox.gfx.createSurface = function(parentNode, width, height){
+	// summary: creates a surface (SVG)
+	// parentNode: Node: a parent node
+	// width: String: width of surface, e.g., "100px"
+	// height: String: height of surface, e.g., "100px"
+
+	var s = new dojox.gfx.Surface();
+	s.rawNode = document.createElementNS(dojox.gfx.svg.xmlns.svg, "svg");
+	s.rawNode.setAttribute("width",  width);
+	s.rawNode.setAttribute("height", height);
+
+	var defs = new dojox.gfx.svg.Defines();
+	var node = document.createElementNS(dojox.gfx.svg.xmlns.svg, dojox.gfx.svg.Defines.nodeType); 
+	defs.setRawNode(node);
+	s.rawNode.appendChild(node);
+	s.defNode = node;
+	
+	dojo.byId(parentNode).appendChild(s.rawNode);
+	return s;	// dojox.gfx.Surface
+};
+
+dojox.gfx.attachSurface = function(node){
+	// summary: creates a surface from a Node
+	// node: Node: an SVG node
+	var s = new dojox.gfx.Surface();
+	s.rawNode = node;
+	var def_elems = node.getElementsByTagName("defs");
+	if(def_elems.length == 0){
+		return null;	// dojox.gfx.Surface
+	}
+	s.defNode = def_elems[0];
+	return s;	// dojox.gfx.Surface
+};
+
+dojo.extend(dojox.gfx.Group, dojox.gfx.svg._creators);
+dojo.extend(dojox.gfx.Surface, dojox.gfx.svg._creators);
+
+delete dojox.gfx.svg._creators;
+
+// Gradient and pattern
+
+dojox.gfx.svg.Defines = function(){
+	this.rawNode = null;
+};
+dojo.extend(dojox.gfx.svg.Defines, {
+	setRawNode: function(rawNode){
+		this.rawNode = rawNode;
+	}
+});
+dojox.gfx.svg.Defines.nodeType = "defs";

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/images/error.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/images/error.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/images/placeholder.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/images/placeholder.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/images/rect.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/images/rect.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_arc.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_arc.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_arc.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,60 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Testing arc</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript">djConfig = { isDebug: true };</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<!--<script type="text/javascript" src="../_base.js"></script>-->
+<!--<script type="text/javascript" src="../shape.js"></script>-->
+<!--<script type="text/javascript" src="../path.js"></script>-->
+<!--<script type="text/javascript" src="../vml.js"></script>-->
+<!--<script type="text/javascript" src="../svg.js"></script>-->
+<script type="text/javascript">
+dojo.require("dojox.gfx");
+
+makeShapes = function(){
+	var surface = dojox.gfx.createSurface("test", 500, 500);
+	
+	var m = dojox.gfx.matrix;
+    var g1 = surface.createGroup();
+    var g2 = g1.createGroup();
+
+	var rx = 100, ry = 60, xRotg = 30;
+    var startPoint = m.multiplyPoint(m.rotateg(xRotg), {x: -rx, y: 0  });
+    var endPoint   = m.multiplyPoint(m.rotateg(xRotg), {x: 0,   y: -ry});
+    
+    var re1 = g1.createPath()
+		.moveTo(startPoint)
+		.arcTo(rx, ry, xRotg, true, false, endPoint)
+		.setStroke({color: "red"})
+		;
+    var ge1 = g1.createPath()
+		.moveTo(re1.getLastPosition())
+		.arcTo(rx, ry, xRotg, false, false, startPoint)
+		.setStroke({color: "blue"})
+		;
+    var re2 = g2.createPath()
+		.moveTo(startPoint)
+		.arcTo(rx, ry, xRotg, false, true, endPoint)
+		.setStroke({color: "red"})
+		;
+    var ge2 = g2.createPath()
+		.moveTo(re2.getLastPosition())
+		.arcTo(rx, ry, xRotg, true, true, startPoint)
+		.setStroke({color: "blue"})
+		;
+		
+	g1.setTransform({dx: 200, dy: 200});
+	g2.setTransform({dx: 10,  dy: 10});
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+</head>
+<body>
+<p>Testing arc</p>
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_bezier.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_bezier.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_bezier.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,74 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Approximation of an arc with bezier</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript">djConfig = { isDebug: true };</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<!--<script type="text/javascript" src="../_base.js"></script>-->
+<!--<script type="text/javascript" src="../path.js"></script>-->
+<!--<script type="text/javascript" src="../vml.js"></script>-->
+<!--<script type="text/javascript" src="../svg.js"></script>-->
+<script type="text/javascript">
+dojo.require("dojox.gfx");
+
+makeShapes = function(){
+	var surface = dojox.gfx.createSurface("test", 500, 300);
+	var g = surface.createGroup();
+	
+	// create a reference ellipse
+	var rx = 200;
+	var ry = 100;
+	var startAngle = 30;
+	var arcAngle = 90;
+	var axisAngle = 30;
+	var e = g.createEllipse({rx: rx, ry: ry}).setStroke({});
+	
+	// calculate a bezier
+	var alpha = dojox.gfx.matrix._degToRad(arcAngle) / 2; // half of our angle
+	var cosa  = Math.cos(alpha);
+	var sina  = Math.sin(alpha);
+	// start point
+	var p1 = {x: cosa, y: sina};
+	// 1st control point
+	var p2 = {x: cosa + (4 / 3) * (1 - cosa), y: sina - (4 / 3) * cosa * (1 - cosa) / sina};
+	// 2nd control point (symmetric to the 1st one)
+	var p3 = {x: p2.x, y: -p2.y};
+	// end point (symmetric to the start point)
+	var p4 = {x: p1.x, y: -p1.y};
+	
+	// rotate and scale poins as appropriate
+	var s = dojox.gfx.matrix.normalize([dojox.gfx.matrix.scale(e.shape.rx, e.shape.ry), dojox.gfx.matrix.rotateg(startAngle + arcAngle / 2)]);
+	p1 = dojox.gfx.matrix.multiplyPoint(s, p1);
+	p2 = dojox.gfx.matrix.multiplyPoint(s, p2);
+	p3 = dojox.gfx.matrix.multiplyPoint(s, p3);
+	p4 = dojox.gfx.matrix.multiplyPoint(s, p4);
+	// draw control trapezoid
+	var t = g.createPath().setStroke({color: "blue"});
+	t.moveTo(p1.x, p1.y);
+	t.lineTo(p2.x, p2.y);
+	t.lineTo(p3.x, p3.y);
+	t.lineTo(p4.x, p4.y);
+	t.lineTo(p1.x, p1.y);
+	t.moveTo((p1.x + p4.x) / 2, (p1.y + p4.y) / 2);
+	t.lineTo((p2.x + p3.x) / 2, (p2.y + p3.y) / 2);
+	t.moveTo((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
+	t.lineTo((p3.x + p4.x) / 2, (p3.y + p4.y) / 2);
+	// draw a bezier
+	var b = g.createPath().setStroke({color: "red"});
+	b.moveTo(p1.x, p1.y);
+	b.curveTo(p2.x, p2.y, p3.x, p3.y, p4.x, p4.y);
+	// move everything in a middle
+	g.setTransform([dojox.gfx.matrix.translate(250, 150), dojox.gfx.matrix.rotateg(axisAngle)]);
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+</head>
+<body>
+<p>Approximation of an arc with bezier</p>
+<!--<p><button onclick="makeShapes();">Make</button></p>-->
+<div id="test" style="width: 500px; height: 300px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_gfx.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_gfx.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_gfx.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,525 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+   <head>
+   <title>Dojo Unified 2D Graphics</title>
+   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+   <script type="text/javascript">
+   // Dojo configuration
+   djConfig = { 
+      isDebug: true
+   };
+</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<!--<script type="text/javascript" src="../_base.js"></script>-->
+<!--<script type="text/javascript" src="../path.js"></script>-->
+<!--<script type="text/javascript" src="../vml.js"></script>-->
+<!--<script type="text/javascript" src="../svg.js"></script>-->
+<script type="text/javascript">
+
+dojo.require("dojox.gfx");
+
+var gTestContainer = null;
+var gTests = {};
+
+function isEqual(foo, bar, prefix)
+{
+    var flag = true;
+    if( foo != bar ) {
+        console.debug(prefix+":"+foo + "!=" + bar + " try dig into it" );
+        if( foo instanceof Array ) {
+            for( var i = 0; i< foo.length; i++ ) {
+                flag = isEqual(foo[i], bar[i], prefix+"["+i+"]") && flag;
+            }
+            flag = false;
+        } else {
+            for(var x in foo) {
+                if(bar[x] != undefined ) {
+                    flag = isEqual(foo[x], bar[x], prefix+"."+x) && flag;
+                } else {
+                    console.debug(prefix+":"+ x + " is undefined in bar" );
+                    flag = false;
+                }
+            }
+        }
+    }
+    return flag;
+}
+
+
+function getTestSurface(testName, testDescription, width, height) 
+{
+   width = width ? width : 300;
+   height = height ? height : 300;
+
+   // Create a DOM node for the surface
+   var testRow = document.createElement('tr');
+   var testCell = document.createElement('td');
+   var testHolder = document.createElement('div');
+   testHolder.id = testName + '_holder';
+   var refCell = document.createElement('td');
+   var refHolder = document.createElement('div');
+   var refImg = document.createElement('img');
+   refImg.src = "images/placeholder.png";
+//   refImg.width = width;
+//   refImg.height = height;
+   refImg.id = testName + '_refimg';
+   var imgUrl = 'images/' + testName + '.png';
+   var errUrl = 'images/error.png';
+   var imgToLoad = new Image();
+   dojo.connect(imgToLoad, 'onload', function() {
+                         refImg.src = imgUrl;
+                      });
+   dojo.connect(imgToLoad, 'onerror', function() {
+                         refImg.src = errUrl;
+                      });
+
+   imgToLoad.src = imgUrl;
+
+   testCell.appendChild(testHolder);
+   testRow.appendChild(testCell);
+   refHolder.appendChild(refImg);
+   refCell.appendChild(refHolder);
+   testRow.appendChild(refCell);
+   gTestContainer.appendChild(testRow);
+
+   var descRow = document.createElement('tr');
+   var desc = document.createElement('td');
+   var ref = document.createElement('td');
+   desc.innerHTML = testDescription;
+   ref.innerHTML = testName + '.png';
+   descRow.appendChild(desc);
+   descRow.appendChild(ref);
+   gTestContainer.appendChild(descRow);
+
+   // see if there's a reference image available
+   // our surface is created from scratch
+   //testSurfaceHolder.width = width + "px";
+   //testSurfaceHolder.height = height + "px";
+   var surface = dojox.gfx.createSurface(testHolder, width, height);
+   return surface;
+}
+
+function addTest(testName, fn)
+{
+   gTests[testName] = fn;
+}
+
+function runTest_nodebug(testName)
+{
+   try {
+      var t = gTests[testName];
+      if (!t) {
+         return 'no test named ' + t;
+      }
+      t(testName);
+      return null; // the success condition
+   } catch (e) {
+      return e.message;
+   }
+}
+
+function runTest_debug(testName)
+{
+      var t = gTests[testName];
+      if (!t) {
+         return 'no test named ' + t;
+      }
+      t(testName);
+      return null; // the success condition
+}
+
+var runTest = djConfig.isDebug ? runTest_debug : runTest_nodebug;
+
+dojo.addOnLoad(function() 
+{
+	gTestContainer = dojo.byId('testcontainer');
+	var rect = { x: 0, y: 0, width: 100, height: 100 };
+
+	addTest('rect', function(testName){
+		var surface = getTestSurface(testName, 'translucent rect with rounded stroke');
+		var red_rect = surface.createRect(rect);
+			red_rect.setFill([255, 0, 0, 0.5]);
+			red_rect.setStroke({color: "blue", width: 10, join: "round" });
+			red_rect.setTransform({ dx: 100, dy: 100 })
+			;
+		dojo.connect(red_rect.getNode(), "onclick", function(){ alert("red"); });
+	});
+
+	addTest('straight_rect', function(testName){
+		var surface = getTestSurface(testName, 'translucent rect with no stroke');
+		var blue_rect = surface.createRect(rect).setFill([0, 255, 0, 0.5]).setTransform({ dx: 100, dy: 100 });
+		dojo.connect( blue_rect.getNode(), "onclick", function(){ blue_rect.setShape({width: blue_rect.getShape().width + 20}); });
+	});
+
+	addTest('rotated_rect', function(testName){
+		var surface = getTestSurface(testName, '30g CCW blue translucent rounded rect');
+		console.debug('rotated_rect');
+		// anonymous 30 degree CCW rotated green rectangle
+		surface.createRect({r: 20})
+			.setFill([0, 0, 255, 0.5])
+			// rotate it around its center and move to (100, 100)
+			.setTransform([dojox.gfx.matrix.translate(100, 100), dojox.gfx.matrix.rotategAt(30, 0, 0)])
+			;
+	});
+
+	addTest('skew_rect', function(testName){
+		var surface = getTestSurface(testName, 'skewed rects' );
+		// anonymous red rectangle
+		surface.createRect(rect).setFill(new dojo.Color([255, 0, 0, 0.5]))
+			// skew it around LB point -30d, rotate it around LB point 30d, and move it to (100, 100)
+			.setTransform([dojox.gfx.matrix.translate(100, 100), dojox.gfx.matrix.rotategAt(30, 0, 100), dojox.gfx.matrix.skewXgAt(-30, 0, 100)]);
+		// anonymous blue rectangle
+		surface.createRect(rect).setFill(new dojo.Color([0, 0, 255, 0.5]))
+			// skew it around LB point -30d, and move it to (100, 100)
+			.setTransform([dojox.gfx.matrix.translate(100, 100), dojox.gfx.matrix.skewXgAt(-30, 0, 100)]);
+		// anonymous yellow rectangle
+		surface.createRect(rect).setFill(new dojo.Color([255, 255, 0, 0.25]))
+			// move it to (100, 100)
+			.setTransform(dojox.gfx.matrix.translate(100, 100));
+	});
+
+	addTest('matrix_rect', function(testName){
+		var surface = getTestSurface(testName, 'all matrix operations, check debug output for more details');
+
+		var group = surface.createGroup();
+		
+		var blue_rect = group.createRect(rect).setFill([0, 0, 255, 0.5]).applyTransform(dojox.gfx.matrix.identity);
+		console.debug( "blue_rect: rect with identity" );
+
+		group.createRect(rect).setFill([0, 255, 0, 0.5]).applyTransform(dojox.gfx.matrix.translate(30, 40));
+		console.debug( "lime_rect: translate(30,40) " );
+		
+		group.createRect(rect).setFill([255, 0, 0, 0.5]).applyTransform(dojox.gfx.matrix.rotateg(30));
+		console.debug( "red_rect: rotate 30 degree counterclockwise " );
+
+		group.createRect(rect).setFill([0, 255, 255, 0.5])
+			.applyTransform(dojox.gfx.matrix.scale({x:1.5, y:0.5}))
+			.applyTransform(dojox.gfx.matrix.translate(-40, 220))
+			;
+		console.debug( "lightblue_rect: scale(1.5, 0.5)" );
+
+		group.createRect(rect).setFill([0, 0, 255, 0.5]).setFill([255, 0, 255, 0.5]).applyTransform(dojox.gfx.matrix.flipX);
+		console.debug( "pink_rect: flipX" );
+
+		group.createRect(rect).setFill([0, 0, 255, 0.5]).setFill([255, 255, 0, 0.5]).applyTransform(dojox.gfx.matrix.flipY);
+		console.debug( "yellow_rect: flipY" );
+
+		group.createRect(rect).setFill([0, 0, 255, 0.5]).setFill([128, 0, 128, 0.5]).applyTransform(dojox.gfx.matrix.flipXY);
+		console.debug( "purple_rect: flipXY" );
+
+		group.createRect(rect).setFill([0, 0, 255, 0.5]).setFill([255, 128, 0, 0.5]).applyTransform(dojox.gfx.matrix.skewXg(15));
+		console.debug( "purple_rect: skewXg 15 degree" );
+
+		group.createRect(rect).setFill([0, 0, 255, 0.5]).setFill([0, 0, 0, 0.5]).applyTransform(dojox.gfx.matrix.skewYg(50));
+		console.debug( "black_rect: skewXg 50 degree" );
+
+		// move
+		group
+			.setTransform({ xx: 1.5, yy: 0.5, dx: 100, dy: 100 })
+			.applyTransform(dojox.gfx.matrix.rotateg(30))
+			;
+	});
+
+   
+	addTest('attach', function(testName){
+		var surface = getTestSurface(testName, 'Attach to existed shape');
+		var red_rect = surface.createRect(rect)
+			.setShape({ width: 75 })
+			.setFill([255, 0, 0, 0.5])
+			.setStroke({ color: "blue", width: 1 })
+			.setTransform({ dx: 50, dy: 50, xx: 1, xy: 0.5, yx: 0.7, yy: 1.1 })
+			;
+
+		console.debug("attaching !");
+		// now attach it!
+		var ar = dojox.gfx.attachNode(red_rect.rawNode);
+		console.assert( ar.rawNode == red_rect.rawNode );
+
+		// FIXME: more generic method to compare two dictionary?
+		console.debug("attach shape: ");
+		isEqual(ar.shape, red_rect.shape, "rect.shape");
+		console.debug("attach matrix: ");
+		isEqual(ar.matrix, red_rect.matrix, "rect.matrix");
+		console.debug("attach strokeStyle: ");
+		isEqual(ar.strokeStyle, red_rect.strokeStyle, "rect.strokeStyle");
+		console.debug("attach fillStyle: ");
+		isEqual(ar.fillStyle, red_rect.fillStyle, "rect.fillStyle");
+	});
+
+	// test circle
+	addTest('circle', function(testName){
+		var surface = getTestSurface(testName, 'translucent green circle');
+		var circle = { cx: 130, cy: 130, r: 50 };
+		surface.createCircle(circle).setFill([0, 255, 0, 0.5]).setTransform({ dx: 20, dy: 20 });
+	});
+
+	// test line
+	addTest('line', function(testName){
+		var surface = getTestSurface(testName, 'straight red line');
+		var line = { x1: 20, y1: 20, x2: 100, y2: 120 };
+		surface.createLine(line).setFill([255, 0, 0, 0.5]).setStroke({color: "red", width: 1}).setTransform({ dx:70, dy: 100 });
+	});
+
+	// test ellipse 
+	addTest('ellipse', function(testName){
+		var surface = getTestSurface(testName, 'translucent cyan ellipse');
+		var ellipse = { cx: 50, cy: 80, rx: 50, ry: 80 };
+		surface.createEllipse(ellipse).setFill([0, 255, 255, 0.5]).setTransform({ dx: 30, dy: 70 });
+	});
+
+	// test polyline
+	addTest('polyline', function(testName){
+		var surface = getTestSurface(testName, 'unfilled open polyline');
+		var points = [ {x: 10, y: 20}, {x: 40, y: 70}, {x: 120, y: 50}, {x: 90, y: 90} ];
+		surface.createPolyline(points).setFill(null).setStroke({ color: "blue", width: 1 }).setTransform({ dx: 15, dy: 0 });
+	});
+
+	// test polygon
+	addTest('polygon', function(testName){
+		var surface = getTestSurface(testName, 'filled polygon');
+		var points2 = [{x: 100, y: 0}, {x: 200, y: 40}, {x: 180, y: 150}, {x: 60, y: 170}, {x: 20, y: 100}];
+		surface.createPolyline(points2).setFill([0, 128, 255, 0.6]).setTransform({dx:30, dy: 20});
+	});
+
+	// test path: lineTo, moveTo, closePath
+	addTest('lineTo', function(testName){
+		var surface = getTestSurface(testName, 'lineTo, moveTo, closePath');
+		surface.createPath()
+			.moveTo(10, 20).lineTo(80, 150)
+			.setAbsoluteMode(false).lineTo(40, 0)
+			.setAbsoluteMode(true).lineTo(180, 100)
+			.setAbsoluteMode(false).lineTo(0, -30).lineTo(-30, -50)
+			.closePath()
+			.setStroke({ color: "red", width: 1 })
+			.setFill(null)
+			.setTransform({ dx: 10, dy: 18 })
+			;
+	});
+
+	addTest('setPath', function(testName){
+		var surface = getTestSurface(testName, 'setPath example with lineTo moveTo');
+		surface.createPath()
+			.moveTo(10, 20).lineTo(80, 150)
+			.setAbsoluteMode(false).lineTo(40,0)
+			.setAbsoluteMode(true).lineTo(180, 100)
+			.setAbsoluteMode(false).lineTo(0, -30).lineTo(-30, -50)
+			.curveTo(10, -80, -150, -10, -90, -10)
+			.closePath()
+			.setStroke({ color: "red", width: 1 })
+			.setFill(null)
+			.setTransform({ dx: 10, dy: 58 })
+			;
+
+		surface.createPath({ path: "M10,20 L80,150 l40,0 L180,100 l0,-30 l-30,-50 c10,-80 -150,-10 -90,-10 z" })
+			.setFill(null)
+			.setStroke({ color: "blue", width: 1 })
+			.setTransform({ dx: 50, dy: 78 })
+			;
+	});
+
+	// test arcTo 
+	addTest('arcTo', function(testName){
+		var surface = getTestSurface(testName, 'arcTo: from 0 to 360 degree, w/ 30 degree of x axis rotation, rendered with different color');
+
+		var m = dojox.gfx.matrix;
+		var g1 = surface.createGroup();
+		var g2 = g1.createGroup();
+
+		var rx = 100, ry = 60, xRotg = 30;
+		var startPoint = m.multiplyPoint(m.rotateg(xRotg), {x: -rx, y: 0  });
+		var endPoint   = m.multiplyPoint(m.rotateg(xRotg), {x: 0,   y: -ry});
+	    
+		var re1 = g1.createPath()
+			.moveTo(startPoint)
+			.arcTo(rx, ry, xRotg, true, false, endPoint)
+			.setStroke({color: "red"})
+			;
+		var ge1 = g1.createPath()
+			.moveTo(re1.getLastPosition())
+			.arcTo(rx, ry, xRotg, false, false, startPoint)
+			.setStroke({color: "blue"})
+			;
+		var re2 = g2.createPath()
+			.moveTo(startPoint)
+			.arcTo(rx, ry, xRotg, false, true, endPoint)
+			.setStroke({color: "red"})
+			;
+		var ge2 = g2.createPath()
+			.moveTo(re2.getLastPosition())
+			.arcTo(rx, ry, xRotg, true, true, startPoint)
+			.setStroke({color: "blue"})
+			;
+			
+		g1.setTransform({dx: 150, dy: 150});
+		g2.setTransform({dx: 10,  dy: 10});
+	});
+
+	// test path: curveTo, smoothCurveTo
+	addTest('curveTo', function(testName) {
+		var surface = getTestSurface(testName, 'curveTo, smoothCurveTo');
+		surface.createPath()
+			.moveTo(10, 20).curveTo(50, 50, 50, 100, 150, 100).smoothCurveTo(300, 300, 200, 200)
+			.setStroke({ color: "green", width: 1 }).setFill(null).setTransform({ dx: 10, dy: 30 })
+			;
+	});
+
+	// test path: curveTo, smoothCurveTo with relative.
+	addTest('curveTo2', function(testName) {
+		var surface = getTestSurface(testName, 'curveTo, smoothCurveTo with relative coordination');
+		surface.createPath()
+			.moveTo(10, 20).curveTo(50, 50, 50, 100, 150, 100)
+			.setAbsoluteMode(false).smoothCurveTo(150, 200, 50, 100)
+			.setAbsoluteMode(true).smoothCurveTo(50, 100, 10, 230)
+			.setStroke({ color: "green", width: 1 }).setFill(null).setTransform({ dx: 10, dy: 30 })
+			;
+	});
+
+	// test path: curveTo, smoothCurveTo with relative.
+	addTest('qbCurveTo', function(testName) {
+		var surface = getTestSurface(testName, 'qbcurveTo, smoothQBCurveTo' );
+		surface.createPath()
+			.moveTo(10, 15).qbCurveTo(50, 50, 100, 100).smoothQBCurveTo(150, 20)
+			.setStroke({ color: "green", width: 1 }).setFill(null).setTransform({ dx: 10, dy: 30 })
+			;
+	});
+
+	addTest('qbCurveTo2', function(testName) {
+		var surface = getTestSurface(testName, 'qbcurveTo, smoothQBCurveTo with relative' );
+		surface.createPath()
+			.moveTo(10, 20).qbCurveTo(50, 50, 100, 100)
+			.setAbsoluteMode(false).smoothQBCurveTo(50, -80)
+			.setAbsoluteMode(true).smoothQBCurveTo(200, 80)
+			.setStroke({ color: "green", width: 1 }).setFill(null).setTransform({ dx: 10, dy: 30 })
+			;
+	});
+
+	// test defines, linearGradient
+	addTest('linearGradient', function(testName) {
+		var surface = getTestSurface(testName, 'linear gradient fill');
+		// this is an example to split the linearGradient from setFill:
+		var lg = {
+			type: "linear",
+			x1: 0, y1: 0, x2: 75, y2: 50,
+			colors: [
+				{ offset: 0, color: "#F60" },
+				{ offset: 1, color: "#FF6" }
+			]
+		};
+		surface.createRect(rect).setFill(lg).setTransform({ dx: 40, dy: 100 });
+	});
+
+	// TODO: test radialGradient
+	addTest('radialGradient', function(testName) {
+		var surface = getTestSurface(testName, 'radial gradient fill');
+		// this is a total inline implementation compared with previous one.
+		var rg = {
+			type: "radial",
+			cx: 100, cy: 100, r: 100,
+			colors: [
+				{ offset:   0, color: "red" },
+				{ offset: 0.5, color: "green" },
+				{ offset:   1, color: "blue" }
+			]
+		};
+		
+		surface.createCircle({cx: 100, cy: 100, r: 100})
+			.setStroke({})
+			.setFill(rg)
+			.setTransform({dx: 40, dy: 30})
+			;
+//		surface.createRect(rect)
+//			.setShape({width: 200})
+//			.setStroke({})
+//			.setFill(rg)
+//			.setTransform({dx: 40, dy: 30})
+//			;
+	});
+
+	// TODO: test defines,pattern, path
+	addTest('pattern', function(testName) {
+		var surface = getTestSurface(testName, 'pattern fill');
+		var pat = new dojox.gfx.Pattern( {x:0, y:0, width:40, height:40, patternUnits:"userSpaceOnUse", viewBox:[0, 0, 10, 10] });
+		pat.createRect().setRect({width:25, height:20}).
+		setFill(new dojo.Color("red"));
+		surface.createRect(rect).setFill(pat).
+		setStroke({ color: new dojo.Color("blue"), width: 2}).
+		setTransform({dx: 40, dy: 30});
+	});
+
+	addTest('attach_gradient', function(testName) {
+		var surface = getTestSurface(testName, 'attach gradient fill');
+		// this is an example to split the linearGradient from setFill:
+		var lg = {
+			type: "linear",
+			x1: 0, y1: 0, x2: 75, y2: 50,
+			colors: [
+				{ offset:   0, color: "#F60" },
+				{ offset: 0.5, color: "#FAF" },
+				{ offset:   1, color: "#FF6" }
+			]
+		};
+
+		var lgr = surface.createRect(rect).setFill(lg).setTransform({ dx: 40, dy: 100 });
+
+		var ar = dojox.gfx.attachNode(lgr.rawNode);
+		// FIXME: more generic method to compare two dictionary?
+		console.debug("attach_gradient!");
+
+		console.debug("attach shape: ");
+		isEqual(lgr.shape, ar.shape, "rect.shape");
+		console.debug("attach matrix: ");
+		isEqual(lgr.matrix, ar.matrix, "rect.matrix");
+		console.debug("attach strokeStyle: ");
+		isEqual(lgr.strokeStyle, ar.strokeStyle, "rect.strokeStyle");
+		console.debug("attach fillStyle: ");
+		isEqual(lgr.fillStyle.gradient, ar.fillStyle.gradient, "rect.fillStyle.gradient");
+		//isEqual(lgr.fillStyle.id, ar.fillStyle.id, "rect.fillStyle.id");
+	});
+
+	var gTestsToRun = [
+		'rect',
+		'straight_rect',
+		'rotated_rect',
+		'skew_rect',
+		'matrix_rect', 
+		'attach',
+		'attach_gradient',
+		'circle',
+		'arcTo',
+		'line',
+		'ellipse',
+		'polyline',
+		'polygon',
+		'lineTo',
+		'setPath',
+		'curveTo',
+		'curveTo2',
+		//'qbCurveTo',
+		//'qbCurveTo2',
+		'linearGradient',
+		'radialGradient'
+		//'pattern'
+	];
+
+	for (var i = 0; i < gTestsToRun.length; ++i) {
+		var testName = gTestsToRun[i];
+		var err = runTest(testName);
+		if (err) {
+			getTestSurface(testName, testName + ' FAILED (' + err + ')');
+		}
+	}
+
+}); // end onload
+</script>
+<style>
+   td { border: 1px solid black; text-align: left; vertical-align: top; }
+   v:group { text-align: left; }
+</style>
+   </head>
+   <body>
+   <table>
+   <tbody id="testcontainer">
+   </tbody>
+   </table>
+   </body>
+   </html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_group.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_group.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_group.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,70 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Dojo Unified 2D Graphics</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript">djConfig = { isDebug: true };</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<!--<script type="text/javascript" src="../matrix.js"></script>-->
+<!--<script type="text/javascript" src="../util.js"></script>-->
+<!--<script type="text/javascript" src="../shape.js"></script>-->
+<!--<script type="text/javascript" src="../path.js"></script>-->
+<!--<script type="text/javascript" src="../vml.js"></script>-->
+<!--<script type="text/javascript" src="../svg.js"></script>-->
+<script type="text/javascript">
+dojo.require("dojox.gfx");
+
+var surface = null;
+var g1 = null;
+var g2 = null;
+var r1 = null;
+
+makeShapes = function(){
+	surface = dojox.gfx.createSurface(document.getElementById("test"), 500, 500);
+	// make a checkerboard
+	for(var i = 0; i < 500; i += 100){
+		for(var j = 0; j < 500; j += 100){
+			if(i % 200 == j % 200) {
+				surface.createRect({ x: i, y: j }).setFill([255, 0, 0, 0.1]);
+			}
+		}
+	}
+	// create groups and shapes
+	g1 = surface.createGroup();
+	g2 = surface.createGroup();
+	r1 = surface.createRect({x: 200, y: 200}).setFill("green").setStroke({});
+	g1.setTransform({dy: -100});
+	//g2.setTransform(dojox.gfx.matrix.rotateAt(-45, 250, 250));
+	g2.setTransform({dx: 100, dy: -100});
+};
+
+switchRect = function(){
+	var radio = document.getElementsByName("switch");
+	if(radio[0].checked){
+		surface.add(r1);
+	}else if(radio[1].checked){
+		g1.add(r1);
+	}else if(radio[2].checked){
+		g2.add(r1);
+	}
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+<!--
+<style>
+v:group { text-align: left; }
+</style>
+-->
+</head>
+<body>
+<p>Test for dojox.gfx:</p>
+<p>
+<input type="radio" name="switch" id="r1_s" checked onclick="switchRect()" /><label for="r1_s">Rectangle belongs to the surface</label><br />
+<input type="radio" name="switch" id="r1_g1" onclick="switchRect()" /><label for="r1_g1">Rectangle belongs to the group #1</label><br />
+<input type="radio" name="switch" id="r1_g2" onclick="switchRect()" /><label for="r1_g2">Rectangle belongs to the group #2</label>
+</p>
+<div id="test"></div>
+<p>That's all Folks!</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_image.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_image.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_image.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,63 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Testing image</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript">djConfig = { isDebug: true };</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<!--<script type="text/javascript" src="../vml.js"></script>-->
+<!--<script type="text/javascript" src="../svg.js"></script>-->
+<script type="text/javascript">
+dojo.require("dojox.gfx");
+
+var image = null;
+var grid_size = 500;
+var grid_step = 50;
+
+makeShapes = function(){
+	var surface = dojox.gfx.createSurface("test", 800, 600);
+	for(var i = 0; i <= grid_size; i += grid_step){
+		surface.createLine({x1: 0, x2: grid_size, y1: i, y2: i}).setStroke("black");
+		surface.createLine({y1: 0, y2: grid_size, x1: i, x2: i}).setStroke("black");
+	}
+    image = surface.createImage({width: 333, height: 80, src: "http://dojotoolkit.org/files/downloadButton.gif"});
+    dojo.connect(image.getEventSource(), "onclick", function(){ alert("You didn't expect a download, did you?"); });
+};
+
+transformImage = function(){
+	var radio = document.getElementsByName("switch");
+	if(radio[0].checked){
+        image.setTransform({});
+	}else if(radio[1].checked){
+        image.setTransform(dojox.gfx.matrix.translate(100,100));
+	}else if(radio[2].checked){
+        image.setTransform([dojox.gfx.matrix.translate(100,0), dojox.gfx.matrix.rotateg(-45)]);
+	}else if(radio[3].checked){
+        image.setTransform([dojox.gfx.matrix.translate(70,90), dojox.gfx.matrix.scale({x:1.5, y:0.5})]);
+	}else if(radio[4].checked){
+        image.setTransform([dojox.gfx.matrix.rotateg(-15), dojox.gfx.matrix.skewXg(30)]);
+	}
+	var cb = document.getElementById("r2");
+	if(cb.checked && !image.getShape().x){
+		image.setShape({x: 100, y: 50});
+	}else if(!cb.checked && image.getShape().x){
+		image.setShape({x: 0, y: 0});
+	}
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+</head>
+<body>
+<p>Testing image:<br />
+<input type="radio" name="switch" id="r1_reset" checked onclick="transformImage()" /><label for="r1_reset">Reset Image</label><br />
+<input type="radio" name="switch" id="r1_move" onclick="transformImage()" /><label for="r1_move">Move Image</label><br />
+<input type="radio" name="switch" id="r1_rotate" onclick="transformImage()" /><label for="r1_rotate">Rotate Image</label><br />
+<input type="radio" name="switch" id="r1_scale" onclick="transformImage()" /><label for="r1_scale">Scale Image</label><br />
+<input type="radio" name="switch" id="r1_skew" onclick="transformImage()" /><label for="r1_skew">Skew Image</label><br />
+</p>
+<p><input type="checkbox" id="r2" onclick="transformImage()" /><label for="r2">Offset image by (100, 50)</label></p>
+<div id="test"></div>
+<p>That's all Folks!</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_linearGradient.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_linearGradient.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_linearGradient.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,54 @@
+<html 
+	xmlns:v="urn:schemas-microsoft-com:vml" 
+	xmlns:o="urn:schemas-microsoft-com:office:office" >
+   <head>
+		<title>Dojo Unified 2D Graphics</title>
+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+		<script type="text/javascript">
+			// Dojo configuration
+			djConfig = { 
+				isDebug: true
+			};
+		</script>
+		<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+		<!--<script type="text/javascript" src="../path.js"></script>-->
+		<!--<script type="text/javascript" src="../vml.js"></script>-->
+		<!--<script type="text/javascript" src="../svg.js"></script>-->
+		<script type="text/javascript">
+			dojo.require("dojox.gfx");
+
+			var makeShapes = function(){
+				var fillObj = {
+					type: "linear",
+					x1: 0, y1: 0,
+					x2: 300, y2: 0,
+					colors: [
+						{ offset: 0, color: "#000000" },
+						{ offset: 1, color: "#4a4949" }
+					]
+				};
+				var surface = dojox.gfx.createSurface(dojo.byId("grad"), 300, 100);
+				var group = surface.createGroup();
+				var rect = surface.createRect({ 
+					width:  300, // "100%", 
+					height: 100  // "100%" 
+				});
+				rect.setFill(fillObj);
+				group.add(rect);
+			};
+			dojo.addOnLoad(makeShapes);
+		</script>
+		<style>
+			v:group { text-align: left; }
+			#grad {
+				width: 300px;
+				height: 100px;
+			}
+		</style>
+	</head>
+	<body>
+		<h3>linear gradient test page</h3>
+		<div id="grad">
+		</div>
+	</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_linestyle.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_linestyle.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_linestyle.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,37 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Dojo Unified 2D Graphics</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript">djConfig = { isDebug: true };</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<!--<script type="text/javascript" src="../_base.js"></script>-->
+<!--<script type="text/javascript" src="../shape.js"></script>-->
+<!--<script type="text/javascript" src="../path.js"></script>-->
+<!--<script type="text/javascript" src="../vml.js"></script>-->
+<!--<script type="text/javascript" src="../svg.js"></script>-->
+<script type="text/javascript">
+dojo.require("dojox.gfx");
+
+makeShapes = function(){
+	var surface = dojox.gfx.createSurface(document.getElementById("test"), 500, 500);
+	var styles = ["none", "Solid", "ShortDash", "ShortDot", "ShortDashDot", "ShortDashDotDot", 
+		"Dot", "Dash", "LongDash", "DashDot", "LongDashDot", "LongDashDotDot"];
+	var font = "normal normal normal 10pt Arial";	// CSS font style
+	var y_offset = dojox.gfx.normalizedLength("4pt");
+	for(var i = 0; i < styles.length; ++i){
+		var y = 20 + i * 20;
+		surface.createText({x: 140, y: y + y_offset, text: styles[i], align: "end"}).setFont(font).setFill("black");
+		surface.createLine({x1: 150, y1: y, x2: 490, y2: y}).setStroke({style: styles[i], width: 3, cap: "round"});
+	}
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+</head>
+<body>
+<p>Test for dojox.gfx:</p>
+<div id="test"></div>
+<p>That's all Folks!</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_matrix.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_matrix.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_matrix.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,87 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Dojo 2D Matrix</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript">djConfig = {isDebug: true};</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<script type="text/javascript">
+
+dojo.require("dojox.gfx");
+
+mdebug = function(matrix){
+	var m = dojox.gfx.matrix.normalize(matrix);
+	console.debug("xx: " + m.xx + ", xy: " + m.xy + " | dx:" + m.dx);
+	console.debug("yx: " + m.yx + ", yy: " + m.yy + " | dy:" + m.dy);
+};
+
+pdebug = function(point){
+	console.debug("x: " + point.x + ", y: " + point.y);
+};
+
+dojo.addOnLoad(function(){
+	var m = dojox.gfx.matrix;
+	var a = new m.Matrix2D();
+	mdebug(a);
+	a = m.rotateg(30);
+	mdebug(a);
+	a = m.rotateg(45);
+	mdebug(a);
+	a = m.rotateg(90);
+	mdebug(a);
+	a = [new m.Matrix2D(), new m.Matrix2D(), new m.Matrix2D()];
+	mdebug(a);
+	a = [m.rotateg(30), m.rotateg(-30)];
+	mdebug(a);
+	a = [m.rotateg(30), m.invert(m.rotateg(30))];
+	mdebug(a);
+	a = m.rotategAt(90, 10, 10);
+	mdebug(a);
+	var b = m.multiplyPoint(a, 10, 10);
+	pdebug(b);
+	b = m.multiplyPoint(a, 10, 5);
+	pdebug(b);
+	b = m.multiplyPoint(a, 10, 15);
+	pdebug(b);
+	a = [m.scale(2,1), m.invert(m.rotateg(45))];
+	mdebug(a);
+	a = [m.scale(1,2), m.invert(m.rotateg(45))];
+	mdebug(a);
+	a = [m.invert(m.rotateg(45)), m.scale(2,1)];
+	mdebug(a);
+	a = [m.invert(m.rotateg(45)), m.scale(1,2)];
+	mdebug(a);
+	a = [m.rotategAt(45, 100, 100), m.scale(2)];
+	mdebug(a);
+	a = [m.scale(2), m.rotategAt(45, 100, 100)];
+	mdebug(a);
+	a = [m.rotateg(45), m.scale(2)];
+	mdebug(a);
+	a = [m.scale(2), m.rotateg(45)];
+	mdebug(a);
+	a = [m.rotategAt(45, 300, 200), m.translate(100, 100), m.scale(2,1)];
+	mdebug(a);
+	a = [m.translate(100, 100), m.rotateg(45), m.scale(2,1)];
+	mdebug(a);
+	a = [m.rotategAt(45, 250, 250), {dx: 150, dy: 150}];
+	mdebug(a);
+	a = 5;
+	mdebug(a);
+	a = [2, m.scale(2,1)];
+	mdebug(a);
+	a = m.reflect(1, 1);
+	b = m.multiplyPoint(a, 1, 0);
+	pdebug(b);
+	b = m.multiplyPoint(a, 0, 1);
+	pdebug(b);
+	a = m.project(1, 1);
+	b = m.multiplyPoint(a, 1, 0);
+	pdebug(b);
+	b = m.multiplyPoint(a, 0, 1);
+	pdebug(b);
+});
+
+</script>
+</head>
+<body>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_pattern.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_pattern.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_pattern.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,34 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Testing pattern</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript">djConfig = { isDebug: true };</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<!--<script type="text/javascript" src="../vml.js"></script>-->
+<!--<script type="text/javascript" src="../svg.js"></script>-->
+<script type="text/javascript">
+dojo.require("dojox.gfx");
+
+makeShapes = function(){
+    var pattern = {
+        type: "pattern",
+        x: 0, y: 0, width: 333, height: 80,
+        src: "http://dojotoolkit.org/files/downloadButton.gif"
+    };
+	var ellipse = {cx: 400, cy: 200, rx: 350, ry: 150};
+	var surface = dojox.gfx.createSurface("test", 800, 600);
+	surface.createEllipse(ellipse)
+        .setStroke({color: "blue", width: 1 })
+        .setFill(pattern);
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+</head>
+<body>
+<p>Testing pattern: </p>
+<div id="test"></div>
+<p>That's all Folks!</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_poly.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_poly.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_poly.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,41 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Testing polyline and line transforms</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript">djConfig = { isDebug: true };</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<!--<script type="text/javascript" src="../shape.js"></script>-->
+<!--<script type="text/javascript" src="../path.js"></script>-->
+<!--<script type="text/javascript" src="../vml.js"></script>-->
+<!--<script type="text/javascript" src="../svg.js"></script>-->
+<script type="text/javascript">
+dojo.require("dojox.gfx");
+
+makeShapes = function(){
+	var surface = dojox.gfx.createSurface("test", 500, 500);
+	var line = surface.createLine({x1: 250, y1: 50, x2: 250, y2: 250})
+		.setStroke({color: "blue"})
+		;
+	var poly = surface.createPolyline([{x: 250, y: 250}, {x: 300, y: 300}, {x: 250, y: 350}, {x: 200, y: 300}, {x: 250, y: 250}])
+		.setStroke({color: "blue"})
+		;
+	var rotate = dojox.gfx.matrix.rotategAt(-5, 250, 250);
+		
+	window.setInterval(function() {
+			line.applyTransform(rotate);
+			poly.applyTransform(rotate);
+		},
+		100
+	);
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+</head>
+<body>
+<p>Testing polyline and line transforms</p>
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_setPath.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_setPath.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_setPath.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,68 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Testing setPath and curves</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript">djConfig = { isDebug: true };</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<!--<script type="text/javascript" src="../path.js"></script>-->
+<!--<script type="text/javascript" src="../vml.js"></script>-->
+<!--<script type="text/javascript" src="../svg.js"></script>-->
+<script type="text/javascript">
+dojo.require("dojox.gfx");
+
+makeShapes = function(){
+	var surface = dojox.gfx.createSurface("test", 500, 500);
+	// relative path with cubic beziers
+	surface
+		.createPath("m100 100 100 0 0 100c0 50-50 50-100 0s-50-100 0-100z")
+		.setStroke({color: "blue"})
+		.setFill("#ddd")
+		.setTransform({dx: -50, dy: -50})
+		;
+	// absolute path with cubic bezier
+	surface
+		.createPath("M100 100 200 100 200 200C200 250 150 250 100 200S50 100 100 100z")
+		.setStroke({color: "blue"})
+		.setFill("#ddd")
+		.setTransform({dx: 100, dy: -50})
+		;
+	// relative path with horizontal and vertical lines, and cubic beziers
+	surface
+		.createPath("m100 100h100v100c0 50-50 50-100 0s-50-100 0-100z")
+		.setStroke({color: "blue"})
+		.setFill("#ddd")
+		.setTransform({dx: 250, dy: -50})
+		;
+	// relative path with quadratic beziers
+	surface
+		.createPath("m100 100 100 0 0 100q0 50-75-25t-25-75z")
+		.setStroke({color: "blue"})
+		.setFill("#ddd")
+		.setTransform({dx: -50, dy: 150})
+		;
+	// absolute path with quadratic bezier
+	surface
+		.createPath("M100 100 200 100 200 200Q200 250 125 175T100 100z")
+		.setStroke({color: "blue"})
+		.setFill("#ddd")
+		.setTransform({dx: 100, dy: 150})
+		;
+	// relative path with horizontal and vertical lines, and quadratic beziers
+	surface
+		.createPath("m100 100h100v100q0 50-75-25t-25-75z")
+		.setStroke({color: "blue"})
+		.setFill("#ddd")
+		.setTransform({dx: 250, dy: 150})
+		;
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+</head>
+<body>
+<p>Testing setPath and curves</p>
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_tbbox.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_tbbox.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_tbbox.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,105 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Dojo Unified 2D Graphics</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript">djConfig = { isDebug: true };</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<!--<script type="text/javascript" src="../shape.js"></script>-->
+<!--<script type="text/javascript" src="../vml.js"></script>-->
+<!--<script type="text/javascript" src="../svg.js"></script>-->
+<script type="text/javascript">
+dojo.require("dojox.gfx");
+
+makeShapes = function(){
+	var surface = dojox.gfx.createSurface(document.getElementById("test"), 500, 500);
+	var g1 = surface.createGroup();
+	// make a checkerboard
+	for(var i = 0; i < 500; i += 100){
+		for(var j = 0; j < 500; j += 100){
+			if(i % 200 == j % 200) {
+				surface.createRect({ x: i, y: j }).setFill([255, 0, 0, 0.1]);
+			}
+		}
+	}
+	var r1 = g1.createRect({ x: 200, y: 200 })
+				.setFill("green")
+				.setStroke({})
+				//.setTransform(dojox.gfx.matrix.rotategAt(45, 250, 250))
+				;
+	var r2 = surface.createRect().setStroke({})
+				.setFill({ type: "linear", to: { x: 50, y: 100 },
+					colors: [{ offset: 0, color: "green" }, { offset: 0.5, color: "red" }, { offset: 1, color: "blue" }] })
+				.setTransform({dx: 100, dy: 100})
+				;
+	var r3 = surface.createRect().setStroke({})
+				.setFill({ type: "linear" })
+				//.setTransform(dojox.gfx.matrix.rotategAt(45, 250, 250))
+				;
+	var r4 = g1.createRect({})
+				.setFill("blue")
+				//.setStroke({})
+				//.setTransform(dojox.gfx.matrix.rotategAt(45, 350, 250))
+				.setTransform([dojox.gfx.matrix.rotategAt(30, 350, 250), { dx: 300, dy: 200 }])
+				;
+	var p1 = g1.createPath()
+				.setStroke({})
+				.moveTo( 300, 100 )
+				.lineTo( 400, 200 )
+				.lineTo( 400, 300 )
+				.lineTo( 300, 400 )
+				.curveTo( 400, 300, 400, 200, 300, 100 )
+				//.setTransform(dojox.gfx.matrix.rotategAt(45, 250, 250))
+				.setTransform({})
+				;
+	var p2 = g1.createPath(p1.getShape())
+				.setStroke({ color: "red", width: 2 })
+				//.moveTo( 300, 100 )
+				//.lineTo( 400, 200 )
+				//.lineTo( 400, 300 )
+				//.lineTo( 300, 400 )
+				//.curveTo( 400, 300, 400, 200, 300, 100 )
+				//.setTransform(dojox.gfx.matrix.rotategAt(180, 250, 250))
+				.setTransform({ dx: 100 })
+				;
+	var p3 = g1.createPath()
+				.setStroke({ color: "blue", width: 2 })
+				.moveTo( 300, 100 )
+				.setAbsoluteMode(false)
+				.lineTo (  100,  100 )
+				.lineTo (    0,  100 )
+				.lineTo ( -100,  100 )
+				.curveTo(  100, -100, 100, -200, 0, -300 )
+				//.setTransform(dojox.gfx.matrix.rotategAt(-135, 250, 250))
+				.setTransform(dojox.gfx.matrix.rotategAt(180, 250, 250))
+				;
+	//g1.setTransform({ dx: 100 });
+	g1.moveToFront();
+	g1.setTransform(dojox.gfx.matrix.rotategAt(15, 250, 250));
+	//g1.setTransform([dojox.gfx.matrix.rotategAt(45, 250, 250), dojox.gfx.matrix.scaleAt(0.5, 250, 250)]);
+	//g1.setTransform([dojox.gfx.matrix.scaleAt(2, 1, 250, 250), dojox.gfx.matrix.rotategAt(45, 250, 250)]);
+	var a = p1.getTransformedBoundingBox();
+	a.push(a[0]);
+	surface.createPolyline(a).setStroke("green");
+	a = p2.getTransformedBoundingBox();
+	a.push(a[0]);
+	surface.createPolyline(a).setStroke("green");
+	a = p3.getTransformedBoundingBox();
+	a.push(a[0]);
+	surface.createPolyline(a).setStroke("green");
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+<!--
+<style>
+v:group { text-align: left; }
+</style>
+-->
+</head>
+<body>
+<p>Test for dojox.gfx:</p>
+<div id="test"></div>
+<p>That's all Folks!</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_text.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_text.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_text.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,70 @@
+<html>
+<head>
+<title>Testing text</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript">djConfig = { isDebug: true };</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<!--
+<script type="text/javascript" src="../common.js"></script>
+<script type="text/javascript" src="../shape.js"></script>
+-->
+<!--<script type="text/javascript" src="../vml.js"></script>-->
+<!--<script type="text/javascript" src="../svg.js"></script>-->
+<script type="text/javascript">
+dojo.require("dojox.gfx");
+
+var ROTATION = -15;
+
+var surface = null;
+
+var placeAnchor = function(surface, x, y){
+	surface.createLine({x1: x - 2, y1: y, x2: x + 2, y2: y}).setStroke("blue");
+	surface.createLine({x1: x, y1: y - 2, x2: x, y2: y + 2}).setStroke("blue");
+};
+
+var makeText = function(surface, text, font, fill, stroke){
+	var t = surface.createText(text);
+	if(font)   t.setFont(font);
+	if(fill)   t.setFill(fill);
+	if(stroke) t.setStroke(stroke);
+	placeAnchor(surface, text.x, text.y);
+	return t;
+};
+
+makeShapes = function(){
+	surface = dojox.gfx.createSurface("test", 500, 500);
+	var m = dojox.gfx.matrix;
+	surface.createLine({x1: 250, y1: 0, x2: 250, y2: 500}).setStroke("green");
+	makeText(surface, {x: 250, y: 50, text: "Start", align: "start"}, 
+		{family: "Times", size: "36pt", weight: "bold"}, "black", "red")
+		.setTransform(m.rotategAt(ROTATION, 250, 50))
+		;
+	makeText(surface, {x: 250, y: 100, text: "Middle", align: "middle"}, 
+		{family: "Symbol", size: "24pt"}, "#FFFF00", "black")
+		.setTransform(m.rotategAt(ROTATION, 250, 100))
+		;
+	makeText(surface, {x: 250, y: 150, text: "End", align: "end"}, 
+		{family: "Helvetica", style: "italic", size: "18pt", rotated: true}, "#FF8000")
+		.setTransform(m.rotategAt(ROTATION, 250, 150))
+		;
+	makeText(surface, {x: 250, y: 200, text: "Define Shuffle Tiff", align: "middle", kerning: true}, 
+		{family: "serif", size: "36pt"}, "black")
+		.setTransform(m.rotategAt(0, 250, 200))
+		;
+	makeText(surface, {x: 250, y: 250, text: "Define Shuffle Tiff", align: "middle", kerning: false}, 
+		{family: "serif", size: "36pt"}, "black")
+		.setTransform(m.rotategAt(0, 250, 250))
+		;
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+</head>
+<body>
+<p>Testing text</p>
+<div id="test" style="width: 500px; height: 500px;"></div>
+<div><button onclick="surface.clear();">Clear</button></div>
+<p>That's all Folks!</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_textpath.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_textpath.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_textpath.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,73 @@
+<html>
+<head>
+<title>Testing textpath</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript">djConfig = { isDebug: true };</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<!--
+<script type="text/javascript" src="../common.js"></script>
+<script type="text/javascript" src="../shape.js"></script>
+<script type="text/javascript" src="../path.js"></script>
+-->
+<!--<script type="text/javascript" src="../vml.js"></script>-->
+<!--<script type="text/javascript" src="../svg.js"></script>-->
+<script type="text/javascript">
+dojo.require("dojox.gfx");
+
+var CPD = 30;
+
+var surface = null;
+
+var makeText = function(surface, text, font, fill, stroke){
+	var t = surface.createText(text);
+	if(font)   t.setFont(font);
+	if(fill)   t.setFill(fill);
+	if(stroke) t.setStroke(stroke);
+	placeAnchor(surface, text.x, text.y);
+	return t;
+};
+
+makeShapes = function(){
+	surface = dojox.gfx.createSurface("test", 500, 500);
+	var p = surface.createPath({})
+		.setStroke("green")
+		.moveTo(0, 100)
+		.setAbsoluteMode(false)
+		.curveTo(CPD, 0, 100 - CPD,  300, 100,  300)
+		.curveTo(CPD, 0, 100 - CPD, -300, 100, -300)
+		.curveTo(CPD, 0, 100 - CPD,  300, 100,  300)
+		.curveTo(CPD, 0, 100 - CPD, -300, 100, -300)
+		.curveTo(CPD, 0, 100 - CPD,  300, 100,  300)
+		;
+	console.debug(p);
+	var t = surface.createTextPath({
+			text: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Praesent erat. " + 
+					"In malesuada ultricies velit. Vestibulum tempor odio vitae diam. " + 
+					"Morbi arcu lectus, laoreet eget, nonummy at, elementum a, quam."
+			, align: "middle"
+			//, rotated: true
+		})
+		//.setShape(p.shape)
+		.moveTo(0, 100)
+		.setAbsoluteMode(false)
+		.curveTo(CPD, 0, 100 - CPD,  300, 100,  300)
+		.curveTo(CPD, 0, 100 - CPD, -300, 100, -300)
+		.curveTo(CPD, 0, 100 - CPD,  300, 100,  300)
+		.curveTo(CPD, 0, 100 - CPD, -300, 100, -300)
+		.curveTo(CPD, 0, 100 - CPD,  300, 100,  300)
+		.setFont({family: "times", size: "12pt"})
+		.setFill("blue")
+		;
+	console.debug(t);
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+</head>
+<body>
+<p>Testing textpath</p>
+<div id="test" style="width: 500px; height: 500px;"></div>
+<p>That's all Folks!</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_transform.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_transform.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/tests/test_transform.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,95 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" >
+<head>
+<title>Dojo Unified 2D Graphics</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<script type="text/javascript">djConfig = { isDebug: true };</script>
+<script type="text/javascript" src="../../../dojo/dojo.js"></script>
+<!--<script type="text/javascript" src="../vml.js"></script>-->
+<!--<script type="text/javascript" src="../svg.js"></script>-->
+<script type="text/javascript">
+dojo.require("dojox.gfx");
+
+makeShapes = function(){
+	var surface = dojox.gfx.createSurface(document.getElementById("test"), 500, 500);
+	var g1 = surface.createGroup();
+	// make a checkerboard
+	for(var i = 0; i < 500; i += 100){
+		for(var j = 0; j < 500; j += 100){
+			if(i % 200 == j % 200) {
+				surface.createRect({ x: i, y: j }).setFill([255, 0, 0, 0.1]);
+			}
+		}
+	}
+	var r1 = g1.createRect({ x: 200, y: 200 })
+				.setFill("green")
+				.setStroke({})
+				//.setTransform(dojox.gfx.matrix.rotategAt(45, 250, 250))
+				;
+	var r2 = surface.createRect().setStroke({})
+				.setFill({ type: "linear", to: { x: 50, y: 100 },
+					colors: [{ offset: 0, color: "green" }, { offset: 0.5, color: "red" }, { offset: 1, color: "blue" }] })
+				.setTransform({dx: 100, dy: 100})
+				;
+	var r3 = surface.createRect().setStroke({})
+				.setFill({ type: "linear" })
+				//.setTransform(dojox.gfx.matrix.rotategAt(45, 250, 250))
+				;
+	var r4 = g1.createRect({})
+				.setFill("blue")
+				//.setStroke({})
+				//.setTransform(dojox.gfx.matrix.rotategAt(45, 350, 250))
+				.setTransform([dojox.gfx.matrix.rotategAt(30, 350, 250), { dx: 300, dy: 200 }])
+				;
+	var p1 = g1.createPath()
+				.setStroke({})
+				.moveTo( 300, 100 )
+				.lineTo( 400, 200 )
+				.lineTo( 400, 300 )
+				.lineTo( 300, 400 )
+				.curveTo( 400, 300, 400, 200, 300, 100 )
+				//.setTransform(dojox.gfx.matrix.rotategAt(45, 250, 250))
+				.setTransform({})
+				;
+	var p2 = g1.createPath(p1.getShape())
+				.setStroke({ color: "red", width: 2 })
+				//.moveTo( 300, 100 )
+				//.lineTo( 400, 200 )
+				//.lineTo( 400, 300 )
+				//.lineTo( 300, 400 )
+				//.curveTo( 400, 300, 400, 200, 300, 100 )
+				//.setTransform(dojox.gfx.matrix.rotategAt(180, 250, 250))
+				.setTransform({ dx: 100 })
+				;
+	var p3 = g1.createPath()
+				.setStroke({ color: "blue", width: 2 })
+				.moveTo( 300, 100 )
+				.setAbsoluteMode(false)
+				.lineTo (  100,  100 )
+				.lineTo (    0,  100 )
+				.lineTo ( -100,  100 )
+				.curveTo(  100, -100, 100, -200, 0, -300 )
+				//.setTransform(dojox.gfx.matrix.rotategAt(-135, 250, 250))
+				.setTransform(dojox.gfx.matrix.rotategAt(180, 250, 250))
+				;
+	//g1.setTransform({ dx: 100 });
+	g1.moveToFront();
+	g1.setTransform(dojox.gfx.matrix.rotategAt(15, 250, 250));
+	//g1.setTransform([dojox.gfx.matrix.rotategAt(45, 250, 250), dojox.gfx.matrix.scaleAt(0.5, 250, 250)]);
+	//g1.setTransform([dojox.gfx.matrix.scaleAt(2, 1, 250, 250), dojox.gfx.matrix.rotategAt(45, 250, 250)]);
+};
+
+dojo.addOnLoad(makeShapes);
+
+</script>
+<!--
+<style>
+v:group { text-align: left; }
+</style>
+-->
+</head>
+<body>
+<p>Test for dojox.gfx:</p>
+<div id="test"></div>
+<p>That's all Folks!</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx/vml.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx/vml.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx/vml.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,1603 @@
+dojo.provide("dojox.gfx.vml");
+
+dojo.require("dojox.gfx._base");
+dojo.require("dojox.gfx.shape");
+dojo.require("dojox.gfx.path");
+
+dojo.experimental("dojox.gfx.vml");
+
+// dojox.gfx.vml.xmlns: String: a VML's namespace
+dojox.gfx.vml.xmlns = "urn:schemas-microsoft-com:vml";
+
+// dojox.gfx.vml.text_alignment: Object: mapping from SVG alignment to VML alignment
+dojox.gfx.vml.text_alignment = {start: "left", middle: "center", end: "right"};
+
+// dojox.gfx.vml.pi4: Number: Pi / 4
+dojox.gfx.vml.pi4 = Math.PI / 4;
+
+// dojox.gfx.vml.two_pi: Number: 2 * Pi
+dojox.gfx.vml.two_pi = Math.PI * 2;
+
+dojox.gfx.vml._parseFloat = function(str) {
+	// summary: a helper function to parse VML-specific floating-point values
+	// str: String: a representation of a floating-point number
+	return str.match(/^\d+f$/i) ? parseInt(str) / 65536 : parseFloat(str);	// Number
+};
+
+dojox.gfx.vml._bool = {"t": 1, "true": 1};
+
+dojo.extend(dojox.gfx.Shape, {
+	// summary: VML-specific implementation of dojox.gfx.Shape methods
+
+	setFill: function(fill){
+		// summary: sets a fill object (VML)
+		// fill: Object: a fill object
+		//	(see dojox.gfx.defaultLinearGradient, 
+		//	dojox.gfx.defaultRadialGradient, 
+		//	dojox.gfx.defaultPattern, 
+		//	or dojo.Color)
+
+		if(!fill){
+			// don't fill
+			this.fillStyle = null;
+			this.rawNode.filled = false;
+			return this;
+		}
+		if(typeof(fill) == "object" && "type" in fill){
+			// gradient
+			switch(fill.type){
+				case "linear":
+					var f = dojox.gfx.makeParameters(dojox.gfx.defaultLinearGradient, fill);
+					this.fillStyle = f;
+					var s = "";
+					for(var i = 0; i < f.colors.length; ++i){
+						f.colors[i].color = dojox.gfx.normalizeColor(f.colors[i].color);
+						s += f.colors[i].offset.toFixed(8) + " " + f.colors[i].color.toHex() + ";";
+					}
+					var fo = this.rawNode.fill;
+					fo.colors.value = s;
+					fo.method = "sigma";
+					fo.type = "gradient";
+					fo.angle = (dojox.gfx.matrix._radToDeg(Math.atan2(f.x2 - f.x1, f.y2 - f.y1)) + 180) % 360;
+					fo.on = true;
+					break;
+				case "radial":
+					var f = dojox.gfx.makeParameters(dojox.gfx.defaultRadialGradient, fill);
+					this.fillStyle = f;
+					var w = parseFloat(this.rawNode.style.width);
+					var h = parseFloat(this.rawNode.style.height);
+					var c = isNaN(w) ? 1 : 2 * f.r / w;
+					var i = f.colors.length - 1;
+					f.colors[i].color = dojox.gfx.normalizeColor(f.colors[i].color);
+					var s = "0 " + f.colors[i].color.toHex();
+					for(; i >= 0; --i){
+						f.colors[i].color = dojox.gfx.normalizeColor(f.colors[i].color);
+						s += (1 - c * f.colors[i].offset).toFixed(8) + " " + f.colors[i].color.toHex() + ";";
+					}
+					var fo = this.rawNode.fill;
+					fo.colors.value = s;
+					fo.method = "sigma";
+					fo.type = "gradientradial";
+					if(isNaN(w) || isNaN(h)){
+						fo.focusposition = "0.5 0.5";
+					}else{
+						fo.focusposition = (f.cx / w).toFixed(8) + " " + (f.cy / h).toFixed(8);
+					}
+					fo.focussize = "0 0";
+					fo.on = true;
+					break;
+				case "pattern":
+					var f = dojox.gfx.makeParameters(dojox.gfx.defaultPattern, fill);
+					this.fillStyle = f;
+					var fo = this.rawNode.fill;
+					fo.type = "tile";
+					fo.src = f.src;
+					if(f.width && f.height){
+						// in points
+						fo.size.x = dojox.gfx.px2pt(f.width);
+						fo.size.y = dojox.gfx.px2pt(f.height);
+					}
+					fo.alignShape = false;
+					fo.position.x = 0;
+					fo.position.y = 0;
+					fo.origin.x = f.width  ? f.x / f.width  : 0;
+					fo.origin.y = f.height ? f.y / f.height : 0;
+					fo.on = true;
+					break;
+			}
+			this.rawNode.fill.opacity = 1;
+			return this;
+		}
+		// color object
+		this.fillStyle = dojox.gfx.normalizeColor(fill);
+		this.rawNode.fillcolor = this.fillStyle.toHex();
+		this.rawNode.fill.opacity = this.fillStyle.a;
+		this.rawNode.filled = true;
+		return this;	// self
+	},
+
+	setStroke: function(stroke){
+		// summary: sets a stroke object (VML)
+		// stroke: Object: a stroke object
+		//	(see dojox.gfx.defaultStroke) 
+	
+		if(!stroke){
+			// don't stroke
+			this.strokeStyle = null;
+			this.rawNode.stroked = false;
+			return this;
+		}
+		// normalize the stroke
+		if(typeof stroke == "string"){
+			stroke = {color: stroke};
+		}
+		var s = this.strokeStyle = dojox.gfx.makeParameters(dojox.gfx.defaultStroke, stroke);
+		s.color = dojox.gfx.normalizeColor(s.color);
+		// generate attributes
+		var rn = this.rawNode;
+		rn.stroked = true;
+		rn.strokecolor = s.color.toCss();
+		rn.strokeweight = s.width + "px";	// TODO: should we assume that the width is always in pixels?
+		if(rn.stroke) {
+			rn.stroke.opacity = s.color.a;
+			rn.stroke.endcap = this._translate(this._capMap, s.cap);
+			if(typeof(s.join) == "number") {
+				rn.stroke.joinstyle = "miter";
+				rn.stroke.miterlimit = s.join;
+			}else{
+				rn.stroke.joinstyle = s.join;
+				// rn.stroke.miterlimit = s.width;
+			}
+			rn.stroke.dashstyle = s.style == "none" ? "Solid" : s.style;
+		}
+		return this;	// self
+	},
+	
+	_capMap: { butt: 'flat' },
+	_capMapReversed: { flat: 'butt' },
+	
+	_translate: function(dict, value) {
+		return (value in dict) ? dict[value] : value;
+	},
+	
+	_applyTransform: function() {
+		var matrix = this._getRealMatrix();
+		if(!matrix) return this;
+		var skew = this.rawNode.skew;
+		if(typeof(skew) == "undefined"){
+			for(var i = 0; i < this.rawNode.childNodes.length; ++i){
+				if(this.rawNode.childNodes[i].tagName == "skew"){
+					skew = this.rawNode.childNodes[i];
+					break;
+				}
+			}
+		}
+		if(skew){
+			skew.on = false;
+			var mt = matrix.xx.toFixed(8) + " " + matrix.xy.toFixed(8) + " " + 
+				matrix.yx.toFixed(8) + " " + matrix.yy.toFixed(8) + " 0 0";
+			var offset = Math.floor(matrix.dx).toFixed() + "px " + Math.floor(matrix.dy).toFixed() + "px";
+			var l = parseFloat(this.rawNode.style.left);
+			var t = parseFloat(this.rawNode.style.top);
+			var w = parseFloat(this.rawNode.style.width);
+			var h = parseFloat(this.rawNode.style.height);
+			if(isNaN(l)) l = 0;
+			if(isNaN(t)) t = 0;
+			if(isNaN(w)) w = 1;
+			if(isNaN(h)) h = 1;
+			var origin = (-l / w - 0.5).toFixed(8) + " " + (-t / h - 0.5).toFixed(8);
+			skew.matrix =  mt;
+			skew.origin = origin;
+			skew.offset = offset;
+			skew.on = true;
+		}
+		return this;
+	},
+
+	setRawNode: function(rawNode){
+		// summary:
+		//	assigns and clears the underlying node that will represent this
+		//	shape. Once set, transforms, gradients, etc, can be applied.
+		//	(no fill & stroke by default)
+		rawNode.stroked = false;
+		rawNode.filled  = false;
+		this.rawNode = rawNode;
+	},
+
+	// Attach family
+	
+	attachFill: function(rawNode){
+		// summary: deduces a fill style from a Node.
+		// rawNode: Node: an VML node
+		var fillStyle = null;
+		var fo = rawNode.fill;
+		if(rawNode) {
+			if(fo.on && fo.type == "gradient"){
+				var fillStyle = dojox.gfx._base._copy(dojox.gfx.defaultLinearGradient, true);
+				var rad = dojox.gfx.matrix._degToRad(fo.angle);
+				fillStyle.x2 = Math.cos(rad);
+				fillStyle.y2 = Math.sin(rad);
+				fillStyle.colors = [];
+				var stops = fo.colors.value.split(";");
+				for(var i = 0; i < stops.length; ++i){
+					var t = stops[i].match(/\S+/g);
+					if(!t || t.length != 2) continue;
+					fillStyle.colors.push({offset: dojox.gfx.vml._parseFloat(t[0]), color: new dojo.Color(t[1])});
+				}
+			}else if(fo.on && fo.type == "gradientradial"){
+				var fillStyle = dojox.gfx._base._copy(dojox.gfx.defaultRadialGradient, true);
+				var w = parseFloat(rawNode.style.width);
+				var h = parseFloat(rawNode.style.height);
+				fillStyle.cx = isNaN(w) ? 0 : fo.focusposition.x * w;
+				fillStyle.cy = isNaN(h) ? 0 : fo.focusposition.y * h;
+				fillStyle.r  = isNaN(w) ? 1 : w / 2;
+				fillStyle.colors = [];
+				var stops = fo.colors.value.split(";");
+				for(var i = stops.length - 1; i >= 0; --i){
+					var t = stops[i].match(/\S+/g);
+					if(!t || t.length != 2) continue;
+					fillStyle.colors.push({offset: dojox.gfx.vml._parseFloat(t[0]), color: new dojo.Color(t[1])});
+				}
+			}else if(fo.on && fo.type == "tile"){
+				var fillStyle = dojox.gfx._base._copy(dojox.gfx.defaultPattern, true);
+				fillStyle.width  = dojox.gfx.pt2px(fo.size.x); // from pt
+				fillStyle.height = dojox.gfx.pt2px(fo.size.y); // from pt
+				fillStyle.x = fo.origin.x * fillStyle.width;
+				fillStyle.y = fo.origin.y * fillStyle.height;
+				fillStyle.src = fo.src;
+			}else if(fo.on && rawNode.fillcolor){
+				// a color object !
+				fillStyle = new dojo.Color(rawNode.fillcolor+"");
+				fillStyle.a = fo.opacity;
+			}
+		}
+		return fillStyle;	// Object
+	},
+
+	attachStroke: function(rawNode) {
+		// summary: deduces a stroke style from a Node.
+		// rawNode: Node: an VML node
+		var strokeStyle = dojox.gfx._base._copy(dojox.gfx.defaultStroke, true);
+		if(rawNode && rawNode.stroked){
+			strokeStyle.color = new dojo.Color(rawNode.strokecolor.value);
+			console.debug("We are expecting an .75pt here, instead of strokeweight = " + rawNode.strokeweight );
+			strokeStyle.width = dojox.gfx.normalizedLength(rawNode.strokeweight+"");
+			strokeStyle.color.a = rawNode.stroke.opacity;
+			strokeStyle.cap = this._translate(this._capMapReversed, rawNode.stroke.endcap);
+			strokeStyle.join = rawNode.stroke.joinstyle == "miter" ? rawNode.stroke.miterlimit : rawNode.stroke.joinstyle;
+			strokeStyle.style = rawNode.stroke.dashstyle;
+		}else{
+			return null;
+		}
+		return strokeStyle;	// Object
+	},
+
+	attachTransform: function(rawNode) {
+		// summary: deduces a transformation matrix from a Node.
+		// rawNode: Node: an VML node
+		var matrix = {};
+		if(rawNode){
+			var s = rawNode.skew;
+			matrix.xx = s.matrix.xtox;
+			matrix.xy = s.matrix.ytox;
+			matrix.yx = s.matrix.xtoy;
+			matrix.yy = s.matrix.ytoy;
+			matrix.dx = dojox.gfx.pt2px(s.offset.x);
+			matrix.dy = dojox.gfx.pt2px(s.offset.y);
+		}
+		return dojox.gfx.matrix.normalize(matrix);	// dojox.gfx.matrix.Matrix
+	},
+
+	attach: function(rawNode){
+		// summary: reconstructs all shape parameters from a Node.
+		// rawNode: Node: an VML node
+		if(rawNode){
+			this.rawNode = rawNode;
+			this.shape = this.attachShape(rawNode);
+			if("attachFont" in this){
+				this.fontStyle = this.attachFont(rawNode);
+			}
+			if("attachText" in this){
+				this.text = this.attachText(rawNode);
+			}
+			this.fillStyle = this.attachFill(rawNode);
+			this.strokeStyle = this.attachStroke(rawNode);
+			this.matrix = this.attachTransform(rawNode);
+		}
+	}
+});
+
+dojo.declare("dojox.gfx.Group", dojox.gfx.shape.VirtualGroup, {
+	// summary: a group shape (VML), which can be used 
+	//	to logically group shapes (e.g, to propagate matricies)
+	add: function(shape){
+		// summary: adds a shape to a group/surface
+		// shape: dojox.gfx.Shape: an VML shape object
+		if(this != shape.getParent()){
+			this.rawNode.appendChild(shape.rawNode);
+			dojox.gfx.Group.superclass.add.apply(this, arguments);
+		}
+		return this;	// self
+	},
+	remove: function(shape, silently){
+		// summary: remove a shape from a group/surface
+		// shape: dojox.gfx.Shape: an VML shape object
+		// silently: Boolean?: if true, regenerate a picture
+		if(this == shape.getParent()){
+			if(this.rawNode == shape.rawNode.parentNode){
+				this.rawNode.removeChild(shape.rawNode);
+			}
+			dojox.gfx.Group.superclass.remove.apply(this, arguments);
+		}
+		return this;	// self
+	},
+	clear: function(){
+		// summary: removes all shapes from a group/surface
+		var r = this.rawNode;
+		while(r.lastChild){
+			r.removeChild(r.lastChild);
+		}
+		return dojox.gfx.Group.superclass.clear.call(this);	// self
+	},
+	attach: function(rawNode){
+		// summary: reconstructs all group shape parameters from a Node (VML).
+		// rawNode: Node: a node
+		if(rawNode){
+			this.rawNode = rawNode;
+			this.shape = null;
+			this.fillStyle = null;
+			this.strokeStyle = null;
+			this.matrix = null;
+		}
+	}
+});
+dojox.gfx.Group.nodeType = "group";
+
+var zIndex = {
+	moveToFront: function(){
+		// summary: moves a shape to front of its parent's list of shapes (VML)
+		this.rawNode.parentNode.appendChild(this.rawNode);
+		return this;
+	},
+	moveToBack: function(){
+		// summary: moves a shape to back of its parent's list of shapes (VML)
+		var r = this.rawNode;
+		var p = r.parentNode;
+		var n = p.firstChild;
+		p.insertBefore(r, n);
+		if(n.tagName == "rect"){
+			// surface has a background rectangle, which position should be preserved
+			n.swapNode(r);
+		}
+		return this;
+	}
+};
+dojo.extend(dojox.gfx.Shape, zIndex);
+dojo.extend(dojox.gfx.Group, zIndex);
+delete zIndex;
+
+dojo.declare("dojox.gfx.Rect", dojox.gfx.shape.Rect, {
+	// summary: a rectangle shape (VML)
+
+	attachShape: function(rawNode){
+		// summary: builds a rectangle shape from a Node.
+		// rawNode: Node: a VML node
+
+		// a workaround for the VML's arcsize bug: cannot read arcsize of an instantiated node
+		var arcsize = rawNode.outerHTML.match(/arcsize = \"(\d*\.?\d+[%f]?)\"/)[1];
+		arcsize = (arcsize.indexOf("%") >= 0) ? parseFloat(arcsize) / 100 : dojox.gfx.vml._parseFloat(arcsize);
+		var style = rawNode.style;
+		var width  = parseFloat(style.width);
+		var height = parseFloat(style.height);
+		// make an object
+		var o = dojox.gfx.makeParameters(dojox.gfx.defaultRect, {
+			x: parseInt(style.left),
+			y: parseInt(style.top),
+			width:  width,
+			height: height,
+			r: Math.min(width, height) * arcsize
+		});
+		return o;	// dojox.gfx.shape.Rect
+	},
+	setShape: function(newShape){
+		// summary: sets a rectangle shape object (VML)
+		// newShape: Object: a rectangle shape object
+		var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape);
+		this.bbox = null;
+		var style = this.rawNode.style;
+		style.left   = shape.x.toFixed();
+		style.top    = shape.y.toFixed();
+		style.width  = (typeof(shape.width) == "string" && shape.width.indexOf("%") >= 0)  ? shape.width  : shape.width.toFixed();
+		style.height = (typeof(shape.width) == "string" && shape.height.indexOf("%") >= 0) ? shape.height : shape.height.toFixed();
+		var r = Math.min(1, (shape.r / Math.min(parseFloat(shape.width), parseFloat(shape.height)))).toFixed(8);
+		// a workaround for the VML's arcsize bug: cannot read arcsize of an instantiated node
+		var parent = this.rawNode.parentNode;
+		var before = null;
+		if(parent){
+			if(parent.lastChild != this.rawNode){
+				for(var i = 0; i < parent.childNodes.length; ++i){
+					if(parent.childNodes[i] == this.rawNode){
+						before = parent.childNodes[i+1];
+						break;
+					}
+				}
+			}
+			parent.removeChild(this.rawNode);
+		}
+		this.rawNode.arcsize = r;
+		if(parent){
+			if(before){
+				parent.insertBefore(this.rawNode, before);
+			}else{
+				parent.appendChild(this.rawNode);
+			}
+		}
+		return this.setTransform(this.matrix);	// self
+	}
+});
+dojox.gfx.Rect.nodeType = "roundrect"; // use a roundrect so the stroke join type is respected
+
+dojo.declare("dojox.gfx.Ellipse", dojox.gfx.shape.Ellipse, {
+	// summary: an ellipse shape (VML)
+
+	attachShape: function(rawNode){
+		// summary: builds an ellipse shape from a Node.
+		// rawNode: Node: an VML node
+		var style = this.rawNode.style;
+		var rx = parseInt(style.width ) / 2;
+		var ry = parseInt(style.height) / 2;
+		var o = dojox.gfx.makeParameters(dojox.gfx.defaultEllipse, {
+			cx: parseInt(style.left) + rx,
+			cy: parseInt(style.top ) + ry,
+			rx: rx,
+			ry: ry
+		});
+		return o;	// dojox.gfx.shape.Ellipse
+	},
+	setShape: function(newShape){
+		// summary: sets an ellipse shape object (VML)
+		// newShape: Object: an ellipse shape object
+		var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape);
+		this.bbox = null;
+		var style = this.rawNode.style;
+		style.left   = (shape.cx - shape.rx).toFixed();
+		style.top    = (shape.cy - shape.ry).toFixed();
+		style.width  = (shape.rx * 2).toFixed();
+		style.height = (shape.ry * 2).toFixed();
+		return this.setTransform(this.matrix);	// self
+	}
+});
+dojox.gfx.Ellipse.nodeType = "oval";
+
+dojo.declare("dojox.gfx.Circle", dojox.gfx.shape.Circle, {
+	// summary: a circle shape (VML)
+
+	attachShape: function(rawNode){
+		// summary: builds a circle shape from a Node.
+		// rawNode: Node: an VML node
+		var style = this.rawNode.style;
+		var r = parseInt(style.width) / 2;
+		var o = dojox.gfx.makeParameters(dojox.gfx.defaultCircle, {
+			cx: parseInt(style.left) + r,
+			cy: parseInt(style.top)  + r,
+			r:  r
+		});
+		return o;	// dojox.gfx.shape.Circle
+	},
+	setShape: function(newShape){
+		// summary: sets a circle shape object (VML)
+		// newShape: Object: a circle shape object
+		var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape);
+		this.bbox = null;
+		var style = this.rawNode.style;
+		style.left   = (shape.cx - shape.r).toFixed();
+		style.top    = (shape.cy - shape.r).toFixed();
+		style.width  = (shape.r * 2).toFixed();
+		style.height = (shape.r * 2).toFixed();
+		return this;	// self
+	}
+});
+dojox.gfx.Circle.nodeType = "oval";
+
+dojo.declare("dojox.gfx.Line", dojox.gfx.shape.Line,
+	function(rawNode){
+		if(rawNode) rawNode.setAttribute("dojoGfxType", "line");
+	}, {
+	// summary: a line shape (VML)
+
+	attachShape: function(rawNode){
+		// summary: builds a line shape from a Node.
+		// rawNode: Node: an VML node
+		var p = rawNode.path.v.match(dojox.gfx.pathVmlRegExp);
+		var shape = {};
+		do{
+			if(p.length < 7 || p[0] != "m" || p[3] != "l" || p[6] != "e") break;
+			shape.x1 = parseInt(p[1]);
+			shape.y1 = parseInt(p[2]);
+			shape.x2 = parseInt(p[4]);
+			shape.y2 = parseInt(p[5]);
+		}while(false);
+		return dojox.gfx.makeParameters(dojox.gfx.defaultLine, shape);	// dojox.gfx.shape.Line
+	},
+	setShape: function(newShape){
+		// summary: sets a line shape object (VML)
+		// newShape: Object: a line shape object
+		var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape);
+		this.bbox = null;
+		this.rawNode.path.v = "m" + shape.x1.toFixed() + " " + shape.y1.toFixed() +
+			"l" + shape.x2.toFixed() + " " + shape.y2.toFixed() + "e";
+		return this.setTransform(this.matrix);	// self
+	}
+});
+dojox.gfx.Line.nodeType = "shape";
+
+dojo.declare("dojox.gfx.Polyline", dojox.gfx.shape.Polyline,
+	function(rawNode){
+		if(rawNode) rawNode.setAttribute("dojoGfxType", "polyline");
+	}, {
+	// summary: a polyline/polygon shape (VML)
+	
+	attachShape: function(rawNode){
+		// summary: builds a polyline/polygon shape from a Node.
+		// rawNode: Node: an VML node
+		var shape = dojox.gfx._base._copy(dojox.gfx.defaultPolyline, true);
+		var p = rawNode.path.v.match(dojox.gfx.pathVmlRegExp);
+		do{
+			if(p.length < 3 || p[0] != "m") break;
+			var x = parseInt(p[0]);
+			var y = parseInt(p[1]);
+			if(isNaN(x) || isNaN(y)) break;
+			shape.points.push({x: x, y: y});
+			if(p.length < 6 || p[3] != "l") break;
+			for(var i = 4; i < p.length; i += 2){
+				x = parseInt(p[i]);
+				y = parseInt(p[i + 1]);
+				if(isNaN(x) || isNaN(y)) break;
+				shape.points.push({x: x, y: y});
+			}
+		}while(false);
+		return shape;	// dojox.gfx.shape.Polyline
+	},
+	setShape: function(points, closed){
+		// summary: sets a polyline/polygon shape object (VML)
+		// points: Object: a polyline/polygon shape object
+		// closed: Boolean?: if true, close the polyline explicitely
+		if(points && points instanceof Array){
+			// branch
+			// points: Array: an array of points
+			this.shape = dojox.gfx.makeParameters(this.shape, { points: points });
+			if(closed && this.shape.points.length) this.shape.points.push(this.shape.points[0]);
+		}else{
+			this.shape = dojox.gfx.makeParameters(this.shape, points);
+		}
+		this.bbox = null;
+		var attr = [];
+		var p = this.shape.points;
+		if(p.length > 0){
+			attr.push("m");
+			var k = 1;
+			if(typeof p[0] == "number"){
+				attr.push(p[0].toFixed());
+				attr.push(p[1].toFixed());
+				k = 2;
+			}else{
+				attr.push(p[0].x.toFixed());
+				attr.push(p[0].y.toFixed());
+			}
+			if(p.length > k){
+				attr.push("l");
+				for(var i = k; i < p.length; ++i){
+					if(typeof p[i] == "number"){
+						attr.push(p[i].toFixed());
+					}else{
+						attr.push(p[i].x.toFixed());
+						attr.push(p[i].y.toFixed());
+					}
+				}
+			}
+		}
+		attr.push("e");
+		this.rawNode.path.v = attr.join(" ");
+		return this.setTransform(this.matrix);	// self
+	}
+});
+dojox.gfx.Polyline.nodeType = "shape";
+
+dojo.declare("dojox.gfx.Image", dojox.gfx.shape.Image,
+	function(rawNode){
+		if(rawNode) rawNode.setAttribute("dojoGfxType", "image");
+	}, {
+	// summary: an image (VML)
+	
+	getEventSource: function() {
+		// summary: returns a Node, which is used as 
+		//	a source of events for this shape
+		return this.rawNode ? this.rawNode.firstChild : null;	// Node
+	},
+	attachShape: function(rawNode){
+		// summary: builds an image shape from a Node.
+		// rawNode: Node: an VML node
+		var shape = dojox.gfx._base._copy(dojox.gfx.defaultImage, true);
+		shape.src = rawNode.firstChild.src;
+		return shape;	// dojox.gfx.shape.Image
+	},
+	setShape: function(newShape){
+		// summary: sets an image shape object (VML)
+		// newShape: Object: an image shape object
+		var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape);
+		this.bbox = null;
+		var firstChild = this.rawNode.firstChild;
+        firstChild.src = shape.src;
+        if(shape.width || shape.height){
+			firstChild.style.width  = shape.width;
+			firstChild.style.height = shape.height;
+        }
+		return this.setTransform(this.matrix);	// self
+	},
+	setStroke: function(){
+		// summary: ignore setting a stroke style
+		return this;	// self
+	},
+	setFill: function(){
+		// summary: ignore setting a fill style
+		return this;	// self
+	},
+	attachStroke: function(rawNode){
+		// summary: ignore attaching a stroke style
+		return null;
+	},
+	attachFill: function(rawNode){
+		// summary: ignore attaching a fill style
+		return null;
+	},
+	attachTransform: function(rawNode) {
+		// summary: deduces a transformation matrix from a Node.
+		// rawNode: Node: an VML node
+		var matrix = {};
+		if(rawNode){
+			var m = rawNode.filters["DXImageTransform.Microsoft.Matrix"];
+			matrix.xx = m.M11;
+			matrix.xy = m.M12;
+			matrix.yx = m.M21;
+			matrix.yy = m.M22;
+			matrix.dx = m.Dx;
+			matrix.dy = m.Dy;
+		}
+		return dojox.gfx.matrix.normalize(matrix);	// dojox.gfx.matrix.Matrix
+	},
+	_applyTransform: function() {
+		var matrix = this._getRealMatrix();
+		if(!matrix) return this;
+		matrix = dojox.gfx.matrix.multiply(matrix, {dx: this.shape.x, dy: this.shape.y});
+		var f = this.rawNode.filters["DXImageTransform.Microsoft.Matrix"];
+		f.M11 = matrix.xx;
+		f.M12 = matrix.xy;
+		f.M21 = matrix.yx;
+		f.M22 = matrix.yy;
+		f.Dx  = matrix.dx;
+		f.Dy  = matrix.dy;
+		return this;
+	}
+});
+dojox.gfx.Image.nodeType = "div";
+
+dojo.declare("dojox.gfx.Text", dojox.gfx.shape.Text, 
+	function(rawNode){
+		if(rawNode) rawNode.setAttribute("dojoGfxType", "text");
+		this.fontStyle = null;
+	}, {
+	// summary: an anchored text (VML)
+
+	attachShape: function(rawNode){
+		// summary: builds a text shape from a Node.
+		// rawNode: Node: an VML node
+		var shape = null;
+		if(rawNode){
+			shape = dojox.gfx._base._copy(dojox.gfx.defaultText, true);
+			var p = rawNode.path.v.match(dojox.gfx.pathVmlRegExp);
+			if(!p || p.length != 7){ return null; }
+			var c = rawNode.childNodes;
+			for(var i = 0; i < c.length; ++i){
+				if(c[i].tagName == "textpath"){
+					var s = c[i].style;
+					shape.text = c[i].string;
+					switch(s["v-text-align"]){
+						case "left":
+							shape.x = parseInt(p[1]);
+							shape.align = "start";
+							break;
+						case "center":
+							shape.x = (parseInt(p[1]) + parseInt(p[4])) / 2;
+							shape.align = "middle";
+							break;
+						case "right":
+							shape.x = parseInt(p[4]);
+							shape.align = "end";
+							break;
+					}
+					shape.y = parseInt(p[2]);
+					shape.decoration = s["text-decoration"];
+					shape.rotated = s["v-rotate-letters"].toLowerCase() in dojox.gfx.vml._bool;
+					shape.kerning = s["v-text-kern"].toLowerCase() in dojox.gfx.vml._bool;
+					break;
+				}
+			}
+		}
+		return shape;	// dojox.gfx.shape.Text
+	},
+	_alignment: {start: "left", middle: "center", end: "right"},
+	setShape: function(newShape){
+		// summary: sets a text shape object (VML)
+		// newShape: Object: a text shape object
+		this.shape = dojox.gfx.makeParameters(this.shape, newShape);
+		this.bbox = null;
+		var r = this.rawNode;
+		var s = this.shape;
+		var x = s.x;
+		var y = s.y.toFixed();
+		switch(s.align){
+			case "middle":
+				x -= 5;
+				break;
+			case "end":
+				x -= 10;
+				break;
+		}
+		this.rawNode.path.v = "m" + x.toFixed() + "," + y + 
+			"l" + (x + 10).toFixed() + "," + y + "e";
+		// find path and text path
+		var p = null, t = null;
+		var c = r.childNodes;
+		for(var i = 0; i < c.length; ++i){
+			var tag = c[i].tagName;
+			if(tag == "path"){
+				p = c[i];
+				if(t) break;
+			}else if(tag == "textpath"){
+				t = c[i];
+				if(p) break;
+			}
+		}
+		if(!p){
+			p = this.rawNode.ownerDocument.createElement("v:path");
+			r.appendChild(p);
+		}
+		if(!t){
+			t = this.rawNode.ownerDocument.createElement("v:textpath");
+			r.appendChild(t);
+		}
+		p.textPathOk = true;
+		t.on = true;
+		var a = dojox.gfx.vml.text_alignment[s.align];
+		t.style["v-text-align"] = a ? a : "left";
+		t.style["text-decoration"] = s.decoration;
+		t.style["v-rotate-letters"] = s.rotated;
+		t.style["v-text-kern"] = s.kerning;
+		t.string = s.text;
+		return this.setTransform(this.matrix);	// self
+	},
+	_setFont: function(){
+		// summary: sets a font object (VML)
+		var f = this.fontStyle;
+		var c = this.rawNode.childNodes;
+		for(var i = 0; i < c.length; ++i){
+			if(c[i].tagName == "textpath"){
+				c[i].style.font = dojox.gfx.makeFontString(f);
+				break;
+			}
+		}
+		this.setTransform(this.matrix);
+	},
+	attachFont: function(rawNode){
+		// summary: deduces a font style from a Node.
+		// rawNode: Node: an VML node
+		if(!rawNode){ return null; }
+		var fontStyle = dojox.gfx._base._copy(dojox.gfx.defaultFont, true);
+		var c = this.rawNode.childNodes;
+		for(var i = 0; i < c.length; ++i){
+			if(c[i].tagName == "textpath"){
+				var s = c[i].style;
+				fontStyle.style = s.fontstyle;
+				fontStyle.variant = s.fontvariant;
+				fontStyle.weight = s.fontweight;
+				fontStyle.size = s.fontsize;
+				fontStyle.family = s.fontfamily;
+				break;
+			}
+		}
+		return fontStyle;	// Object
+	},
+	attachTransform: function(rawNode) {
+		// summary: deduces a transformation matrix from a Node.
+		// rawNode: Node: an VML node
+		var matrix = dojox.gfx.Shape.prototype.attachTransform.call(this);
+		// see comments in _getRealMatrix()
+		if(matrix){
+			matrix = dojox.gfx.matrix.multiply(matrix, {dy: dojox.gfx.normalizedLength(this.fontStyle.size) * 0.35});
+		}
+		return matrix;	// dojox.gfx.Matrix2D
+	},
+	_getRealMatrix: function(){
+		// summary: returns the cumulative ("real") transformation matrix
+		//	by combining the shape's matrix with its parent's matrix;
+		//	it makes a correction for a font size
+		var matrix = dojox.gfx.Shape.prototype._getRealMatrix.call(this);
+		// It appears that text is always aligned vertically at a middle of x-height (???).
+		// It is impossible to obtain these metrics from VML => I try to approximate it with 
+		// more-or-less util value of 0.7 * FontSize, which is typical for European fonts.
+		if(matrix){
+			matrix = dojox.gfx.matrix.multiply(matrix, 
+				{dy: -dojox.gfx.normalizedLength(this.fontStyle ? this.fontStyle.size : "10pt") * 0.35});
+		}
+		return matrix;	// dojox.gfx.Matrix2D
+	}
+});
+dojox.gfx.Text.nodeType = "shape";
+
+dojox.gfx.path._calcArc = function(alpha){
+	var cosa  = Math.cos(alpha);
+	var sina  = Math.sin(alpha);
+	// return a start point, 1st and 2nd control points, and an end point
+	var p2 = {x: cosa + (4 / 3) * (1 - cosa), y: sina - (4 / 3) * cosa * (1 - cosa) / sina};
+	return {
+		s:  {x: cosa, y: sina},
+		c1: p2,
+		c2: {x: p2.x, y: -p2.y},
+		e:  {x: cosa, y: -sina}
+	};
+};
+
+dojo.declare("dojox.gfx.Path", dojox.gfx.path.Path,
+	function(rawNode){
+		if(rawNode && !rawNode.getAttribute("dojoGfxType")){
+			rawNode.setAttribute("dojoGfxType", "path");
+		}
+		this.vmlPath = "";
+		this.lastControl = {};
+	}, {
+	// summary: a path shape (VML)
+
+	_updateWithSegment: function(segment){
+		// summary: updates the bounding box of path with new segment
+		// segment: Object: a segment
+		var last = dojox.gfx._base._copy(this.last);
+		dojox.gfx.Path.superclass._updateWithSegment.apply(this, arguments);
+		// add a VML path segment
+		var path = this[this.renderers[segment.action]](segment, last);
+		if(typeof(this.vmlPath) == "string"){
+			this.vmlPath += path.join("");
+		}else{
+			this.vmlPath = this.vmlPath.concat(path);
+		}
+		if(typeof(this.vmlPath) == "string"){
+			this.rawNode.path.v = this.vmlPath + " e";
+		}
+	},
+	attachShape: function(rawNode){
+		// summary: builds a path shape from a Node.
+		// rawNode: Node: an VML node
+		var shape = dojox.gfx._base._copy(dojox.gfx.defaultPath, true);
+		var p = rawNode.path.v.match(dojox.gfx.pathVmlRegExp);
+		var t = [], skip = false;
+		for(var i = 0; i < p.length; ++p){
+			var s = p[i];
+			if(s in this._pathVmlToSvgMap) {
+				skip = false;
+				t.push(this._pathVmlToSvgMap[s]);
+			} else if(!skip){
+				var n = parseInt(s);
+				if(isNaN(n)){
+					skip = true;
+				}else{
+					t.push(n);
+				}
+			}
+		}
+		if(t.length) shape.path = t.join(" ");
+		return shape;	// dojox.gfx.path.Path
+	},
+	setShape: function(newShape){
+		// summary: forms a path using a shape (VML)
+		// newShape: Object: an VML path string or a path object (see dojox.gfx.defaultPath)
+		this.vmlPath = [];
+		this.lastControl = {};
+		dojox.gfx.Path.superclass.setShape.apply(this, arguments);
+		this.vmlPath = this.vmlPath.join("");
+		this.rawNode.path.v = this.vmlPath + " e";
+		return this;
+	},
+	_pathVmlToSvgMap: {m: "M", l: "L", t: "m", r: "l", c: "C", v: "c", qb: "Q", x: "z", e: ""},
+	// VML-specific segment renderers
+	renderers: {
+		M: "_moveToA", m: "_moveToR", 
+		L: "_lineToA", l: "_lineToR", 
+		H: "_hLineToA", h: "_hLineToR", 
+		V: "_vLineToA", v: "_vLineToR", 
+		C: "_curveToA", c: "_curveToR", 
+		S: "_smoothCurveToA", s: "_smoothCurveToR", 
+		Q: "_qCurveToA", q: "_qCurveToR", 
+		T: "_qSmoothCurveToA", t: "_qSmoothCurveToR", 
+		A: "_arcTo", a: "_arcTo", 
+		Z: "_closePath", z: "_closePath"
+	},
+	_addArgs: function(path, args, from, upto){
+		if(typeof(upto) == "undefined"){
+			upto = args.length;
+		}
+		if(typeof(from) == "undefined"){
+			from = 0;
+		}
+		for(var i = from; i < upto; ++i){
+			path.push(" ");
+			path.push(args[i].toFixed());
+		}
+	},
+	_addArgsAdjusted: function(path, last, args, from, upto){
+		if(typeof(upto) == "undefined"){
+			upto = args.length;
+		}
+		if(typeof(from) == "undefined"){
+			from = 0;
+		}
+		for(var i = from; i < upto; i += 2){
+			path.push(" ");
+			path.push((last.x + args[i]).toFixed());
+			path.push(" ");
+			path.push((last.y + args[i + 1]).toFixed());
+		}
+	},
+	_moveToA: function(segment){
+		var p = [" m"];
+		var n = segment.args;
+		var l = n.length;
+		if(l == 2){
+			this._addArgs(p, n);
+		}else{
+			this._addArgs(p, n, 0, 2);
+			p.push(" l");
+			this._addArgs(p, n, 2);
+		}
+		this.lastControl = {};
+		return p;
+	},
+	_moveToR: function(segment, last){
+		var p = ["x" in last ? " t" : " m"];
+		var n = segment.args;
+		var l = n.length;
+		if(l == 2){
+			this._addArgs(p, n);
+		}else{
+			this._addArgs(p, n, 0, 2);
+			p.push(" r");
+			this._addArgs(p, n, 2);
+		}
+		this.lastControl = {};
+		return p;
+	},
+	_lineToA: function(segment){
+		var p = [" l"];
+		this._addArgs(p, segment.args);
+		this.lastControl = {};
+		return p;
+	},
+	_lineToR: function(segment){
+		var p = [" r"];
+		this._addArgs(p, segment.args);
+		this.lastControl = {};
+		return p;
+	},
+	_hLineToA: function(segment, last){
+		var p = [" l"];
+		var n = segment.args;
+		var l = n.length;
+		var y = " " + last.y.toFixed();
+		for(var i = 0; i < l; ++i){
+			p.push(" ");
+			p.push(n[i].toFixed());
+			p.push(y);
+		}
+		this.lastControl = {};
+		return p;
+	},
+	_hLineToR: function(segment){
+		var p = [" r"];
+		var n = segment.args;
+		var l = n.length;
+		for(var i = 0; i < l; ++i){
+			p.push(" ");
+			p.push(n[i].toFixed());
+			p.push(" 0");
+		}
+		this.lastControl = {};
+		return p;
+	},
+	_vLineToA: function(segment, last){
+		var p = [" l"];
+		var n = segment.args;
+		var l = n.length;
+		var x = " " + last.x.toFixed();
+		for(var i = 0; i < l; ++i){
+			p.push(x);
+			p.push(" ");
+			p.push(n[i].toFixed());
+		}
+		this.lastControl = {};
+		return p;
+	},
+	_vLineToR: function(segment){
+		var p = [" r"];
+		var n = segment.args;
+		var l = n.length;
+		for(var i = 0; i < l; ++i){
+			p.push(" 0 ");
+			p.push(n[i].toFixed());
+		}
+		this.lastControl = {};
+		return p;
+	},
+	_curveToA: function(segment){
+		var p = [];
+		var n = segment.args;
+		var l = n.length;
+		for(var i = 0; i < l; i += 6){
+			p.push(" c");
+			this._addArgs(p, n, i, i + 6);
+		}
+		this.lastControl = {x: n[l - 4], y: n[l - 3], type: "C"};
+		return p;
+	},
+	_curveToR: function(segment, last){
+		var p = [];
+		var n = segment.args;
+		var l = n.length;
+		for(var i = 0; i < l; i += 6){
+			p.push(" v");
+			this._addArgs(p, n, i, i + 6);
+			this.lastControl = {x: last.x + n[i + 2], y: last.y + n[i + 3]};
+			last.x += n[i + 4];
+			last.y += n[i + 5];
+		}
+		this.lastControl.type = "C";
+		return p;
+	},
+	_smoothCurveToA: function(segment, last){
+		var p = [];
+		var n = segment.args;
+		var l = n.length;
+		for(var i = 0; i < l; i += 4){
+			p.push(" c");
+			if(this.lastControl.type == "C"){
+				this._addArgs(p, [
+					2 * last.x - this.lastControl.x, 
+					2 * last.y - this.lastControl.y
+				]);
+			}else{
+				this._addArgs(p, [last.x, last.y]);
+			}
+			this._addArgs(p, n, i, i + 4);
+		}
+		this.lastControl = {x: n[l - 4], y: n[l - 3], type: "C"};
+		return p;
+	},
+	_smoothCurveToR: function(segment, last){
+		var p = [];
+		var n = segment.args;
+		var l = n.length;
+		for(var i = 0; i < l; i += 4){
+			p.push(" v");
+			if(this.lastControl.type == "C"){
+				this._addArgs(p, [
+					last.x - this.lastControl.x, 
+					last.y - this.lastControl.y
+				]);
+			}else{
+				this._addArgs(p, [0, 0]);
+			}
+			this._addArgs(p, n, i, i + 4);
+			this.lastControl = {x: last.x + n[i], y: last.y + n[i + 1]};
+			last.x += n[i + 2];
+			last.y += n[i + 3];
+		}
+		this.lastControl.type = "C";
+		return p;
+	},
+	_qCurveToA: function(segment){
+		var p = [];
+		var n = segment.args;
+		var l = n.length;
+		for(var i = 0; i < l; i += 4){
+			p.push(" qb");
+			this._addArgs(p, n, i, i + 4);
+		}
+		this.lastControl = {x: n[l - 4], y: n[l - 3], type: "Q"};
+		return p;
+	},
+	_qCurveToR: function(segment, last){
+		var p = [];
+		var n = segment.args;
+		var l = n.length;
+		for(var i = 0; i < l; i += 4){
+			p.push(" qb");
+			this._addArgsAdjusted(p, last, n, i, i + 4);
+			this.lastControl = {x: last.x + n[i], y: last.y + n[i + 1]};
+			last.x += n[i + 2];
+			last.y += n[i + 3];
+		}
+		this.lastControl.type = "Q";
+		return p;
+	},
+	_qSmoothCurveToA: function(segment, last){
+		var p = [];
+		var n = segment.args;
+		var l = n.length;
+		for(var i = 0; i < l; i += 2){
+			p.push(" qb");
+			if(this.lastControl.type == "Q"){
+				this._addArgs(p, [
+					this.lastControl.x = 2 * last.x - this.lastControl.x, 
+					this.lastControl.y = 2 * last.y - this.lastControl.y
+				]);
+			}else{
+				this._addArgs(p, [
+					this.lastControl.x = last.x, 
+					this.lastControl.y = last.y
+				]);
+			}
+			this._addArgs(p, n, i, i + 2);
+		}
+		this.lastControl.type = "Q";
+		return p;
+	},
+	_qSmoothCurveToR: function(segment, last){
+		var p = [];
+		var n = segment.args;
+		var l = n.length;
+		for(var i = 0; i < l; i += 2){
+			p.push(" qb");
+			if(this.lastControl.type == "Q"){
+				this._addArgs(p, [
+					this.lastControl.x = 2 * last.x - this.lastControl.x, 
+					this.lastControl.y = 2 * last.y - this.lastControl.y
+				]);
+			}else{
+				this._addArgs(p, [
+					this.lastControl.x = last.x, 
+					this.lastControl.y = last.y
+				]);
+			}
+			this._addArgsAdjusted(p, last, n, i, i + 2);
+		}
+		this.lastControl.type = "Q";
+		return p;
+	},
+	_curvePI4: dojox.gfx.path._calcArc(Math.PI / 8),
+	_calcArcTo: function(path, last, rx, ry, xRotg, large, cw, x, y){
+		var m = dojox.gfx.matrix;
+		// calculate parameters
+		var xRot = -dojox.gfx.matrix._degToRad(xRotg);
+		var rx2 = rx * rx;
+		var ry2 = ry * ry;
+		var pa = m.multiplyPoint(
+			m.rotate(-xRot), 
+			{x: (last.x - x) / 2, y: (last.y - y) / 2}
+		);
+		var pax2 = pa.x * pa.x;
+		var pay2 = pa.y * pa.y;
+		var c1 = Math.sqrt((rx2 * ry2 - rx2 * pay2 - ry2 * pax2) / (rx2 * pay2 + ry2 * pax2));
+		var ca = {
+			x:  c1 * rx * pa.y / ry,
+			y: -c1 * ry * pa.x / rx
+		};
+		if(large == cw){
+			ca = {x: -ca.x, y: -ca.y};
+		}
+		// our center
+		var c = m.multiplyPoint(
+			[
+				m.translate(
+					(last.x + x) / 2,
+					(last.y + y) / 2
+				),
+				m.rotate(xRot)
+			], 
+			ca
+		);
+		// start of our arc
+		var startAngle = Math.atan2(c.y - last.y, last.x - c.x) - xRot;
+		var endAngle   = Math.atan2(c.y - y, x - c.x) - xRot;
+		// size of our arc in radians
+		var theta = cw ? startAngle - endAngle : endAngle - startAngle;
+		if(theta < 0){
+			theta += dojox.gfx.vml.two_pi;
+		}else if(theta > dojox.gfx.vml.two_pi){
+			theta = dojox.gfx.vml.two_pi;
+		}
+		// calculate our elliptic transformation
+		var elliptic_transform = m.normalize([
+			m.translate(c.x, c.y),
+			m.rotate(xRot),
+			m.scale(rx, ry)
+		]);
+		// draw curve chunks
+		var alpha = dojox.gfx.vml.pi4 / 2;
+		var curve = this._curvePI4;
+		var step  = cw ? -alpha : alpha;
+		for(var angle = theta; angle > 0; angle -= dojox.gfx.vml.pi4){
+			if(angle < dojox.gfx.vml.pi4){
+				alpha = angle / 2;
+				curve = dojox.gfx.path._calcArc(alpha);
+				step  = cw ? -alpha : alpha;
+			}
+			var c1, c2, e;
+			var M = m.normalize([elliptic_transform, m.rotate(startAngle + step)]);
+			if(cw){
+				c1 = m.multiplyPoint(M, curve.c2);
+				c2 = m.multiplyPoint(M, curve.c1);
+				e  = m.multiplyPoint(M, curve.s );
+			}else{
+				c1 = m.multiplyPoint(M, curve.c1);
+				c2 = m.multiplyPoint(M, curve.c2);
+				e  = m.multiplyPoint(M, curve.e );
+			}
+			// draw the curve
+			path.push(" c");
+			this._addArgs(path, [c1.x, c1.y, c2.x, c2.y, e.x, e.y]);
+			startAngle += 2 * step;
+		}
+	},
+	_arcTo: function(segment, last){
+		var p = [];
+		var n = segment.args;
+		var l = n.length;
+		var relative = segment.action == "a";
+		for(var i = 0; i < l; i += 7){
+			var x1 = n[i + 5];
+			var y1 = n[i + 6];
+			if(relative){
+				x1 += last.x;
+				y1 += last.y;
+			}
+			this._calcArcTo(
+				p, last, n[i], n[i + 1], n[i + 2], 
+				n[i + 3] ? 1 : 0, n[i + 4] ? 1 : 0,
+				x1, y1
+			);
+			last = {x: x1, y: y1};
+		}
+		this.lastControl = {};
+		return p;
+	},
+	_closePath: function(){
+		this.lastControl = {};
+		return ["x"];
+	}
+});
+dojox.gfx.Path.nodeType = "shape";
+
+dojo.declare("dojox.gfx.TextPath", dojox.gfx.Path,
+	function(rawNode){
+		if(rawNode) rawNode.setAttribute("dojoGfxType", "textpath");
+		this.fontStyle = null;
+		if(!("text" in this)){
+			this.text = dojox.gfx._base._copy(dojox.gfx.defaultTextPath, true);
+		}
+		if(!("fontStyle" in this)){
+			this.fontStyle = dojox.gfx._base._copy(dojox.gfx.defaultFont, true);
+		}
+	}, {
+	// summary: a textpath shape (VML)
+
+	setText: function(newText){
+		// summary: sets a text to be drawn along the path
+		this.text = dojox.gfx.makeParameters(this.text, 
+			typeof(newText) == "string" ? {text: newText} : newText);
+		this._setText();
+		return this;	// self
+	},
+	setFont: function(newFont){
+		// summary: sets a font for text
+		this.fontStyle = typeof newFont == "string" ? 
+			dojox.gfx.splitFontString(newFont) :
+			dojox.gfx.makeParameters(dojox.gfx.defaultFont, newFont);
+		this._setFont();
+		return this;	// self
+	},
+
+	_setText: function(){
+		// summary: sets a text shape object (VML)
+		this.bbox = null;
+		var r = this.rawNode;
+		var s = this.text;
+		// find path and text path
+		var p = null, t = null;
+		var c = r.childNodes;
+		for(var i = 0; i < c.length; ++i){
+			var tag = c[i].tagName;
+			if(tag == "path"){
+				p = c[i];
+				if(t) break;
+			}else if(tag == "textpath"){
+				t = c[i];
+				if(p) break;
+			}
+		}
+		if(!p){
+			p = this.rawNode.ownerDocument.createElement("v:path");
+			r.appendChild(p);
+		}
+		if(!t){
+			t = this.rawNode.ownerDocument.createElement("v:textpath");
+			r.appendChild(t);
+		}
+		p.textPathOk = true;
+		t.on = true;
+		var a = dojox.gfx.vml.text_alignment[s.align];
+		t.style["v-text-align"] = a ? a : "left";
+		t.style["text-decoration"] = s.decoration;
+		t.style["v-rotate-letters"] = s.rotated;
+		t.style["v-text-kern"] = s.kerning;
+		t.string = s.text;
+	},
+	_setFont: function(){
+		// summary: sets a font object (VML)
+		var f = this.fontStyle;
+		var c = this.rawNode.childNodes;
+		for(var i = 0; i < c.length; ++i){
+			if(c[i].tagName == "textpath"){
+				c[i].style.font = dojox.gfx.makeFontString(f);
+				break;
+			}
+		}
+	},
+	attachText: function(rawNode){
+		// summary: builds a textpath shape from a Node.
+		// rawNode: Node: an VML node
+		return dojox.gfx.Text.prototype.attachText.call(this, rawNode);
+	},
+	attachFont: function(rawNode){
+		// summary: deduces a font style from a Node.
+		// rawNode: Node: an VML node
+		return dojox.gfx.Text.prototype.attachFont.call(this, rawNode);
+	}
+});
+dojox.gfx.TextPath.nodeType = "shape";
+
+
+dojox.gfx.vml._creators = {
+	// summary: VML shape creators
+	createPath: function(path){
+		// summary: creates a VML path shape
+		// path: Object: a path object (see dojox.gfx.defaultPath)
+		return this.createObject(dojox.gfx.Path, path, true);	// dojox.gfx.Path
+	},
+	createRect: function(rect){
+		// summary: creates a VML rectangle shape
+		// rect: Object: a path object (see dojox.gfx.defaultRect)
+		return this.createObject(dojox.gfx.Rect, rect);	// dojox.gfx.Rect
+	},
+	createCircle: function(circle){
+		// summary: creates a VML circle shape
+		// circle: Object: a circle object (see dojox.gfx.defaultCircle)
+		return this.createObject(dojox.gfx.Circle, circle);	// dojox.gfx.Circle
+	},
+	createEllipse: function(ellipse){
+		// summary: creates a VML ellipse shape
+		// ellipse: Object: an ellipse object (see dojox.gfx.defaultEllipse)
+		return this.createObject(dojox.gfx.Ellipse, ellipse);	// dojox.gfx.Ellipse
+	},
+	createLine: function(line){
+		// summary: creates a VML line shape
+		// line: Object: a line object (see dojox.gfx.defaultLine)
+		return this.createObject(dojox.gfx.Line, line, true);	// dojox.gfx.Line
+	},
+	createPolyline: function(points){
+		// summary: creates a VML polyline/polygon shape
+		// points: Object: a points object (see dojox.gfx.defaultPolyline)
+		//	or an Array of points
+		return this.createObject(dojox.gfx.Polyline, points, true);	// dojox.gfx.Polyline
+	},
+	createImage: function(image){
+		// summary: creates a VML image shape
+		// image: Object: an image object (see dojox.gfx.defaultImage)
+		if(!this.rawNode) return null;
+		var shape = new dojox.gfx.Image();
+		var node = this.rawNode.ownerDocument.createElement('div');
+		node.style.position = "absolute";
+		node.style.width  = this.rawNode.style.width;
+		node.style.height = this.rawNode.style.height;
+		node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11=1, M12=0, M21=0, M22=1, Dx=0, Dy=0)";
+		var img  = this.rawNode.ownerDocument.createElement('img');
+		node.appendChild(img);
+		shape.setRawNode(node);
+		this.rawNode.appendChild(node);
+		shape.setShape(image);
+		this.add(shape);
+		return shape;	// dojox.gfx.Image
+	},
+	createText: function(text){
+		// summary: creates a VML text shape
+		// text: Object: a text object (see dojox.gfx.defaultText)
+		return this.createObject(dojox.gfx.Text, text, true);	// dojox.gfx.Text
+	},
+	createTextPath: function(text){
+		// summary: creates an VML text shape
+		// text: Object: a textpath object (see dojox.gfx.defaultTextPath)
+		return this.createObject(dojox.gfx.TextPath, {}, true).setText(text);	// dojox.gfx.TextPath
+	},
+	createGroup: function(){
+		// summary: creates a VML group shape
+		return this.createObject(dojox.gfx.Group, null, true);	// dojox.gfx.Group
+	},
+	createObject: function(shapeType, rawShape, overrideSize) {
+		// summary: creates an instance of the passed shapeType class
+		// shapeType: Function: a class constructor to create an instance of
+		// rawShape: Object: properties to be passed in to the classes "setShape" method
+		if(!this.rawNode) return null;
+		var shape = new shapeType();
+		var node = this.rawNode.ownerDocument.createElement('v:' + shapeType.nodeType);
+		shape.setRawNode(node);
+		this.rawNode.appendChild(node);
+		if(overrideSize) this._overrideSize(node);
+		shape.setShape(rawShape);
+		this.add(shape);
+		return shape;	// dojox.gfx.Shape
+	},
+	_overrideSize: function(node){
+		node.style.width  = this.rawNode.style.width;
+		node.style.height = this.rawNode.style.height;
+		node.coordsize = parseFloat(node.style.width) + " " + parseFloat(node.style.height);
+	}
+};
+
+dojo.extend(dojox.gfx.Group, dojox.gfx.vml._creators);
+dojo.extend(dojox.gfx.Surface, dojox.gfx.vml._creators);
+
+delete dojox.gfx.vml._creators;
+
+dojox.gfx.attachNode = function(node){
+	// summary: creates a shape from a Node
+	// node: Node: an VML node
+	if(!node) return null;
+	var s = null;
+	switch(node.tagName.toLowerCase()){
+		case dojox.gfx.Rect.nodeType:
+			s = new dojox.gfx.Rect();
+			break;
+		case dojox.gfx.Ellipse.nodeType:
+			s = (node.style.width == node.style.height)
+				? new dojox.gfx.Circle()
+				: new dojox.gfx.Ellipse();
+			break;
+		case dojox.gfx.Path.nodeType:
+			switch(node.getAttribute("dojoGfxType")){
+				case "line":
+					s = new dojox.gfx.Line();
+					break;
+				case "polyline":
+					s = new dojox.gfx.Polyline();
+					break;
+				case "path":
+					s = new dojox.gfx.Path();
+					break;
+				case "text":
+					s = new dojox.gfx.Text();
+					break;
+				case "textpath":
+					s = new dojox.gfx.TextPath();
+					break;
+			}
+			break;
+		case dojox.gfx.Image.nodeType:
+			switch(node.getAttribute("dojoGfxType")){
+				case "image":
+					s = new dojox.gfx.Image();
+					break;
+			}
+			break;
+		default:
+			console.debug("FATAL ERROR! tagName = " + node.tagName);
+			return null;	// dojox.gfx.Shape
+	}
+	s.attach(node);
+	return s;	// dojox.gfx.Shape
+};
+
+dojo.extend(dojox.gfx.Surface, {
+	// summary: a surface object to be used for drawings (VML)
+
+	setDimensions: function(width, height){
+		// summary: sets the width and height of the rawNode
+		// width: String: width of surface, e.g., "100px"
+		// height: String: height of surface, e.g., "100px"
+		if(!this.rawNode) return this;
+		this.rawNode.style.width = width;
+		this.rawNode.style.height = height;
+		this.rawNode.coordsize = width + " " + height;
+		this.bgNode.style.width = width;
+		this.bgNode.style.height = height;
+		return this;	// self
+	},
+	getDimensions: function(){
+		// summary: returns an object with properties "width" and "height"
+		return this.rawNode ? { width: this.rawNode.style.width, height: this.rawNode.style.height } : null; // Object
+	},
+	// group control
+	add: function(shape){
+		// summary: adds a shape to a group/surface
+		// shape: dojox.gfx.Shape: an VMLshape object
+		var oldParent = shape.getParent();
+		if(this != oldParent){
+			this.rawNode.appendChild(shape.rawNode);
+			if(oldParent){
+				oldParent.remove(shape, true);
+			}
+			shape._setParent(this, null);
+		}
+		return this;	// self
+	},
+	remove: function(shape, silently){
+		// summary: remove a shape from a group/surface
+		// shape: dojox.gfx.Shape: an VML shape object
+		// silently: Boolean?: if true, regenerate a picture
+		if(this == shape.getParent()){
+			if(this.rawNode == shape.rawNode.parentNode){
+				this.rawNode.removeChild(shape.rawNode);
+			}
+			shape._setParent(null, null);
+		}
+		return this;	// self
+	},
+	clear: function(){
+		// summary: removes all shapes from a group/surface
+		var r = this.rawNode;
+		while(r.firstChild != r.lastChild){
+			if(r.firstChild != this.bgNode){
+				r.removeChild(r.firstChild);
+			}
+			if(r.lastChild != this.bgNode){
+				r.removeChild(r.lastChild);
+			}
+		}
+		return this;	// self
+	}
+});
+
+dojox.gfx.createSurface = function(parentNode, width, height){
+	// summary: creates a surface (VML)
+	// parentNode: Node: a parent node
+	// width: String: width of surface, e.g., "100px"
+	// height: String: height of surface, e.g., "100px"
+
+	var s = new dojox.gfx.Surface();
+	s.rawNode = dojo.byId(parentNode).ownerDocument.createElement("v:group");
+	s.rawNode.style.width  = width  ? width  : "100%";
+	s.rawNode.style.height = height ? height : "100%";
+	s.rawNode.style.position = "relative";
+	s.rawNode.coordsize = (width && height)
+		? (parseFloat(width) + " " + parseFloat(height))
+		: "100% 100%";
+	s.rawNode.coordorigin = "0 0";
+	dojo.byId(parentNode).appendChild(s.rawNode);
+	// create a background rectangle, which is required to show all other shapes
+	var r = s.rawNode.ownerDocument.createElement("v:rect");
+	r.style.left = r.style.top = 0;
+	r.style.width  = s.rawNode.style.width;
+	r.style.height = s.rawNode.style.height;
+	r.filled = r.stroked = false;
+	s.rawNode.appendChild(r);
+	s.bgNode = r;
+	return s;	// dojox.gfx.Surface
+};
+
+dojox.gfx.attachSurface = function(node){
+	// summary: creates a surface from a Node
+	// node: Node: an VML node
+	var s = new dojox.gfx.Surface();
+	s.rawNode = node;
+	var r = node.firstChild;
+	if(!r || r.tagName != "rect"){
+		return null;	// dojox.gfx.Surface
+	}
+	s.bgNode = r;
+	return s;	// dojox.gfx.Surface
+};

Added: trunk/examples/typeface/root/static/dojo/dojox/gfx.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/gfx.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/gfx.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+dojo.provide("dojox.gfx");
+
+dojo.require("dojox.gfx.matrix");
+dojo.require("dojox.gfx._base");
+
+// include a renderer conditionally
+dojo.requireIf(dojo.isIE == 0, "dojox.gfx.svg");
+dojo.requireIf(dojo.isIE != 0, "dojox.gfx.vml");
+

Added: trunk/examples/typeface/root/static/dojo/dojox/resources/README.template
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/resources/README.template	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/resources/README.template	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,36 @@
+-------------------------------------------------------------------------------
+Project Name
+-------------------------------------------------------------------------------
+Version X.XXX
+Release date: MM/DD/YYYY
+-------------------------------------------------------------------------------
+Project state:
+prototype | expermental | beta | stable | production
+-------------------------------------------------------------------------------
+Project authors
+	Author one (author contact info)
+	Author two (author contact info)
+-------------------------------------------------------------------------------
+Project description
+
+Describe the point of the project here.
+-------------------------------------------------------------------------------
+Dependencies:
+
+List any dependencies here.
+-------------------------------------------------------------------------------
+Documentation
+
+-------------------------------------------------------------------------------
+Installation instructions
+
+Use this to explain in detail what a person needs to do in order to use this
+project.  Include URLs for grabbing source, URLs for any dependencies, etc.
+Also be sure to include any additional information, such as where to place
+CSS files, images, other media, etc.  The goal is that someone reading this
+file can follow your instructions and be using this project within minutes.
+-------------------------------------------------------------------------------
+Additional Notes
+
+Anything else you think is of interest (for example, object hierarchy) should
+be placed here.

Added: trunk/examples/typeface/root/static/dojo/dojox/rpc/yahoo.smd
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/rpc/yahoo.smd	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/rpc/yahoo.smd	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,293 @@
+{
+	"SMDVersion":".1",
+	"objectName":"yahoo",
+	"serviceType":"JSON-P",
+	"required": {
+		"appid": "dojotoolkit",
+		"output": "json"
+	},
+	"methods":[
+		//
+		// MAPS 
+		//
+		{
+			// http://developer.yahoo.com/maps/rest/V1/mapImage.html
+			"name":"mapImage",
+			"serviceURL": "http://api.local.yahoo.com/MapsService/V1/mapImage",
+			"parameters":[
+				{ "name":"street", "type":"STRING" },
+				{ "name":"city", "type":"STRING" },
+				{ "name":"zip", "type":"INTEGER" },
+				{ "name":"location", "type":"STRING" },
+				{ "name":"longitude", "type":"FLOAT" },
+				{ "name":"latitude", "type":"FLOAT" },
+				{ "name":"image_type", "type":"STRING" },
+				{ "name":"image_width", "type":"INTEGER" },
+				{ "name":"image_height", "type":"INTEGER" },
+				{ "name":"zoom", "type":"INTEGER" },
+				{ "name":"radius", "type":"INTEGER" }
+			]
+		},
+		{
+			// http://developer.yahoo.com/traffic/rest/V1/index.html
+			"name":"trafficData",
+			"serviceURL": "http://api.local.yahoo.com/MapsService/V1/trafficData",
+			"parameters":[
+				{ "name":"street", "type":"STRING" },
+				{ "name":"city", "type":"STRING" },
+				{ "name":"zip", "type":"INTEGER" },
+				{ "name":"location", "type":"STRING" },
+				{ "name":"longitude", "type":"FLOAT" },
+				{ "name":"latitude", "type":"FLOAT" },
+				{ "name":"severity", "type":"INTEGER" },
+				{ "name":"include_map", "type":"INTEGER" },
+				{ "name":"image_type", "type":"STRING" },
+				{ "name":"image_width", "type":"INTEGER" },
+				{ "name":"image_height", "type":"INTEGER" },
+				{ "name":"zoom", "type":"INTEGER" },
+				{ "name":"radius", "type":"INTEGER" }
+			]
+		},
+		/*
+			// Yahoo's geocoding service is f'd for JSON and Y! advises that it
+			// may not be returning
+		{
+			// http://developer.yahoo.com/maps/rest/V1/geocode.html
+			"name":"geocode",
+			"serviceURL": "http://api.local.yahoo.com/MapsService/V1/geocode",
+			"parameters":[
+				{ "name":"street", "type":"STRING" },
+				{ "name":"city", "type":"STRING" },
+				{ "name":"zip", "type":"INTEGER" },
+				{ "name":"location", "type":"STRING" }
+			]
+		},
+		*/
+		//
+		// LOCAL SEARCH
+		//
+		{
+			// http://developer.yahoo.com/search/local/V3/localSearch.html
+			"name":"localSearch",
+			"serviceURL": "http://api.local.yahoo.com/LocalSearchService/V3/localSearch",
+			"parameters":[
+				{ "name":"street", "type":"STRING" },
+				{ "name":"city", "type":"STRING" },
+				{ "name":"zip", "type":"INTEGER" },
+				{ "name":"location", "type":"STRING" },
+				{ "name":"listing_id", "type":"STRING" },
+				{ "name":"sort", "type":"STRING" }, // "relevence", "title", "distance", or "rating"
+				{ "name":"start", "type":"INTEGER" },
+				{ "name":"radius", "type":"FLOAT" },
+				{ "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
+				{ "name":"longitude", "type":"FLOAT" },
+				{ "name":"latitude", "type":"FLOAT" },
+				{ "name":"category", "type":"INTEGER" },
+				{ "name":"omit_category", "type":"INTEGER" },
+				{ "name":"minimum_rating", "type":"INTEGER" }
+			]
+		},
+		//
+		// WEB SEARCH
+		//
+		{
+			// http://developer.yahoo.com/search/web/V1/webSearch.html 
+			"name":"webSearch",
+			"serviceURL": "http://api.search.yahoo.com/WebSearchService/V1/webSearch",
+			"parameters":[
+				{ "name":"query", "type":"STRING" },
+				{ "name":"type", "type":"STRING" }, // defaults to "all"
+				{ "name":"region", "type":"STRING" }, // defaults to "us"
+				{ "name":"results", "type":"INTEGER" }, // defaults to 10
+				{ "name":"start", "type":"INTEGER" }, // defaults to 1
+				{ "name":"format", "type":"STRING" }, // defaults to "any", can be "html", "msword", "pdf", "ppt", "rst", "txt", or "xls"
+				{ "name":"adult_ok", "type":"INTEGER" }, // defaults to null
+				{ "name":"similar_ok", "type":"INTEGER" }, // defaults to null
+				{ "name":"language", "type":"STRING" }, // defaults to null
+				{ "name":"country", "type":"STRING" }, // defaults to null
+				{ "name":"site", "type":"STRING" }, // defaults to null
+				{ "name":"subscription", "type":"STRING" }, // defaults to null
+				{ "name":"license", "type":"STRING" } // defaults to "any"
+			]
+		},
+		{
+			// http://developer.yahoo.com/search/web/V1/spellingSuggestion.html
+			"name":"spellingSuggestion",
+			"serviceURL": "http://api.search.yahoo.com/WebSearchService/V1/spellingSuggestion",
+			"parameters":[ { "name":"query", "type":"STRING" } ]
+		},
+		{
+			// http://developer.yahoo.com/search/web/V1/relatedSuggestion.html
+			"name":"spellingSuggestion",
+			"serviceURL": "http://api.search.yahoo.com/WebSearchService/V1/relatedSuggestion",
+			"parameters":[
+				{ "name":"query", "type":"STRING" },
+				{ "name":"results", "type":"INTEGER" } // 1-50, defaults to 10
+			]
+		},
+		{
+			// http://developer.yahoo.com/search/content/V1/termExtraction.html
+			"name":"termExtraction",
+			"serviceURL": "http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction",
+			"parameters":[
+				{ "name":"query", "type":"STRING" },
+				{ "name":"context", "type":"STRING" },
+				{ "name":"results", "type":"INTEGER" } // 1-50, defaults to 10
+			]
+		},
+		{
+			// http://developer.yahoo.com/search/web/V1/contextSearch.html
+			"name":"contextSearch",
+			"serviceURL": "http://search.yahooapis.com/WebSearchService/V1/contextSearch",
+			"parameters":[
+				{ "name":"query", "type":"STRING" },
+				{ "name":"context", "type":"STRING" },
+				{ "name":"type", "type":"STRING" }, // defaults to "all"
+				{ "name":"results", "type":"INTEGER" }, // defaults to 10
+				{ "name":"start", "type":"INTEGER" }, // defaults to 1
+				{ "name":"format", "type":"STRING" }, // defaults to "any", can be "html", "msword", "pdf", "ppt", "rst", "txt", or "xls"
+				{ "name":"adult_ok", "type":"INTEGER" }, // defaults to null
+				{ "name":"similar_ok", "type":"INTEGER" }, // defaults to null
+				{ "name":"language", "type":"STRING" }, // defaults to null
+				{ "name":"country", "type":"STRING" }, // defaults to null
+				{ "name":"site", "type":"STRING" }, // defaults to null
+				{ "name":"license", "type":"STRING" } // defaults to "any", could be "cc_any", "cc_commercial", "cc_modifiable"
+			]
+		},
+		//
+		// IMAGE SEARCH
+		//
+		{
+			// http://developer.yahoo.com/search/image/V1/imageSearch.html
+			"name":"imageSearch",
+			"serviceURL": "http://api.search.yahoo.com/ImageSearchService/V1/imageSearch",
+			"parameters":[
+				{ "name":"query", "type":"STRING" },
+				{ "name":"type", "type":"STRING" }, // defaults to "all", can by "any" or "phrase"
+				{ "name":"results", "type":"INTEGER" }, // defaults to 10
+				{ "name":"start", "type":"INTEGER" }, // defaults to 1
+				{ "name":"format", "type":"STRING" }, // defaults to "any", can be "bmp", "gif", "jpeg", or "png"
+				{ "name":"adult_ok", "type":"INTEGER" }, // defaults to null
+				{ "name":"coloration", "type":"STRING" }, // "any", "color", or "bw"
+				{ "name":"site", "type":"STRING" } // defaults to null
+			]
+		},
+		//
+		// SITE EXPLORER
+		//
+		{
+			// http://developer.yahoo.com/search/siteexplorer/V1/inlinkData.html 
+			"name":"inlinkData",
+			"serviceURL": "http://api.search.yahoo.com/SiteExplorerService/V1/inlinkData",
+			"parameters":[
+				{ "name":"query", "type":"STRING" },
+				{ "name":"type", "type":"STRING" }, // defaults to "all", can by "any" or "phrase"
+				{ "name":"entire_site", "type":"INTEGER" }, // defaults to null
+				{ "name":"omit_inlinks", "type":"STRING" }, // "domain" or "subdomain", defaults to null
+				{ "name":"results", "type":"INTEGER" }, // defaults to 50
+				{ "name":"start", "type":"INTEGER" }, // defaults to 1
+				{ "name":"site", "type":"STRING" } // defaults to null
+			]
+		},
+		{
+			// http://developer.yahoo.com/search/siteexplorer/V1/pageData.html
+			"name":"pageData",
+			"serviceURL": "http://api.search.yahoo.com/SiteExplorerService/V1/pageData",
+			"parameters":[
+				{ "name":"query", "type":"STRING" },
+				{ "name":"type", "type":"STRING" }, // defaults to "all", can by "any" or "phrase"
+				{ "name":"domain_only", "type":"INTEGER" }, // defaults to null
+				{ "name":"results", "type":"INTEGER" }, // defaults to 50
+				{ "name":"start", "type":"INTEGER" }, // defaults to 1
+				{ "name":"site", "type":"STRING" } // defaults to null
+			]
+		},
+		//
+		// MUSIC SEARCH
+		//
+		{
+			// http://developer.yahoo.com/search/audio/V1/artistSearch.html
+			"name":"artistSearch",
+			"serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/artistSearch",
+			"parameters":[
+				{ "name":"artist", "type":"STRING" },
+				{ "name":"artistid", "type":"STRING" },
+				{ "name":"type", "type":"STRING" }, // "all", "any", or "phrase"
+				{ "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
+				{ "name":"start", "type":"INTEGER" } // defaults to 1
+			]
+		},
+		{
+			// http://developer.yahoo.com/search/audio/V1/albumSearch.html
+			"name":"albumSearch",
+			"serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/albumSearch",
+			"parameters":[
+				{ "name":"artist", "type":"STRING" },
+				{ "name":"artistid", "type":"STRING" },
+				{ "name":"album", "type":"STRING" },
+				{ "name":"type", "type":"STRING" }, // "all", "any", or "phrase"
+				{ "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
+				{ "name":"start", "type":"INTEGER" } // defaults to 1
+			]
+		},
+		{
+			// http://developer.yahoo.com/search/audio/V1/songSearch.html
+			"name":"songSearch",
+			"serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/songSearch",
+			"parameters":[
+				{ "name":"artist", "type":"STRING" },
+				{ "name":"artistid", "type":"STRING" },
+				{ "name":"album", "type":"STRING" },
+				{ "name":"albumid", "type":"STRING" },
+				{ "name":"song", "type":"STRING" },
+				{ "name":"songid", "type":"STRING" },
+				{ "name":"type", "type":"STRING" }, // "all", "any", or "phrase"
+				{ "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
+				{ "name":"start", "type":"INTEGER" } // defaults to 1
+			]
+		},
+		{
+			// http://developer.yahoo.com/search/audio/V1/songDownloadLocation.html
+			"name":"songDownloadLocation",
+			"serviceURL": "http://api.search.yahoo.com/AudioSearchService/V1/songDownloadLocation",
+			"parameters":[
+				{ "name":"songid", "type":"STRING" },
+				// "source" can contain:
+				//	audiolunchbox artistdirect buymusic dmusic
+				//	emusic epitonic garageband itunes yahoo
+				//	livedownloads mp34u msn musicmatch mapster passalong
+				//	rhapsody soundclick theweb
+				{ "name":"source", "type":"STRING" },
+				{ "name":"results", "type":"INTEGER" }, // 1-50, defaults to 10
+				{ "name":"start", "type":"INTEGER" } // defaults to 1
+			]
+		},
+		//
+		// NEWS SEARCH
+		//
+		{
+			// http://developer.yahoo.com/search/news/V1/newsSearch.html
+			"name":"newsSearch",
+			"serviceURL": "http://api.search.yahoo.com/NewsSearchService/V1/newsSearch",
+			"parameters":[
+				{ "name":"query", "type":"STRING" },
+				{ "name":"type", "type":"STRING" }, // defaults to "all"
+				{ "name":"results", "type":"INTEGER" }, // defaults to 10
+				{ "name":"start", "type":"INTEGER" }, // defaults to 1
+				{ "name":"sort", "type":"STRING" }, // "rank" or "date"
+				{ "name":"language", "type":"STRING" }, // defaults to null
+				{ "name":"site", "type":"STRING" } // defaults to null
+			]
+		}
+		/*
+		{
+			// 
+			"name":"",
+			"serviceURL": "",
+			"parameters":[
+				{ "name":"street", "type":"STRING" },
+			]
+		}
+		*/
+	]
+}

Added: trunk/examples/typeface/root/static/dojo/dojox/string/Builder.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/string/Builder.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/string/Builder.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,110 @@
+dojo.provide("dojox.string.Builder");
+
+(function(){
+	dojox.string.Builder = function(/*String?*/str){
+		// summary:
+		//		A fast buffer for creating large strings
+		// str: The initial string to seed the buffer with
+		this.b = dojo.isIE ? [] : "";
+		if(str){ this.append(str); }
+	};
+	
+	var m = {
+	 	append: function(){ 
+			// summary: Append all arguments to the end of the buffer
+			dojo.forEach(arguments, function(s){
+				if(dojo.isArrayLike(s)){ 
+					this.append.apply(this, s); 
+				}else{
+					if(!dojo.isString(s)){ s = String(s); } 
+					this._append(s);
+					this.length += s.length;
+				}
+			}, this);
+			return this; // dojox.string.Builder
+		},
+		concat: function(){
+			return this.append.apply(this, arguments);
+		},
+		clear: function(){
+			// summary: Remove all characters from the buffer
+			this._clear();
+			this.length = 0;
+			return this;
+		},
+		replace: function(oldStr,newStr){
+			// summary: Replace instances of one string with another in the buffer
+			var s = this.toString();
+			s = s.replace(oldStr,newStr);
+			this._reset(s);
+			this.length = s.length;
+			return this;
+		},
+		remove: function(start, len){
+			// summary: Remove len characters starting at index start
+			if(len == 0){ return this; }
+			var s = this.toString();
+			this.clear();
+			if(start > 0){
+				this.append(s.substring(0, start));
+			}
+			if(start+len < s.length){
+				this.append(s.substring(start+len));
+			}
+			return this;
+		},
+		insert: function(index, str){
+			// summary: Insert string str starting at index
+			var s = this.toString();
+			this.clear();
+			if(index == 0){
+				this.append(str);
+				this.append(s);
+				return this;
+			}else{
+				this.append(s.substring(0, index));
+				this.append(str);
+				this.append(s.substring(index));
+			}
+			return this;
+		}
+		
+	}; // will hold methods for Builder
+	
+	
+	if(dojo.isIE){
+		dojo.mixin(m, {
+			toString: function(){ 
+				// Summary: Get the buffer as a string
+				return this.b.join(""); 
+			},
+			_append: function(s){
+				this.b.push(s);
+			},
+			_clear: function(){
+				this.b = [];
+			},
+			_reset: function(s){
+				this.b = [ s ];
+			}
+		});
+	}else{
+		dojo.mixin(m, {
+			toString: function(){ 
+				// Summary: Get the buffer as a string
+				return this.b; 
+			},
+			_append: function(s){
+				this.b += s;
+			},
+			_clear: function(){
+				this.b = "";
+			},
+			_reset: function(s){
+				this.b = s;
+			}
+		});
+	}
+	
+	dojo.extend(dojox.string.Builder, m);
+})();

Added: trunk/examples/typeface/root/static/dojo/dojox/string/README
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/string/README	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/string/README	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,36 @@
+-------------------------------------------------------------------------------
+DojoX String Utilities
+-------------------------------------------------------------------------------
+Version 0.9
+Release date: 05/08/2007
+-------------------------------------------------------------------------------
+Project state:
+stable
+-------------------------------------------------------------------------------
+Project authors
+	Ben Lowery
+	Tom Trenka (ttrenka at gmail.com)
+-------------------------------------------------------------------------------
+Project description
+
+The DojoX String utilties project is a placeholder for miscellaneous string
+utility functions.  At the time of writing, only the Builder object has been
+added; but we anticipate other string utilities may end up living here as well.
+-------------------------------------------------------------------------------
+Dependencies:
+
+Dojo Core (package loader).
+-------------------------------------------------------------------------------
+Documentation
+
+See the Dojo Toolkit API docs (http://dojotookit.org/api), dojo.string.Builder.
+-------------------------------------------------------------------------------
+Installation instructions
+
+Grab the following from the Dojo SVN Repository:
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/string/*
+
+Install into the following directory structure:
+/dojox/string/
+
+...which should be at the same level as your Dojo checkout.

Added: trunk/examples/typeface/root/static/dojo/dojox/string/tests/Builder.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/string/tests/Builder.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/string/tests/Builder.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,87 @@
+dojo.provide("dojox.string.tests.Builder");
+
+dojo.require("dojox.string.Builder");
+
+tests.register("dojox.string.tests.Builder", [
+	{
+		name: "Append",
+		runTest: function(t) {
+			var b = new dojox.string.Builder();
+			b.append("foo");
+			t.is("foo", b.toString());
+			b.append("bar", "baz");
+			t.is("foobarbaz", b.toString());
+			b.append("ben").append("zoo");
+			t.is("foobarbazbenzoo", b.toString());
+			b.append(5);
+			t.is("foobarbazbenzoo5", b.toString());
+		}
+	},
+	{
+		name: "Construction",
+		runTest: function(t){
+			var b = new dojox.string.Builder();
+			t.is("", b.toString());
+			b = new dojox.string.Builder("foo");
+			t.is("foo", b.toString()); 
+		}
+	},
+	{
+		name: "Replace",
+		runTest: function(t){
+			var b = new dojox.string.Builder("foobar");
+			t.is("foobar", b.toString());
+			b.replace("foo", "baz");
+			t.is("bazbar", b.toString());
+			b.replace("baz", "ben");
+			t.is("benbar", b.toString());
+			b.replace("foo", "moo");
+			t.is("benbar", b.toString());
+			b.replace("enba", "o");
+			t.is("bor", b.toString());
+			b.replace("o", "a").replace("b", "f");
+			t.is("far", b.toString());
+		}
+	},
+	{
+		name: "Insert",
+		runTest: function(t){
+			var b = new dojox.string.Builder();
+			//insert at 0 is prepend
+			b.insert(0, "foo");
+			t.is("foo", b.toString());
+			b.insert(0, "more");
+			t.is("morefoo", b.toString());
+			
+			//insert positions stuff after the 4th character
+			b.insert(4, "fun");
+			t.is("morefunfoo", b.toString());
+			
+			//insert at len of string is push_back
+			b.insert(10, "awesome");
+			t.is("morefunfooawesome", b.toString());
+			
+			//insert past len of string is push_back
+			b.insert(100, "bad");
+			t.is("morefunfooawesomebad", b.toString());
+			
+			b = new dojox.string.Builder();
+			b.insert(0, "foo").insert(3, "bar").insert(3, "zoo");
+			t.is("foozoobar", b.toString());
+		}
+	},
+	{
+		name: "Remove",
+		runTest: function(t){
+			var b = new dojox.string.Builder("foobarbaz");
+			b.remove(3,3);
+			t.is("foobaz", b.toString());
+			b.remove(0,3);
+			t.is("baz", b.toString());
+			b.remove(2, 100);
+			t.is("ba", b.toString());
+			b.remove(0,0);
+			t.is("ba", b.toString())
+		}
+	}
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/string/tests/runTests.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/string/tests/runTests.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/string/tests/runTests.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+    <head>
+    <title>Dojox Unit Test Runner</title>
+    <meta http-equiv="REFRESH" content="0;url=../../../util/doh/runner.html?testModule=dojox.string.tests.string"></HEAD>
+    <BODY>
+        Redirecting to D.O.H runner.
+    </BODY>
+</HTML> 

Added: trunk/examples/typeface/root/static/dojo/dojox/string/tests/string.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/string/tests/string.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/string/tests/string.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+dojo.provide("dojox.string.tests.string");
+
+try{
+	dojo.require("dojox.string.tests.Builder");
+} catch(e){ }

Added: trunk/examples/typeface/root/static/dojo/dojox/tests/date/posix.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/tests/date/posix.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/tests/date/posix.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,233 @@
+dojo.provide("dojox.tests.date.posix");
+
+dojo.require("dojox.date.posix");
+
+tests.register("dojox.tests.date.posix", 
+	[
+	
+	//FIXME: set up by loading 'en' resources
+function test_date_strftime(t){
+	var date = new Date(2006, 7, 11, 0, 55, 12, 3456);
+	t.is("06/08/11", dojox.date.posix.strftime(date, "%y/%m/%d"));
+
+	var dt = null; // Date to test
+	var fmt = ''; // Format to test
+	var res = ''; // Expected result
+	
+	dt = new Date(2006, 0, 1, 18, 23);
+	fmt = '%a';
+	res = 'Sun';
+	t.is(res, dojox.date.posix.strftime(dt, fmt, 'en'));
+	
+	fmt = '%A';
+	res = 'Sunday';
+	t.is(res, dojox.date.posix.strftime(dt, fmt, 'en'));
+	
+	fmt = '%b';
+	res = 'Jan';
+	t.is(res, dojox.date.posix.strftime(dt, fmt, 'en'));
+	
+	fmt = '%B';
+	res = 'January';
+	t.is(res, dojox.date.posix.strftime(dt, fmt, 'en'));
+
+	fmt = '%c';
+	res = 'Sunday, January 1, 2006 6:23:00 PM';
+	t.is(res, dojox.date.posix.strftime(dt, fmt).substring(0, res.length));
+	
+	fmt = '%C';
+	res = '20';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%d';
+	res = '01';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%D';
+	res = '01/01/06';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%e';
+	res = ' 1';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%h';
+	res = 'Jan';
+	t.is(res, dojox.date.posix.strftime(dt, fmt, 'en'));
+	
+	fmt = '%H';
+	res = '18';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%I';
+	res = '06';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%j';
+	res = '001';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%k';
+	res = '18';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%l';
+	res = ' 6';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%m';
+	res = '01';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%M';
+	res = '23';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%p';
+	res = 'PM';
+	t.is(res, dojox.date.posix.strftime(dt, fmt, 'en'));
+	
+	fmt = '%r';
+	res = '06:23:00 PM';
+	t.is(res, dojox.date.posix.strftime(dt, fmt, 'en'));
+	
+	fmt = '%R';
+	res = '18:23';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%S';
+	res = '00';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%T';
+	res = '18:23:00';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%u';
+	res = '7';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%w';
+	res = '0';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+
+	fmt = '%x';
+	res = 'Sunday, January 1, 2006';
+	t.is(res, dojox.date.posix.strftime(dt, fmt, 'en'));
+
+	fmt = '%X';
+	res = '6:23:00 PM';
+	t.is(res, dojox.date.posix.strftime(dt, fmt, 'en').substring(0,res.length));
+	
+	fmt = '%y';
+	res = '06';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%Y';
+	res = '2006';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+	
+	fmt = '%%';
+	res = '%';
+	t.is(res, dojox.date.posix.strftime(dt, fmt));
+},
+function test_date_getStartOfWeek(t){
+	var weekStart;
+	
+	// Monday
+	var date = new Date(2007, 0, 1);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 1), 1);
+	t.is(date, weekStart);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 2), 1);
+	t.is(date, weekStart);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 3), 1);
+	t.is(date, weekStart);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 4), 1);
+	t.is(date, weekStart);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 5), 1);
+	t.is(date, weekStart);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 6), 1);
+	t.is(date, weekStart);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 7), 1);
+	t.is(date, weekStart);
+
+	// Sunday
+	date = new Date(2007, 0, 7);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 7), 0);
+	t.is(date, weekStart);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 8), 0);
+	t.is(date, weekStart);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 9), 0);
+	t.is(date, weekStart);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 10), 0);
+	t.is(date, weekStart);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 11), 0);
+	t.is(date, weekStart);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 12), 0);
+	t.is(date, weekStart);
+	weekStart = dojox.date.posix.getStartOfWeek(new Date(2007, 0, 13), 0);
+	t.is(date, weekStart);
+},
+
+function test_date_setIsoWeekOfYear(t){
+	var date = new Date(2006,10,10);
+	var result = dojox.date.posix.setIsoWeekOfYear(date, 1);
+	t.is(new Date(2006,0,6), result);
+	result = dojox.date.posix.setIsoWeekOfYear(date, 10);
+	result = dojox.date.posix.setIsoWeekOfYear(date, 2);
+	t.is(new Date(2006,0,13), result);
+	result = dojox.date.posix.setIsoWeekOfYear(date, 10);
+	t.is(new Date(2006,2,10), result);
+	result = dojox.date.posix.setIsoWeekOfYear(date, 52);
+	t.is(new Date(2006,11,29), result);
+	var result = dojox.date.posix.setIsoWeekOfYear(date, -1);
+	t.is(new Date(2006,11,29), result);
+	var result = dojox.date.posix.setIsoWeekOfYear(date, -2);
+	t.is(new Date(2006,11,22), result);
+	var result = dojox.date.posix.setIsoWeekOfYear(date, -10);
+	t.is(new Date(2006,9,27), result);
+	
+	date = new Date(2004,10,10);
+	result = dojox.date.posix.setIsoWeekOfYear(date, 1);
+	t.is(new Date(2003,11,31), result);
+	result = dojox.date.posix.setIsoWeekOfYear(date, 2);
+	t.is(new Date(2004,0,7), result);
+	result = dojox.date.posix.setIsoWeekOfYear(date, -1);
+	t.is(new Date(2004,11,29), result);
+},
+
+function test_date_getIsoWeekOfYear(t){
+	var week = dojox.date.posix.getIsoWeekOfYear(new Date(2006,0,1));
+	t.is(52, week);
+	week = dojox.date.posix.getIsoWeekOfYear(new Date(2006,0,4));
+	t.is(1, week);
+	week = dojox.date.posix.getIsoWeekOfYear(new Date(2006,11,31));
+	t.is(52, week);
+	week = dojox.date.posix.getIsoWeekOfYear(new Date(2007,0,1));
+	t.is(1, week);
+	week = dojox.date.posix.getIsoWeekOfYear(new Date(2007,11,31));
+	t.is(53, week);
+	week = dojox.date.posix.getIsoWeekOfYear(new Date(2008,0,1));
+	t.is(1, week);
+	week = dojox.date.posix.getIsoWeekOfYear(new Date(2007,11,31));
+	t.is(53, week);
+},
+
+function test_date_getIsoWeeksInYear(t){
+	// 44 long years in a 400 year cycle.
+	var longYears = [4, 9, 15, 20, 26, 32, 37, 43, 48, 54, 60, 65, 71, 76, 82, 
+		88,	93, 99, 105, 111, 116, 122, 128, 133, 139, 144, 150, 156, 161, 167,
+		172, 178, 184, 189, 195, 201, 207, 212, 218, 224, 229, 235, 240, 246, 
+		252, 257, 263, 268, 274, 280, 285, 291, 296, 303, 308, 314, 320, 325,
+		331, 336, 342, 348, 353, 359, 364, 370, 376, 381, 387, 392, 398];
+
+	var i, j, weeks, result;
+	for(i=0; i < 400; i++) {
+		weeks = 52;
+		if(i == longYears[0]) { weeks = 53; longYears.shift(); }
+		result = dojox.date.posix.getIsoWeeksInYear(new Date(2000 + i, 0, 1));
+		t.is(/*weeks +" weeks in "+ (2000+i), */weeks, result);
+	}
+}
+	]
+);

Added: trunk/examples/typeface/root/static/dojo/dojox/tests/module.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/tests/module.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/tests/module.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,8 @@
+dojo.provide("dojox.tests.module");
+
+try{
+	dojo.require("dojox.tests.date.posix");
+}catch(e){
+	doh.debug(e);
+}
+

Added: trunk/examples/typeface/root/static/dojo/dojox/tests/runTests.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/tests/runTests.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/tests/runTests.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+    <head>
+    <title>Dojox Unit Test Runner</title>
+    <meta http-equiv="REFRESH" content="0;url=../../util/doh/runner.html?testModule=dojox.tests.module"></HEAD>
+    <BODY>
+        Redirecting to D.O.H runner.
+    </BODY>
+</HTML> 

Added: trunk/examples/typeface/root/static/dojo/dojox/tests/widget/test_Toaster.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/tests/widget/test_Toaster.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/tests/widget/test_Toaster.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,147 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+        "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+	<title>Toaster Widget Dojo Tests</title>
+	<style type="text/css">
+		@import "../../../dojo/resources/dojo.css";
+		@import "../../../dijit/themes/tundra/tundra.css";
+	</style>
+
+	<script type="text/javascript" src="../../../dojo/dojo.js"
+		djConfig="isDebug: true, debugAtAllCosts: true"></script>
+
+	<script type="text/javascript">
+		dojo.require("dojox.widget.Toaster");
+		dojo.require("dijit.util.parser");	// scan page for widgets and instantiate them
+
+		var toast = null;
+		function showTestMessage(){
+			dojo.publish("testMessageTopic", 
+				[ "This is a message! It's kind of long to show message wrapping."]
+			);
+		}
+		function showAnotherMessage(){
+			dojo.publish("testMessageTopic", 
+				[
+					{
+						message: "This is another message!", 
+						type: "warning", 
+						duration: 500
+					}
+				]
+			);
+		}
+		function showYetAnotherMessage(){
+			dojo.publish("testMessageTopic", 
+				[
+					{ message: "This is yet another message!" }
+				]
+			);
+		}
+
+		dojo.addOnLoad(function(){
+			toast = dijit.byId("toast");
+		});
+	</script>
+</head>
+<body>
+	<div dojoType="dojox.widget.Toaster" id="toast" 
+		positionDirection="br-left" duration="0" 
+		messageTopic="testMessageTopic"></div>
+
+	<div dojoType="dojox.widget.Toaster" id="toast2" 
+		separator="&lt;hr&gt;" positionDirection="bl-up" 
+		messageTopic="testMessageTopic"></div>
+
+	<button type="submit" 
+		onclick="showTestMessage();">Click to show message</button>
+	<button type="submit" 
+		onclick="showAnotherMessage();">Click to show another message</button>
+	<button type="submit" 
+		onclick="showYetAnotherMessage();">Click to show yet another message</button>
+	<div style="color: #FF0000;">
+		When you click any of the buttons above, the bottom right hand message will
+		stay on the screen until you acknowledge it by clicking inside the message
+		box. If you click one of the message buttons while a message is still
+		displayed in the bottom right corner it should append the new message below
+		the old one with a separator between them.
+	</div>
+	<p>
+		Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper
+		sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum
+		lacus. Etiam consequat scelerisque quam. Nulla facilisi.  Maecenas luctus
+		venenatis nulla. In sit amet dui non mi semper iaculis.  Sed molestie
+		tortor at ipsum. Morbi dictum rutrum magna. Sed vitae risus.
+	</p>
+	<p>
+		Aliquam vitae enim. Duis scelerisque metus auctor est venenatis imperdiet.
+		Fusce dignissim porta augue. Nulla vestibulum. Integer lorem nunc,
+		ullamcorper a, commodo ac, malesuada sed, dolor. Aenean id mi in massa
+		bibendum suscipit. Integer eros. Nullam suscipit mauris. In pellentesque.
+		Mauris ipsum est, pharetra semper, pharetra in, viverra quis, tellus. Etiam
+		purus. Quisque egestas, tortor ac cursus lacinia, felis leo adipiscing
+		nisi, et rhoncus elit dolor eget eros. Fusce ut quam. Suspendisse eleifend
+		leo vitae ligula. Nulla facilisi. Nulla rutrum, erat vitae lacinia dictum,
+		pede purus imperdiet lacus, ut semper velit ante id metus. Praesent massa
+		dolor, porttitor sed, pulvinar in, consequat ut, leo. Nullam nec est.
+		Aenean id risus blandit tortor pharetra congue. Suspendisse pulvinar.
+	</p>
+	<p>
+		Vestibulum convallis eros ac justo. Proin dolor. Etiam aliquam. Nam ornare
+		elit vel augue. Suspendisse potenti. Etiam sed mauris eu neque nonummy
+		mollis. Vestibulum vel purus ac pede semper accumsan. Vivamus lobortis, sem
+		vitae nonummy lacinia, nisl est gravida magna, non cursus est quam sed
+		urna. Phasellus adipiscing justo in ipsum. Duis sagittis dolor sit amet
+		magna. Suspendisse suscipit, neque eu dictum auctor, nisi augue tincidunt
+		arcu, non lacinia magna purus nec magna. Praesent pretium sollicitudin
+		sapien. Suspendisse imperdiet. Class aptent taciti sociosqu ad litora
+		torquent per conubia nostra, per inceptos hymenaeos.
+	</p>
+	<p>
+		Mauris pharetra lorem sit amet sapien. Nulla libero metus, tristique et,
+		dignissim a, tempus et, metus. Ut libero. Vivamus tempus purus vel ipsum.
+		Quisque mauris urna, vestibulum commodo, rutrum vitae, ultrices vitae,
+		nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra,
+		per inceptos hymenaeos. Nulla id erat sit amet odio luctus eleifend. Proin
+		massa libero, ultricies non, tincidunt a, vestibulum non, tellus. Nunc nunc
+		purus, lobortis a, pulvinar at, egestas a, mi. Cras adipiscing velit a
+		mauris. Morbi felis. Etiam at felis. Cras eget eros et justo mattis
+		pulvinar. Nullam at justo id risus porttitor dignissim. Vestibulum sed
+		velit vel metus tincidunt tempus. Nunc euismod nisl id dolor tristique
+		tincidunt. Nullam placerat turpis sed odio. Curabitur in est id nibh tempus
+		ultrices. Aliquam consectetuer dapibus eros. Aliquam nisl.
+	</p>
+	<p>
+		Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper
+		sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum
+		lacus. Etiam consequat scelerisque quam. Nulla facilisi.  Maecenas luctus
+		venenatis nulla. In sit amet dui non mi semper iaculis.  Sed molestie
+		tortor at ipsum. Morbi dictum rutrum magna. Sed vitae risus.
+	</p>
+	<p>
+		Aliquam vitae enim. Duis scelerisque metus auctor est venenatis imperdiet.
+		Fusce dignissim porta augue. Nulla vestibulum. Integer lorem nunc,
+		ullamcorper a, commodo ac, malesuada sed, dolor. Aenean id mi in massa
+		bibendum suscipit. Integer eros. Nullam suscipit mauris. In pellentesque.
+		Mauris ipsum est, pharetra semper, pharetra in, viverra quis, tellus. Etiam
+		purus. Quisque egestas, tortor ac cursus lacinia, felis leo adipiscing
+		nisi, et rhoncus elit dolor eget eros. Fusce ut quam. Suspendisse eleifend
+		leo vitae ligula. Nulla facilisi. Nulla rutrum, erat vitae lacinia dictum,
+		pede purus imperdiet lacus, ut semper velit ante id metus. Praesent massa
+		dolor, porttitor sed, pulvinar in, consequat ut, leo. Nullam nec est.
+		Aenean id risus blandit tortor pharetra congue. Suspendisse pulvinar.
+	</p>
+	<p>
+		Vestibulum convallis eros ac justo. Proin dolor. Etiam aliquam. Nam ornare
+		elit vel augue. Suspendisse potenti. Etiam sed mauris eu neque nonummy
+		mollis. Vestibulum vel purus ac pede semper accumsan. Vivamus lobortis, sem
+		vitae nonummy lacinia, nisl est gravida magna, non cursus est quam sed
+		urna. Phasellus adipiscing justo in ipsum. Duis sagittis dolor sit amet
+		magna. Suspendisse suscipit, neque eu dictum auctor, nisi augue tincidunt
+		arcu, non lacinia magna purus nec magna. Praesent pretium sollicitudin
+		sapien. Suspendisse imperdiet. Class aptent taciti sociosqu ad litora
+		torquent per conubia nostra, per inceptos hymenaeos.
+	</p>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/widget/Toaster.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/widget/Toaster.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/widget/Toaster.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,255 @@
+dojo.provide("dojox.widget.Toaster");
+
+dojo.require("dojo.fx");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.TemplatedWidget");
+dojo.require("dijit.util.BackgroundIframe");
+dojo.require("dijit.util.place");
+
+// This is mostly taken from Jesse Kuhnert's MessageNotifier.
+// Modified by Bryan Forbes to support topics and a variable delay.
+// Modified by Karl Tiedt to support 0 duration messages that require user interaction and message stacking
+
+dojo.declare(
+	"dojox.widget.Toaster",
+	[dijit.base.Widget, dijit.base.TemplatedWidget],
+	null,
+	{
+		// summary
+		//		Message that slides in from the corner of the screen, used for notifications
+		//		like "new email".
+		templateString: '<div dojoAttachPoint="clipNode"><div dojoAttachPoint="containerNode" dojoAttachEvent="onclick:onSelect"><div dojoAttachPoint="contentNode"></div></div></div>',
+
+		// messageTopic: String
+		//		Name of topic; anything published to this topic will be displayed as a message.
+		//		Message format is either String or an object like
+		//		{message: "hello word", type: "error", duration: 500}
+		messageTopic: "",
+		
+		// messageTypes: Enumeration
+		//		Possible message types.
+		messageTypes: {
+			MESSAGE: "message",
+			WARNING: "warning",
+			ERROR: "error",
+			FATAL: "fatal"
+		},
+
+		// defaultType: String
+		//		If message type isn't specified (see "messageTopic" parameter),
+		//		then display message as this type.
+		//		Possible values in messageTypes enumeration ("message", "warning", "error", "fatal")
+		defaultType: "message",
+
+		// positionDirection: String
+		//		Position from which message slides into screen, one of
+		//		["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right"]
+		positionDirection: "br-up",
+		
+		// positionDirectionTypes: Array
+		//		Possible values for positionDirection parameter
+		positionDirectionTypes: ["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right"],
+
+		// duration: Integer
+		//		Number of milliseconds to show message
+		duration: "2000",
+
+		//separator: String
+		//		String used to separate messages if consecutive calls are made to setContent before previous messages go away
+		separator: "<hr></hr>",
+
+		postCreate: function(){
+			dojox.widget.Toaster.superclass.postCreate.apply(this);
+			this.hide();
+
+			this.clipNode.className = "dijitToasterClip";
+			this.containerNode.className += " dijitToasterContainer";
+			this.contentNode.className = "dijitToasterContent";
+			if(this.messageTopic){
+				dojo.subscribe(this.messageTopic, this, "_handleMessage");
+			}
+		},
+
+		_handleMessage: function(/*String|Object*/message){
+			if(dojo.isString(message)){
+				this.setContent(message);
+			}else{
+				this.setContent(message.message, message.type, message.duration);
+			}
+		},
+
+		setContent: function(/*String*/message, /*String*/messageType, /*int?*/duration){
+			// summary
+			//		sets and displays the given message and show duration
+			// message:
+			//		the message
+			// messageType:
+			//		type of message; possible values in messageTypes enumeration ("message", "warning", "error", "fatal")
+			// duration:
+			//		duration in milliseconds to display message before removing it. Widget has default value.
+			duration = duration||this.duration;
+			// sync animations so there are no ghosted fades and such
+			if(this.slideAnim){
+				if(this.slideAnim.status() != "playing"){
+					this.slideAnim.stop();
+				}
+				if(this.slideAnim.status() == "playing" || (this.fadeAnim && this.fadeAnim.status() == "playing")){
+					setTimeout(dojo.hitch(this, function(){
+						this.setContent(message, messageType);
+					}), 50);
+					return;
+				}
+			}
+
+			var capitalize = function(word){
+				return word.substring(0,1).toUpperCase() + word.substring(1);
+			};
+
+			// determine type of content and apply appropriately
+			for(var type in this.messageTypes){
+				dojo.removeClass(this.containerNode, "dijitToaster" + capitalize(this.messageTypes[type]));
+			}
+
+			dojo.style(this.containerNode, "opacity", 1);
+
+			if(message && this.isVisible){
+				message = this.contentNode.innerHTML + this.separator + message;
+			}
+			this.contentNode.innerHTML = message;
+
+			dojo.addClass(this.containerNode, "dijitToaster" + capitalize(messageType || this.defaultType));
+
+			// now do funky animation of widget appearing from
+			// bottom right of page and up
+			this.show();
+			var nodeSize = dojo.marginBox(this.containerNode);
+			
+			if(this.isVisible){
+				this._placeClip();
+			}else{
+				var style = this.containerNode.style;
+				var pd = this.positionDirection;
+				// sets up initial position of container node and slide-out direction
+				if(pd.indexOf("-up") >= 0){
+					style.left=0+"px";
+					style.top=nodeSize.h + 10 + "px";
+				}else if(pd.indexOf("-left") >= 0){
+					style.left=nodeSize.w + 10 +"px";
+					style.top=0+"px";
+				}else if(pd.indexOf("-right") >= 0){
+					style.left = 0 - nodeSize.w - 10 + "px";
+					style.top = 0+"px";
+				}else if(pd.indexOf("-down") >= 0){
+					style.left = 0+"px";
+					style.top = 0 - nodeSize.h - 10 + "px";
+				}else{
+					throw new Error(this.id + ".positionDirection is an invalid value: " + pd);
+				}
+
+				this.slideAnim = dojo.fx.slideTo({
+					node: this.containerNode,
+					top: 0, left: 0,
+					duration: 450});
+				dojo.connect(this.slideAnim, "onEnd", this, function(nodes, anim){
+						//we build the fadeAnim here so we dont have to duplicate it later
+						// can't do a fadeHide because we're fading the
+						// inner node rather than the clipping node
+						this.fadeAnim = dojo.fadeOut({
+							node: this.containerNode,
+							duration: 1000});
+						dojo.connect(this.fadeAnim, "onEnd", this, function(evt){
+								this.isVisible = false;
+								this.hide();
+							});
+						//if duration == 0 we keep the message displayed until clicked
+						//TODO: fix so that if a duration > 0 is displayed when a duration==0 is appended to it, the fadeOut is canceled
+						if(duration>0){
+							setTimeout(dojo.hitch(this, function(evt){
+								// we must hide the iframe in order to fade
+								// TODO: figure out how to fade with a BackgroundIframe
+								if(this.bgIframe){
+									this.bgIframe.hide();
+								}
+								this.fadeAnim.play();
+							}), duration);
+						}else{
+							dojo.connect(
+								this,
+								'onSelect',
+								this,
+								function(evt){
+									this.fadeAnim.play();
+								});
+						}
+						this.isVisible = true;
+					});
+				this.slideAnim.play();
+			}
+		},
+
+		_placeClip: function(){
+			var scroll = dijit.util.getScroll();
+			var view = dijit.util.getViewport();
+
+			var nodeSize = dojo.marginBox(this.containerNode);
+
+			var style = this.clipNode.style;
+			// sets up the size of the clipping node
+			style.height = nodeSize.h+"px";
+			style.width = nodeSize.w+"px";
+
+			// sets up the position of the clipping node
+			var pd = this.positionDirection;
+			if(pd.match(/^t/)){
+				style.top = scroll.top+"px";
+			}else if(pd.match(/^b/)){
+				style.top = (view.h - nodeSize.h - 2 + scroll.top)+"px";
+			}
+			if(pd.match(/^[tb]r-/)){
+				style.left = (view.w - nodeSize.w - 1 - scroll.left)+"px";
+			}else if(pd.match(/^[tb]l-/)){
+				style.left = 0 + "px";
+			}
+
+			style.clip = "rect(0px, " + nodeSize.w + "px, " + nodeSize.h + "px, 0px)";
+			if(dojo.isIE){
+				if(!this.bgIframe){
+					this.bgIframe = new dijit.util.BackgroundIframe(this.clipNode);
+					this.bgIframe.setZIndex(this.clipNode);
+				}
+				this.bgIframe.onResized();
+				this.bgIframe.show();
+			}
+		},
+
+		onSelect: function(/*Event*/e){
+			// summary: callback for when user clicks the message
+		},
+
+		show: function(){
+			// summary: show the Toaster
+			dojo.style(this.containerNode, 'display', '');
+
+			this._placeClip();
+
+			if(!this._scrollConnected){
+				this._scrollConnected = dojo.connect(window, "onscroll", this, this._placeClip);
+			}
+		},
+
+		hide: function(){
+			// summary: hide the Toaster
+
+			//Q: ALP: I didn't port all the toggler stuff from d.w.HtmlWidget.  Is it needed? Ditto for show.
+			dojo.style(this.containerNode, 'display', 'none');
+
+			if(this._scrollConnected){
+				dojo.disconnect(this._scrollConnected);
+				this._scrollConnected = false;
+			}
+
+			dojo.style(this.containerNode, "opacity", 1);
+		}
+	}
+);

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/CompositeWire.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/CompositeWire.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/CompositeWire.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,99 @@
+dojo.provide("dojox.wire.CompositeWire");
+
+dojo.require("dojox.wire._base");
+dojo.require("dojox.wire.Wire");
+
+dojo.declare("dojox.wire.CompositeWire",
+	dojox.wire.Wire,
+	function(/*Object*/args){
+		//	summary:
+		//		Initialize properties
+		//	description:
+		//		If object properties or array elements specified in 'children'
+		//		property are not Wires, Wires are created from them as
+		//		arguments, with 'parent' property set to this Wire instance.
+		//	args:
+		//		Arguments to initialize properties
+		//		children:
+		//			An object or array containing child Wires
+		this._initializeChildren(this.children);
+	}, {
+	//	summary:
+	//		A Wire for composite values in object or array
+	//	description:
+	//		This class has multiple child Wires for object properties or array
+	//		elements.
+	//		When an object with Wires is specified to 'children' property, they
+	//		are used to get or set an object with property values.
+	//		When an array of Wiares is specified to 'children' property, they
+	//		are used to get or set an array with element values.
+	_wireClass: "dojox.wire.CompositeWire",
+
+	_getValue: function(/*Object||Array*/object){
+		//	summary:
+		//		Return an object with property values or an array with element
+		//		values
+		//	description:
+		//		This method calls getValue() method of the child Wires with
+		//		'object' argument and returns an object with the values as
+		//		properties or an arary of the values as elements.
+		//	object:
+		//		A root object
+		//	returns:
+		//		An object or array with values
+		if(!object || !this.children){
+			return object; //Object||Array
+		}
+
+		var value = (dojo.isArray(this.children) ? [] : {}); // array or object
+		for(var c in this.children){
+			value[c] = this.children[c].getValue(object);
+		}
+		return value;//Object||Array
+	},
+
+	_setValue: function(/*Object||Array*/object, /*Object||Array*/value){
+		//	summary:
+		//		Set an object properties or an array elements to an object
+		//	desription:
+		//		This method calls setValues() method of the child Wires with
+		//		a corresponding property or element in 'value' argument and
+		//		'object' argument.
+		//	object:
+		//		A root object
+		//	value:
+		//		An object or array with values to set
+		//	returns:
+		//		'object'
+		if(!object || !this.children){
+			return object; //Object||Array
+		}
+
+		for(var c in this.children){
+			this.children[c].setValue(value[c], object);
+		}
+		return object; //Object||Array
+	},
+
+	_initializeChildren: function(/*Object||Array*/children){
+		//	summary:
+		//		Initialize child Wires
+		//	description:
+		//		If object properties or array elements specified in 'children'
+		//		argument are not Wires, Wires are created from them as
+		//		arguments, with 'parent' property set to this Wire instance.
+		//	children:
+		//		An object or array containing child Wires
+		if(!children){
+			return; //undefined
+		}
+
+		for(var c in children){
+			var child = children[c];
+			child.parent = this;
+			if(!dojox.wire.isWire(child)){
+				children[c] = dojox.wire.create(child);
+			}
+		}
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/DataWire.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/DataWire.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/DataWire.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,175 @@
+dojo.provide("dojox.wire.DataWire");
+
+dojo.require("dojox.wire.Wire");
+
+dojo.declare("dojox.wire.DataWire",
+	dojox.wire.Wire,
+	function(/*Object*/args){
+		//	summary:
+		//		Initialize properties
+		//	description:
+		//		If 'dataStore' property is not specified, but 'parent' property
+		//		is specified, 'dataStore' property is copied from the parent.
+		//	args:
+		//		Arguments to initialize properties
+		//		dataStore:
+		//			A data store
+		//		attribute:
+		//			A dotted notation to a descendant attribute
+		if(!this.dataStore && this.parent){
+			this.dataStore = this.parent.dataStore;
+		}
+	}, {
+	//	summary:
+	//		A Wire for item attributes of data stores
+	//	description:
+	//		This class accesses item attributes of data stores with a dotted
+	//		notation of attribute names specified to 'attribute' property,
+	//		using data APIs of a data store specified to 'dataStore' property.
+	//		The root object for this class must be an item of the data store.
+	//		Intermediate attribute names in the dotted notation specify
+	//		attributes for child items, which are used for repeated calls to
+	//		data APIs until reached to a descendant attribute.
+	//		Attribute names may have an array index, such as "a[0]", to
+	//		identify an array element of the attribute value.
+	_wireClass: "dojox.wire.DataWire",
+
+	_getValue: function(/*Object*/object){
+		//	summary:
+		//		Return an attribute value of an item
+		//	description:
+		//		This method uses a root item passed in 'object' argument and
+		//		'attribute' property to call getValue() method of
+		//		'dataStore'.
+		//		If an attribute name have an array suffix ("[]"), getValues()
+		//		method is called, instead.
+		//		If an index is specified in the array suffix, an array element
+		//		for the index is returned, instead of the array itself.
+		//	object:
+		//		A root item
+		//	returns:
+		//		A value found, otherwise 'undefined'
+		if(!object || !this.attribute || !this.dataStore){
+			return object; //Object
+		}
+
+		var value = object;
+		var list = this.attribute.split('.');
+		for(var i in list){
+			value = this._getAttributeValue(value, list[i]);
+			if(!value){
+				return undefined; //undefined
+			}
+		}
+		return value; //anything
+	},
+
+	_setValue: function(/*Object*/object, /*anything*/value){
+		//	summary:
+		//		Set an attribute value to an item
+		//	description:
+		//		This method uses a root item passed in 'object' argument and
+		//		'attribute' property to identify an item.
+		//		Then, setValue() method of 'dataStore' is called with a leaf
+		//		attribute name and 'value' argument.
+		//		If an attribute name have an array suffix ("[]"), setValues()
+		//		method is called, instead.
+		//		If an index is specified in the array suffix, an array element
+		//		for the index is set to 'value', instead of the array itself.
+		//	object:
+		//		A root item
+		//	value:
+		//		A value to set
+		//	returns:
+		//		'object', or 'undefined' for invalid attribute
+		if(!object || !this.attribute || !this.dataStore){
+			return object; //Object
+		}
+
+		var item = object;
+		var list = this.attribute.split('.');
+		var last = list.length - 1;
+		for(var i = 0; i < last; i++){
+			item = this._getAttributeValue(item, list[i]);
+			if(!item){
+				return undefined; //undefined
+			}
+		}
+		this._setAttributeValue(item, list[last], value);
+		return object; //Object
+	},
+
+	_getAttributeValue: function(/*Object*/item, /*String*/attribute){
+		//	summary:
+		//		Return an attribute value of an item
+		//	description:
+		//		This method uses an item passed in 'item' argument and
+		//		'attribute' argument to call getValue() method of 'dataStore'.
+		//		If an attribute name have an array suffix ("[]"), getValues()
+		//		method is called, instead.
+		//		If an index is specified in the array suffix, an array element
+		//		for the index is returned, instead of the array itself.
+		//	item:
+		//		An item
+		//	attribute
+		//		An attribute name
+		//	returns:
+		//		A value found, otherwise 'undefined'
+		var value = undefined;
+		var i1 = attribute.indexOf('[');
+		if(i1 >= 0){
+			var i2 = attribute.indexOf(']');
+			var index = attribute.substring(i1 + 1, i2);
+			attribute = attribute.substring(0, i1);
+			var array = this.dataStore.getValues(item, attribute);
+			if(array){
+				if(!index){ // return array for "attribute[]"
+					value = array;
+				}else{
+					value = array[index];
+				}
+			}
+		}else{
+			value = this.dataStore.getValue(item, attribute);
+		}
+		return value; //anything 
+	},
+
+	_setAttributeValue: function(/*Object*/item, /*String*/attribute, /*anything*/value){
+		//	summary:
+		//		Set an attribute value to an item
+		//	description:
+		//		This method uses an item passed in 'item' argument and
+		//		'attribute' argument to call setValue() method of 'dataStore'
+		//		with 'value' argument.
+		//		If an attribute name have an array suffix ("[]"), setValues()
+		//		method is called, instead.
+		//		If an index is specified in the array suffix, an array element
+		//		for the index is set to 'value', instead of the array itself.
+		//	item:
+		//		An item
+		//	attribute:
+		//		An attribute name
+		//	value:
+		//		A value to set
+		var i1 = attribute.indexOf('[');
+		if(i1 >= 0){
+			var i2 = attribute.indexOf(']');
+			var index = attribute.substring(i1 + 1, i2);
+			attribute = attribute.substring(0, i1);
+			var array = null;
+			if(!index){ // replace whole array for "attribute[]"
+				array = value;
+			}else{
+				array = this.dataStore.getValues(item, attribute);
+				if(!array){
+					array = [];
+				}
+				array[index] = value;
+			}
+			this.dataStore.setValues(item, attribute, array);
+		}else{
+			this.dataStore.setValue(item, attribute, value);
+		}
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/README
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/README	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/README	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,53 @@
+-------------------------------------------------------------------------------
+DojoX Wire
+-------------------------------------------------------------------------------
+Version 0.9
+Release date: 05/29/2007
+-------------------------------------------------------------------------------
+Project state: beta
+-------------------------------------------------------------------------------
+Project authors
+	Jared Jurkiewicz (jared.jurkiewicz at gmail.com)
+-------------------------------------------------------------------------------
+Project description
+
+The DojoX Wire project is a set of functions that build a generic data binding
+and service invocation library to simplify how data values across a wide
+variety of widget and non-widget JavaScript constructs are accessed, updated,
+and passed to and from services.  It also provides a set of widgets 
+within the dojox.wire.ml package to allow for declarative data binding 
+definitions in addition to the programmatic APIs.
+
+In essense, this project is an API to provide a simplified way of doing MVC
+patterns in the client.
+
+-------------------------------------------------------------------------------
+Dependencies:
+
+DojoX Wire has dependencies on core dojo, the dijit widget system (for classes 
+in the dojox.wire.ml package), dojox.data, and the D.O.H. unit test framework.
+-------------------------------------------------------------------------------
+Documentation:
+
+See the Dojo API tool (http://dojotoolkit.org/api)
+-------------------------------------------------------------------------------
+Installation instructions
+
+Grab the following from the Dojo SVN Repository:
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/wire.js
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/wire/*
+
+Install into the following directory structure:
+/dojox/wire/
+
+...which should be at the same level as your Dojo checkout.
+
+It should look like:
+/dojox/wire.js
+/dojox/wire/*
+
+Require in dojox.wire for all baseline functions (dojox.wire.connect, 
+dojox.wire.register, etc).  For specific Wire classes,
+require in the appropriate dojox.wire.<Class>.
+-------------------------------------------------------------------------------
+

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/TableAdapter.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/TableAdapter.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/TableAdapter.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,83 @@
+dojo.provide("dojox.wire.TableAdapter");
+
+dojo.require("dojox.wire.CompositeWire");
+
+dojo.declare("dojox.wire.TableAdapter",
+	dojox.wire.CompositeWire,
+	function(/*Object*/args){
+		//	summary:
+		//		Initialize properties
+		//	description:
+		//		If object properties or array elements specified in 'columns'
+		//		property are not Wires, Wires are created from them as
+		//		arguments, with 'parent' property set to this Wire instance.
+		//	args:
+		//		Arguments to initialize properties
+		//		columns:
+		//			An object or array containing child Wires for column values
+		this._initializeChildren(this.columns);
+	}, {
+	//	summary:
+	//		A composite Wire for table rows
+	//	description:
+	//		This class has multiple child Wires for object properties or array
+	//		elements of a table row.
+	//		The root object for this class must be an array.
+	//		When an object with Wires is specified to 'columns' property, they
+	//		are used to get a row object with property values.
+	//		When an array of Wires is specified to 'columns' property, they
+	//		are used to get a row array with element values.
+	//		The row values are returned in an array.
+	//		This class only supports getValue(), but not setValue().
+	_wireClass: "dojox.wire.TableAdapter",
+
+	_getValue: function(/*Array*/object){
+		//	summary:
+		//		Return an array of table row value (object or array)
+		//	description:
+		//		This method iterates over an array specified to 'object'
+		//		argument and calls getValue() method of the child Wires with
+		//		each element of the array to get a row object or array.
+		//		Finally, an array with the row objects or arrays are retuned.
+		//	object:
+		//		A root array
+		//	returns:
+		//		An array of table row value
+		if(!object || !this.columns){
+			return object; //Array
+		}
+
+		var array = object;
+		if(!dojo.isArray(array)){
+			array = [array];
+		}
+
+		var rows = [];
+		for(var i in array){
+			var row = this._getRow(array[i]);
+			rows.push(row);
+		}
+		return rows; //Array
+	},
+
+	_setValue: function(/*Array*/object, /*Array*/value){
+		//	summary:
+		//		Not supported
+		dojo.unimplemented(this._wireClass + "._setValue");
+	},
+
+	_getRow: function(/*Object||Array*/object){
+		//	summary:
+		//		Return an array or object for a table row
+		//	description:
+		//		This method calls getValue() method of the child Wires to
+		//		create a row object or array.
+		//	returns:
+		//		An array or object for a table row
+		var row = (dojo.isArray(this.columns) ? [] : {}); // array or object
+		for(var c in this.columns){
+			row[c] = this.columns[c].getValue(object);
+		}
+		return row; //Array||Object
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/TextAdapter.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/TextAdapter.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/TextAdapter.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,83 @@
+dojo.provide("dojox.wire.TextAdapter");
+
+dojo.require("dojox.wire.CompositeWire");
+
+dojo.declare("dojox.wire.TextAdapter",
+	dojox.wire.CompositeWire,
+	function(/*Object*/args){
+		//	summary:
+		//		Initialize properties
+		//	description:
+		//		If array elements specified in 'segments' are not Wires, Wires
+		//		are created from them as arguments, with 'parent' property set
+		//		to this Wire instance.
+		//	args:
+		//		Arguments to initialize properties
+		//		segments:
+		//			An array containing child Wires for text segment values
+		//		delimiter:
+		//			A delimiter string
+		this._initializeChildren(this.segments);
+		if(!this.delimiter){
+			this.delimiter = "";
+		}
+	}, {
+	//	summary:
+	//		A composite Wire for a concatenated text
+	//	description:
+	//		This class has multiple child Wires for text segment values.
+	//		Wires in 'segments' property are used to get text segments and
+	//		values are concatenated with an optional delimiter string specified
+	//		to 'delimiter' property.
+	_wireClass: "dojox.wire.TextAdapter",
+
+	_getValue: function(/*Object||Array*/object){
+		//	summary:
+		//		Return a concatenated text
+		//	description:
+		//		This method calls getValue() method of the child Wires wuth
+		//		'object' argument and concatenate the values with 'delimiter'
+		//		property to return.
+		//	arg:
+		//		A root object
+		//	returns:
+		//		A concatinated text
+		if(!object || !this.segments){
+			return object; //Object||Array
+		}
+
+		var text = "";
+		for(var i in this.segments){
+			var segment = this.segments[i].getValue(object);
+			text = this._addSegment(text, segment);
+		}
+		return text; //String
+	},
+
+	_setValue: function(/*Object||Array*/object, /*String*/value){
+		//	summary:
+		//		Not supported
+		dojo.unimplemented(this._wireClass + "._setValue");
+	},
+
+	_addSegment: function(/*String*/text, /*String*/segment){
+		//	summary:
+		//		Return a concatenated text
+		//	description:
+		//		This method add a text segment specified to 'segment' argument
+		//		to a base text specified to 'text', with 'delimiter' property.
+		//	text:
+		//		A base text
+		//	segment:
+		//		A text segment to add
+		//	returns:
+		//		A concatinated text
+		if(!segment){
+			return text; //String
+		}else if(!text){
+			return segment; //String
+		}else{
+			return text + this.delimiter + segment; //String
+		}
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/TreeAdapter.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/TreeAdapter.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/TreeAdapter.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,184 @@
+dojo.provide("dojox.wire.TreeAdapter");
+
+dojo.require("dojox.wire.CompositeWire");
+
+dojo.declare("dojox.wire.TreeAdapter",
+	dojox.wire.CompositeWire,
+	function(/*Object*/args){
+		//	summary:
+		//		Initialize properties
+		//	description:
+		//		If object properties ('node', 'title' and 'children') of array
+		//		elements specified in 'nodes' property are not Wires, Wires are
+		//		created from them as arguments, with 'parent' property set to
+		//		this Wire instance.
+		//	args:
+		//		Arguments to initialize properties
+		//		nodes:
+		//			An array containing objects for child Wires for node values
+		this._initializeChildren(this.nodes);
+	}, {
+	//	summary:
+	//		A composite Wire for tree nodes
+	//	description:
+	//		This class has multiple child Wires for tree nodes, their title and
+	//		child nodes.
+	//		The root object for this class must be an array.
+	//		'node' Wires in 'nodes' property is used to identify an object
+	//		representing a node.
+	//		'title' Wires in 'nodes' property is used to get the title string
+	//		of a node.
+	//		'children' Wires in 'nodes' property is used to iterate over child
+	//		node objects.
+	//		The node values are returned in an array as follows:
+	//			[
+	//				{title: title1,
+	//		  	 	children: [
+	//					{title: title2,
+	//					 child: ...},
+	//					{title: title3,
+	//					 child: ...},
+	//					...
+	//				]},
+	//				...
+	//			]
+	//		This class only supports getValue(), but not setValue().
+	_wireClass: "dojox.wire.TreeAdapter",
+
+	_getValue: function(/*Array*/object){
+		//	summary:
+		//		Return an array of tree node values
+		//	description:
+		//		This method iterates over an array specified to 'object'
+		//		argument and calls getValue() method of 'node' Wires with each
+		//		element of the array to get object(s) that represetns nodes.
+		//		(If 'node' Wires are omitted, the array element is used for
+		//		further processing.)
+		//		Then, getValue() method of 'title' Wires are called to get
+		//		title strings for nodes.
+		//		(If 'title' Wires are omitted, the objects representing nodes
+		//		are used as title strings.)
+		//		And if an array of objects with 'node' and 'title' Wires is
+		//		specified to 'children', it is used to gather child nodes and
+		//		their title strings in the same way recursively.
+		//		Finally, an array of the top-level node objects are retuned.
+		//	object:
+		//		A root array
+		//	returns:
+		//		An array of tree node values
+		if(!object || !this.nodes){
+			return object; //Array
+		}
+
+		var array = object;
+		if(!dojo.isArray(array)){
+			array = [array];
+		}
+
+		var nodes = [];
+		for(var i in array){
+			for(var i2 in this.nodes){
+				nodes = nodes.concat(this._getNodes(array[i], this.nodes[i2]));
+			}
+		}
+		return nodes; //Array
+	},
+
+	_setValue: function(/*Array*/object, /*Array*/value){
+		//	summary:
+		//		Not supported
+		dojo.unimplemented(this._wireClass + "._setValue");
+	},
+
+	_initializeChildren: function(/*Array*/children){
+		//	summary:
+		//		Initialize child Wires
+		//	description:
+		//		If 'node' or 'title' properties of array elements specified in
+		//		'children' argument are not Wires, Wires are created from them
+		//		as arguments, with 'parent' property set to this Wire instance.
+		//		If an array element has 'children' property, this method is
+		//		called recursively with it.
+		//	children:
+		//		An array of objects containing child Wires
+		if(!children){
+			return; //undefined
+		}
+
+		for(var i in children){
+			var child = children[i];
+			if(child.node){
+				child.node.parent = this;
+				if(!dojox.wire.isWire(child.node)){
+					child.node = dojox.wire.create(child.node);
+				}
+			}
+			if(child.title){
+				child.title.parent = this;
+				if(!dojox.wire.isWire(child.title)){
+					child.title = dojox.wire.create(child.title);
+				}
+			}
+			if(child.children){
+				this._initializeChildren(child.children);
+			}
+		}
+	},
+
+	_getNodes: function(/*Object*/object, /*Object*/child){
+		//	summary:
+		//		Return an array of tree node values
+		//	description:
+		//		This method calls getValue() method of 'node' Wires with
+		//		'object' argument to get object(s) that represents nodes.
+		//		(If 'node' Wires are omitted, 'object' is used for further
+		//		processing.)
+		//		Then, getValue() method of 'title' Wires are called to get
+		//		title strings for nodes.
+		//		(If 'title' Wires are omitted, the objects representing nodes
+		//		are used as title strings.)
+		//		And if an array of objects with 'node' and 'title' Wires is
+		//		specified to 'children', it is used to gather child nodes and
+		//		their title strings in the same way recursively.
+		//		Finally, an array of node objects are returned.
+		//	object:
+		//		An object
+		//	child:
+		//		An object with child Wires
+		//	returns:
+		var array = null;
+		if(child.node){
+			array = child.node.getValue(object);
+			if(!array){
+				return [];
+			}
+			if(!dojo.isArray(array)){
+				array = [array];
+			}
+		}else{
+			array = [object];
+		}
+
+		var nodes = [];
+		for(var i in array){
+			object = array[i];
+			var node = {};
+			if(child.title){
+				node.title = child.title.getValue(object);
+			}else{
+				node.title = object;
+			}
+			if(child.children){
+				var children = [];
+				for(var i2 in child.children){
+					children = children.concat(this._getNodes(object, child.children[i2]));
+				}
+				if(children.length > 0){
+					node.children = children;
+				}
+			}
+			nodes.push(node);
+		}
+		return nodes; //Array
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/Wire.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/Wire.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/Wire.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,304 @@
+dojo.provide("dojox.wire.Wire");
+
+dojo.require("dojox.wire._base");
+
+dojo.declare("dojox.wire.Wire",
+	null,
+	function(/*Object*/args){
+		//	summary:
+		//		Initialize properties
+		//	description:
+		//		If 'converter' property is specified and is a string for
+		//		a converter class, an instanceof the converter class is
+		//		created.
+		//	args:
+		//		Arguments to initialize properties
+		//		object:
+		//			A root object (or another Wire to access a root object)
+		//		property:
+		//			A dotted notation to a descendant property
+		//		type:
+		//			A type of the return value (for the source Wire)
+		//		converter:
+		//			A converter object (or class name) to convert the return
+		//			value (for the source Wire)
+		dojo.mixin(this, args);
+
+		if(this.converter){
+			if(dojo.isString(this.converter)){
+				var converterClass = dojox.wire._getClass(this.converter);
+				if(converterClass){
+					this.converter = new converterClass();
+				}else{
+					this.converter = undefined;
+				}
+			}else if(dojo.isFunction(this.converter)){
+				this.converter = {convert: this.converter};
+			}
+		}
+	}, {
+	//	summary:
+	//		A default and base Wire to access an object property
+	//	description:
+	//		This class accesses a property of an object with a dotted notation
+	//		specified to 'property' property, such as "a.b.c", which identifies
+	//		a descendant property, "object.a.b.c".
+	//		Property names in the dotted notation may have an array index, such
+	//		as "a[0]", to identify an array element, literally, "object.a[0]".
+	//		When a notation start with an array index, such as "[0].a", it
+	//		specifies an array element of the root object (array),
+	//		"object[0].a".
+	//		This class also serves as a base class for other Wire classes,
+	//		preparing a root object and converting a return value, so that
+	//		sub-classes just can implement _getValue() and _setValue() called
+	//		from getValue() and setValue() implemented by this calss.
+	_wireClass: "dojox.wire.Wire",
+
+	getValue: function(/*Object||Array*/defaultObject){
+		//	summary:
+		//		Return a value of an object
+		//	description:
+		//		This method first determins a root object as follows:
+		//		1. If 'object' property specified,
+		//		1.1 If 'object' is a Wire, its getValue() method is called to
+		//	    	obtain a root object.
+		//		1.2 Otherwise, use 'object' as a root object.
+		//		2. Otherwise, use 'defaultObject' argument.
+		//		3. If 'property' is specified, it is used to get a property
+		//			value.
+		//		Then, if a sub-class implements _getValue() method, it is
+		//		called with the root object to get the return value.
+		//		Otherwise, the root object (typically, a property valye) is
+		//		used for the return value.
+		//		Finally, if 'type' property is specified, the return value is
+		//		converted to the specified primitive type ("string", "number",
+		//		"boolean" and "array").
+		//		If 'converter' property is specified, its convert() method is
+		//		called to convert the value.
+		//	defaultObject:
+		//		A default root object
+		//	returns:
+		//		A value found
+		var object = undefined;
+		if(dojox.wire.isWire(this.object)){
+			object = this.object.getValue(defaultObject);
+		}else{
+			object = (this.object || defaultObject);
+		}
+
+		if(this.property){
+			var list = this.property.split('.');
+			for(var i in list){
+				if(!object){
+					throw new Error(this._wireClass + ".getValue(): invalid property=" + this.property);
+				}
+				object = this._getPropertyValue(object, list[i]);
+			}
+		}
+
+		var value = undefined;
+		if(this._getValue){
+			value = this._getValue(object);
+		}else{
+			value = object;
+		}
+
+		if(value){
+			if(this.type){
+				if(this.type == "string"){
+					value = value.toString();
+				}else if(this.type == "number"){
+					value = parseInt(value);
+				}else if(this.type == "boolean"){
+					value = (value != "false");
+				}else if(this.type == "array"){
+					if(!dojo.isArray(value)){
+						value = [value];
+					}
+				}
+			}
+			if(this.converter && this.converter.convert){
+				value = this.converter.convert(value, this); // optional "this" context
+			}
+		}
+		return value; //anything
+	},
+
+	setValue: function(/*anything*/value, /*Object||Array*/defaultObject){
+		//	summary:
+		//		Set a value to an object
+		//	description:
+		//		This method first determins a root object as follows:
+		//		1. If 'object' property specified,
+		//		1.1 If 'object' is a Wire, its getValue() method is called to
+		//	    	obtain a root object.
+		//		1.2 Otherwise, use 'object' as a root object.
+		//		2. Otherwise, use 'defaultObject' argument.
+		//		3. If 'property' is specified, it is used to get a property
+		//			value.
+		//		Then, if a sub-class implements _setValue() method, it is
+		//		called with the root object and 'value' argument to set
+		//		the value.
+		//		Otherwise, 'value' is set to a property specified with
+		//		'property' property.
+		//		If the root object is undefined and 'object' property is a Wire
+		//		and a new object is created and returned by _setValue() it is
+		//		set through 'object' (setValue() method).
+		//	value:
+		//		A value to set
+		//	defaultObject:
+		//		A default root object
+		var object = undefined;
+		if(dojox.wire.isWire(this.object)){
+			object = this.object.getValue(defaultObject);
+		}else{
+			object = (this.object || defaultObject);
+		}
+
+		var property = undefined;
+		if(this.property){
+			if(!object){
+				if(dojox.wire.isWire(this.object)){
+					object = {};
+					this.object.setValue(object, defaultObject);
+				}else{
+					throw new Error(this._wireClass + ".setValue(): invalid object");
+				}
+			}
+			var list = this.property.split('.');
+			var last = list.length - 1;
+			for(var i = 0; i < last; i++){
+				var p = list[i];
+				var o = this._getPropertyValue(object, p);
+				if(!o){
+					o = {};
+					this._setPropertyValue(object, p, o);
+				}
+				object = o;
+			}
+			property = list[last];
+		}
+
+		if(this._setValue){
+			if(property){
+				var o = this._getPropertyValue(object, property);
+				if(!o){
+					o = {};
+					this._setPropertyValue(object, property, o);
+				}
+				object = o;
+			}
+			var newObject = this._setValue(object, value);
+			if(!object && newObject){
+				if(dojox.wire.isWire(this.object)){
+					this.object.setValue(newObject, defaultObject);
+				}else{
+					throw new Error(this._wireClass + ".setValue(): invalid object");
+				}
+			}
+		}else{
+			if(property){
+				this._setPropertyValue(object, property, value);
+			}else{
+				if(dojox.wire.isWire(this.object)){
+					this.object.setValue(value, defaultObject);
+				}else{
+					throw new Error(this._wireClass + ".setValue(): invalid property");
+				}
+			}
+		}
+	},
+
+	_getPropertyValue: function(/*Object||Array*/object, /*String*/property){
+		//	summary:
+		//		Return a property value of an object
+		//	description:
+		//		A value for 'property' of 'object' is returned.
+		//		If 'property' ends with an array index, it is used to indentify
+		//		an element of an array property.
+		//		If 'object' implements getPropertyValue(), it is called with
+		//		'property' to obtain the property value.
+		//		If 'object' implements a getter for the property, it is called
+		//		to obtain the property value.
+		//	object:
+		//		A default root object
+		//	property:
+		//		A property name
+		//	returns:
+		//		A value found, otherwise 'undefined'
+		var value = undefined;
+		var i1 = property.indexOf('[');
+		if(i1 >= 0){
+			var i2 = property.indexOf(']');
+			var index = property.substring(i1 + 1, i2);
+			var array = null;
+			if(i1 === 0){ // object is array
+				array = object;
+			}else{
+				property = property.substring(0, i1);
+				array = this._getPropertyValue(object, property);
+				if(array && !dojo.isArray(array)){
+					array = [array];
+				}
+			}
+			if(array){
+				value = array[index];
+			}
+		}else if(object.getPropertyValue){
+			value = object.getPropertyValue(property);
+		}else{
+			var getter = "get" + property.charAt(0).toUpperCase() + property.substring(1);
+			if(object[getter]){
+				value = object[getter]();
+			}else{
+				value = object[property];
+			}
+		}
+		return value; //anything
+	},
+
+	_setPropertyValue: function(/*Object||Array*/object, /*String*/property, /*anything*/value){
+		//	summary:
+		//		Set a property value to an object
+		//	description:
+		//		'value' is set to 'property' of 'object'.
+		//		If 'property' ends with an array index, it is used to indentify
+		//		an element of an array property to set the value.
+		//		If 'object' implements setPropertyValue(), it is called with
+		//		'property' and 'value' to set the property value.
+		//		If 'object' implements a setter for the property, it is called
+		//		with 'value' to set the property value.
+		//	object:
+		//		An object
+		//	property:
+		//		A property name
+		//	value:
+		//		A value to set
+		var i1 = property.indexOf('[');
+		if(i1 >= 0){
+			var i2 = property.indexOf(']');
+			var index = property.substring(i1 + 1, i2);
+			var array = null;
+			if(i1 === 0){ // object is array
+				array = object;
+			}else{
+				property = property.substring(0, i1);
+				array = this._getPropertyValue(object, property);
+				if(!array){
+					array = [];
+					this._setPropertyValue(object, property, array);
+				}
+			}
+			array[index] = value;
+		}else if(object.setPropertyValue){
+			object.setPropertyValue(property, value);
+		}else{
+			var setter = "set" + property.charAt(0).toUpperCase() + property.substring(1);
+			if(object[setter]){
+				object[setter](value);
+			}else{
+				object[property] = value;
+			}
+		}
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/XmlWire.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/XmlWire.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/XmlWire.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,240 @@
+dojo.provide("dojox.wire.XmlWire");
+
+dojo.require("dojox.data.dom");
+dojo.require("dojox.wire.Wire");
+
+dojo.declare("dojox.wire.XmlWire",
+	dojox.wire.Wire,
+	function(/*Object*/args){
+		//	summary:
+		//		Initialize properties
+		//	description:
+		//		'args' is just mixed in with no further processing.
+		//	args:
+		//		Arguments to initialize properties
+		//		path:
+		//			A simplified XPath to an attribute, a text or elements
+	},{
+	//	summary:
+	//		A Wire for XML nodes or values (element, attribute and text)
+	//	description:
+	//		This class accesses XML nodes or value with a simplified XPath
+	//		specified to 'path' property.
+	//		The root object for this class must be an DOM document or element
+	//		node.
+	//		"@name" accesses to an attribute value of an element and "text()"
+	//		accesses to a text value of an element.
+	//		The hierarchy of the elements from the root node can be specified
+	//		with slash-separated list, such as "a/b/@c", which specifies
+	//		the value of an attribute named "c" of an element named "b" as
+	//		a child of another element named "a" of a child of the root node.
+	_wireClass: "dojox.wire.XmlWire",
+
+	_getValue: function(/*Node*/object){
+		//	summary:
+		//		Return an attribute value, a text value or an array of elements
+		//	description:
+		//		This method first uses a root node passed in 'object' argument
+		//		and 'path' property to identify an attribute, a text or
+		//		elements.
+		//		If 'path' starts with a slash (absolute), the first path
+		//		segment is ignored assuming it point to the root node.
+		//		(That is, "/a/b/@c" and "b/@c" against a root node access
+		//		the same attribute value, assuming the root node is an element
+		//		with a tag name, "a".)
+		//	object:
+		//		A root node
+		//	returns:
+		//		A value found, otherwise 'undefined'
+		if(!object || !this.path){
+			return object; //Node
+		}
+
+		var node = object;
+		var path = this.path;
+		if(path.charAt(0) == '/'){ // absolute
+			// skip the first expression (supposed to select the top node)
+			var i = path.indexOf('/', 1);
+			path = path.substring(i + 1);
+		}
+		var list = path.split('/');
+		var last = list.length - 1;
+		for(var i = 0; i < last; i++){
+			node = this._getChildNode(node, list[i]);
+			if(!node){
+				return undefined; //undefined
+			}
+		}
+		var value = this._getNodeValue(node, list[last]);
+		return value; //String||Array
+	},
+
+	_setValue: function(/*Node*/object, /*String*/value){
+		//	summary:
+		//		Set an attribute value or a child text value to an element
+		//	description:
+		//		This method first uses a root node passed in 'object' argument
+		//		and 'path' property to identify an attribute, a text or
+		//		elements.
+		//		If an intermediate element does not exist, it creates
+		//		an element of the tag name in the 'path' segment as a child
+		//		node of the current node.
+		//		Finally, 'value' argument is set to an attribute or a text
+		//		(a child node) of the leaf element.
+		//	object:
+		//		A root node
+		//	value:
+		//		A value to set
+		if(!this.path){
+			return object; //Node
+		}
+
+		var node = object;
+		var doc = this._getDocument(node);
+		var path = this.path;
+		if(path.charAt(0) == '/'){ // absolute
+			var i = path.indexOf('/', 1);
+			if(!node){
+				var name = path.substring(1, i);
+				node = doc.createElement(name);
+				object = node; // to be returned as a new object
+			}
+			// skip the first expression (supposed to select the top node)
+			path = path.substring(i + 1);
+		}else{
+			if(!node){
+				return undefined; //undefined
+			}
+		}
+
+		var list = path.split('/');
+		var last = list.length - 1;
+		for(var i = 0; i < last; i++){
+			var child = this._getChildNode(node, list[i]);
+			if(!child){
+				child = doc.createElement(list[i]);
+				node.appendChild(child);
+			}
+			node = child;
+		}
+		this._setNodeValue(node, list[last], value);
+		return object; //Node
+	},
+
+	_getNodeValue: function(/*Node*/node, /*String*/exp){
+		//	summary:
+		//		Return an attribute value, a text value or an array of elements
+		//	description:
+		//		If 'exp' starts with '@', an attribute value of the specified
+		//		attribute is returned.
+		//		If 'exp' is "text()", a child text value is returned.
+		//		Otherwise, an array of child elements, the tag name of which
+		//		match 'exp', is returned.
+		//	node:
+		//		A node
+		//	exp:
+		//		An expression for attribute, text or elements
+		//	returns:
+		//		A value found, otherwise 'undefined'
+		var value = undefined;
+		if(exp.charAt(0) == '@'){
+			var attribute = exp.substring(1);
+			value = node.getAttribute(attribute);
+		}else if(exp == "text()"){
+			var text = node.firstChild;
+			if(text){
+				value = text.nodeValue;
+			}
+		}else{ // assume elements
+			value = [];
+			for(var i = 0; i < node.childNodes.length; i++){
+				var child = node.childNodes[i];
+				if(child.nodeName == exp){
+					value.push(child);
+				}
+			}
+		}
+		return value; //String||Array
+	},
+
+	_setNodeValue: function(/*Node*/node, /*String*/exp, /*String*/value){
+		//	summary:
+		//		Set an attribute value or a child text value to an element
+		//	description:
+		//		If 'exp' starts with '@', 'value' is set to the specified
+		//		attribute.
+		//		If 'exp' is "text()", 'value' is set to a child text.
+		//	node:
+		//		A node
+		//	exp:
+		//		An expression for attribute or text
+		//	value:
+		//		A value to set
+		if(exp.charAt(0) == '@'){
+			var attribute = exp.substring(1);
+			if(value){
+				node.setAttribute(attribute, value);
+			}else{
+				node.removeAttribute(attribute);
+			}
+		}else if(exp == "text()"){
+			while(node.firstChild){
+				node.removeChild(node.firstChild);
+			}
+			if(value){
+				var text = this._getDocument(node).createTextNode(value);
+				node.appendChild(text);
+			}
+		}
+		// else not supported
+	},
+
+	_getChildNode: function(/*Node*/node, /*String*/name){
+		//	summary:
+		//		Return a child node
+		//	description:
+		//		A child element of the tag name specified with 'name' is
+		//		returned.
+		//		If 'name' ends with an array index, it is used to pick up
+		//		the corresponding element from multiple child elements.
+		//	node:
+		//		A parent node
+		//	name:
+		//		A tag name	
+		//	returns:
+		//		A child node
+		var index = 1;
+		var i1 = name.indexOf('[');
+		if(i1 >= 0){
+			var i2 = name.indexOf(']');
+			index = name.substring(i1 + 1, i2);
+			name = name.substring(0, i1);
+		}
+		var count = 1;
+		for(var i = 0; i < node.childNodes.length; i++){
+			var child = node.childNodes[i];
+			if(child.nodeName == name){
+				if(count == index){
+					return child; //Node
+				}
+				count++;
+			}
+		}
+		return null; //null
+	},
+
+	_getDocument: function(/*Node*/node){
+		//	summary:
+		//		Return a DOM document
+		//	description:
+		//		If 'node' is specified, a DOM document of the node is returned.
+		//		Otherwise, a DOM document is created.
+		//	returns:
+		//		A DOM document
+		if(node){
+			return (node.nodeType == 9 /* DOCUMENT_NODE */ ? node : node.ownerDocument); //Document
+		}else{
+			return dojox.data.dom.createDocument(); //Document
+		}
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/_base.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/_base.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/_base.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,191 @@
+dojo.provide("dojox.wire._base");
+
+dojox.wire._defaultWireClass = "dojox.wire.Wire";
+
+dojox.wire._wireClasses = {
+	"attribute": "dojox.wire.DataWire",
+	"path": "dojox.wire.XmlWire",
+	"children": "dojox.wire.CompositeWire",
+	"columns": "dojox.wire.TableAdapter",
+	"nodes": "dojox.wire.TreeAdapter",
+	"segments": "dojox.wire.TextAdapter"
+};
+
+dojox.wire.register = function(/*Function||String*/wireClass, /*String*/key){
+	//	summary:
+	//		Register a Wire class
+	//	desription:
+	//		The specified Wire class or a class name is registered with
+	//		a key property of arguments to create a Wire
+	//	wireClass:
+	//		A class or full qualified class name
+	//	key:
+	//		A key property of arguments to create a Wire
+	if(!wireClass || !key){
+		return; //undefined
+	}
+	if(dojox.wire._wireClasses[key]){ // key already in use
+		return; //undefined
+	}
+	dojox.wire._wireClasses[key] = wireClass;
+};
+
+dojox.wire._getClass = function(/*String*/name){
+	//	summary:
+	//		Returns a class 
+	//	description:
+	//		The class is loaded by dojo.require() and returned
+	//		by dojo.getObject().
+	//	name:
+	//		A class name
+	//	returns:
+	//		A class
+	dojo["require"](name); // use dojo["require"] instead of dojo.require to avoid a build problem
+	return dojo.getObject(name); //Function
+};
+
+dojox.wire.create = function(/*Object*/args){
+	//	summary:
+	//		Create a Wire from arguments
+	//	description:
+	//		If 'args' specifies 'wireClass', it is used as a class or full
+	//		qualified class name to create a Wire with 'args' as arguments.
+	//		Otherwise, a Wire class is determined by other proeprties of 'args'
+	//		checking if 'args' specifies a key property for a Wire class.
+	//		If no key property found, the default Wire class is used.
+	//	args:
+	//		Arguments to create a Wire
+	//	returns:
+	//		A Wire
+	if(!args){
+		args = {};
+	}
+	var wireClass = args.wireClass;
+	if(wireClass){
+		if(dojo.isString(wireClass)){
+			wireClass = dojox.wire._getClass(wireClass);
+		}
+	}else{
+		for(var key in args){
+			if(!args[key]){
+				continue;
+			}
+			wireClass = dojox.wire._wireClasses[key];
+			if(wireClass){
+				if(dojo.isString(wireClass)){
+					wireClass = dojox.wire._getClass(wireClass);
+					dojox.wire._wireClasses[key] = wireClass;
+				}
+				break;
+			}
+		}
+	}
+	if(!wireClass){
+		if(dojo.isString(dojox.wire._defaultWireClass)){
+			dojox.wire._defaultWireClass = dojox.wire._getClass(dojox.wire._defaultWireClass);
+		}
+		wireClass = dojox.wire._defaultWireClass;
+	}
+	return new wireClass(args); //Object
+};
+
+dojox.wire.isWire = function(/*Object*/wire){
+	//	summary:
+	//		Check if an object is a Wire
+	//	description:
+	//		If the specified object is a Wire, true is returned.
+	//		Otherwise, false is returned.
+	//	wire:
+	//		An object to check
+	//	returns:
+	//		True if the object is a Wire, otherwise false
+	return (wire && wire._wireClass); //Boolean
+};
+
+dojox.wire.transfer = function(/*Wire||Object*/source, /*Wire||Object*/target, /*Object?*/defaultObject, /*Object?*/defaultTargetObject){
+	//	summary:
+	//		Transfer a source value to a target value
+	//	description:
+	//		If 'source' and/or 'target' are not Wires, Wires are created with
+	//		them as arguments.
+	//		A value is got through the source Wire and set through the target
+	//		Wire.
+	//		'defaultObject' is passed to Wires as a default root object.
+	//		If 'defaultTargetObject' is specified, it is passed to the target
+	//		Wire as a default root object, instead of 'defaultObject'.
+	//	source:
+	//		A Wire or arguments to create a Wire for a source value
+	//	target:
+	//		A Wire or arguments to create a Wire for a target value
+	//	defaultObject:
+	//	defaultTargetObject;
+	//		Optional default root objects passed to Wires
+	if(!source || !target){
+		return; //undefined
+	}
+	if(!dojox.wire.isWire(source)){
+		source = dojox.wire.create(source);
+	}
+	if(!dojox.wire.isWire(target)){
+		target = dojox.wire.create(target);
+	}
+
+	var value = source.getValue(defaultObject);
+	target.setValue(value, (defaultTargetObject || defaultObject));
+};
+
+dojox.wire.connect = function(/*Object*/trigger, /*Wire||Object*/source, /*Wire||Object*/target){
+	//	summary:
+	//		Transfer a source value to a target value on a trigger event or
+	//		topic
+	//	description:
+	//		If 'trigger' specifies 'topic', the topic is subscribed to transer
+	//		a value on the topic.
+	//		Otherwise, the event specified to 'event' of 'trigger' is listened
+	//		to transfer a value.
+	//		On the specified event or topic, transfer() is called with
+	//		'source', 'target' and the arguments of the event or topic (as
+	//		default root objects).
+	//	trigger:
+	//		An event or topic to trigger a transfer
+	//	source:
+	//		A Wire or arguments to create a Wire for a source value
+	//	target:
+	//		A Wire or arguments to create a Wire for a target value
+	//	returns:
+	//		A connection handle for disconnect()
+	if(!trigger || !source || !target){
+		return; //undefined
+	}
+
+	var connection = {topic: trigger.topic};
+	if(trigger.topic){
+		connection.handle = dojo.subscribe(trigger.topic, function(){
+			dojox.wire.transfer(source, target, arguments);
+		});
+	}else if(trigger.event){
+		connection.handle = dojo.connect(trigger.scope, trigger.event, function(){
+			dojox.wire.transfer(source, target, arguments);
+		});
+	}
+	return connection; //Object
+};
+
+dojox.wire.disconnect = function(/*Object*/connection){
+	//	summary:
+	//		Remove a connection or subscription for transfer
+	//	description:
+	//		If 'handle' has 'topic', the topic is unsubscribed.
+	//		Otherwise, the listener to an event is removed.
+	//	connection:
+	//		A connection handle returned by connect()
+	if(!connection || !connection.handle){
+		return; //undefined
+	}
+
+	if(connection.topic){
+		dojo.unsubscribe(connection.topic, connection.handle);
+	}else{
+		dojo.disconnect(connection.handle);
+	}
+};

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Action.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Action.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Action.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,182 @@
+dojo.provide("dojox.wire.ml.Action");
+dojo.provide("dojox.wire.ml.ActionFilter");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.Container");
+dojo.require("dojox.wire.Wire");
+dojo.require("dojox.wire.ml.util");
+
+dojo.declare("dojox.wire.ml.Action",
+	[dijit.base.Widget, dijit.base.Container], {
+	//	summary:
+	//		A base widget to "run" a task on an event or a topic
+	//	description:
+	//		This widget represents a controller task to be run when an event
+	//		(a function) or a topic is issued.
+	//		Sub-classes must implement _run() method to implement their tasks.
+	//		'trigger' specifies an event scope, an ID of a widget or an DOM
+	//		element, or its property with the optional dotted notation.
+	//		If this widget has child ActionFilter widgets, their filter()
+	//		methods are called with the arguments to the event or the topic.
+	//		If one of filter() methods returns false, run() won't be invoked.
+	//		This widget also can serve as a composite task to run child
+	//		Actions on an event or a topic specified to this widget.
+	//	trigger:
+	//		An event scope
+	//	triggerEvent:
+	//		An event (function) name
+	//	triggerTopic:
+	//		A topic name
+	trigger: "",
+	triggerEvent: "",
+	triggerTopic: "",
+
+	postCreate: function(){
+		//	summary:
+		//		Call _connect()
+		//	description:
+		//		See _connect().
+		this._connect();
+	},
+
+	_connect: function(){
+		//	summary:
+		//		Connect run() method to an event or a topic
+		//	description:
+		//		If 'triggerEvent' and 'trigger' are specified, connect() is
+		//		used to set up run() to be called on the event.
+		//		If 'triggerTopic' is specified, subscribe() is used to set up
+		//		run() to be called on the topic.
+		if(this.triggerEvent){
+			if(this.trigger){
+				var scope = dojox.wire.ml._getValue(this.trigger);
+				if(scope){
+					if(!scope[this.triggerEvent]){
+						// set a dummy function for an anonymous object
+						scope[this.triggerEvent] = function(){};
+					}
+					this._triggerHandle = dojo.connect(scope, this.triggerEvent, this, "run");
+				}
+			}else{
+				var event = this.triggerEvent.toLowerCase();
+				if(event == "onload"){
+					var self = this;
+					dojo.addOnLoad(function(){
+						self._run.apply(self, arguments);
+					});
+				}
+			}
+		}else if(this.triggerTopic){
+			this._triggerHandle = dojo.subscribe(this.triggerTopic, this, "run");
+		}
+	},
+
+	_disconnect: function(){
+		//	summary:
+		//		Disconnect run() method from an event or a topic
+		//	description:
+		//		If 'triggerEvent' and 'trigger' are specified, disconnect() is
+		//		used to set up run() not to be called on the event.
+		//		If 'triggerTopic' is specified, unsubscribe() is used to set up
+		//		run() not to be called on the topic.
+		if(this._triggerHandle){
+			if(this.triggerTopic){
+				dojo.unsubscribe(this.triggerTopic, this._triggerHandle);
+			}else{
+				dojo.disconnect(this._triggerHandle);
+			}
+		}
+	},
+
+	run: function(){
+		//	summary:
+		//		Run a task
+		//	description:
+		//		This method calls filter() method of child ActionFilter
+		//		widgets.
+		//		If one of them returns false, this method returns.
+		//		Otherwise, _run() method is called.
+		var children = this.getChildren();
+		for(var i in children){
+			var child = children[i];
+			if(child instanceof dojox.wire.ml.ActionFilter){
+				if(!child.filter.apply(child, arguments)){
+					return;
+				}
+			}
+		}
+		this._run.apply(this, arguments);
+	},
+
+	_run: function(){
+		//	summary:
+		//		Call run() methods of child Action widgets
+		//	description:
+		//		If this widget has child Action widgets, their run() methods
+		//		are called.
+		var children = this.getChildren();
+		for(var i in children){
+			var child = children[i];
+			if(child instanceof dojox.wire.ml.Action){
+				child.run.apply(child, arguments);
+			}
+		}
+	},
+
+	_destroy: function(finalize /*boolean*/){
+		//	summary:
+		//		Over-ride of base widget _destroy function to do some connection cleanup.
+		this._disconnect();
+		dojox.wire.ml.Action.superclass._destroy.apply(this,arguments);
+	}
+});
+
+dojo.declare("dojox.wire.ml.ActionFilter",
+	dijit.base.Widget, {
+	//	summary:
+	//		A widget to define a filter for the parent Action to run
+	//	description:
+	//		This base class checks a required property specified with
+	//		'required' attribute.
+	//		If 'message' is specified, the message is set to a property
+	//		specified with 'error'.
+	//		Subclasses may implement their own filter() method.
+	//	required:
+	//		A property required
+	//	message:
+	//		An error message
+	//	error:
+	//		A property to store an error
+	required: "",
+	message: "",
+	error: "",
+
+	filter: function(){
+		//	summary:
+		//		Check if a required property is specified
+		//	description:
+		//		If a value is undefined for a property, specifieid with
+		//		'required', this method returns false.
+		//		If 'message' is specified, it is set to a proeprty specified
+		//		with 'error' or shown with alert().
+		//		If 'required' starts with "arguments", a property of
+		//		the method arguments are checked.
+		//	returns:
+		//		True if a required property is specified, otherwise false
+		if(!this.required){
+			return true; //Boolean
+		}
+		var value = dojox.wire.ml._getValue(this.required);
+		if(value){
+			return true; //Boolean
+		}
+		if(this.message){
+			if(this.error){
+				dojox.wire.ml._setValue(this.error, this.message);
+			}else{
+				alert(this.message);
+			}
+		}
+		return false; //Boolean
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Data.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Data.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Data.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,141 @@
+dojo.provide("dojox.wire.ml.Data");
+dojo.provide("dojox.wire.ml.DataProperty");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.Container");
+dojo.require("dojox.wire.ml.util");
+
+dojo.declare("dojox.wire.ml.Data",
+	[dijit.base.Widget, dijit.base.Container], {
+	//	summary:
+	//		A widget for a data object
+	//	description:
+	//		This widget represents an object with '_properties' property.
+	//		If child 'DataProperty' widgets exist, they are used to initialize
+	//		propertiy values of '_properties' object.
+
+	startup: function(){
+		//	summary:
+		//		Call _initializeProperties()
+		//	description:
+		//		See _initializeProperties().
+		this._initializeProperties();
+	},
+
+	_initializeProperties: function(/*Boolean*/reset){
+		//	summary:
+		//		Initialize a data object
+		//	description:
+		//		If this widget has child DataProperty widgets, their getValue()
+		//		methods are called and set the return value to a property
+		//		specified by 'name' attribute of the child widgets.
+		//	reset:
+		//		A boolean to reset current properties
+		if(!this._properties || reset){
+			this._properties = {};
+		}
+		var children = this.getChildren();
+		for(var i in children){
+			var child = children[i];
+			if((child instanceof dojox.wire.ml.DataProperty) && child.name){
+				this.setPropertyValue(child.name, child.getValue());
+			}
+		}
+	},
+
+	getPropertyValue: function(/*String*/property){
+		//	summary:
+		//		Return a property value
+		//	description:
+		//		This method returns the value of a property, specified with
+		//		'property' argument, in '_properties' object.
+		//	property:
+		//		A property name
+		//	returns:
+		//		A property value
+		return this._properties[property]; //anything
+	},
+
+	setPropertyValue: function(/*String*/property, /*anything*/value){
+		//	summary:
+		//		Store a property value
+		//	description:
+		//		This method stores 'value' as a property, specified with
+		//		'property' argument, in '_properties' object.
+		//	property:
+		//		A property name
+		//	value:
+		//		A property value
+		this._properties[property] = value;
+	}
+});
+
+dojo.declare("dojox.wire.ml.DataProperty",
+	[dijit.base.Widget, dijit.base.Container], {
+	//	summary:
+	//		A widget to define a data property
+	//	description:
+	//		Attributes of this widget are used to add a property to the parent
+	//		Data widget.
+	//		'type' attribute specifies one of "string", "number", "boolean",
+	//		"array", "object" and "element" (DOM Element)
+	//		(default to "string").
+	//		If 'type' is "array" or "object", child DataProperty widgets are
+	//		used to initialize the array elements or the object properties.
+	//	name:
+	//		A property name
+	//	type:
+	//		A property type name
+	//	value:
+	//		A property value
+	name: "",
+	type: "",
+	value: "",
+
+	getValue: function(){
+		//	summary:
+		//		Returns a property value
+		//	description:
+		//		If 'type' is specified, 'value' attribute is converted to
+		//		the specified type and returned.
+		//		Otherwise, 'value' attribute is returned as is.
+		//	returns:
+		//		A property value
+		var value = this.value;
+		if(this.type){
+			if(this.type == "number"){
+				value = parseInt(value);
+			}else if(this.type == "boolean"){
+				value = (value == "true");
+			}else if(this.type == "array"){
+				value = [];
+				var children = this.getChildren();
+				for(var i in children){
+					var child = children[i];
+					if(child instanceof dojox.wire.ml.DataProperty){
+						value.push(child.getValue());
+					}
+				}
+			}else if(this.type == "object"){
+				value = {};
+				var children = this.getChildren();
+				for(var i in children){
+					var child = children[i];
+					if((child instanceof dojox.wire.ml.DataProperty) && child.name){
+						value[child.name] = child.getValue();
+					}
+				}
+			}else if(this.type == "element"){
+				value = new dojox.wire.ml.XmlElement(value);
+				var children = this.getChildren();
+				for(var i in children){
+					var child = children[i];
+					if((child instanceof dojox.wire.ml.DataProperty) && child.name){
+						value.setPropertyValue(child.name, child.getValue());
+					}
+				}
+			}
+		}
+		return value; //anything
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/ml/DataStore.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/ml/DataStore.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/ml/DataStore.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,113 @@
+dojo.provide("dojox.wire.ml.DataStore");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dojox.wire._base");
+
+dojo.declare("dojox.wire.ml.DataStore",
+	dijit.base.Widget, {
+	//	summary:
+	//		A widget for a data store
+	//	description:
+	//		This widget represents a data store of 'storeClass' attribute.
+	//	storeClass:
+	//		A class name of a data store
+	storeClass: "",
+
+	postCreate: function(){
+		//	summary:
+		//		Call _createStore()
+		//	description:
+		//		See _createStore().
+		this.store = this._createStore();
+	},
+
+	_createStore: function(){
+		//	summary:
+		//		Create a data store
+		//	desription:
+		//		A data store of 'storeClass' is created with arguments
+		//		specified with attributes.
+		//	returns:
+		//		A data store
+		if(!this.storeClass){
+			return null; //null
+		}
+		var storeClass = dojox.wire._getClass(this.storeClass);
+		if(!storeClass){
+			return null; //null
+		}
+		var args = {};
+		var attributes = this.domNode.attributes;
+		for(var i = 0; i < attributes.length; i++){
+			var a = attributes.item(i);
+			if(a.specified && !this[a.nodeName]){
+				args[a.nodeName] = a.nodeValue;
+			}
+		}
+		return new storeClass(args); //Object
+	},
+
+	getFeatures: function(){
+		//	summary:
+		//		Call getFeatures() method of a data store
+		//	description:
+		//		See dojo.data.api.Read.getFeatures().
+		//	returns:
+		//		A features object
+		return this.store.getFeatures(); //Object
+	},
+
+	fetch: function(/*Object*/request){
+		//	summary:
+		//		Call fetch() method of a data store
+		//	description:
+		//		See dojo.data.api.Read.fetch().
+		//	request:
+		//		A request object
+		//	returns:
+		//		A request object
+		return this.store.fetch(request); //Object
+	},
+
+	save: function(/*Object*/args){
+		//	summary:
+		//		Call save() method of a data store
+		//	description:
+		//		See dojo.data.api.Write.save().
+		//	args:
+		//		A save arguments object
+		this.store.save(args);
+	},
+
+	newItem: function(/*Object*/args){
+		//	summary:
+		//		Call newItem() method of a data store
+		//	description:
+		//		See dojo.data.api.Write.newItem().
+		//	args:
+		//		A new item arguments object
+		//	returns:
+		//		A new item
+		return this.store.newItem(args); //Object
+	},
+
+	deleteItem: function(/*Object*/item){
+		//	summary:
+		//		Call deleteItem() method of a data store
+		//	description:
+		//		See dojo.data.api.Write.deleteItem().
+		//	returns:
+		//		A boolean
+		return this.store.deleteItem(item); //Boolean
+	},
+
+	revert: function(){
+		//	summary:
+		//		Call revert() method of a data store
+		//	description:
+		//		See dojo.data.api.Write.revert().
+		//	returns:
+		//		A boolean
+		return this.store.revert(); //Boolean
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Invocation.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Invocation.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Invocation.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,168 @@
+dojo.provide("dojox.wire.ml.Invocation");
+
+dojo.require("dojox.wire.ml.Action");
+
+dojo.declare("dojox.wire.ml.Invocation",
+	dojox.wire.ml.Action, {
+	//	summary:
+	//		A widget to invoke a method or publish a topic
+	//	description:
+	//		This widget represents a controller task to invoke a method or
+	//		publish a topic when an event (a function) or a topic is issued.
+	//	object:
+	//		A scope of a method to invoke
+	//	method:
+	//		A name of a method to invoke
+	//	topic:
+	//		A name of a topic to publish
+	//	parameters:
+	//		Arguments for the method or the topic
+	//	result:
+	//		A property to store a return value of the method call
+	//	error:
+	//		A property to store an error on the method call
+	object: "",
+	method: "",
+	topic: "",
+	parameters: "",
+	result: "",
+	error: "",
+
+	_run: function(){
+		//	summary:
+		//		Invoke a method or publish a topic
+		//	description:
+		//		If 'topic' is specified, the topic is published with arguments
+		//		specified to 'parameters'.
+		//		If 'method' and 'object' are specified, the method is invoked
+		//		with arguments specified to 'parameters' and set the return
+		//		value to a property specified to 'result'.
+		//		'object', 'parameters' and 'result' can specify properties of
+		//		a widget or an DOM element with the dotted notation.
+		//		If 'parameters' are omitted, the arguments to this method are
+		//		passed as is.
+		if(this.topic){
+			var args = this._getParameters(arguments);
+			try{
+				dojo.publish(this.topic, args);
+				this.onComplete();
+			}catch(e){
+				this.onError(e);
+			}
+		}else if(this.method){
+			var scope = (this.object ? dojox.wire.ml._getValue(this.object) : dj_global);
+			if(!scope){
+				return; //undefined
+			}
+			var args = this._getParameters(arguments);
+			var func = scope[this.method];
+			if(!func){
+				func = scope.callMethod;
+				if(!func){
+					return; //undefined
+				}
+				args = [this.method, args];
+			}
+			try{
+				var connected = false;
+				if(scope.getFeatures){
+					var features = scope.getFeatures();
+					if((this.method == "fetch" && features["dojo.data.api.Read"]) ||
+						(this.method == "save" && features["dojo.data.api.Write"])){
+						var arg = args[0];
+						if(!arg.onComplete){
+							arg.onComplete = function(){};
+						}
+						//dojo.connect(arg, "onComplete", this, "onComplete");
+						this.connect(arg, "onComplete", "onComplete");
+                        if(!arg.onError){
+							arg.onError = function(){};
+						}
+						//dojo.connect(arg, "onError", this, "onError");
+						this.connect(arg, "onError", "onError");
+                        connected = true;
+					}
+				}
+				var r = func.apply(scope, args);
+				if(!connected){
+					if(r && (r instanceof dojo.Deferred)){
+						var self = this;
+						r.addCallbacks(
+							function(result){self.onComplete(result);},
+							function(error){self.onError(error);}
+						);
+					}else{
+						this.onComplete(r);
+					}
+				}
+			}catch(e){
+				this.onError(e);
+			}
+		}
+	},
+
+	onComplete: function(/*anything*/result){
+		//	summary:
+		//		A function called when the method or the topic publish
+		//		completed
+		//	description:
+		//		If 'result' attribute is specified, the result object also set
+		//		to the specified property.
+		//	result:
+		//		The return value of a method or undefined for a topic
+		if(this.result){
+			dojox.wire.ml._setValue(this.result, result);
+		}
+		if(this.error){ // clear error
+			dojox.wire.ml._setValue(this.error, "");
+		}
+	},
+
+	onError: function(/*anything*/error){
+		//	summary:
+		//		A function called on an error occurs
+		//	description:
+		//		If 'error' attribute is specified, the error object also set to
+		//		the specified property.
+		//	error:
+		//		The exception or error occurred
+		if(this.error){
+			if(error && error.message){
+				error = error.message;
+			}
+			dojox.wire.ml._setValue(this.error, error);
+		}
+	},
+
+	_getParameters: function(/*Array*/args){
+		//	summary:
+		//		Returns arguments to a method or topic to invoke
+		//	description:
+		//		This method retunrs an array of arguments specified by
+		//		'parameters' attribute, a comma-separated list of IDs and
+		//		their properties in a dotted notation.
+		//		If 'parameters' are omitted, the original arguments are
+		//		used.
+		//	args:
+		//		Arguments to a trigger event or topic
+		if(!this.parameters){
+		 	// use arguments as is
+			return args; //Array
+		}
+		var parameters = [];
+		var list = this.parameters.split(",");
+		if(list.length == 1){
+			var parameter = dojox.wire.ml._getValue(list[0]);
+			if(dojo.isArray(parameter)){
+				parameters = parameter;
+			}else{
+				parameters.push(parameter);
+			}
+		}else{
+			for(var i in list){
+				parameters.push(dojox.wire.ml._getValue(list[i]));
+			}
+		}
+		return parameters; //Array
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Service.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Service.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Service.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,325 @@
+dojo.provide("dojox.wire.ml.Service");
+dojo.provide("dojox.wire.ml.RestHandler");
+dojo.provide("dojox.wire.ml.XmlHandler");
+dojo.provide("dojox.wire.ml.JsonHandler");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dojox.data.dom");
+dojo.require("dojox.wire._base");
+dojo.require("dojox.wire.ml.util");
+
+dojo.declare("dojox.wire.ml.Service",
+	dijit.base.Widget, {
+	//	summary:
+	//		A widget for a service
+	//	description:
+	//		This widget represents a service defined by a service description
+	//		specified with 'url' attribute.
+	//		If 'serviceType' and 'serviceUrl' attributes are specified, 'url'
+	//		attribute can be omitted.
+	//	url:
+	//		A URL to a service description
+	//	serviceUrl:
+	//		A URL to a service
+	//	serviceType:
+	//		A service type
+	//	handlerClass:
+	//		A service handler class name
+	url: "",
+	serviceUrl: "",
+	serviceType: "",
+	handlerClass: "",
+
+	postCreate: function(){
+		//	summary:
+		//		Call _createHandler()
+		//	description:
+		//		See _createHandler().
+		this.handler = this._createHandler();
+	},
+
+	_handlerClasses: {
+		"TEXT": "dojox.wire.ml.RestHandler",
+		"XML": "dojox.wire.ml.XmlHandler",
+		"JSON": "dojox.wire.ml.JsonHandler",
+		"JSON-RPC": "dojo.rpc.JsonService"
+	},
+
+	_createHandler: function(){
+		//	summary:
+		//		Create a service handler
+		//	desription:
+		//		A service handler class is determined by:
+		//		1. 'handlerClass' attribute
+		//		2. 'serviceType' attribute
+		//		3. 'serviceType' property in a service description
+		//	returns:
+		//		A service handler
+		if(this.url){
+			var self = this;
+			var d = dojo.xhrGet({
+				url: this.url,
+				handleAs: "json",
+				sync: true
+			});
+			d.addCallback(function(result){
+				self.smd = result;
+			});
+			if(this.smd && !this.serviceUrl){
+				this.serviceUrl = (this.smd.serviceUrl || this.smd.serviceURL);
+			}
+		}
+		var handlerClass = undefined;
+		if(this.handlerClass){
+			handlerClass = dojox.wire._getClass(this.handlerClass);
+		}else if(this.serviceType){
+			handlerClass = this._handlerClasses[this.serviceType];
+			if(handlerClass && dojo.isString(handlerClass)){
+				handlerClass = dojox.wire._getClass(handlerClass);
+				this._handlerClasses[this.serviceType] = handlerClass;
+			}
+		}else if(this.smd && this.smd.serviceType){
+			handlerClass = this._handlerClasses[this.smd.serviceType];
+			if(handlerClass && dojo.isString(handlerClass)){
+				handlerClass = dojox.wire._getClass(handlerClass);
+				this._handlerClasses[this.smd.serviceType] = handlerClass;
+			}
+		}
+		if(!handlerClass){
+			return null; //null
+		}
+		return new handlerClass(); //Object
+	},
+
+	callMethod: function(method, parameters){
+		//	summary:
+		//		Call a service method with parameters
+		//	method:
+		//		A method name
+		//	parameters:
+		//		An array parameters
+		var deferred = new dojo.Deferred();
+		this.handler.bind(method, parameters, deferred, this.serviceUrl);
+		return deferred;
+	}
+});
+
+dojo.declare("dojox.wire.ml.RestHandler",
+	null, {
+	//	summary:
+	//		A REST service handler
+	//	description:
+	//		This class serves as a base REST service.
+	//		Sub-classes may override _getContent() and _getResult() to handle
+	//		specific content types.
+	contentType: "text/plain",
+	handleAs: "text",
+
+	bind: function(method, parameters, deferred, url){
+		//	summary:
+		//		Call a service method with parameters.
+		//	description:
+		//		A service is called with a URL generated by _getUrl() and
+		//		an HTTP method specified with 'method'.
+		//		For "POST" and "PUT", a content is generated by _getContent().
+		//		When data is loaded, _getResult() is used to pass the result to
+		//		Deferred.callback().
+		//	method:
+		//		A method name
+		//	parameters:
+		//		An array of parameters
+		//	deferred:
+		//		'Deferred'
+		//	url:
+		//		A URL for the method
+		method = method.toUpperCase();
+		var self = this;
+		var args = {
+			url: this._getUrl(method, parameters, url),
+			postData: this._getContent(method, parameters),
+			contentType: this.contentType,
+			handleAs: this.handleAs
+		};
+		// TODO: support this.headers?
+		var d = null;
+		if(method == "POST"){
+			d = dojo.rawXhrPost(args);
+		}
+		// TODO: support "PUT" and "DELETE"
+		else{ // "GET"
+			d = dojo.xhrGet(args);
+		}
+		d.addCallbacks(function(result){
+			deferred.callback(self._getResult(result));
+		}, function(error){
+			deferred.errback(error);
+		});
+	},
+
+	_getUrl: function(/*String*/method, /*Array*/parameters, /*String*/url){
+		//	summary:
+		//		Generate a URL
+		//	description:
+		//		If 'method' is "GET" or "DELETE", a query string is generated
+		//		from a query object specified to the first parameter in
+		//		'parameters' and appended to 'url'.
+		//		If 'url' contains variable seguments ("{parameter_name}"),
+		//		they are replaced with corresponding parameter values, instead.
+		//	method:
+		//		A method name
+		//	parameters:
+		//		An array of parameters
+		//	url:
+		//		A base URL
+		//	returns:
+		//		A URL
+		if(method == "GET" || method == "DELETE"){
+			var query = parameters[0];
+			var queryString = "";
+			for(var name in query){
+				var value = query[name];
+				if(value){
+					var variable = "{" + name + "}";
+					var index = url.indexOf(variable);
+					if(index >= 0){ // encode in path
+						url = url.substring(0, index) + value + url.substring(index + variable.length);
+					}else{ // encode as query string
+						if(queryString){
+							queryString += "&";
+						}
+						queryString += (name + "=" + value);
+					}
+				}
+			}
+			if(queryString){
+				url += "?" + queryString;
+			}
+		}
+		return url; //String
+	},
+
+	_getContent: function(/*String*/method, /*Array*/parameters){
+		//	summary:
+		//		Generate a request content
+		//	description:
+		//		If 'method' is "POST" or "PUT", the first parameter in
+		//		'parameters' is returned.
+		//	method:
+		//		A method name
+		//	parameters:
+		//		An array of parameters
+		//	returns:
+		//		A request content
+		if(method == "POST" || method == "PUT"){
+			return (parameters ? parameters[0] : null); //anything
+		}else{
+			return null; //null
+		}
+	},
+
+	_getResult: function(/*anything*/data){
+		//	summary:
+		//		Extract a result
+		//	description:
+		//		A response data is returned as is.
+		//	data:
+		//		A response data returned by a service
+		//	returns:
+		//		A result object
+		return data; //anything
+	}
+});
+
+dojo.declare("dojox.wire.ml.XmlHandler",
+	dojox.wire.ml.RestHandler, {
+	//	summary:
+	//		A REST service handler for XML
+	//	description:
+	//		This class provides XML handling for a REST service.
+	contentType: "text/xml",
+	handleAs: "xml",
+
+	_getContent: function(/*String*/method, /*Array*/parameters){
+		//	description:
+		//		If 'method' is "POST" or "PUT", the first parameter in
+		//		'parameters' is used to generate an XML content.
+		//	method:
+		//		A method name
+		//	parameters:
+		//		An array of parameters
+		//	returns:
+		//		A request content
+		var content = null;
+		if(method == "POST" || method == "PUT"){
+			var p = parameters[0];
+			if(p){
+				if(dojo.isString(p)){
+					content = p;
+				}else{
+					var element = p;
+					if(element instanceof dojox.wire.ml.XmlElement){
+						element = element.element;
+					}else if(element.nodeType === 9 /* DOCUMENT_NODE */){
+						element = element.documentElement;
+					}
+					var declaration = "<?xml version=\"1.0\"?>"; // TODO: encoding?
+					content = declaration + dojox.data.dom.innerXML(element);
+				}
+			}
+		}
+		return content;
+	},
+
+	_getResult: function(/*Document*/data){
+		//	summary:
+		//		Extract a result
+		//	description:
+		//		A response data (XML Document) is returned wrapped with
+		//		XmlElement.
+		//	data:
+		//		A response data returned by a service
+		//	returns:
+		//		A result object
+		if(data){
+			data = new dojox.wire.ml.XmlElement(data);
+		}
+		return data;
+	}
+});
+
+dojo.declare("dojox.wire.ml.JsonHandler",
+	dojox.wire.ml.RestHandler, {
+	//	summary:
+	//		A REST service handler for JSON
+	//	description:
+	//		This class provides JSON handling for a REST service.
+	contentType: "text/json",
+	handleAs: "json",
+	headers: {"Accept": "*/json"},
+
+	_getContent: function(/*String*/method, /*Array*/parameters){
+		//	summary:
+		//		Generate a request content
+		//	description:
+		//		If 'method' is "POST" or "PUT", the first parameter in
+		//		'parameter' is used to generate a JSON content.
+		//	method:
+		//		A method name
+		//	parameters:
+		//		An array of parameters
+		//	returns:
+		//		A request content
+		var content = null;
+		if(method == "POST" || method == "PUT"){
+			var p = (parameters ? parameters[0] : undefined);
+			if(p){
+				if(dojo.isString(p)){
+					content = p;
+				}else{
+					content = dojo.toJson(p);
+				}
+			}
+		}
+		return content; //String
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Transfer.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Transfer.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/ml/Transfer.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,360 @@
+dojo.provide("dojox.wire.ml.Transfer");
+dojo.provide("dojox.wire.ml.ChildWire");
+dojo.provide("dojox.wire.ml.ColumnWire");
+dojo.provide("dojox.wire.ml.NodeWire");
+dojo.provide("dojox.wire.ml.SegmentWire");
+
+dojo.require("dijit.base.Widget");
+dojo.require("dijit.base.Container");
+dojo.require("dojox.wire._base");
+dojo.require("dojox.wire.ml.Action");
+
+dojo.declare("dojox.wire.ml.Transfer",
+	dojox.wire.ml.Action, {
+	//	summary:
+	//		A widget to transfer values through source and target Wires
+	//	description:
+	//		This widget represents a controller task to transfer a value from
+	//		a source to a target, through a source and a target Wires, when
+	//		an event (a function) or a topic is issued.
+	//		If this widget has child ChildWire widgets, their _addWire()
+	//		methods are called to add Wire arguments to a source or a target
+	//		Wire.
+	//	source:
+	//		A source object and/or property
+	//	sourceStore:
+	//		A data store for a source data item
+	//	sourceAttribute:
+	//		An attribute of a source data item
+	//	sourcePath:
+	//		A simplified XPath to a source property of an XML element
+	//	type:
+	//		A type of the value to be transferred
+	//	converter:
+	//		A class name of a converter for the value to be transferred
+	//	target:
+	//		A target object and/or property
+	//	targetStore:
+	//		A data store for a target data item
+	//	targetAttribute:
+	//		An attribute of a target data item
+	//	targetPath:
+	//		A simplified XPath to a target property of an XML element
+	source: "",
+	sourceStore: "",
+	sourceAttribute: "",
+	sourcePath: "",
+	type: "",
+	converter: "",
+	delimiter: "",
+	target: "",
+	targetStore: "",
+	targetAttribute: "",
+	targetPath: "",
+
+	_run: function(){
+		//	summary:
+		//		Transfer a value from a source to a target
+		//	description:
+		//		First, Wires for a source and a target are created from attributes.
+		//		Then, a value is obtained by getValue() of the source Wire is set
+		//		by setValue() of the target Wire.
+		//		The arguments to this method is passed to getValue() and setValue()
+		//		of Wires, so that they can be used to identify the root objects off
+		//		the arguments.
+		var sourceWire = this._getWire("source");
+		var targetWire = this._getWire("target");
+		dojox.wire.transfer(sourceWire, targetWire, arguments);
+	},
+
+	_getWire: function(/*String*/which){
+		//	summary:
+		//		Build Wire arguments from attributes
+		//	description:
+		//		Arguments object for a source or a target Wire, specified by
+		//		'which' argument, are build from corresponding attributes,
+		//		including '*Store' (for 'dataStore'), '*Attribute'
+		//		(for 'attribute), '*Path' (for 'path'), 'type' and 'converter'.
+		//		'source' or 'target' attribute is parsed as:
+		//			"object_id.property_name[.sub_property_name...]"
+		//		If 'source' or 'target' starts with "arguments", 'object'
+		//		argument for a Wire is set to null, so that the root object is
+		//		given as an event or topic arguments.
+		//		If this widget has child ChildWire widgets with a corresponding
+		//		'which' attribute, their _addWire() methods are called to add
+		//		additional Wire arguments and nested Wire is created,
+		//		specifying the Wire defined by this widget to 'object' argument.
+		//	which:
+		//		Which Wire arguments to build, "source" or "target"
+		//	returns:
+		//		Wire arguments object
+		var args = undefined;
+		if(which == "source"){
+			args = {
+				object: this.source,
+				dataStore: this.sourceStore,
+				attribute: this.sourceAttribute,
+				path: this.sourcePath,
+				type: this.type,
+				converter: this.converter
+			};
+		}else{ // "target"
+			args = {
+				object: this.target,
+				dataStore: this.targetStore,
+				attribute: this.targetAttribute,
+				path: this.targetPath
+			};
+		}
+		if(args.object){
+			if(args.object.length >= 9 && args.object.substring(0, 9) == "arguments"){
+				args.property = args.object.substring(9);
+				args.object = null;
+			}else{
+				var i = args.object.indexOf('.');
+				if(i < 0){
+					args.object = dojox.wire.ml._getValue(args.object);
+				}else{
+					args.property = args.object.substring(i + 1);
+					args.object = dojox.wire.ml._getValue(args.object.substring(0, i));
+				}
+			}
+		}
+		if(args.dataStore){
+			args.dataStore = dojox.wire.ml._getValue(args.dataStore);
+		}
+		var childArgs = undefined;
+		var children = this.getChildren();
+		for(var i in children){
+			var child = children[i];
+			if(child instanceof dojox.wire.ml.ChildWire && child.which == which){
+				if(!childArgs){
+					childArgs = {};
+				}
+				child._addWire(this, childArgs);
+			}
+		}
+		if(childArgs){ // make nested Wires
+			childArgs.object = dojox.wire.create(args);
+			childArgs.dataStore = args.dataStore;
+			args = childArgs;
+		}
+		return args; //Object
+	}
+});
+
+dojo.declare("dojox.wire.ml.ChildWire",
+	dijit.base.Widget, {
+	//	summary:
+	//		A widget to add a child wire
+	//	description:
+	//		Attributes of this widget are used to add a child Wire to
+	//		a composite Wire of the parent Transfer widget.
+	//	which:
+	//		Which Wire to add a child Wire, "source" or "target", default to
+	//		"source"
+	//	object:
+	//		A root object for the value
+	//	property:
+	//		A property for the value
+	//	type:
+	//		A type of the value
+	//	converter:
+	//		A class name of a converter for the value
+	//	attribute:
+	//		A data item attribute for the value
+	//	path:
+	//		A simplified XPath for the value
+	//	name:
+	//		A composite property name
+	which: "source",
+	object: "",
+	property: "",
+	type: "",
+	converter: "",
+	attribute: "",
+	path: "",
+	name: "",
+
+	_addWire: function(/*Transfer*/parent, /*Object*/args){
+		//	summary:
+		//		Add a child Wire to Wire arguments
+		//	description:
+		//		If 'name' attribute is specified, a child Wire is added as
+		//		the named property of 'children' object of 'args'.
+		//		Otherwise, a child Wire is added to 'children' array of 'args'.
+		//	parent:
+		//		A parent Transfer widget
+		//	args:
+		//		Wire arguments
+		if(this.name){ // object
+			if(!args.children){
+				args.children = {};
+			}
+			args.children[this.name] = this._getWire(parent);
+		}else{ // array
+			if(!args.children){
+				args.children = [];
+			}
+			args.children.push(this._getWire(parent));
+		}
+	},
+
+	_getWire: function(/*Transfer*/parent){
+		//	summary:
+		//		Build child Wire arguments from attributes
+		//	description:
+		//		Arguments object for a child Wire are build from attributes,
+		//		including 'object', 'property', 'type', 'converter',
+		//		'attribute' and 'path'.
+		//	parent:
+		//		A parent Transfer widget
+		//	returns:
+		//		Wire arguments object
+		return {
+			object: (this.object ? dojox.wire.ml._getValue(this.object) : undefined),
+			property: this.property,
+			type: this.type,
+			converter: this.converter,
+			attribute: this.attribute,
+			path: this.path
+		}; //Object
+	}
+});
+
+dojo.declare("dojox.wire.ml.ColumnWire",
+	dojox.wire.ml.ChildWire, {
+	//	summary:
+	//		A widget to add a column wire
+	//	description:
+	//		Attributes of this widget are used to add a column Wire to
+	//		a TableAdapter of the parent Transfer widget.
+	//	column:
+	//		A column name
+	column: "",
+
+	_addWire: function(/*Transfer*/parent, /*Object*/args){
+		//	summary:
+		//		Add a column Wire to Wire arguments
+		//	description:
+		//		If 'column' attribute is specified, a column Wire is added as
+		//		the named property of 'columns' object of 'args'.
+		//		Otherwise, a column Wire is added to 'columns' array of 'args'.
+		//	parent:
+		//		A parent Transfer widget
+		//	args:
+		//		Wire arguments
+		if(this.column){ // object
+			if(!args.columns){
+				args.columns = {};
+			}
+			args.columns[this.column] = this._getWire(parent);
+		}else{ // array
+			if(!args.columns){
+				args.columns = [];
+			}
+			args.columns.push(this._getWire(parent));
+		}
+	}
+});
+
+dojo.declare("dojox.wire.ml.NodeWire",
+	[dojox.wire.ml.ChildWire, dijit.base.Container], {
+	//	summary:
+	//		A widget to add node wires
+	//	description:
+	//		Attributes of this widget are used to add node Wires to
+	//		a TreeAdapter of the parent Transfer widget.
+	//	titleProperty:
+	//		A property for the node title
+	//	titleAttribute:
+	//		A data item attribute for the node title
+	//	titlePath:
+	//		A simplified XPath for the node title
+	titleProperty: "",
+	titleAttribute: "",
+	titlePath: "",
+
+	_addWire: function(/*Transfer*/parent, /*Object*/args){
+		//	summary:
+		//		Add node Wires to Wire arguments
+		//	description:
+		//		Node Wires are added to 'nodes' array of 'args'.
+		//	parent:
+		//		A parent Transfer widget
+		//	args:
+		//		Wire arguments
+		if(!args.nodes){
+			args.nodes = [];
+		}
+		args.nodes.push(this._getWires(parent));
+	},
+
+	_getWires: function(/*Transfer*/parent){
+		//	summary:
+		//		Build node Wires arguments from attributes
+		//	description:
+		//		Arguments object for 'node' Wire are build from attributes,
+		//		including 'object', 'property', 'type', 'converter',
+		//		'attribute' and 'path'.
+		//		Arguments object for 'title' Wire are build from another set of
+		//		attributes, 'titleProperty', 'titleAttribute' and 'titlePath'.
+		//		If this widget has child NodeWire widgets, their _getWires()
+		//		methods are called recursively to build 'children' array of
+		//		'args'.
+		//	parent:
+		//		A parent Transfer widget
+		//	returns:
+		//		Wire arguments object
+		var args = {
+			node: this._getWire(parent),
+			title: {
+				type: "string",
+				property: this.titleProperty,
+				attribute: this.titleAttribute,
+				path: this.titlePath
+			}
+		};
+		var childArgs = [];
+		var children = this.getChildren();
+		for(var i in children){
+			var child = children[i];
+			if(child instanceof dojox.wire.ml.NodeWire){
+				childArgs.push(child._getWires(parent));
+			}
+		}
+		if(childArgs.length > 0){
+			args.children = childArgs;
+		}
+		return args; //Object
+	}
+});
+
+dojo.declare("dojox.wire.ml.SegmentWire",
+	dojox.wire.ml.ChildWire, {
+	//	summary:
+	//		A widget to add a segment wire
+	//	description:
+	//		Attributes of this widget are used to add a segment Wire to
+	//		a TextAdapter of the parent Transfer widget.
+
+	_addWire: function(/*Transfer*/parent, /*Object*/args){
+		//	summary:
+		//		Add a segument Wire to Wire arguments
+		//	description:
+		//		A segment Wire is added to 'segments' array of 'args'.
+		//		If 'parent' has 'delimiter' attribute, it is used for
+		//		'delimiter' property of 'args'.
+		//	parent:
+		//		A parent Transfer widget
+		//	args:
+		//		Wire arguments
+		if(!args.segments){
+			args.segments = [];
+		}
+		args.segments.push(this._getWire(parent));
+		if(parent.delimiter && !args.delimiter){
+			args.delimiter = parent.delimiter;
+		}
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/ml/util.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/ml/util.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/ml/util.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,292 @@
+dojo.provide("dojox.wire.ml.util");
+
+dojo.require("dijit.util.manager");
+dojo.require("dojox.data.dom");
+dojo.require("dojox.wire.Wire");
+
+dojox.wire.ml._getValue = function(/*String*/source, /*Array*/args){
+	//	summary:
+	//		Return a value
+	//	description:
+	//		This method obtains an object by an ID of a widget or an DOM
+	//		element.
+	//		If 'source' specifies a dotted notation to its property, a Wire is
+	//		used to get the object property.
+	//		If 'source' starts with "arguments", 'args' is used as a root
+	//		object for the Wire.
+	//	source:
+	//		A string to specify an object and its property
+	//	args:
+	//		An optional arguments array
+	//	returns:
+	//		A value
+	if(!source){
+		return undefined; //undefined
+	}
+	var property = undefined;
+	if(args && source.length >= 9 && source.substring(0, 9) == "arguments"){
+		property = this.required.substring(9);
+		return new dojox.wire.Wire({property: property}).getValue(args);
+	}
+	var i = source.indexOf('.');
+	if(i >= 0){
+		property = source.substring(i + 1);
+		source = source.substring(0, i);
+	}
+	var object = (dijit.byId(source) || dojo.byId(source) || dojo.getObject(source));
+	if(!object){
+		return undefined; //undefined
+	}
+	if(!property){
+		return object; //Object
+	}else{
+		return new dojox.wire.Wire({object: object, property: property}).getValue(); //anything
+	}
+};
+
+dojox.wire.ml._setValue = function(/*String*/target, /*anything*/value){
+	//	summary:
+	//		Store a value
+	//	description:
+	//		This method stores a value by an ID of a widget or an DOM
+	//		element with a dotted notation to its property, using a Wire.
+	//	target:
+	//		A string to specify an object and its property
+	//	value:
+	//		A value
+	if(!target){
+		return; //undefined
+	}
+	var i = target.indexOf('.');
+	if(i < 0){
+		return; //undefined
+	}
+	var object = this._getValue(target.substring(0, i));
+	if(!object){
+		return; //undefined
+	}
+	var property = target.substring(i + 1);
+	new dojox.wire.Wire({object: object, property: property}).setValue(value);
+};
+
+dojo.declare("dojox.wire.ml.XmlElement",
+	null,
+	function(/*Element||String*/element){
+		//	summary:
+		//		Initialize with an XML element or a tag name
+		//	element:
+		//		An XML element or a tag name
+		if(dojo.isString(element)){
+			element = this._getDocument().createElement(element);
+		}
+		this.element = element;
+	}, {
+	//	summary:
+	//		An object wrapping an XML element
+	//	description:
+	//		This class represents an XML element.
+
+	getPropertyValue: function(/*String*/property){
+		//	summary:
+		//		Return a property value
+		//	description:
+		//		If 'property' starts with '@', the attribute value is returned.
+		//		If 'property' specifies "text()", the value of the first child
+		//		text is returned.
+		//		Otherwise, child elements of the tag name specified with
+		//		'property' are returned.
+		//	property:
+		//		A property name
+		//	returns:
+		//		A property value
+		var value = undefined;
+		if(!this.element){
+			return value; //undefined
+		}
+		if(!property){
+			return value; //undefined
+		}
+
+		if(property.charAt(0) == '@'){
+			var attribute = property.substring(1);
+			value = this.element.getAttribute(attribute);
+		}else if(property == "text()"){
+			var text = this.element.firstChild;
+			if(text){
+				value = text.nodeValue;
+			}
+		}else{ // child elements
+			var elements = [];
+			for(var i = 0; i < this.element.childNodes.length; i++){
+				var child = this.element.childNodes[i];
+				if(child.nodeName == property){
+					elements.push(new dojox.wire.ml.XmlElement(child));
+				}
+			}
+			if(elements.length > 0){
+				if(elements.length === 1){
+					value = elements[0];
+				}else{
+					value = elements;
+				}
+			}
+		}
+		return value; //String||Array||XmlElement
+	},
+
+	setPropertyValue: function(/*String*/property, /*String||Array||XmlElement*/value){
+		//	summary:
+		//		Store a property value
+		//	description:
+		//		If 'property' starts with '@', 'value' is set to the attribute.
+		//		If 'property' specifies "text()", 'value' is set as the first
+		//		child text.
+		//		If 'value' is a string, a child element of the tag name
+		//		specified with 'property' is created and 'value' is set as
+		//		the first child text of the child element.
+		//		Otherwise, 'value' is set to as child elements.
+		//	property:
+		//		A property name
+		//	value:
+		//		A property value
+		if(!this.element){
+			return; //undefined
+		}
+		if(!property){
+			return; //undefined
+		}
+
+		if(property.charAt(0) == '@'){
+			var attribute = property.substring(1);
+			if(value){
+				this.element.setAttribute(attribute, value);
+			}else{
+				this.element.removeAttribute(attribute);
+			}
+		}else if(property == "text()"){
+			while(this.element.firstChild){
+				this.element.removeChild(this.element.firstChild);
+			}
+			if(value){
+				var text = this._getDocument().createTextNode(value);
+				this.element.appendChild(text);
+			}
+		}else{ // child elements
+			var nextChild = null;
+			for(var i = this.element.childNodes.length - 1; i >= 0; i--){
+				var child = this.element.childNodes[i];
+				if(child.nodeName == property){
+					if(!nextChild){
+						nextChild = child.nextSibling;
+					}
+					this.element.removeChild(child);
+				}
+			}
+			if(value){
+				if(dojo.isArray(value)){
+					for(var i in value){
+						var e = value[i];
+						if(e.element){
+							this.element.insertBefore(e.element, nextChild);
+						}
+					}
+				}else if(value instanceof dojox.wire.ml.XmlElement){
+					if(value.element){
+						this.element.insertBefore(value.element, nextChild);
+					}
+				}else{ // assume string
+					var child = this._getDocument().createElement(property);
+					var text = this._getDocument().createTextNode(value);
+					child.appendChild(text);
+					this.element.insertBefore(child, nextChild);
+				}
+			}
+		}
+	},
+
+	toString: function(){
+		//	summary:
+		//		Return a value of the first text child of the element
+		//	description:
+		//		A value of the first text child of the element is returned.
+		//	returns:
+		//		A value of the first text child of the element
+		var s = "";
+		if(this.element){
+			var text = this.element.firstChild;
+			if(text){
+				s = text.nodeValue;
+			}
+		}
+		return s; //String
+	},
+
+	toObject: function(){
+		//	summary:
+		//		Return an object representation of the element
+		//	description:
+		//		An object with properties for child elements, attributes and
+		//		text is returned.
+		//	returns:
+		//		An object representation of the element
+		if(!this.element){
+			return null; //null
+		}
+		var text = "";
+		var obj = {};
+		var elements = 0;
+		for(var i = 0; i < this.element.childNodes.length; i++){
+			var child = this.element.childNodes[i];
+			if(child.nodeType === 1 /* ELEMENT_NODE */){
+				elements++;
+				var o = new dojox.wire.ml.XmlElement(child).toObject();
+				var name = child.nodeName;
+				var p = obj[name];
+				if(!p){
+					obj[name] = o;
+				}else if(dojo.isArray(p)){
+					p.push(o);
+				}else{
+					obj[name] = [p, o]; // make them array
+				}
+			}else if(child.nodeType === 3 /* TEXT_NODE */){
+				text += child.nodeValue;
+			}
+		}
+		var attributes = 0;
+		if(this.element.nodeType === 1 /* ELEMENT_NODE */){
+			attributes = this.element.attributes.length;
+			for(var i = 0; i < attributes; i++){
+				var attr = this.element.attributes[i];
+				obj["@" + attr.nodeName] = attr.nodeValue;
+			}
+		}
+		if(elements === 0){
+			if(attributes === 0){
+				// text only
+				return text; //String
+			}
+			// text with attributes
+			obj["text()"] = text;
+		}
+		// else ignore text
+		return obj; //Object
+	},
+
+	_getDocument: function(){
+		//	summary:
+		//		Return a DOM document
+		//	description:
+		//		If 'element' is specified, a DOM document of the element is
+		//		returned.
+		//		Otherwise, a DOM document is created.
+		//	returns:
+		//		A DOM document
+		if(this.element){
+			return (this.element.nodeType == 9 /* DOCUMENT_NODE */ ?
+				this.element : this.element.ownerDocument); //Document
+		}else{
+			return dojox.data.dom.createDocument(); //Document
+		}
+	}
+});

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Action.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Action.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Action.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,77 @@
+<html>
+<head>
+<title>Test Action</title>
+<script type="text/javascript" src="../../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+dojo.provide("dojox.wire.ml.tests.markup.Action");
+
+dojo.require("dijit.util.parser");
+dojo.require("doh.runner");
+dojo.require("dojox.wire.ml.Action");
+dojo.require("dojox.wire.ml.Transfer");
+
+dojox.wire.ml.tests.markup.Action = {
+	transfer: function(){},
+	source: {a: "A", b: "B"}
+};
+
+dojo.addOnLoad(function(){
+	doh.register("dojox.wire.ml.tests.markup.Action", [
+
+		function test_Action_triggerEvent(t){
+			dojox.wire.ml.tests.markup.Action.target = {};
+			dojox.wire.ml.tests.markup.Action.transfer();
+			t.assertEqual(dojox.wire.ml.tests.markup.Action.source.a, dojox.wire.ml.tests.markup.Action.target.a);
+			t.assertEqual(dojox.wire.ml.tests.markup.Action.source.b, dojox.wire.ml.tests.markup.Action.target.b);
+		},
+
+		function test_Action_triggerTopic(t){
+			dojox.wire.ml.tests.markup.Action.target = {};
+			dojo.publish("transfer");
+			t.assertEqual(dojox.wire.ml.tests.markup.Action.source.a, dojox.wire.ml.tests.markup.Action.target.a);
+		},
+
+		function test_ActionFilter_required(t){
+			dojox.wire.ml.tests.markup.Action.target = {};
+			dojo.publish("transferFilter");
+			t.assertEqual(undefined, dojox.wire.ml.tests.markup.Action.target.a);
+			t.assertEqual("no required", dojox.wire.ml.tests.markup.Action.error);
+			dojox.wire.ml.tests.markup.Action.required = true;
+			dojo.publish("transferFilter");
+			t.assertEqual(dojox.wire.ml.tests.markup.Action.source.a, dojox.wire.ml.tests.markup.Action.target.a);
+		}
+
+	]);
+	doh.run();
+});
+</script>
+</head>
+<body>
+<div dojoType="dojox.wire.ml.Action"
+	trigger="dojox.wire.ml.tests.markup.Action"
+	triggerEvent="transfer">
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="dojox.wire.ml.tests.markup.Action.source.a"
+		target="dojox.wire.ml.tests.markup.Action.target.a"></div>
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="dojox.wire.ml.tests.markup.Action.source.b"
+		target="dojox.wire.ml.tests.markup.Action.target.b"></div>
+</div>
+<div dojoType="dojox.wire.ml.Action"
+	triggerTopic="transfer">
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="dojox.wire.ml.tests.markup.Action.source.a"
+		target="dojox.wire.ml.tests.markup.Action.target.a"></div>
+</div>
+<div dojoType="dojox.wire.ml.Action"
+	triggerTopic="transferFilter">
+	<div dojoType="dojox.wire.ml.ActionFilter"
+		required="dojox.wire.ml.tests.markup.Action.required"
+		message="no required"
+		error="dojox.wire.ml.tests.markup.Action.error"></div>
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="dojox.wire.ml.tests.markup.Action.source.a"
+		target="dojox.wire.ml.tests.markup.Action.target.a"></div>
+</div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Data.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Data.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Data.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,105 @@
+<html>
+<head>
+<title>Test Data</title>
+<script type="text/javascript" src="../../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+dojo.provide("dojox.wire.ml.tests.markup.Data");
+
+dojo.require("dijit.util.parser");
+dojo.require("doh.runner");
+dojo.require("dojox.wire.ml.Action");
+dojo.require("dojox.wire.ml.Data");
+dojo.require("dojox.wire.ml.Transfer");
+
+dojox.wire.ml.tests.markup.Data = {};
+
+dojo.addOnLoad(function(){
+	doh.register("dojox.wire.ml.tests.markup.Data", [
+
+		function test_DataProperty(t){
+			dojox.wire.ml.tests.markup.Data.target = {};
+			dojo.publish("transfer");
+			t.assertEqual("A", dojox.wire.ml.tests.markup.Data.target.a);
+			t.assertEqual(1, dojox.wire.ml.tests.markup.Data.target.b);
+			t.assertEqual(true, dojox.wire.ml.tests.markup.Data.target.c);
+			t.assertEqual("DA", dojox.wire.ml.tests.markup.Data.target.d.a);
+			t.assertEqual("DB", dojox.wire.ml.tests.markup.Data.target.d.b);
+			t.assertEqual("E1", dojox.wire.ml.tests.markup.Data.target.e[0]);
+			t.assertEqual("E2", dojox.wire.ml.tests.markup.Data.target.e[1]);
+			t.assertEqual("F", dojox.wire.ml.tests.markup.Data.target.f);
+			t.assertEqual("G", dojox.wire.ml.tests.markup.Data.target.g);
+		}
+
+	]);
+	doh.run();
+});
+</script>
+</head>
+<body>
+<div dojoType="dojox.wire.ml.Data"
+	id="Data1">
+	<div dojoType="dojox.wire.ml.DataProperty"
+		name="a"
+		value="A"></div>
+	<div dojoType="dojox.wire.ml.DataProperty"
+		name="b"
+		type="number" value="1"></div>
+	<div dojoType="dojox.wire.ml.DataProperty"
+		name="c"
+		type="boolean" value="true"></div>
+	<div dojoType="dojox.wire.ml.DataProperty"
+		name="d"
+		type="object">
+		<div dojoType="dojox.wire.ml.DataProperty"
+			name="a"
+			value="DA"></div>
+		<div dojoType="dojox.wire.ml.DataProperty"
+			name="b"
+			value="DB"></div>
+	</div>
+	<div dojoType="dojox.wire.ml.DataProperty"
+		name="e"
+		type="array">
+		<div dojoType="dojox.wire.ml.DataProperty"
+			value="E1"></div>
+		<div dojoType="dojox.wire.ml.DataProperty"
+			value="E2"></div>
+	</div>
+	<div dojoType="dojox.wire.ml.DataProperty"
+		name="f"
+		type="element"
+		value="x">
+		<div dojoType="dojox.wire.ml.DataProperty"
+			name="text()"
+			value="F"></div>
+		<div dojoType="dojox.wire.ml.DataProperty"
+			name="@y"
+			value="G"></div>
+	</div>
+</div>
+<div dojoType="dojox.wire.ml.Action"
+	triggerTopic="transfer">
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="Data1.a"
+		target="dojox.wire.ml.tests.markup.Data.target.a"></div>
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="Data1.b"
+		target="dojox.wire.ml.tests.markup.Data.target.b"></div>
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="Data1.c"
+		target="dojox.wire.ml.tests.markup.Data.target.c"></div>
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="Data1.d"
+		target="dojox.wire.ml.tests.markup.Data.target.d"></div>
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="Data1.e"
+		target="dojox.wire.ml.tests.markup.Data.target.e"></div>
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="Data1.f"
+		target="dojox.wire.ml.tests.markup.Data.target.f"></div>
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="Data1.f. at y"
+		target="dojox.wire.ml.tests.markup.Data.target.g"></div>
+</div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/DataStore.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/DataStore.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/DataStore.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,66 @@
+<html>
+<head>
+<title>Test DataStore</title>
+<script type="text/javascript" src="../../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+dojo.provide("dojox.wire.ml.tests.markup.DataStore");
+
+dojo.require("dijit.util.parser");
+dojo.require("doh.runner");
+dojo.require("dojox.wire.ml.DataStore");
+dojo.require("dojox.wire.ml.Invocation");
+dojo.require("dojox.wire.ml.Transfer");
+
+dojox.wire.ml.tests.markup.DataStore = {
+	request: {onComplete: function(){}, onError: function(){}}
+};
+
+dojo.addOnLoad(function(){
+	doh.register("dojox.wire.ml.tests.markup.DataStore", [
+
+		function test_DataStore_url(t){
+			var d = new doh.Deferred();
+			dojo.connect(dojox.wire.ml.tests.markup.DataStore.request, "onComplete", function(){
+				t.assertEqual("X1", dojox.wire.ml.tests.markup.DataStore.target[0].a);
+				t.assertEqual("Y2", dojox.wire.ml.tests.markup.DataStore.target[1].b);
+				t.assertEqual("Z3", dojox.wire.ml.tests.markup.DataStore.target[2].c);
+				d.callback(true);
+			});
+			dojo.connect(dojox.wire.ml.tests.markup.DataStore.request, "onError", function(error){
+				d.errback(error);
+			});
+			dojo.publish("invokeFetch");
+			return d;
+		}
+
+	]);
+	doh.run();
+});
+</script>
+</head>
+<body>
+<div dojoType="dojox.wire.ml.DataStore"
+	id="DataStore1"
+	storeClass="dojox.data.XmlStore"
+	url="DataStore.xml"></div>
+<div dojoType="dojox.wire.ml.Invocation"
+	triggerTopic="invokeFetch"
+	object="DataStore1"
+	method="fetch"
+	parameters="dojox.wire.ml.tests.markup.DataStore.request">
+</div>
+<div dojoType="dojox.wire.ml.Transfer"
+	trigger="dojox.wire.ml.tests.markup.DataStore.request"
+	triggerEvent="onComplete"
+	source="arguments[0]"
+	sourceStore="DataStore1.store"
+	target="dojox.wire.ml.tests.markup.DataStore.target">
+	<div dojoType="dojox.wire.ml.ColumnWire"
+		column="a" attribute="x"></div>
+	<div dojoType="dojox.wire.ml.ColumnWire"
+		column="b" attribute="y"></div>
+	<div dojoType="dojox.wire.ml.ColumnWire"
+		column="c" attribute="z"></div>
+</div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/DataStore.xml
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/DataStore.xml	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/DataStore.xml	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<dataStore>
+	<item>
+		<x>X1</x>
+		<y>Y1</y>
+		<z>Z1</z>
+	</item>
+	<item>
+		<x>X2</x>
+		<y>Y2</y>
+		<z>Z2</z>
+	</item>
+	<item>
+		<x>X3</x>
+		<y>Y3</y>
+		<z>Z3</z>
+	</item>
+</dataStore>

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Invocation.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Invocation.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Invocation.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,53 @@
+<html>
+<head>
+<title>Test Invocation</title>
+<script type="text/javascript" src="../../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+dojo.provide("dojox.wire.ml.tests.markup.Invocation");
+
+dojo.require("dijit.util.parser");
+dojo.require("doh.runner");
+dojo.require("dojox.wire.ml.Invocation");
+
+dojox.wire.ml.tests.markup.Invocation = {
+	invoke: function(p1, p2){return p1 + p2;},
+	invokeError: function(p){throw new Error(p);},
+	parameters: {a: "A", b: "B", c: "C"}
+};
+
+dojo.addOnLoad(function(){
+	doh.register("dojox.wire.ml.tests.markup.Invocation", [
+
+		function test_Invocation_method(t){
+			dojo.publish("invokeMethod");
+			t.assertEqual("AB", dojox.wire.ml.tests.markup.Invocation.result);
+		},
+
+		function test_Invocation_topic(t){
+			dojo.publish("invokeTopic");
+			t.assertEqual("C", dojox.wire.ml.tests.markup.Invocation.error);
+		}
+
+	]);
+	doh.run();
+});
+</script>
+</head>
+<body>
+<div dojoType="dojox.wire.ml.Invocation"
+	triggerTopic="invokeMethod"
+	object="dojox.wire.ml.tests.markup.Invocation"
+	method="invoke"
+	parameters="dojox.wire.ml.tests.markup.Invocation.parameters.a,dojox.wire.ml.tests.markup.Invocation.parameters.b"
+	result="dojox.wire.ml.tests.markup.Invocation.result"></div>
+<div dojoType="dojox.wire.ml.Invocation"
+	triggerTopic="invokeTopic"
+	topic="invokeError"
+	parameters="dojox.wire.ml.tests.markup.Invocation.parameters.c"></div>
+<div dojoType="dojox.wire.ml.Invocation"
+	triggerTopic="invokeError"
+	object="dojox.wire.ml.tests.markup.Invocation"
+	method="invokeError"
+	error="dojox.wire.ml.tests.markup.Invocation.error"></div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/JSON.smd
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/JSON.smd	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/JSON.smd	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,11 @@
+{
+	"serviceType": "JSON",
+	"serviceURL": "Service/{name}.json",
+	"methods": [{
+		"name": "get",
+		"parameters": [{
+			"name": "name",
+			"type": "str"
+		}]
+	}]
+}

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/XML.smd
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/XML.smd	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/XML.smd	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,11 @@
+{
+	"serviceType": "XML",
+	"serviceURL": "Service/{name}.xml",
+	"methods": [{
+		"name": "get",
+		"parameters": [{
+			"name": "name",
+			"type": "str"
+		}]
+	}]
+}

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/a.json
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/a.json	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/a.json	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+{
+	"item": {
+		"name": "a"
+	}
+}

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/a.xml
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/a.xml	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service/a.xml	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<item>
+	<name>a</name>
+</item>

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Service.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,81 @@
+<html>
+<head>
+<title>Test Service</title>
+<script type="text/javascript" src="../../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+dojo.provide("dojox.wire.ml.tests.markup.Service");
+
+dojo.require("dijit.util.parser");
+dojo.require("doh.runner");
+dojo.require("dojox.wire.ml.Service");
+dojo.require("dojox.wire.ml.Invocation");
+dojo.require("dojox.wire.ml.Transfer");
+
+dojox.wire.ml.tests.markup.Service = {
+	query: {name: "a"}
+};
+
+dojo.addOnLoad(function(){
+	doh.register("dojox.wire.ml.tests.markup.Service", [
+
+		function test_Service_url(t){
+			var d = new doh.Deferred();
+			dojo.connect(dijit.byId("Invocation1"), "onComplete", function(result){
+ 				t.assertEqual("a", dojox.wire.ml.tests.markup.Service.target.a);
+				t.assertEqual("a", result.toObject().item.name); // test XmlElement.toObject()
+ 				d.callback(true);
+ 			});
+			dojo.connect(dijit.byId("Invocation1"), "onError", function(error){
+				d.errback(error);
+			});
+			dojo.publish("invokeGetXml");
+			return d;
+		},
+
+		function test_Service_serviceUrl(t){
+			var d = new doh.Deferred();
+			dojo.connect(dijit.byId("Invocation2"), "onComplete", function(){
+				t.assertEqual("a", dojox.wire.ml.tests.markup.Service.result.item.name);
+				d.callback(true);
+			});
+			dojo.connect(dijit.byId("Invocation2"), "onError", function(error){
+				d.errback(error);
+			});
+			dojo.publish("invokeGetJson");
+			return d;
+		}
+
+	]);
+	doh.run();
+});
+</script>
+</head>
+<body>
+<div dojoType="dojox.wire.ml.Service"
+	id="Service1"
+	url="Service/XML.smd"></div>
+<div dojoType="dojox.wire.ml.Invocation"
+	id="Invocation1"
+	triggerTopic="invokeGetXml"
+	object="Service1"
+	method="get"
+	parameters="dojox.wire.ml.tests.markup.Service.query">
+</div>
+<div dojoType="dojox.wire.ml.Transfer"
+	trigger="Invocation1"
+	triggerEvent="onComplete"
+	source="arguments[0].item.name"
+	target="dojox.wire.ml.tests.markup.Service.target.a"></div>
+<div dojoType="dojox.wire.ml.Service"
+	id="Service2"
+	serviceType="JSON"
+	serviceUrl="Service/{name}.json"></div>
+<div dojoType="dojox.wire.ml.Invocation"
+	id="Invocation2"
+	triggerTopic="invokeGetJson"
+	object="Service2"
+	method="get"
+	parameters="dojox.wire.ml.tests.markup.Service.query"
+	result="dojox.wire.ml.tests.markup.Service.result"></div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Transfer.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Transfer.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/markup/Transfer.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,157 @@
+<html>
+<head>
+<title>Test Transfer</title>
+<script type="text/javascript" src="../../../../dojo/dojo.js" djConfig="isDebug: true"></script>
+<script type="text/javascript">
+dojo.provide("dojox.wire.ml.tests.markup.Transfer");
+
+dojo.require("dijit.util.parser");
+dojo.require("doh.runner");
+dojo.require("dojox.data.dom");
+dojo.require("dojox.data.XmlStore");
+dojo.require("dojox.wire.ml.Action");
+dojo.require("dojox.wire.ml.Transfer");
+
+dojox.wire.ml.tests.markup.Transfer = {
+	source: {a: "A", b: "B", c: [
+		{d: "D1", e: "E1"},
+		{d: "D2", e: "E2"}
+	]}
+};
+
+dojo.addOnLoad(function(){
+	doh.register("dojox.wire.ml.tests.markup.Transfer", [
+
+		function test_Transfer_attribute(t){
+			dojox.wire.ml.tests.markup.Transfer.store = new dojox.data.XmlStore();
+			dojox.wire.ml.tests.markup.Transfer.item = dojox.wire.ml.tests.markup.Transfer.store.newItem({tagName: "x"});
+			dojox.wire.ml.tests.markup.Transfer.target = {};
+			dojo.publish("transferData");
+			t.assertEqual(dojox.wire.ml.tests.markup.Transfer.source.a, dojox.wire.ml.tests.markup.Transfer.target.a);
+		},
+
+		function test_Transfer_path(t){
+			dojox.wire.ml.tests.markup.Transfer.element = dojox.data.dom.createDocument().createElement("x");
+			dojox.wire.ml.tests.markup.Transfer.target = {};
+			dojo.publish("transferXml");
+			t.assertEqual(dojox.wire.ml.tests.markup.Transfer.source.a, dojox.wire.ml.tests.markup.Transfer.target.a);
+		},
+
+		function test_ChildWire(t){
+			dojox.wire.ml.tests.markup.Transfer.target = {};
+			dojo.publish("transferComposite");
+			t.assertEqual(dojox.wire.ml.tests.markup.Transfer.source.a, dojox.wire.ml.tests.markup.Transfer.target.c);
+			t.assertEqual(dojox.wire.ml.tests.markup.Transfer.source.b, dojox.wire.ml.tests.markup.Transfer.target.d);
+		},
+
+		function test_ColumnWire(t){
+			dojox.wire.ml.tests.markup.Transfer.target = {};
+			dojo.publish("transferTable");
+			t.assertEqual(dojox.wire.ml.tests.markup.Transfer.source.c[0].d, dojox.wire.ml.tests.markup.Transfer.target.a[0].b);
+			t.assertEqual(dojox.wire.ml.tests.markup.Transfer.source.c[1].e, dojox.wire.ml.tests.markup.Transfer.target.a[1].c);
+		},
+
+		function test_NodeWire(t){
+			dojox.wire.ml.tests.markup.Transfer.target = {};
+			dojo.publish("transferTree");
+			t.assertEqual(dojox.wire.ml.tests.markup.Transfer.source.c[0].d, dojox.wire.ml.tests.markup.Transfer.target.a[0].title);
+			t.assertEqual(dojox.wire.ml.tests.markup.Transfer.source.c[1].e, dojox.wire.ml.tests.markup.Transfer.target.a[1].children[0].title);
+		},
+
+		function test_SegimentWire(t){
+			dojox.wire.ml.tests.markup.Transfer.target = {};
+			dojo.publish("transferText");
+			t.assertEqual("A/B", dojox.wire.ml.tests.markup.Transfer.target.c);
+		}
+
+	]);
+	doh.run();
+});
+</script>
+</head>
+<body>
+<div dojoType="dojox.wire.ml.Action"
+	triggerTopic="transferData">
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="dojox.wire.ml.tests.markup.Transfer.source.a"
+		target="dojox.wire.ml.tests.markup.Transfer.item"
+		targetStore="dojox.wire.ml.tests.markup.Transfer.store"
+		targetAttribute="y"></div>
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="dojox.wire.ml.tests.markup.Transfer.item"
+		sourceStore="dojox.wire.ml.tests.markup.Transfer.store"
+		sourceAttribute="y"
+		target="dojox.wire.ml.tests.markup.Transfer.target.a"></div>
+</div>
+<div dojoType="dojox.wire.ml.Action"
+	triggerTopic="transferXml">
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="dojox.wire.ml.tests.markup.Transfer.source.a"
+		target="dojox.wire.ml.tests.markup.Transfer.element"
+		targetPath="y/text()"></div>
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="dojox.wire.ml.tests.markup.Transfer.element"
+		sourcePath="y/text()"
+		target="dojox.wire.ml.tests.markup.Transfer.target.a"></div>
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="dojox.wire.ml.tests.markup.Transfer.source.b"
+		target="dojox.wire.ml.tests.markup.Transfer.element"
+		targetPath="y/@z"></div>
+	<div dojoType="dojox.wire.ml.Transfer"
+		source="dojox.wire.ml.tests.markup.Transfer.element"
+		sourcePath="y/@z"
+		target="dojox.wire.ml.tests.markup.Transfer.target.b"></div>
+</div>
+<div dojoType="dojox.wire.ml.Transfer"
+	triggerTopic="transferComposite"
+	source="dojox.wire.ml.tests.markup.Transfer.source"
+	target="dojox.wire.ml.tests.markup.Transfer.target">
+	<div dojoType="dojox.wire.ml.ChildWire"
+		name="x"
+		property="a"></div>
+	<div dojoType="dojox.wire.ml.ChildWire"
+		which="source"
+		name="y"
+		property="b"></div>
+	<div dojoType="dojox.wire.ml.ChildWire"
+		which="target"
+		name="x"
+		property="c"></div>
+	<div dojoType="dojox.wire.ml.ChildWire"
+		which="target"
+		name="y"
+		property="d"></div>
+</div>
+<div dojoType="dojox.wire.ml.Transfer"
+	triggerTopic="transferTable"
+	source="dojox.wire.ml.tests.markup.Transfer.source.c"
+	target="dojox.wire.ml.tests.markup.Transfer.target.a">
+	<div dojoType="dojox.wire.ml.ColumnWire"
+		column="b"
+		property="d"></div>
+	<div dojoType="dojox.wire.ml.ColumnWire"
+		column="c"
+		property="e"></div>
+</div>
+<div dojoType="dojox.wire.ml.Transfer"
+	triggerTopic="transferTree"
+	source="dojox.wire.ml.tests.markup.Transfer.source.c"
+	target="dojox.wire.ml.tests.markup.Transfer.target.a">
+	<div dojoType="dojox.wire.ml.NodeWire"
+		titleProperty="d">
+		<div dojoType="dojox.wire.ml.NodeWire"
+			titleProperty="e"></div>
+	</div>
+</div>
+<div dojoType="dojox.wire.ml.Transfer"
+	triggerTopic="transferText"
+	source="dojox.wire.ml.tests.markup.Transfer.source"
+	delimiter="/"
+	target="dojox.wire.ml.tests.markup.Transfer.target.c">
+	<div dojoType="dojox.wire.ml.SegmentWire"
+		property="a"></div>
+	<div dojoType="dojox.wire.ml.SegmentWire"
+		property="b"></div>
+</div>
+</body>
+</html>

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/module.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/module.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/module.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+dojo.provide("dojox.tests.module");
+
+try{
+	dojo.require("dojox.wire.tests.wire");
+	dojo.require("dojox.wire.tests.wireml");
+}catch(e){
+	doh.debug(e);
+}
+

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/CompositeWire.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/CompositeWire.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/CompositeWire.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,47 @@
+dojo.provide("dojox.wire.tests.programmatic.CompositeWire");
+
+dojo.require("dojox.wire.CompositeWire");
+
+tests.register("dojox.wire.tests.programmatic.CompositeWire", [
+
+	function test_CompositeWire_children(t){
+		var source = {a: "A", b: "B"};
+		var target = {};
+		var children = {x: {property: "a"}, y: {property: "b"}};
+		var value = new dojox.wire.CompositeWire({object: source, children: children}).getValue();
+		t.assertEqual(source.a, value.x);
+		t.assertEqual(source.b, value.y);
+		new dojox.wire.CompositeWire({object: target, children: children}).setValue(value);
+		t.assertEqual(source.a, target.a);
+		t.assertEqual(source.b, target.b);
+
+		// with argument
+		target = {};
+		value = new dojox.wire.CompositeWire({children: children}).getValue(source);
+		t.assertEqual(source.a, value.x);
+		t.assertEqual(source.b, value.y);
+		new dojox.wire.CompositeWire({children: children}).setValue(value, target);
+		t.assertEqual(source.a, target.a);
+		t.assertEqual(source.b, target.b);
+
+		// by array
+		target = {};
+		children = [{property: "a"}, {property: "b"}];
+		value = new dojox.wire.CompositeWire({object: source, children: children}).getValue();
+		t.assertEqual(source.a, value[0]);
+		t.assertEqual(source.b, value[1]);
+		new dojox.wire.CompositeWire({object: target, children: children}).setValue(value);
+		t.assertEqual(source.a, target.a);
+		t.assertEqual(source.b, target.b);
+
+		// by array with argument
+		target = {};
+		value = new dojox.wire.CompositeWire({children: children}).getValue(source);
+		t.assertEqual(source.a, value[0]);
+		t.assertEqual(source.b, value[1]);
+		new dojox.wire.CompositeWire({children: children}).setValue(value, target);
+		t.assertEqual(source.a, target.a);
+		t.assertEqual(source.b, target.b);
+	}
+
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/DataWire.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/DataWire.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/DataWire.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,21 @@
+dojo.provide("dojox.wire.tests.programmatic.DataWire");
+
+dojo.require("dojox.wire.DataWire");
+dojo.require("dojox.data.XmlStore");
+
+tests.register("dojox.wire.tests.programmatic.DataWire", [
+
+	function test_DataWire_attribute(t){
+		var store = new dojox.data.XmlStore();
+		var item = store.newItem({tagName: "x"});
+		new dojox.wire.DataWire({dataStore: store, object: item, attribute: "y"}).setValue("Y");
+		var value = new dojox.wire.DataWire({dataStore: store, object: item, attribute: "y"}).getValue();
+		t.assertEqual("Y", value);
+
+		// nested attribute
+		new dojox.wire.DataWire({dataStore: store, object: item, attribute: "y.z"}).setValue("Z");
+		value = new dojox.wire.DataWire({dataStore: store, object: item, attribute: "y.z"}).getValue();
+		t.assertEqual("Z", value);
+	}
+
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/TableAdapter.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/TableAdapter.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/TableAdapter.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,20 @@
+dojo.provide("dojox.wire.tests.programmatic.TableAdapter");
+
+dojo.require("dojox.wire.TableAdapter");
+
+tests.register("dojox.wire.tests.programmatic.TableAdapter", [
+
+	function test_TableAdapter_columns(t){
+		var source = [
+			{a: "A1", b: "B1", c: "C1"},
+			{a: "A2", b: "B2", c: "C2"},
+			{a: "A3", b: "B3", c: "C3"}
+		];
+		var columns = {x: {property: "a"}, y: {property: "b"}, z: {property: "c"}};
+		var value = new dojox.wire.TableAdapter({object: source, columns: columns}).getValue();
+		t.assertEqual(source[0].a, value[0].x);
+		t.assertEqual(source[1].b, value[1].y);
+		t.assertEqual(source[2].c, value[2].z);
+	}
+
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/TextAdapter.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/TextAdapter.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/TextAdapter.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,21 @@
+dojo.provide("dojox.wire.tests.programmatic.TextAdapter");
+
+dojo.require("dojox.wire.TextAdapter");
+
+tests.register("dojox.wire.tests.programmatic.TextAdapter", [
+
+	function test_TextAdapter_segments(t){
+		var source = {a: "a", b: "b", c: "c"};
+		var segments = [{property: "a"}, {property: "b"}, {property: "c"}];
+		var value = new dojox.wire.TextAdapter({object: source, segments: segments}).getValue();
+		t.assertEqual("abc", value);
+	},
+
+	function test_TextAdapter_delimiter(t){
+		var source = {a: "a", b: "b", c: "c"};
+		var segments = [{property: "a"}, {property: "b"}, {property: "c"}];
+		var value = new dojox.wire.TextAdapter({object: source, segments: segments, delimiter: "/"}).getValue();
+		t.assertEqual("a/b/c", value);
+	}
+
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/TreeAdapter.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/TreeAdapter.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/TreeAdapter.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,25 @@
+dojo.provide("dojox.wire.tests.programmatic.TreeAdapter");
+
+dojo.require("dojox.wire.TreeAdapter");
+
+tests.register("dojox.wire.tests.programmatic.TreeAdapter", [
+
+	function test_TreeAdapter_nodes(t){
+		var source = [
+			{a: "A1", b: "B1", c: "C1"},
+			{a: "A2", b: "B2", c: "C2"},
+			{a: "A3", b: "B3", c: "C3"}
+		];
+		var nodes = [
+			{title: {property: "a"}, children: [
+				{node: {property: "b"}},
+				{title: {property: "c"}}
+			]}
+		];
+		var value = new dojox.wire.TreeAdapter({object: source, nodes: nodes}).getValue();
+		t.assertEqual(source[0].a, value[0].title);
+		t.assertEqual(source[1].b, value[1].children[0].title);
+		t.assertEqual(source[2].c, value[2].children[1].title);
+	}
+
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/Wire.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/Wire.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/Wire.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,76 @@
+dojo.provide("dojox.wire.tests.programmatic.Wire");
+
+dojo.require("dojox.wire.Wire");
+
+tests.register("dojox.wire.tests.programmatic.Wire", [
+
+	function test_Wire_property(t){
+		var source = {a: "A", b: {c: "B.C"}};
+		var target = {a: "a", b: {c: "b.c"}};
+		var value = new dojox.wire.Wire({object: source, property: "a"}).getValue();
+		new dojox.wire.Wire({object: target, property: "a"}).setValue(value);
+		t.assertEqual(source.a, target.a);
+
+		// child property
+		value = new dojox.wire.Wire({object: source, property: "b.c"}).getValue();
+		new dojox.wire.Wire({object: target, property: "b.c"}).setValue(value);
+		t.assertEqual(source.b.c, target.b.c);
+
+		// new property
+		target = {};
+		value = new dojox.wire.Wire({object: source, property: "a"}).getValue();
+		new dojox.wire.Wire({object: target, property: "a"}).setValue(value);
+		t.assertEqual(source.a, target.a);
+
+		// new parent and child property
+		target.b = {};
+		value = new dojox.wire.Wire({object: source, property: "b.c"}).getValue();
+		new dojox.wire.Wire({object: target, property: "b.c"}).setValue(value);
+		t.assertEqual(source.b.c, target.b.c);
+
+		// new parent and child property
+		target = {};
+		value = new dojox.wire.Wire({object: source, property: "b.c"}).getValue();
+		new dojox.wire.Wire({object: target, property: "b.c"}).setValue(value);
+		t.assertEqual(source.b.c, target.b.c);
+
+		// new array property
+		source = {a: ["A"]};
+		target = {};
+		value = new dojox.wire.Wire({object: source, property: "a[0]"}).getValue();
+		new dojox.wire.Wire({object: target, property: "a[0]"}).setValue(value);
+		t.assertEqual(source.a[0], target.a[0]);
+
+		// by getter/setter
+		source = {getA: function() { return this._a; }, _a: "A"};
+		target = {setA: function(a) { this._a = a; }};
+		value = new dojox.wire.Wire({object: source, property: "a"}).getValue();
+		new dojox.wire.Wire({object: target, property: "a"}).setValue(value);
+		t.assertEqual(source._a, target._a);
+
+		// by get/setPropertyValue
+		source = {getPropertyValue: function(p) { return this["_" + p]; }, _a: "A"};
+		target = {setPropertyValue: function(p, v) { this["_" + p] = v; }};
+		value = new dojox.wire.Wire({object: source, property: "a"}).getValue();
+		new dojox.wire.Wire({object: target, property: "a"}).setValue(value);
+		t.assertEqual(source._a, target._a);
+	},
+
+	function test_Wire_type(t){
+		var source = {a: "1"};
+		var string = new dojox.wire.Wire({object: source, property: "a"}).getValue();
+		t.assertEqual("11", string + 1);
+		var number = new dojox.wire.Wire({object: source, property: "a", type: "number"}).getValue();
+		t.assertEqual(2, number + 1);
+	},
+
+	function test_Wire_converter(t){
+		var source = {a: "1"};
+		var converter = {convert: function(v) { return v + 1; }};
+		var string = new dojox.wire.Wire({object: source, property: "a", converter: converter}).getValue();
+		t.assertEqual("11", string);
+		var number = new dojox.wire.Wire({object: source, property: "a", type: "number", converter: converter.convert}).getValue();
+		t.assertEqual(2, number);
+	}
+
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/XmlWire.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/XmlWire.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/XmlWire.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,28 @@
+dojo.provide("dojox.wire.tests.programmatic.XmlWire");
+
+dojo.require("dojox.wire.XmlWire");
+
+tests.register("dojox.wire.tests.programmatic.XmlWire", [
+
+	function test_XmlWire_path(t){
+		var object = {};
+		var wire = dojox.wire.create({object: object, property: "element"});
+		new dojox.wire.XmlWire({object: wire, path: "/x/y/text()"}).setValue("Y");
+		var value = new dojox.wire.XmlWire({object: object, property: "element", path: "y/text()"}).getValue();
+		t.assertEqual("Y", value);
+
+		// attribute
+		new dojox.wire.XmlWire({object: object, property: "element", path: "y/@z"}).setValue("Z");
+		value = new dojox.wire.XmlWire({object: wire, path: "/x/y/@z"}).getValue();
+		t.assertEqual("Z", value);
+
+		// with index
+		var document = object.element.ownerDocument;
+		var element = document.createElement("y");
+		element.appendChild(document.createTextNode("Y2"));
+		object.element.appendChild(element);
+		value = new dojox.wire.XmlWire({object: object.element, path: "y[2]/text()"}).getValue();
+		t.assertEqual("Y2", value);
+	}
+
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/_base.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/_base.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/programmatic/_base.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,107 @@
+dojo.provide("dojox.wire.tests.programmatic._base");
+
+dojo.require("dojox.wire._base");
+
+tests.register("dojox.wire.tests.programmatic._base", [
+
+	function test_create(t){
+		var wire = dojox.wire.create({});
+		t.assertTrue(wire instanceof dojox.wire.Wire);
+
+		wire = dojox.wire.create({property: "a"});
+		t.assertTrue(wire instanceof dojox.wire.Wire);
+
+		wire = dojox.wire.create({attribute: "a"});
+		t.assertTrue(wire instanceof dojox.wire.DataWire);
+
+		wire = dojox.wire.create({path: "a"});
+		t.assertTrue(wire instanceof dojox.wire.XmlWire);
+
+		wire = dojox.wire.create({children: "a"});
+		t.assertTrue(wire instanceof dojox.wire.CompositeWire);
+
+		wire = dojox.wire.create({columns: "a"});
+		t.assertTrue(wire instanceof dojox.wire.TableAdapter);
+
+		wire = dojox.wire.create({nodes: "a"});
+		t.assertTrue(wire instanceof dojox.wire.TreeAdapter);
+
+		wire = dojox.wire.create({segments: "a"});
+		t.assertTrue(wire instanceof dojox.wire.TextAdapter);
+
+		wire = dojox.wire.create({wireClass: "dojox.wire.DataWire"});
+		t.assertTrue(wire instanceof dojox.wire.DataWire);
+	},
+	
+	function test_transfer(t){
+		var source = {a: "A"};
+		var target = {};
+		dojox.wire.transfer(
+			{object: source, property: "a"},
+			{object: target, property: "a"});
+		t.assertEqual(source.a, target.a);
+	},
+
+	function test_connect(t){
+		var trigger = {transfer: function() {}, transferArgument: function() {}};
+		var source = {a: "A"};
+		var target = {};
+		dojox.wire.connect({scope: trigger, event: "transfer"},
+			{object: source, property: "a"},
+			{object: target, property: "a"});
+		trigger.transfer();
+		t.assertEqual(source.a, target.a);
+
+		// with argument
+		target = {};
+		dojox.wire.connect({scope: trigger, event: "transferArgument"},
+			{property: "[0].a"},
+			{object: target, property: "a"});
+		trigger.transferArgument(source);
+		t.assertEqual(source.a, target.a);
+
+		// by topic
+		target = {};
+		dojox.wire.connect({topic: "transfer"},
+			{object: source, property: "a"},
+			{object: target, property: "a"});
+		dojo.publish("transfer");
+		t.assertEqual(source.a, target.a);
+
+		// by topic with argument
+		target = {};
+		dojox.wire.connect({topic: "transferArgument"},
+			{property: "[0].a"},
+			{object: target, property: "a"});
+		dojo.publish("transferArgument", [source]);
+		t.assertEqual(source.a, target.a);
+	},
+
+	function test_disconnect(t){
+		var trigger = {transferDisconnect: function() {}};
+		var source = {a: "A"};
+		var target = {};
+		var connection = dojox.wire.connect({scope: trigger, event: "transferDisconnect"},
+			{object: source, property: "a"},
+			{object: target, property: "a"});
+		trigger.transferDisconnect();
+		t.assertEqual(source.a, target.a);
+		delete target.a;
+		dojox.wire.disconnect(connection);
+		trigger.transferDisconnect();
+		t.assertEqual(undefined, target.a);
+
+		// by topic
+		target = {};
+		connection = dojox.wire.connect({topic: "transferDisconnect"},
+			{object: source, property: "a"},
+			{object: target, property: "a"});
+		dojo.publish("transferDisconnect");
+		t.assertEqual(source.a, target.a);
+		delete target.a;
+		dojox.wire.disconnect(connection);
+		dojo.publish("transferDisconnect");
+		t.assertEqual(undefined, target.a);
+	}
+
+]);

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/runTests.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/runTests.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/runTests.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+    <head>
+    <title>Dojox.wire Unit Test Runner</title>
+    <meta http-equiv="REFRESH" content="0;url=../../../util/doh/runner.html?testModule=dojox.wire.tests.module"></HEAD>
+    <BODY>
+        Redirecting to D.O.H runner.
+    </BODY>
+</HTML> 

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/wire.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/wire.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/wire.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,14 @@
+dojo.provide("dojox.wire.tests.wire");
+
+try{
+	dojo.require("dojox.wire.tests.programmatic._base");
+	dojo.require("dojox.wire.tests.programmatic.Wire");
+	dojo.require("dojox.wire.tests.programmatic.DataWire");
+	dojo.require("dojox.wire.tests.programmatic.XmlWire");
+	dojo.require("dojox.wire.tests.programmatic.CompositeWire");
+	dojo.require("dojox.wire.tests.programmatic.TableAdapter");
+	dojo.require("dojox.wire.tests.programmatic.TreeAdapter");
+	dojo.require("dojox.wire.tests.programmatic.TextAdapter");
+}catch(e){
+	doh.debug(e);
+}

Added: trunk/examples/typeface/root/static/dojo/dojox/wire/tests/wireml.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire/tests/wireml.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire/tests/wireml.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,14 @@
+dojo.provide("dojox.wire.tests.wireml");
+
+try{
+	if(dojo.isBrowser){
+		doh.registerUrl("dojox.wire.tests.ml.Action", dojo.moduleUrl("dojox", "wire/tests/markup/Action.html"));
+		doh.registerUrl("dojox.wire.tests.ml.Transfer", dojo.moduleUrl("dojox", "wire/tests/markup/Transfer.html"));
+		doh.registerUrl("dojox.wire.tests.ml.Invocation", dojo.moduleUrl("dojox", "wire/tests/markup/Invocation.html"));
+		doh.registerUrl("dojox.wire.tests.ml.Data", dojo.moduleUrl("dojox", "wire/tests/markup/Data.html"));
+		doh.registerUrl("dojox.wire.tests.ml.DataStore", dojo.moduleUrl("dojox", "wire/tests/markup/DataStore.html"));
+		doh.registerUrl("dojox.wire.tests.ml.Service", dojo.moduleUrl("dojox", "wire/tests/markup/Service.html"));
+	}
+}catch(e){
+	doh.debug(e);
+}

Added: trunk/examples/typeface/root/static/dojo/dojox/wire.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/wire.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/wire.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,3 @@
+dojo.provide("dojox.wire");
+dojo.require("dojox.wire._base");
+

Added: trunk/examples/typeface/root/static/dojo/dojox/xml/DomParser.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/xml/DomParser.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/xml/DomParser.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,372 @@
+dojo.provide("dojox.xml.DomParser");
+
+dojox.xml.DomParser=new (function(){
+	/**********************************************************
+	 *	The DomParser is a close-to (but not entirely)
+	 *	conforming XML parser based on regular
+	 *	expressions.  It will take any XML fragment
+	 *	and return a lightweight JS structure that is
+	 *	similar to (but not exactly) the DOM specification.
+	 *
+	 *	Getter and setter methods are NOT available; the goal
+	 *	was to keep the resulting object model entirely JS-like.
+	 *
+	 *	All node types but document fragments are supported;
+	 *	all nodes support getElementsByTagName and 
+	 *	getElementsByTagNameNS (with short names byName and 
+	 *	byNameNS).  The document node supports getElementById
+	 *	(byId), and all nodes support a supplimental
+	 *	childrenByName/childrenByNameNS method as well.
+	 *
+	 *	The object model is intended to be a READONLY format;
+	 *	mutation events are NOT supported, and though you
+	 *	can change properties on a node-by-node basis, certain
+	 *	operations are not supported (such as changing the ID 
+	 *	of an element).
+	 **********************************************************/
+
+	//	internal use only.
+	var nodeTypes={ ELEMENT:1, ATTRIBUTE:2, TEXT:3, CDATA_SECTION:4, PROCESSING_INSTRUCTION:7, COMMENT:8, DOCUMENT:9 };
+
+	//	compile the regular expressions once.
+	var reTags=/<([^>\/\s+]*)([^>]*)>([^<]*)/g;
+	var reAttr=/([^=]*)="([^"]*)"/g;
+	var reEntity=/<!ENTITY\s+([^"]*)\s+"([^"]*)">/g;
+	var reCData=/<!\[CDATA\[([\u0001-\uFFFF]*?)\]\]>/g;
+	var reComments=/<!--([\u0001-\uFFFF]*?)-->/g;
+	var trim=/^\s+|\s+$/g;
+	var normalize=/\s+/g;
+	var egt=/\&gt;/g;
+	var elt=/\&lt;/g;
+	var equot=/\&quot;/g;
+	var eapos=/\&apos;/g;
+	var eamp=/\&amp;/g;
+	var dNs="_def_";
+
+	//	create a root node.
+	function _doc(){
+		return new (function(){
+			var all={};
+			this.nodeType=nodeTypes.DOCUMENT;
+			this.nodeName="#document";
+			this.namespaces={};
+			this._nsPaths={};
+			this.childNodes=[];
+			this.documentElement=null;
+
+			//	any element with an ID attribute will be added to the internal hashtable.
+			this._add=function(obj){
+				if(typeof(obj.id)!="undefined"){ all[obj.id]=obj; }
+			};
+			this._remove=function(id){
+				if(all[id]){ delete all[id]; }
+			};
+
+			this.byId=this.getElementById=function(id){ return keys[id]; };
+			this.byName=this.getElementsByTagName=byName;
+			this.byNameNS=this.getElementsByTagNameNS=byNameNS;
+			this.childrenByName=childrenByName;
+		})();
+	}
+
+	//	functions attached to element nodes
+	function byName(name){
+		//	return all descendants with name.  Fully qualified (i.e. svg:svg)
+		function __(node, name, arr){
+			for(var i=0; i<node.childNodes.length; i++){
+				var c=node.childNodes[i];
+				if(c.nodeType==nodeTypes.ELEMENT){
+					if(name=="*"){ arr.push(c); }
+					else if(c.nodeName==name){ arr.push(c); }
+					__(c, name, arr);
+				}
+			}
+		}
+		var a=[];
+		__(this, name, a);
+		return a;
+	}
+	function byNameNS(name, ns){
+		//	return all descendants with name by namespace.  If no namespace passed, the default is used.
+		function __(node, name, ns, arr){
+			for(var i=0; i<node.childNodes.length; i++){
+				var c=node.childNodes[i];
+				if(c.nodeType==nodeTypes.ELEMENT){
+					if(name=="*"&&c.ownerDocument._nsPaths[ns]==c.namespace){ arr.push(c); }
+					else if(c.localName==name&&c.ownerDocument._nsPaths[ns]==c.namespace){ arr.push(c); }
+					__(c, name, ns, arr);
+				}
+			}
+		}
+		if(!ns){ ns=dNs; }
+		var a=[];
+		__(this, name, ns, a);
+		return a;
+	}
+	//	Only child nodes with name.
+	function childrenByName(name){
+		var a=[];
+		for(var i=0; i<this.childNodes.length; i++){
+			var c=this.childNodes[i];
+			if(c.nodeType==nodeTypes.ELEMENT){
+				if(name=="*"){ a.push(c); }
+				else if(c.nodeName==name){ a.push(c); }
+			}
+		}
+		return a;
+	}
+
+	//	attribute functions
+	function getAttr(name){
+		for(var i=0; i<this.attributes.length; i++){
+			if(this.attributes[i].nodeName==name){
+				return this.attributes[i].nodeValue;
+			}
+		}
+		return null;
+	}
+	function getAttrNS(name, ns){
+		for(var i=0; i<this.attributes.length; i++){
+			if(this.ownerDocument._nsPaths[ns]==this.attributes[i].namespace
+				&&this.attributes[i].localName==name
+			){
+				return this.attributes[i].nodeValue;
+			}
+		}
+		return null;
+	}
+	//	note that you can only swap IDs using setAttribute, NOT with setAttributeNS.
+	function setAttr(name, val){
+		var old=null;
+		for(var i=0; i<this.attributes.length; i++){
+			if(this.attributes[i].nodeName==name){
+				old=this.attributes[i].nodeValue;
+				this.attributes[i].nodeValue=val;
+				break;
+			}
+		}
+		if(name=="id"){
+			if(old!=null){ this.ownerDocument._remove(old); }
+			this.ownerDocument._add(this);
+		}
+	}
+	function setAttrNS(name, val, ns){
+		for(var i=0; i<this.attributes.length; i++){
+			if(this.ownerDocument._nsPaths[ns]==this.attributes[i].namespace
+				&&this.attributes[i].localName==name
+			){
+				this.attributes[i].nodeValue=val;
+				return;
+			}
+		}
+	}
+
+	//	navigation
+	function prev(){
+		var p=this.parentNode;
+		if(p){
+			for(var i=0;i<p.childNodes.length;i++){
+				if(p.childNodes[i]==this&&i>0){
+					return p.childNodes[i-1];
+				}
+			}
+		}
+		return null;
+	}
+	function next(){
+		var p=this.parentNode;
+		if(p){
+			for(var i=0;i<p.childNodes.length;i++){
+				if(p.childNodes[i]==this&&(i+1)<p.childNodes.length){
+					return p.childNodes[i+1];
+				}
+			}
+		}
+		return null;
+	}
+
+	//	the main method.
+	this.parse=function(/* String */str){
+		var root=_doc();
+		if(str==null){ return root; }
+		if(str.length==0){ return root; }
+
+		//	preprocess custom entities
+		if(str.indexOf("<!ENTITY")>0){
+			var entity, eRe=[];
+			if(reEntity.test(str)){
+				reEntity.lastIndex=0;
+				//	match entities
+				while((entity=reEntity.exec(str))!=null){
+					eRe.push({ 
+						entity:"&"+entity[1].replace(trim,"")+";", 
+						expression:entity[2] 
+					});
+				}
+				//	replace instances in the document.
+				for(var i=0; i<eRe.length; i++){
+					str=str.replace(new RegExp(eRe[i].entity, "g"), eRe[i].expression);
+				}
+			}
+		}
+
+		//	pre-parse for CData, and tokenize.
+		var cdSections=[], cdata;
+		while((cdata=reCData.exec(str))!=null){ cdSections.push(cdata[1]); }
+		for(var i=0; i<cdSections.length; i++){ str=str.replace(cdSections[i], i); }
+		
+		//	pre-parse for comments, and tokenize.
+		var comments=[], comment;
+		while((comment=reComments.exec(str))!=null){ comments.push(comment[1]); }
+		for(i=0; i<comments.length; i++){ str=str.replace(comments[i], i); }
+
+		//	parse the document
+		var res, obj=root;
+		while((res=reTags.exec(str))!=null){
+			//	closing tags.
+			if(res[2].charAt(0)=="/"){
+				if(obj.parentNode){
+					obj=obj.parentNode;
+				}
+				continue;
+			}
+
+			//	open tags.
+			if(res[1].length>0){
+				//	figure out the type of node.
+				if(res[1].charAt(0)=="?"){
+					//	processing instruction
+					var name=res[1].substr(1);
+					var target=res[2].substr(0,res[2].length-2);
+					obj.childNodes.push({ 
+						nodeType:nodeTypes.PROCESSING_INSTRUCTION, 
+						nodeName:name, 
+						nodeValue:target 
+					});
+				}
+				else if(res[1].charAt(0)=="!"){
+					//	CDATA; skip over any declaration elements.
+					if(res[1].indexOf("![CDATA[")==0){
+						var val=parseInt(res[1].replace("![CDATA[","").replace("]]",""));
+						obj.childNodes.push({ 
+							nodeType:nodeTypes.CDATA_SECTION, 
+							nodeName:"#cdata-section", 
+							nodeValue:cdSections[val] 
+						});
+					}
+					//	Comments.
+					else if(res[1].substr(0,3)=="!--"){
+						var val=parseInt(res[1].replace("!--","").replace("--",""));
+						obj.childNodes.push({ 
+							nodeType:nodeTypes.COMMENT, 
+							nodeName:"#comment", 
+							nodeValue:comments[val] 
+						});
+					}
+				}
+				else {
+					//	Elements (with attribute and text)
+					var name=res[1].replace(trim,"");
+					var o={ 
+						nodeType:nodeTypes.ELEMENT, 
+						nodeName:name, 
+						localName:name, 
+						namespace:dNs, 
+						ownerDocument:root, 
+						attributes:[], 
+						parentNode:null, 
+						childNodes:[] 
+					};
+
+					//	check to see if it's namespaced.
+					if(name.indexOf(":")>-1){
+						var t=name.split(":");
+						o.namespace=t[0];
+						o.localName=t[1];
+					}
+
+					//	set the function references.
+					o.byName=o.getElementsByTagName=byName;
+					o.byNameNS=o.getElementsByTagNameNS=byNameNS;
+					o.childrenByName=childrenByName;
+					o.getAttribute=getAttr;
+					o.getAttributeNS=getAttrNS;
+					o.setAttribute=setAttr;
+					o.setAttributeNS=setAttrNS;
+					o.previous=o.previousSibling=prev;
+					o.next=o.nextSibling=next;
+
+					//	parse the attribute string.
+					var attr;
+					while((attr=reAttr.exec(res[2]))!=null){
+						if(attr.length>0){
+							var name=attr[1].replace(trim,"");
+							var val=attr[2].replace(normalize," ")
+								.replace(egt,">")
+								.replace(elt,"<")
+								.replace(eapos,"'")
+								.replace(equot,'"')
+								.replace(eamp,"&");
+							if(name.indexOf("xmlns")==0){
+								if(name.indexOf(":")>0){
+									var ns=name.split(":");
+									root.namespaces[ns[1]]=val;
+									root._nsPaths[val]=ns[1];
+								} else {
+									root.namespaces[dNs]=val;
+									root._nsPaths[val]=dNs;
+								}
+							} else {
+								var ln=name;
+								var ns=dNs;
+								if(name.indexOf(":")>0){
+									var t=name.split(":");
+									ln=t[1];
+									ns=t[0];
+								}
+								o.attributes.push({
+									nodeType:nodeTypes.ATTRIBUTE, 
+									nodeName:name, 
+									localName:ln, 
+									namespace:ns, 
+									nodeValue:val 
+								});
+
+								//	only add id as a property.
+								if(ln=="id"){ o.id=val; }
+							}
+						}
+					}
+					root._add(o);
+
+					var text=res[3].replace(trim,"");
+					if(text.length>0)
+						o.childNodes.push({ 
+							nodeType:nodeTypes.TEXT, 
+							nodeName:"#text", 
+							nodeValue:text.replace(normalize," ").replace(egt,">").replace(elt,"<").replace(eapos,"'").replace(equot,'"').replace(eamp,"&") 
+						});
+
+					if(obj){
+						obj.childNodes.push(o);
+						o.parentNode=obj;
+						//	if it's not a self-closing node.
+						if(res[2].charAt(res[2].length-1)!="/"){
+							obj=o;
+						}
+					}
+				}
+			}
+		}
+
+		//	set the document element
+		for(var i=0; i<root.childNodes.length; i++){
+			var e=root.childNodes[i];
+			if(e.nodeType==nodeTypes.ELEMENT){
+				root.documentElement=e;
+				break;
+			}
+		}
+		return root;
+	};
+})();

Added: trunk/examples/typeface/root/static/dojo/dojox/xml/README
===================================================================
--- trunk/examples/typeface/root/static/dojo/dojox/xml/README	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/dojox/xml/README	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,39 @@
+-------------------------------------------------------------------------------
+DojoX XML Utilities
+-------------------------------------------------------------------------------
+Version 0.1
+Release date: 05/30/2007	
+-------------------------------------------------------------------------------
+Project state:
+expermental
+-------------------------------------------------------------------------------
+Project authors
+	Tom Trenka (ttrenka at gmail.com)
+-------------------------------------------------------------------------------
+Project description
+
+The goal of DojoX XML Utilities is provide differing XML utilities for use
+in various places.  Currently this includes a native JS DomParser, but will
+most likely be expanded to include things as dealing with x-browser forks
+(like the Sarissa project), various DOM utilites, and more.
+-------------------------------------------------------------------------------
+Dependencies:
+
+DojoX XML relies only on the Dojo Base package system.
+-------------------------------------------------------------------------------
+Documentation
+
+None at the time of writing.  The only object is dojox.xml.DomParser (a singleton),
+which has one method: parse:
+
+dojox.xml.DomParser.parse(xmlString)
+-------------------------------------------------------------------------------
+Installation instructions
+
+Grab the following from the Dojo SVN Repository:
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/xml/*
+
+Install into the following directory structure:
+/dojox/xml/
+
+...which should be at the same level as your Dojo checkout.

Added: trunk/examples/typeface/root/static/dojo/util/doh/_browserRunner.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/util/doh/_browserRunner.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/util/doh/_browserRunner.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,465 @@
+if(window["dojo"]){
+	dojo.provide("doh._browserRunner");
+}
+
+// FIXME: need to add prompting for monkey-do testing
+// FIXME: need to implement progress bar
+// FIXME: need to implement errors in progress bar
+
+(function(){
+	if(window.parent == window){
+		// we're the top-dog window.
+
+		// borrowed from Dojo, etc.
+		var byId = function(id){
+			return document.getElementById(id);
+		}
+
+		var _addOnEvt = function(	type,		// string
+									refOrName,	// function or string
+									scope){		// object, defaults is window
+
+			if(!scope){ scope = window; }
+
+			var funcRef = refOrName;
+			if(typeof refOrName == "string"){
+				funcRef = scope[refOrName];
+			}
+			var enclosedFunc = function(){ return funcRef.apply(scope, arguments); };
+
+			if((window["dojo"])&&(type == "load")){
+				dojo.addOnLoad(enclosedFunc);
+			}else{
+				if(window["attachEvent"]){
+					window.attachEvent("on"+type, enclosedFunc);
+				}else if(window["addEventListener"]){
+					window.addEventListener(type, enclosedFunc, false);
+				}else if(document["addEventListener"]){
+					document.addEventListener(type, enclosedFunc, false);
+				}
+			}
+		};
+
+		//
+		// Over-ride or implement base runner.js-provided methods
+		//
+		var _logBacklog = [];
+		var sendToLogPane = function(args, skip){
+			var msg = "";
+			for(var x=0; x<args.length; x++){
+				msg += " "+args[x];
+			}
+			// workarounds for IE. Wheeee!!!
+			msg = msg.replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;");
+			msg = msg.replace(" ", "&nbsp;");
+			msg = msg.replace("\n", "<br>&nbsp;");
+			if(!byId("logBody")){
+				_logBacklog.push(msg);
+				return;
+			}else if((_logBacklog.length)&&(!skip)){
+				var tm;
+				while(tm=_logBacklog.shift()){
+					sendToLogPane(tm, true);
+				}
+			}
+			var tn = document.createElement("div");
+			tn.innerHTML = msg;
+			byId("logBody").appendChild(tn);
+		}
+
+		doh._init = (function(oi){
+			return function(){
+				var lb = byId("logBody");
+				if(lb){
+					// clear the console before each run
+					while(lb.firstChild){
+						lb.removeChild(lb.firstChild);
+					}
+				}
+				oi.apply(doh, arguments);
+			}
+		})(doh._init);
+
+		if(this["opera"] && opera.postError){
+			doh.debug = function(){
+				var msg = "";
+				for(var x=0; x<arguments.length; x++){
+					msg += " "+arguments[x];
+				}
+				sendToLogPane([msg]);
+				opera.postError("DEBUG:"+msg);
+			}
+		}else if(window["console"]){
+			if(console.info){
+				doh.debug = function(){
+					sendToLogPane.call(window, arguments);
+					console.debug.apply(console, arguments);
+				}
+			}else{
+				doh.debug = function(){
+					var msg = "";
+					for(var x=0; x<arguments.length; x++){
+						msg += " "+arguments[x];
+					}
+					sendToLogPane([msg]);
+					console.log("DEBUG:"+msg);
+				}
+			}
+		}else{
+			doh.debug = function(){
+				sendToLogPane.call(window, arguments);
+			}
+		}
+
+		var loaded = false;
+		var groupTemplate = null;
+		var testTemplate = null;
+
+		var groupNodes = {};
+
+		var _groupTogglers = {};
+
+		var _getGroupToggler = function(group, toggle){
+			if(_groupTogglers[group]){ return _groupTogglers[group]; }
+			var rolledUp = true;
+			return _groupTogglers[group] = function(evt, forceOpen){
+				var nodes = groupNodes[group].__items;
+				if(rolledUp||forceOpen){
+					rolledUp = false;
+					for(var x=0; x<nodes.length; x++){
+						nodes[x].style.display = "";
+					}
+					toggle.innerHTML = "&#054;";
+				}else{
+					rolledUp = true;
+					for(var x=0; x<nodes.length; x++){
+						nodes[x].style.display = "none";
+					}
+					toggle.innerHTML = "&#052;";
+				}
+			};
+		}
+
+		var addGroupToList = function(group){
+			if(!byId("testList")){ return; }
+			var tb = byId("testList").tBodies[0];
+			var tg = groupTemplate.cloneNode(true);
+			var tds = tg.getElementsByTagName("td");
+			var toggle = tds[0];
+			toggle.onclick = _getGroupToggler(group, toggle);
+			var cb = tds[1].getElementsByTagName("input")[0];
+			cb.group = group;
+			cb.onclick = function(evt){
+				doh._groups[group].skip = (!this.checked);
+			}
+			tds[2].innerHTML = group;
+			tds[3].innerHTML = "";
+
+			tb.appendChild(tg);
+			return tg;
+		}
+
+		var addFixtureToList = function(group, fixture){
+			if(!testTemplate){ return; }
+			var cgn = groupNodes[group];
+			if(!cgn["__items"]){ cgn.__items = []; }
+			var tn = testTemplate.cloneNode(true);
+			var tds = tn.getElementsByTagName("td");
+
+			tds[2].innerHTML = fixture.name;
+			tds[3].innerHTML = "";
+
+			var nn = (cgn.__lastFixture||cgn.__groupNode).nextSibling;
+			if(nn){
+				nn.parentNode.insertBefore(tn, nn);
+			}else{
+				cgn.__groupNode.parentNode.appendChild(tn);
+			}
+			// FIXME: need to make group display toggleable!!
+			tn.style.display = "none";
+			cgn.__items.push(tn);
+			return cgn.__lastFixture = tn;
+		}
+
+		var getFixtureNode = function(group, fixture){
+			if(groupNodes[group]){
+				return groupNodes[group][fixture.name];
+			}
+			return null;
+		}
+
+		var getGroupNode = function(group){
+			if(groupNodes[group]){
+				return groupNodes[group].__groupNode;
+			}
+			return null;
+		}
+
+		var updateBacklog = [];
+		doh._updateTestList = function(group, fixture, unwindingBacklog){
+			if(!loaded){
+				if(group && fixture){
+					updateBacklog.push([group, fixture]);
+				}
+				return;
+			}else if((updateBacklog.length)&&(!unwindingBacklog)){
+				var tr;
+				while(tr=updateBacklog.shift()){
+					doh._updateTestList(tr[0], tr[1], true);
+				}
+			}
+			if(group && fixture){
+				if(!groupNodes[group]){
+					groupNodes[group] = {
+						"__groupNode": addGroupToList(group)
+					};
+				}
+				if(!groupNodes[group][fixture.name]){
+					groupNodes[group][fixture.name] = addFixtureToList(group, fixture)
+				}
+			}
+		}
+
+		doh._testRegistered = doh._updateTestList;
+
+		doh._groupStarted = function(group){
+			// console.debug("_groupStarted", group);
+			var gn = getGroupNode(group);
+			if(gn){
+				gn.className = "inProgress";
+			}
+		}
+
+		doh._groupFinished = function(group, success){
+			// console.debug("_groupFinished", group);
+			var gn = getGroupNode(group);
+			if(gn){
+				gn.className = (success) ? "success" : "failure";
+			}
+		}
+
+		doh._testStarted = function(group, fixture){
+			// console.debug("_testStarted", group, fixture.name);
+			var fn = getFixtureNode(group, fixture);
+			if(fn){
+				fn.className = "inProgress";
+			}
+		}
+
+		var _nameTimes = {};
+		var _playSound = function(name){
+			if(byId("hiddenAudio") && byId("audio") && byId("audio").checked){
+				// console.debug("playing:", name);
+				var nt = _nameTimes[name];
+				// only play sounds once every second or so
+				if((!nt)||(((new Date)-nt) > 700)){
+					_nameTimes[name] = new Date();
+					var tc = document.createElement("span");
+					byId("hiddenAudio").appendChild(tc);
+					tc.innerHTML = '<embed src="_sounds/'+name+'.wav" autostart="true" loop="false" hidden="true" width="1" height="1"></embed>';
+				}
+			}
+		}
+
+		doh._testFinished = function(group, fixture, success){
+			var fn = getFixtureNode(group, fixture);
+			if(fn){
+				fn.getElementsByTagName("td")[3].innerHTML = (fixture.endTime-fixture.startTime)+"ms";
+				fn.className = (success) ? "success" : "failure";
+
+				if(!success){
+					_playSound("doh");
+					var gn = getGroupNode(group);
+					if(gn){
+						gn.className = "failure";
+						_getGroupToggler(group)(null, true);
+					}
+				}
+			}
+			this.debug(((success) ? "PASSED" : "FAILED"), "test:", fixture.name);
+		}
+
+		// FIXME: move implementation to _browserRunner?
+		doh.registerUrl = function(	/*String*/ group, 
+										/*String*/ url, 
+										/*Integer*/ timeout){
+			var tg = new String(group);
+			this.register(group, {
+				name: url,
+				setUp: function(){
+					doh.currentGroupName = tg;
+					doh.currentGroup = this;
+					doh.currentUrl = url;
+					this.d = new doh.Deferred();
+					doh.currentTestDeferred = this.d;
+					showTestPage();
+					byId("testBody").src = url;
+				},
+				timeout: timeout||10000, // 10s
+				// timeout: timeout||1000, // 10s
+				runTest: function(){
+					// FIXME: implement calling into the url's groups here!!
+					return this.d;
+				},
+				tearDown: function(){
+					doh.currentGroupName = null;
+					doh.currentGroup = null;
+					doh.currentTestDeferred = null;
+					doh.currentUrl = null;
+					// this.d.errback(false);
+					// byId("testBody").src = "about:blank";
+					showLogPage();
+				}
+			});
+		}
+
+		// 
+		// Utility code for runner.html
+		//
+		// var isSafari = navigator.appVersion.indexOf("Safari") >= 0;
+		var tabzidx = 1;
+		var _showTab = function(toShow, toHide){
+			// FIXME: I don't like hiding things this way.
+			byId(toHide).style.display = "none";
+			with(byId(toShow).style){
+				display = "";
+				zIndex = ++tabzidx;
+			}
+		}
+
+		showTestPage = function(){
+			_showTab("testBody", "logBody");
+		}
+
+		showLogPage = function(){
+			_showTab("logBody", "testBody");
+		}
+
+		var runAll = true;
+		toggleRunAll = function(){
+			// would be easier w/ query...sigh
+			runAll = (!runAll);
+			if(!byId("testList")){ return; }
+			var tb = byId("testList").tBodies[0];
+			var inputs = tb.getElementsByTagName("input");
+			var x=0; var tn;
+			while(tn=inputs[x++]){
+				tn.checked = runAll;
+				doh._groups[tn.group].skip = (!runAll);
+			}
+		}
+
+		var listHeightTimer = null;
+		var setListHeight = function(){
+			if(listHeightTimer){
+				clearTimeout(listHeightTimer);
+			}
+			var tl = byId("testList");
+			if(!tl){ return; }
+			listHeightTimer = setTimeout(function(){
+				tl.style.display = "none";
+				tl.style.display = "";
+
+			}, 10);
+		}
+
+		_addOnEvt("resize", setListHeight);
+		_addOnEvt("load", setListHeight);
+		_addOnEvt("load", function(){
+			if(loaded){ return; }
+			loaded = true;
+			groupTemplate = byId("groupTemplate");
+			if(!groupTemplate){ 
+				// make sure we've got an ammenable DOM structure
+				return;
+			}
+			groupTemplate.parentNode.removeChild(groupTemplate);
+			groupTemplate.style.display = "";
+			testTemplate = byId("testTemplate");
+			testTemplate.parentNode.removeChild(testTemplate);
+			testTemplate.style.display = "";
+			doh._updateTestList();
+		});
+
+		_addOnEvt("load", 
+			function(){
+				doh._onEnd = function(){
+					if(doh._failureCount == 0){
+						doh.debug("WOOHOO!!");
+						_playSound("woohoo");
+					}else{
+						console.debug("doh._failureCount:", doh._failureCount);
+					}
+					if(byId("play")){
+						toggleRunning();
+					}
+				}
+				if(!byId("play")){ 
+					// make sure we've got an ammenable DOM structure
+					return;
+				}
+				var isRunning = false;
+				var toggleRunning = function(){
+					// ugg, this would be so much better w/ dojo.query()
+					if(isRunning){
+						byId("play").style.display = byId("pausedMsg").style.display = "";
+						byId("playingMsg").style.display = byId("pause").style.display = "none";
+						isRunning = false;
+					}else{
+						byId("play").style.display = byId("pausedMsg").style.display = "none";
+						byId("playingMsg").style.display = byId("pause").style.display = "";
+						isRunning = true;
+					}
+				}
+				doh.run = (function(oldRun){
+					return function(){
+						if(!doh._currentGroup){
+							toggleRunning();
+						}
+						return oldRun.apply(doh, arguments);
+					}
+				})(doh.run);
+				var btns = byId("toggleButtons").getElementsByTagName("span");
+				var node; var idx=0;
+				while(node=btns[idx++]){
+					node.onclick = toggleRunning;
+				}
+			}
+		);
+	}else{
+		// we're in an iframe environment. Time to mix it up a bit.
+
+		_doh = window.parent.doh;
+		var _thisGroup = _doh.currentGroupName;
+		var _thisUrl = _doh.currentUrl;
+		if(_thisGroup){
+			doh._testRegistered = function(group, tObj){
+				_doh._updateTestList(_thisGroup, tObj);
+			}
+			doh._onEnd = function(){
+				_doh._errorCount += doh._errorCount;
+				_doh._failureCount += doh._failureCount;
+				_doh._testCount += doh._testCount;
+				// should we be really adding raw group counts?
+				_doh._groupCount += doh._groupCount;
+				_doh.currentTestDeferred.callback(true);
+			}
+			var otr = doh._getTestObj;
+			doh._getTestObj = function(){
+				var tObj = otr.apply(doh, arguments);
+				tObj.name = _thisUrl+"::"+arguments[0]+"::"+tObj.name;
+				return tObj;
+			}
+			doh.debug = doh.hitch(_doh, "debug");
+			doh.registerUrl = doh.hitch(_doh, "registerUrl");
+			doh._testStarted = function(group, fixture){
+				_doh._testStarted(_thisGroup, fixture);
+			}
+			doh._testFinished = function(g, f, s){
+				_doh._testFinished(_thisGroup, f, s);
+			}
+			doh._report = function(){};
+		}
+	}
+
+})();

Added: trunk/examples/typeface/root/static/dojo/util/doh/_rhinoRunner.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/util/doh/_rhinoRunner.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/util/doh/_rhinoRunner.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,5 @@
+if(this["dojo"]){
+	dojo.provide("doh._rhinoRunner");
+}
+
+doh.debug = print;

Added: trunk/examples/typeface/root/static/dojo/util/doh/_sounds/LICENSE
===================================================================
--- trunk/examples/typeface/root/static/dojo/util/doh/_sounds/LICENSE	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/util/doh/_sounds/LICENSE	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,10 @@
+License Disclaimer:
+
+All contents of this directory are Copyright (c) the Dojo Foundation, with the
+following exceptions:
+-------------------------------------------------------------------------------
+
+woohoo.wav, doh.wav, dohaaa.wav:
+	* Copyright original authors.
+	  Copied from:
+	  	http://simpson-homer.com/homer-simpson-soundboard.html

Added: trunk/examples/typeface/root/static/dojo/util/doh/_sounds/doh.wav
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/util/doh/_sounds/doh.wav
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/util/doh/_sounds/dohaaa.wav
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/util/doh/_sounds/dohaaa.wav
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/util/doh/_sounds/woohoo.wav
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/util/doh/_sounds/woohoo.wav
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/dojo/util/doh/runner.html
===================================================================
--- trunk/examples/typeface/root/static/dojo/util/doh/runner.html	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/util/doh/runner.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,283 @@
+<html>
+	<!--
+		NOTE: we are INTENTIONALLY in quirks mode. It makes it much easier to
+		get a "full screen" UI w/ straightforward CSS.
+	-->
+	<!--
+		// TODO: implement global progress bar
+		// TODO: provide a UI for prompted tests
+	-->
+	<head>
+		<title>The Dojo Unit Test Harness, $Rev$</title>
+		<script type="text/javascript">
+			window.dojoUrl = "../../dojo/dojo.js";
+			window.testUrl = "";
+			window.testModule = "";
+
+			// parse out our test URL and our Dojo URL from the query string
+			var qstr = window.location.search.substr(1);
+			if(qstr.length){
+				var qparts = qstr.split("&");
+				for(var x=0; x<qparts.length; x++){
+					var tp = qparts[x].split("=");
+					if(tp[0] == "dojoUrl"){
+						window.dojoUrl = tp[1];
+					}
+					if(tp[0] == "testUrl"){
+						window.testUrl = tp[1];
+					}
+					if(tp[0] == "testModule"){
+						window.testModule = tp[1];
+					}
+				}
+			}
+
+			document.write("<scr"+"ipt type='text/javascript' djConfig='isDebug: true' src='"+dojoUrl+"'></scr"+"ipt>");
+		</script>
+		<script type="text/javascript">
+			try{
+				dojo.require("doh.runner");
+			}catch(e){
+				document.write("<scr"+"ipt type='text/javascript' src='runner.js'></scr"+"ipt>");
+				document.write("<scr"+"ipt type='text/javascript' src='_browserRunner.js'></scr"+"ipt>");
+			}
+			if(testUrl.length){
+				document.write("<scr"+"ipt type='text/javascript' src='"+testUrl+".js'></scr"+"ipt>");
+			}
+		</script>
+		<style type="text/css">
+			@import "../../dojo/resources/dojo.css";
+			/*
+			body {
+				margin: 0px;
+				padding: 0px;
+				font-size: 13px;
+				color: #292929;
+				font-family: Myriad, Lucida Grande, Bitstream Vera Sans, Arial, Helvetica, sans-serif;
+				*font-size: small;
+				*font: x-small;
+			}
+
+			th, td {
+				font-size: 13px;
+				color: #292929;
+				font-family: Myriad, Lucida Grande, Bitstream Vera Sans, Arial, Helvetica, sans-serif;
+				font-weight: normal;
+			}
+
+			* body {
+				line-height: 1.25em;
+			}
+			
+			table {
+				border-collapse: collapse;
+			}
+			*/
+
+			#testLayout {
+				position: relative;
+				left: 0px;
+				top: 0px;
+				width: 100%;
+				height: 100%;
+				border: 1px solid black;
+				border: 0px;
+			}
+
+			.tabBody {
+				margin: 0px;
+				padding: 0px;
+				/*
+				border: 1px solid black;
+				*/
+				background-color: #DEDEDE;
+				border: 0px;
+				width: 100%;
+				height: 100%;
+				position: absolute;
+				left: 0px; 
+				top: 0px;
+				overflow: auto;
+			}
+
+			#logBody {
+				padding-left: 5px;
+				padding-top: 5px;
+				font-family: Monaco, monospace;
+				font-size: 11px;
+				white-space: pre;
+			}
+
+			#progressOuter {
+				background:#e9e9e9 url("http://svn.dojotoolkit.org/dojo/dijit/trunk/themes/tundra/dojoTundraGradientBg.png") repeat-x 0 0;
+				/*
+				border-color: #e8e8e8;
+				*/
+			}
+
+			#progressInner {
+				background: blue url("http://svn.dojotoolkit.org/dojo/dijit/trunk/themes/tundra/bar.gif") repeat-x 0 0;
+				width: 0%;
+				position: relative;
+				left: 0px;
+				top: 0px;
+				height: 100%;
+			}
+
+			#play, #pause {
+				font-family: Webdings;
+				font-size: 1.4em;
+				border: 1px solid #DEDEDE;
+				cursor: pointer;
+				padding-right: 0.5em;
+			}
+
+			.header {
+				border: 1px solid #DEDEDE;
+			}
+
+			button.tab {
+				border-width: 1px 1px 0px 1px;
+				border-style: solid;
+				border-color: #DEDEDE;
+				margin-right: 5px;
+			}
+
+			#testListContainer {
+				/*
+				border: 1px solid black;
+				*/
+				position: relative;
+				height: 99%;
+				width: 100%;
+				overflow: auto;
+			}
+
+			#testList {
+				border-collapse: collapse;
+				position: absolute;
+				left: 0px;
+				width: 100%;
+			}
+
+			#testList > tbody > tr > td {
+				border-bottom: 1px solid #DEDEDE;
+				border-right : 1px solid #DEDEDE;
+				padding: 3px;
+			}
+
+			#testListHeader th {
+				border-bottom: 1px solid #DEDEDE;
+				border-right : 1px solid #DEDEDE;
+				padding: 3px;
+				font-weight: bolder;
+				font-style: italic;
+			}
+
+			#toggleButtons {
+				float: left;
+				background-color: #DEDEDE;
+			}
+
+			tr.inProgress {
+				background-color: #85afde;
+			}
+
+			tr.success {
+				background-color: #7cdea7;
+			}
+
+			tr.failure {
+				background-color: #de827b;
+			}
+		</style>
+	</head>
+	<body>
+		<table id="testLayout" cellpadding="0" cellspacing="0" style="margin: 0;">
+			<tr valign="top" height="40">
+				<td colspan="2" id="logoBar">
+					<h3 style="margin: 5px 5px 0px 5px; float: left;">D.O.H.: The Dojo Objective Harness</h3>
+					<img src="small_logo.png" height="40" style="margin: 0px 5px 0px 5px; float: right;">
+					<span style="margin: 10px 5px 0px 5px; float: right;">
+						<input type="checkbox" id="audio" name="audio" checked>
+						<label for="audio">sounds?</label>
+					</span>
+				</td>
+			</tr>
+			<!--
+			<tr valign="top" height="10">
+				<td colspan="2" id="progressOuter">
+					<div id="progressInner">blah</div>
+				</td>
+			</tr>
+			-->
+			<tr valign="top" height="30">
+				<td width="30%" class="header">
+					<span id="toggleButtons" onclick="doh.togglePaused();">
+						<button id="play">&#052;</button>
+						<button id="pause" style="display: none;">&#059;</button>
+					</span>
+					<span id="runningStatus">
+						<span id="pausedMsg">Stopped</span>
+						<span id="playingMsg" style="display: none;">Tests Running</span>
+					</span>
+				</td>
+				<td width="*" class="header" valign="bottom">
+					<button class="tab" onclick="showTestPage();">Test Page</button>
+					<button class="tab" onclick="showLogPage();">Log</button>
+				</td>
+			</tr>
+			<tr valign="top" style="border: 0; padding: 0; margin: 0;">
+				<td height="100%" style="border: 0; padding: 0; margin: 0;">
+					<div id="testListContainer">
+						<table cellpadding="0" cellspacing="0" border="0"
+							width="100%" id="testList" style="margin: 0;">
+							<thead>
+								<tr id="testListHeader" style="border: 0; padding: 0; margin: 0;" >
+									<th>&nbsp;</th>
+									<th width="20">
+										<input type="checkbox" checked 
+											onclick="toggleRunAll();">
+									</th>
+									<th width="*" style="text-align: left;">test</th>
+									<th width="50">time</th>
+								</tr>
+							</thead>
+							<tbody valign="top">
+								<tr id="groupTemplate" style="display: none;">
+									<td style="font-family: Webdings; width: 15px;">&#052;</td>
+									<td>
+										<input type="checkbox" checked>
+									</td>
+									<td>group name</td>
+									<td>10ms</td>
+								</tr>
+								<tr id="testTemplate" style="display: none;">
+									<td>&nbsp;</td>
+									<td>&nbsp;</td>
+									<td style="padding-left: 20px;">test name</td>
+									<td>10ms</td>
+								</tr>
+							</tbody>
+						</table>
+					</div>
+				</td>
+				<td>
+					<div style="position: relative; width: 99%; height: 100%; top: 0px; left: 0px;">
+						<div class="tabBody"
+							style="z-index: 1;">
+<pre id="logBody"></pre>
+						</div>
+						<iframe id="testBody" class="tabBody"
+							style="z-index: 0;"></iframe>
+						<!--
+							src="http://redesign.dojotoolkit.org"></iframe>
+						-->
+					</div>
+				</td>
+			</tr>
+		</table>
+		<span id="hiddenAudio"></span>
+	</body>
+</html>
+

Added: trunk/examples/typeface/root/static/dojo/util/doh/runner.js
===================================================================
--- trunk/examples/typeface/root/static/dojo/util/doh/runner.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/dojo/util/doh/runner.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,879 @@
+// FIXME: need to add async doh
+// FIXME: need to handle URL wrapping and test registration/running from URLs
+
+// package system gunk. 
+try{
+	dojo.provide("doh.runner");
+}catch(e){
+	if(!this["doh"]){
+		doh = {};
+	}
+}
+
+//
+// Utility Functions and Classes
+//
+
+doh.selfTest = false;
+
+doh.hitch = function(/*Object*/thisObject, /*Function|String*/method /*, ...*/){
+	var args = [];
+	for(var x=2; x<arguments.length; x++){
+		args.push(arguments[x]);
+	}
+	var fcn = ((typeof method == "string") ? thisObject[method] : method) || function(){};
+	return function(){
+		var ta = args.concat([]); // make a copy
+		for(var x=0; x<arguments.length; x++){
+			ta.push(arguments[x]);
+		}
+		return fcn.apply(thisObject, ta); // Function
+	};
+}
+
+doh._mixin = function(/*Object*/ obj, /*Object*/ props){
+	// summary:
+	//		Adds all properties and methods of props to obj. This addition is
+	//		"prototype extension safe", so that instances of objects will not
+	//		pass along prototype defaults.
+	var tobj = {};
+	for(var x in props){
+		// the "tobj" condition avoid copying properties in "props"
+		// inherited from Object.prototype.  For example, if obj has a custom
+		// toString() method, don't overwrite it with the toString() method
+		// that props inherited from Object.protoype
+		if((typeof tobj[x] == "undefined") || (tobj[x] != props[x])){
+			obj[x] = props[x];
+		}
+	}
+	// IE doesn't recognize custom toStrings in for..in
+	if(	this["document"] 
+		&& document.all
+		&& (typeof props["toString"] == "function")
+		&& (props["toString"] != obj["toString"])
+		&& (props["toString"] != tobj["toString"])
+	){
+		obj.toString = props.toString;
+	}
+	return obj; // Object
+}
+
+doh.mixin = function(/*Object*/obj, /*Object...*/props){
+	// summary:	Adds all properties and methods of props to obj. 
+	for(var i=1, l=arguments.length; i<l; i++){
+		doh._mixin(obj, arguments[i]);
+	}
+	return obj; // Object
+}
+
+doh.extend = function(/*Object*/ constructor, /*Object...*/ props){
+	// summary:
+	//		Adds all properties and methods of props to constructor's
+	//		prototype, making them available to all instances created with
+	//		constructor.
+	for(var i=1, l=arguments.length; i<l; i++){
+		doh._mixin(constructor.prototype, arguments[i]);
+	}
+	return constructor; // Object
+}
+
+
+doh._line = "------------------------------------------------------------";
+
+/*
+doh._delegate = function(obj, props){
+	// boodman-crockford delegation
+	function TMP(){};
+	TMP.prototype = obj;
+	var tmp = new TMP();
+	if(props){
+		dojo.lang.mixin(tmp, props);
+	}
+	return tmp;
+}
+*/
+
+doh.debug = function(){
+	// summary:
+	//		takes any number of arguments and sends them to whatever debugging
+	//		or logging facility is available in this environment
+
+	// YOUR TEST RUNNER NEEDS TO IMPLEMENT THIS
+}
+
+doh._AssertFailure = function(msg){
+	// idea for this as way of dis-ambiguating error types is from JUM. 
+	// The JUM is dead! Long live the JUM!
+
+	if(!(this instanceof doh._AssertFailure)){
+		return new doh._AssertFailure(msg);
+	}
+	this.message = new String(msg||"");
+	return this;
+}
+doh._AssertFailure.prototype = new Error();
+doh._AssertFailure.prototype.constructor = doh._AssertFailure;
+doh._AssertFailure.prototype.name = "doh._AssertFailure";
+
+doh.Deferred = function(canceller){
+	this.chain = [];
+	this.id = this._nextId();
+	this.fired = -1;
+	this.paused = 0;
+	this.results = [null, null];
+	this.canceller = canceller;
+	this.silentlyCancelled = false;
+};
+
+doh.extend(doh.Deferred, {
+	getTestCallback: function(cb, scope){
+		var _this = this;
+		return function(){
+			try{
+				cb.apply(scope||dojo.global||_this, arguments);
+			}catch(e){
+				_this.errback(e);
+				return;
+			}
+			_this.callback(true);
+		}
+	},
+
+	getFunctionFromArgs: function(){
+		var a = arguments;
+		if((a[0])&&(!a[1])){
+			if(typeof a[0] == "function"){
+				return a[0];
+			}else if(typeof a[0] == "string"){
+				return dj_global[a[0]];
+			}
+		}else if((a[0])&&(a[1])){
+			return doh.hitch(a[0], a[1]);
+		}
+		return null;
+	},
+
+	makeCalled: function() {
+		var deferred = new doh.Deferred();
+		deferred.callback();
+		return deferred;
+	},
+
+	_nextId: (function(){
+		var n = 1;
+		return function(){ return n++; };
+	})(),
+
+	cancel: function(){
+		if(this.fired == -1){
+			if (this.canceller){
+				this.canceller(this);
+			}else{
+				this.silentlyCancelled = true;
+			}
+			if(this.fired == -1){
+				this.errback(new Error("Deferred(unfired)"));
+			}
+		}else if(	(this.fired == 0)&&
+					(this.results[0] instanceof doh.Deferred)){
+			this.results[0].cancel();
+		}
+	},
+			
+
+	_pause: function(){
+		this.paused++;
+	},
+
+	_unpause: function(){
+		this.paused--;
+		if ((this.paused == 0) && (this.fired >= 0)) {
+			this._fire();
+		}
+	},
+
+	_continue: function(res){
+		this._resback(res);
+		this._unpause();
+	},
+
+	_resback: function(res){
+		this.fired = ((res instanceof Error) ? 1 : 0);
+		this.results[this.fired] = res;
+		this._fire();
+	},
+
+	_check: function(){
+		if(this.fired != -1){
+			if(!this.silentlyCancelled){
+				throw new Error("already called!");
+			}
+			this.silentlyCancelled = false;
+			return;
+		}
+	},
+
+	callback: function(res){
+		this._check();
+		this._resback(res);
+	},
+
+	errback: function(res){
+		this._check();
+		if(!(res instanceof Error)){
+			res = new Error(res);
+		}
+		this._resback(res);
+	},
+
+	addBoth: function(cb, cbfn){
+		var enclosed = this.getFunctionFromArgs(cb, cbfn);
+		if(arguments.length > 2){
+			enclosed = doh.hitch(null, enclosed, arguments, 2);
+		}
+		return this.addCallbacks(enclosed, enclosed);
+	},
+
+	addCallback: function(cb, cbfn){
+		var enclosed = this.getFunctionFromArgs(cb, cbfn);
+		if(arguments.length > 2){
+			enclosed = doh.hitch(null, enclosed, arguments, 2);
+		}
+		return this.addCallbacks(enclosed, null);
+	},
+
+	addErrback: function(cb, cbfn){
+		var enclosed = this.getFunctionFromArgs(cb, cbfn);
+		if(arguments.length > 2){
+			enclosed = doh.hitch(null, enclosed, arguments, 2);
+		}
+		return this.addCallbacks(null, enclosed);
+	},
+
+	addCallbacks: function(cb, eb){
+		this.chain.push([cb, eb])
+		if(this.fired >= 0){
+			this._fire();
+		}
+		return this;
+	},
+
+	_fire: function(){
+		var chain = this.chain;
+		var fired = this.fired;
+		var res = this.results[fired];
+		var self = this;
+		var cb = null;
+		while (chain.length > 0 && this.paused == 0) {
+			// Array
+			var pair = chain.shift();
+			var f = pair[fired];
+			if(f == null){
+				continue;
+			}
+			try {
+				res = f(res);
+				fired = ((res instanceof Error) ? 1 : 0);
+				if(res instanceof doh.Deferred){
+					cb = function(res){
+						self._continue(res);
+					}
+					this._pause();
+				}
+			}catch(err){
+				fired = 1;
+				res = err;
+			}
+		}
+		this.fired = fired;
+		this.results[fired] = res;
+		if((cb)&&(this.paused)){
+			res.addBoth(cb);
+		}
+	}
+});
+
+//
+// State Keeping and Reporting
+//
+
+doh._testCount = 0;
+doh._groupCount = 0;
+doh._errorCount = 0;
+doh._failureCount = 0;
+doh._currentGroup = null;
+doh._currentTest = null;
+doh._paused = true;
+
+doh._init = function(){
+	this._currentGroup = null;
+	this._currentTest = null;
+	this._errorCount = 0;
+	this._failureCount = 0;
+	this.debug(this._testCount, "tests to run in", this._groupCount, "groups");
+}
+
+// doh._urls = [];
+doh._groups = {};
+
+//
+// Test Registration
+//
+
+doh.registerTestNs = function(/*String*/ group, /*Object*/ ns){
+	// summary:
+	//		adds the passed namespace object to the list of objects to be
+	//		searched for test groups. Only "public" functions (not prefixed
+	//		with "_") will be added as doh to be run. If you'd like to use
+	//		fixtures (setUp(), tearDown(), and runTest()), please use
+	//		registerTest() or registerdoh().
+	for(var x in ns){
+		if(	(x.charAt(0) == "_") &&
+			(typeof ns[x] == "function") ){
+			this.registerTest(group, ns[x]);
+		}
+	}
+}
+
+doh._testRegistered = function(group, fixture){
+	// slot to be filled in
+}
+
+doh._groupStarted = function(group){
+	// slot to be filled in
+}
+
+doh._groupFinished = function(group, success){
+	// slot to be filled in
+}
+
+doh._testStarted = function(group, fixture){
+	// slot to be filled in
+}
+
+doh._testFinished = function(group, fixture, success){
+	// slot to be filled in
+}
+
+doh.registerGroup = function(	/*String*/ group, 
+								/*Array||Function||Object*/ doh, 
+								/*Function*/ setUp, 
+								/*Function*/ tearDown){
+	// summary:
+	//		registers an entire group of doh at once and provides a setUp and
+	//		tearDown facility for groups. If you call this method with only
+	//		setUp and tearDown parameters, they will replace previously
+	//		installed setUp or tearDown functions for the group with the new
+	//		methods.
+	// group:
+	//		string name of the group
+	// doh:
+	//		either a function or an object or an array of functions/objects. If
+	//		an object, it must contain at *least* a "runTest" method, and may
+	//		also contain "setUp" and "tearDown" methods. These will be invoked
+	//		on either side of the "runTest" method (respectively) when the test
+	//		is run. If an array, it must contain objects matching the above
+	//		description or test functions.
+	// setUp: a function for initializing the test group
+	// tearDown: a function for initializing the test group
+	if(doh){
+		this.register(group, doh);
+	}
+	if(setUp){
+		this._groups[group].setUp = setUp;
+	}
+	if(tearDown){
+		this._groups[group].tearDown = tearDown;
+	}
+}
+
+doh._getTestObj = function(group, test){
+	var tObj = test;
+	if(typeof test == "string"){
+		if(test.substr(0, 4)=="url:"){
+			return this.registerUrl(group, test);
+		}else{
+			tObj = {
+				name: test.replace("/\s/g", "_")
+			};
+			tObj.runTest = new Function("t", test);
+		}
+	}else if(typeof test == "function"){
+		// if we didn't get a fixture, wrap the function
+		tObj = { "runTest": test };
+		if(test["name"]){
+			tObj.name = test.name;
+		}else{
+			try{
+				var fStr = "function ";
+				var ts = tObj.runTest+"";
+				if(0 <= ts.indexOf(fStr)){
+					tObj.name = ts.split(fStr)[1].split("(", 1)[0];
+				}
+				// doh.debug(tObj.runTest.toSource());
+			}catch(e){
+			}
+		}
+		// FIXME: try harder to get the test name here
+	}
+	return tObj;
+}
+
+doh.registerTest = function(/*String*/ group, /*Function||Object*/ test){
+	// summary:
+	//		add the provided test function or fixture object to the specified
+	//		test group.
+	// group:
+	//		string name of the group to add the test to
+	// test:
+	//		either a function or an object. If an object, it must contain at
+	//		*least* a "runTest" method, and may also contain "setUp" and
+	//		"tearDown" methods. These will be invoked on either side of the
+	//		"runTest" method (respectively) when the test is run.
+	if(!this._groups[group]){
+		this._groupCount++;
+		this._groups[group] = [];
+		this._groups[group].inFlight = 0;
+	}
+	var tObj = this._getTestObj(group, test);
+	if(!tObj){ return; }
+	this._groups[group].push(tObj);
+	this._testCount++;
+	this._testRegistered(group, tObj);
+	return tObj;
+}
+
+doh.registerdoh = function(/*String*/ group, /*Array*/ testArr){
+	// summary:
+	//		registers a group of doh, treating each element of testArr as
+	//		though it were being (along with group) passed to the registerTest
+	//		method.
+	for(var x=0; x<testArr.length; x++){
+		this.registerTest(group, testArr[x]);
+	}
+}
+
+// FIXME: move implementation to _browserRunner?
+doh.registerUrl = function(	/*String*/ group, 
+								/*String*/ url, 
+								/*Integer*/ timeout){
+	this.debug("ERROR:");
+	this.debug("\tNO registerUrl() METHOD AVAILABLE.");
+	// this._urls.push(url);
+}
+
+doh.registerString = function(group, str){
+}
+
+// FIXME: remove the doh.add alias SRTL.
+doh.register = doh.add = function(groupOrNs, testOrNull){
+	// summary:
+	// 		"magical" variant of registerdoh, registerTest, and
+	// 		registerTestNs. Will accept the calling arguments of any of these
+	// 		methods and will correctly guess the right one to register with.
+	if(	(arguments.length == 1)&&
+		(typeof groupOrNs == "string") ){
+		if(groupOrNs.substr(0, 4)=="url:"){
+			this.registerUrl(groupOrNs);
+		}else{
+			this.registerTest("ungrouped", groupOrNs);
+		}
+	}
+	if(arguments.length == 1){
+		this.debug("invalid args passed to doh.register():", groupOrNs, ",", testOrNull);
+		return;
+	}
+	if(typeof testOrNull == "string"){
+		if(testOrNull.substr(0, 4)=="url:"){
+			this.registerUrl(testOrNull);
+		}else{
+			this.registerTest(groupOrNs, testOrNull);
+		}
+		// this.registerTestNs(groupOrNs, testOrNull);
+		return;
+	}
+	if(	doh._isArray(testOrNull) ){
+		this.registerdoh(groupOrNs, testOrNull);
+		return;
+	}
+	this.registerTest(groupOrNs, testOrNull);
+}
+
+//
+// Assertions and In-Test Utilities
+//
+
+doh.t = doh.assertTrue = function(/*Object*/ condition){
+	// summary:
+	//		is the passed item "truthy"?
+	if(!eval(condition)){
+		throw doh._AssertFailure("assertTrue('" + condition + "') failed");
+	}
+}
+
+doh.f = doh.assertFalse = function(/*Object*/ condition){
+	// summary:
+	//		is the passed item "falsey"?
+	if(eval(condition)){
+		throw doh._AssertFailure("assertFalse('" + condition + "') failed");
+	}
+}
+
+doh.is = doh.assertEqual = function(/*Object*/ expected, /*Object*/ actual){
+	// summary:
+	//		are the passed expected and actual objects/values deeply
+	//		equivalent?
+	if((expected == undefined)&&(actual == undefined)){ 
+		return true;
+	}
+	if(expected === actual){
+		return true;
+	}
+	if(expected == actual){ 
+		return true;
+	}
+	if(	(this._isArray(expected) && this._isArray(actual))&&
+		(this._arrayEq(expected, actual)) ){
+		return true;
+	}
+	if( ((typeof expected == "object")&&((typeof actual == "object")))&&
+		(this._objPropEq(expected, actual)) ){
+		return true;
+	}
+	throw new doh._AssertFailure("assertEqual() failed: expected |"+expected+"| but got |"+actual+"|");
+}
+
+doh._arrayEq = function(expected, actual){
+	if(expected.length != actual.length){ return false; }
+	// FIXME: we're not handling circular refs. Do we care?
+	for(var x=0; x<expected.length; x++){
+		if(!doh.assertEqual(expected[x], actual[x])){ return false; }
+	}
+	return true;
+}
+
+doh._objPropEq = function(expected, actual){
+	for(var x in expected){
+		if(!doh.assertEqual(expected[x], actual[x])){
+			return false;
+		}
+	}
+	return true;
+}
+
+doh._isArray = function(arr){
+	return ((arr instanceof Array)||(typeof arr == "array") );
+}
+
+//
+// Runner-Wrapper
+//
+
+doh._setupGroupForRun = function(/*String*/ groupName, /*Integer*/ idx){
+	var tg = this._groups[groupName];
+	this.debug(this._line);
+	this.debug("GROUP", "\""+groupName+"\"", "has", tg.length, "test"+((tg.length > 1) ? "s" : "")+" to run");
+}
+
+doh._handleFailure = function(groupName, fixture, e){
+	// this.debug("FAILED test:", fixture.name);
+	// mostly borrowed from JUM
+	this._groups[groupName].failures++;
+	var out = "";
+	if(e instanceof this._AssertFailure){
+		this._failureCount++;
+		if(e["fileName"]){ out += e.fileName + ':'; }
+		if(e["lineNumber"]){ out += e.lineNumber + ' '; }
+		out += e+": "+e.message;
+		this.debug("\t_AssertFailure:", out);
+	}else{
+		this._errorCount++;
+	}
+	this.debug(e);
+	if(fixture.runTest["toSource"]){
+		var ss = fixture.runTest.toSource();
+		this.debug("\tERROR IN:\n\t\t", ss);
+	}else{
+		this.debug("\tERROR IN:\n\t\t", fixture.runTest);
+	}
+}
+
+try{
+	setTimeout(function(){}, 0);
+}catch(e){
+	setTimeout = function(func){
+		return func();
+	}
+}
+
+doh._runFixture = function(groupName, fixture){
+	var tg = this._groups[groupName];
+	this._testStarted(groupName, fixture);
+	var threw = false;
+	var err = null;
+	// run it, catching exceptions and reporting them
+	try{
+		// let doh reference "this.group.thinger..." which can be set by
+		// another test or group-level setUp function
+		fixture.group = tg; 
+		// only execute the parts of the fixture we've got
+		if(fixture["setUp"]){ fixture.setUp(this); }
+		if(fixture["runTest"]){  // should we error out of a fixture doesn't have a runTest?
+			fixture.startTime = new Date();
+			var ret = fixture.runTest(this); 
+			fixture.endTime = new Date();
+			// if we get a deferred back from the test runner, we know we're
+			// gonna wait for an async result. It's up to the test code to trap
+			// errors and give us an errback or callback.
+			if(ret instanceof doh.Deferred){
+
+				tg.inFlight++;
+				ret.groupName = groupName;
+				ret.fixture = fixture;
+
+				ret.addErrback(function(err){
+					doh._handleFailure(groupName, fixture, err);
+				});
+
+				var retEnd = function(){
+					if(fixture["tearDown"]){ fixture.tearDown(doh); }
+					tg.inFlight--;
+					if((!tg.inFlight)&&(tg.iterated)){
+						doh._groupFinished(groupName, (!tg.failures));
+					}
+					doh._testFinished(groupName, fixture, ret.results[0]);
+					if(doh._paused){
+						doh.run();
+					}
+				}
+
+				var timer = setTimeout(function(){
+					ret.cancel();
+					retEnd();
+				}, fixture["timeout"]||1000);
+
+				ret.addBoth(function(arg){
+					clearTimeout(timer);
+					retEnd();
+				});
+				if(ret.fired < 0){
+					doh.pause();
+				}
+				return ret;
+			}
+		}
+		if(fixture["tearDown"]){ fixture.tearDown(this); }
+	}catch(e){
+		threw = true;
+		err = e;
+		if(!fixture.endTime){
+			fixture.endTime = new Date();
+		}
+	}
+	var d = new doh.Deferred();
+	setTimeout(this.hitch(this, function(){
+		if(threw){
+			this._handleFailure(groupName, fixture, err);
+		}
+		this._testFinished(groupName, fixture, (!threw));
+
+		if((!tg.inFlight)&&(tg.iterated)){
+			doh._groupFinished(groupName, (!tg.failures));
+		}
+		if(doh._paused){
+			doh.run();
+		}
+	}), 30);
+	doh.pause();
+	return d;
+}
+
+doh._testId = 0;
+doh.runGroup = function(/*String*/ groupName, /*Integer*/ idx){
+	// summary:
+	//		runs the specified test group
+
+	// the general structure of the algorithm is to run through the group's
+	// list of doh, checking before and after each of them to see if we're in
+	// a paused state. This can be caused by the test returning a deferred or
+	// the user hitting the pause button. In either case, we want to halt
+	// execution of the test until something external to us restarts it. This
+	// means we need to pickle off enough state to pick up where we left off.
+
+	// FIXME: need to make fixture execution async!!
+
+	var tg = this._groups[groupName];
+	if(tg.skip === true){ return; }
+	if(this._isArray(tg)){
+		if(idx<=tg.length){
+			if((!tg.inFlight)&&(tg.iterated == true)){
+				doh._groupFinished(groupName, (!tg.failures));
+				return;
+			}
+		}
+		if(!idx){
+			tg.inFlight = 0;
+			tg.iterated = false;
+			tg.failures = 0;
+		}
+		doh._groupStarted(groupName);
+		if(!idx){
+			this._setupGroupForRun(groupName, idx);
+		}
+		for(var y=(idx||0); y<tg.length; y++){
+			if(this._paused){
+				this._currentTest = y;
+				// this.debug("PAUSED at:", tg[y].name, this._currentGroup, this._currentTest);
+				return;
+			}
+			doh._runFixture(groupName, tg[y]);
+			if(this._paused){
+				this._currentTest = y+1;
+				if(this._currentTest == tg.length){
+					tg.iterated = true;
+				}
+				// this.debug("PAUSED at:", tg[y].name, this._currentGroup, this._currentTest);
+				return;
+			}
+		}
+		tg.iterated = true;
+		if(!tg.inFlight){
+			doh._groupFinished(groupName, (!tg.failures));
+		}
+	}
+}
+
+doh._onEnd = function(){}
+
+doh._report = function(){
+	// summary:
+	//		a private method to be implemented/replaced by the "locally
+	//		appropriate" test runner
+
+	// this.debug("ERROR:");
+	// this.debug("\tNO REPORTING OUTPUT AVAILABLE.");
+	// this.debug("\tIMPLEMENT doh._report() IN YOUR TEST RUNNER");
+
+	this.debug(this._line);
+	this.debug("| TEST SUMMARY:");
+	this.debug(this._line);
+	this.debug("\t", this._testCount, "tests in", this._groupCount, "groups");
+	this.debug("\t", this._errorCount, "errors");
+	this.debug("\t", this._failureCount, "failures");
+}
+
+doh.togglePaused = function(){
+	this[(this._paused) ? "run" : "pause"]();
+}
+
+doh.pause = function(){
+	// summary:
+	//		halt test run. Can be resumed.
+	this._paused = true;
+}
+
+doh.run = function(){
+	// summary:
+	//		begins or resumes the test process.
+	// this.debug("STARTING");
+	this._paused = false;
+	var cg = this._currentGroup;
+	var ct = this._currentTest;
+	var found = false;
+	if(!cg){
+		this._init(); // we weren't paused
+		found = true;
+	}
+	this._currentGroup = null;
+	this._currentTest = null;
+
+	for(var x in this._groups){
+		if(
+			( (!found)&&(x == cg) )||( found )
+		){
+			if(this._paused){ return; }
+			this._currentGroup = x;
+			if(!found){
+				found = true;
+				this.runGroup(x, ct);
+			}else{
+				this.runGroup(x);
+			}
+			if(this._paused){ return; }
+		}
+	}
+	this._currentGroup = null;
+	this._currentTest = null;
+	this._paused = false;
+	this._onEnd();
+	this._report();
+}
+
+tests = doh;
+
+try{
+	dojo.platformRequire({
+		browser: ["doh._browserRunner"],
+		rhino: ["doh._rhinoRunner"],
+		spidermonkey: ["doh._rhinoRunner"]
+	});
+	var _shouldRequire = (dojo.isBrowser) ? (dojo.global == dojo.global["parent"]) : true;
+	if(_shouldRequire){
+		if(dojo.isBrowser){
+			dojo.addOnLoad(function(){
+				if(dojo.byId("testList")){
+					var _tm = ( (dojo.global.testModule && dojo.global.testModule.length) ? dojo.global.testModule : "dojo.tests.module");
+					dojo.forEach(_tm.split(","), dojo.require, dojo);
+					setTimeout(function(){
+						doh.run();
+					}, 500);
+				}
+			});
+		}else{
+			dojo.require("doh._base");
+		}
+	}
+}catch(e){
+	print("\n"+doh._line);
+	print("The Dojo Unit Test Harness, $Rev$");
+	print("Copyright (c) 2007, The Dojo Foundation, All Rights Reserved");
+	print(doh._line, "\n");
+
+	load("_rhinoRunner.js");
+
+	try{
+		var dojoUrl = "../../dojo/dojo.js";
+		var testUrl = "";
+		var testModule = "dojo.tests.module";
+		for(var x=0; x<arguments.length; x++){
+			if(arguments[x].indexOf("=") > 0){
+				var tp = arguments[x].split("=");
+				if(tp[0] == "dojoUrl"){
+					dojoUrl = tp[1];
+				}
+				if(tp[0] == "testUrl"){
+					testUrl = tp[1];
+				}
+				if(tp[0] == "testModule"){
+					testModule = tp[1];
+				}
+			}
+		}
+		if(dojoUrl.length){
+			if(!this["djConfig"]){
+				djConfig = {};
+			}
+			djConfig.baseUrl = dojoUrl.split("dojo.js")[0];
+			load(dojoUrl);
+		}
+		if(testUrl.length){
+			load(testUrl);
+		}
+		if(testModule.length){
+			dojo.forEach(testModule.split(","), dojo.require, dojo);
+		}
+	}catch(e){
+	}
+
+	doh.run();
+}

Added: trunk/examples/typeface/root/static/dojo/util/doh/small_logo.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/dojo/util/doh/small_logo.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/RSS.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/RSS.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/bg.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/bg.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/btn_120x50_built.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/btn_120x50_built.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/btn_120x50_built_shadow.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/btn_120x50_built_shadow.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/btn_120x50_powered.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/btn_120x50_powered.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/btn_120x50_powered_shadow.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/btn_120x50_powered_shadow.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/btn_88x31_built.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/btn_88x31_built.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/btn_88x31_built_shadow.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/btn_88x31_built_shadow.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/btn_88x31_powered.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/btn_88x31_powered.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/btn_88x31_powered_shadow.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/btn_88x31_powered_shadow.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/catalyst_logo.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/catalyst_logo.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/catalyst_small.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/catalyst_small.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/comments.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/comments.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/icons/delicious.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/icons/delicious.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/icons/digg.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/icons/digg.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/icons/furl.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/icons/furl.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/icons/google.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/icons/google.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/icons/newsvine.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/icons/newsvine.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/icons/reddit.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/icons/reddit.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/icons/technorati.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/icons/technorati.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/icons/yahoo.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/icons/yahoo.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/ntbg.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/ntbg.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/rails.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/rails.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/rss.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/rss.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/images/search.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/static/images/search.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/static/javascripts/application.js
===================================================================
--- trunk/examples/typeface/root/static/javascripts/application.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/javascripts/application.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,106 @@
+function clear_cache(id) {
+	var handler = dojo.xhrGet({
+		url: '/admin/clear/' + id,
+		content: { field: null }
+	});
+	handler.addCallback(function(data) {
+	    dojo.byId('jaxdate').innerHTML="Cleared Cache";
+	});
+}
+
+function clear_cache_page(id) {
+	var handler = dojo.xhrGet({
+		url: '/admin/clear_page/' + id,
+		content: { field: null }
+	});
+	handler.addCallback(function(data) {
+	    dojo.byId('jaxdate').innerHTML="Cleared Cache";
+	});
+}
+
+function help_complete_combobox(field,db_table,db_field) {
+	var handler = dojo.xhrGet({
+		url: '/ajax/help_complete_combobox/'+db_table+'/'+db_field,
+		mimetype: "text/json",
+		content: { field: field.getValue() } 
+	});
+	handler.addCallback(function(data) {
+	    field.dataProvider.setData(data['result']);
+	});
+}
+
+function sort_categories(field) {
+	var handler = dojo.xhrGet({
+		url: '/ajax/sort_by',
+		content: { field: field.id }
+	});
+	handler.addCallback(function(data) {
+	    dojo.byId('cat_list').innerHTML=data;
+	});
+}
+
+function toggle_cat_list() {
+    dojo.connect(
+		dojo.byId("alpha"), "onclick" , function (e) { 
+			e.preventDefault(); 
+			dojo.byId("alpha").className="selected";
+			dojo.byId("freq").className="";
+			sort_categories(dojo.byId("alpha"));  
+			}
+	);
+	dojo.connect(
+		dojo.byId("freq"), "onclick" , function (e) { 
+			e.preventDefault(); 
+			dojo.byId("alpha").className="";
+			dojo.byId("freq").className="selected";
+			sort_categories(dojo.byId("freq")); 
+			 }
+	);
+}
+
+function switch_editor(what) {
+	if(what == 'wysiwyg') {
+		dojo.widget.createWidget("Editor2", 
+			{ 	shareToolbar: false, 
+				toolbarAlwaysVisible: true,
+				height: "90%",
+				width: "800",
+				focusOnLoad: false 
+			}, dojo.byId("body"));
+			dojo.byId("pborder").style.border="1px solid";
+	}
+	else {
+		var value="";
+		dojo.forEach(dojo.widget.byType('Editor2'), 
+			function(e) { value= e.getEditorContent(); });
+			
+		dojo.forEach(dojo.widget.byType('Editor2'), 
+			function(e){ e.destroy(); });
+		dojo.byId('body').value=value;
+		dojo.byId("pborder").style.border="";
+	}
+}
+
+function toggle_cats() {
+	if( dojo.byId("select_cats").style.display=="none" ) {
+		dojo.byId("select_cats").style.display="block";
+	}
+	else {
+		dojo.byId("select_cats").style.display="none";
+	}
+}
+
+function check_articles(field) {
+	if ((field.value.length > 0 && field.value.length < 3) || field.value.length==0 ) {
+		dojo.byId('search_board').style.display="none";
+		return;
+	}
+	var handler = dojo.xhrGet({
+		url: '/ajax/check_articles',
+		content: { field: field.value }
+	});
+	handler.addCallback(function(data) {
+	    dojo.byId('search_board').style.display="block";
+		dojo.byId('search_board').innerHTML=data;
+	});
+}
\ No newline at end of file


Property changes on: trunk/examples/typeface/root/static/javascripts/application.js
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/static/javascripts/nicetitles.js
===================================================================
--- trunk/examples/typeface/root/static/javascripts/nicetitles.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/javascripts/nicetitles.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,216 @@
+addEvent(window, "load", makeNiceTitles);
+
+var XHTMLNS = "http://www.w3.org/1999/xhtml";
+var CURRENT_NICE_TITLE;
+var browser = new Browser();
+
+function makeNiceTitles() {
+    if (!document.createElement || !document.getElementsByTagName) return;
+    // add namespace methods to HTML DOM; this makes the script work in both
+    // HTML and XML contexts.
+    if(!document.createElementNS)
+    {
+        document.createElementNS = function(ns,elt) {
+            return document.createElement(elt);
+        }
+    }
+
+    if( !document.links )
+    {
+        document.links = document.getElementsByTagName("a");
+    }
+    for (var ti=0;ti<document.links.length;ti++) {
+        var lnk = document.links[ti];
+        if (lnk.title) {
+            lnk.setAttribute("nicetitle",lnk.title);
+            lnk.removeAttribute("title");
+            addEvent(lnk,"mouseover",showNiceTitle);
+            addEvent(lnk,"mouseout",hideNiceTitle);
+            addEvent(lnk,"focus",showNiceTitle);
+            addEvent(lnk,"blur",hideNiceTitle);
+        }
+    }
+    var instags = document.getElementsByTagName("ins");
+    if (instags) {
+    for (var ti=0;ti<instags.length;ti++) {
+        var instag = instags[ti];
+        if (instag.dateTime) {
+            var strDate = instag.dateTime;
+            var dtIns = new Date(strDate.substring(0,4),parseInt(strDate.substring(4,6)-1),strDate.substring(6,8),strDate.substring(9,11),strDate.substring(11,13),strDate.substring(13,15));
+            instag.setAttribute("nicetitle","Added on "+dtIns.toString());
+            addEvent(instag,"mouseover",showNiceTitle);
+            addEvent(instag,"mouseout",hideNiceTitle);
+            addEvent(instag,"focus",showNiceTitle);
+            addEvent(instag,"blur",hideNiceTitle);
+        }
+    }
+    }
+}
+
+function findPosition( oLink ) {
+  if( oLink.offsetParent ) {
+    for( var posX = 0, posY = 0; oLink.offsetParent; oLink = oLink.offsetParent ) {
+      posX += oLink.offsetLeft;
+      posY += oLink.offsetTop;
+    }
+    return [ posX, posY ];
+  } else {
+    return [ oLink.x, oLink.y ];
+  }
+}
+
+function showNiceTitle(e) {
+    if (CURRENT_NICE_TITLE) hideNiceTitle(CURRENT_NICE_TITLE);
+    if (!document.getElementsByTagName) return;
+    if (window.event && window.event.srcElement) {
+        lnk = window.event.srcElement
+    } else if (e && e.target) {
+        lnk = e.target
+    }
+    if (!lnk) return;
+    if (lnk.nodeType == 3) {
+        // lnk is a textnode -- ascend parents until we hit a link
+        lnk = getParent(lnk,"A");
+    }
+    if (!lnk) return;
+    nicetitle = lnk.getAttribute("nicetitle");
+
+    var d = document.createElementNS(XHTMLNS,"div");
+    d.className = "nicetitle";
+    tnt = document.createTextNode(nicetitle);
+    pat = document.createElementNS(XHTMLNS,"p");
+    pat.className = "titletext";
+    pat.appendChild(tnt);
+    d.appendChild(pat);
+    if (lnk.href) {
+        tnd = document.createTextNode(lnk.href);
+        pad = document.createElementNS(XHTMLNS,"p");
+        pad.className = "destination";
+        pad.appendChild(tnd);
+        d.appendChild(pad);
+    }
+
+    STD_WIDTH = 300;
+    if (lnk.href) {
+        h = lnk.href.length;
+    } else { h = nicetitle.length; }
+    if (nicetitle.length) {
+      t = nicetitle.length;
+    }
+    h_pixels = h*6; t_pixels = t*10;
+
+    if (h_pixels > STD_WIDTH) {
+        w = h_pixels;
+    } else if ((STD_WIDTH>t_pixels) && (t_pixels>h_pixels)) {
+        w = t_pixels;
+    } else if ((STD_WIDTH>t_pixels) && (h_pixels>t_pixels)) {
+        w = h_pixels;
+    } else {
+        w = STD_WIDTH;
+    }
+
+    d.style.width = w + 'px';    
+
+    /*
+    mx = lnk.offsetLeft;
+    my = lnk.offsetTop;
+    */
+    mpos = findPosition(lnk);
+    mx = mpos[0];
+    my = mpos[1];
+    //xy = getMousePosition(e);
+    //mx = xy[0]; my = xy[1];
+
+    d.style.left = (mx+15) + 'px';
+    d.style.top = (my+35) + 'px';
+    if (window.innerWidth && ((mx+w) > window.innerWidth)) {
+        d.style.left = (window.innerWidth - w - 25) + "px";
+    }
+    if (document.body.scrollWidth && ((mx+w) > document.body.scrollWidth)) {
+        d.style.left = (document.body.scrollWidth - w - 25) + "px";
+    }
+
+    document.getElementsByTagName("body")[0].appendChild(d);
+
+    CURRENT_NICE_TITLE = d;
+}
+
+function hideNiceTitle(e) {
+    if (!document.getElementsByTagName) return;
+    if (CURRENT_NICE_TITLE) {
+        document.getElementsByTagName("body")[0].removeChild(CURRENT_NICE_TITLE);
+        CURRENT_NICE_TITLE = null;
+    }
+}
+
+// Add an eventListener to browsers that can do it somehow.
+// Originally by the amazing Scott Andrew.
+function addEvent(obj, evType, fn){
+  if (obj.addEventListener){
+    obj.addEventListener(evType, fn, false);
+    return true;
+  } else if (obj.attachEvent){
+	var r = obj.attachEvent("on"+evType, fn);
+    return r;
+  } else {
+	return false;
+  }
+}
+
+function getParent(el, pTagName) {
+	if (el == null) return null;
+	else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())	// Gecko bug, supposed to be uppercase
+		return el;
+	else
+		return getParent(el.parentNode, pTagName);
+}
+
+function getMousePosition(event) {
+  if (browser.isIE) {
+    x = window.event.clientX + document.documentElement.scrollLeft
+      + document.body.scrollLeft;
+    y = window.event.clientY + document.documentElement.scrollTop
+      + document.body.scrollTop;
+  }
+  if (browser.isNS) {
+    x = event.clientX + window.scrollX;
+    y = event.clientY + window.scrollY;
+  }
+  return [x,y];
+}
+
+// Determine browser and version.
+
+function Browser() {
+// blah, browser detect, but mouse-position stuff doesn't work any other way
+  var ua, s, i;
+
+  this.isIE    = false;
+  this.isNS    = false;
+  this.version = null;
+
+  ua = navigator.userAgent;
+
+  s = "MSIE";
+  if ((i = ua.indexOf(s)) >= 0) {
+    this.isIE = true;
+    this.version = parseFloat(ua.substr(i + s.length));
+    return;
+  }
+
+  s = "Netscape6/";
+  if ((i = ua.indexOf(s)) >= 0) {
+    this.isNS = true;
+    this.version = parseFloat(ua.substr(i + s.length));
+    return;
+  }
+
+  // Treat any other "Gecko" browser as NS 6.1.
+
+  s = "Gecko";
+  if ((i = ua.indexOf(s)) >= 0) {
+    this.isNS = true;
+    this.version = 6.1;
+    return;
+  }
+}
\ No newline at end of file

Added: trunk/examples/typeface/root/static/javascripts/niftycube.js
===================================================================
--- trunk/examples/typeface/root/static/javascripts/niftycube.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/javascripts/niftycube.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,299 @@
+
+/* Nifty Corners Cube - rounded corners with CSS and Javascript
+Copyright 2006 Alessandro Fulciniti (a.fulciniti html.it)
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+var niftyOk=(document.getElementById && document.createElement && Array.prototype.push);
+var niftyCss=false;
+
+String.prototype.find=function(what){
+return(this.indexOf(what)>=0 ? true : false);
+}
+
+var oldonload=window.onload;
+if(typeof(NiftyLoad)!='function') NiftyLoad=function(){};
+if(typeof(oldonload)=='function')
+    window.onload=function(){oldonload();AddCss();NiftyLoad()};
+else window.onload=function(){AddCss();NiftyLoad()};
+
+function AddCss(){
+niftyCss=true;
+var l=CreateEl("link");
+l.setAttribute("type","text/css");
+l.setAttribute("rel","stylesheet");
+l.setAttribute("href","/static/stylesheets/niftyCorners.css");
+l.setAttribute("media","screen");
+document.getElementsByTagName("head")[0].appendChild(l);
+}
+
+function Nifty(selector,options){
+if(niftyOk==false) return;
+if(niftyCss==false) AddCss();
+var i,v=selector.split(","),h=0;
+if(options==null) options="";
+if(options.find("fixed-height"))
+    h=getElementsBySelector(v[0])[0].offsetHeight;
+for(i=0;i<v.length;i++)
+    Rounded(v[i],options);
+if(options.find("height")) SameHeight(selector,h);
+}
+
+function Rounded(selector,options){
+var i,top="",bottom="",v=new Array();
+if(options!=""){
+    options=options.replace("left","tl bl");
+    options=options.replace("right","tr br");
+    options=options.replace("top","tr tl");
+    options=options.replace("bottom","br bl");
+    options=options.replace("transparent","alias");
+    if(options.find("tl")){
+        top="both";
+        if(!options.find("tr")) top="left";
+        }
+    else if(options.find("tr")) top="right";
+    if(options.find("bl")){
+        bottom="both";
+        if(!options.find("br")) bottom="left";
+        }
+    else if(options.find("br")) bottom="right";
+    }
+if(top=="" && bottom=="" && !options.find("none")){top="both";bottom="both";}
+v=getElementsBySelector(selector);
+for(i=0;i<v.length;i++){
+    FixIE(v[i]);
+    if(top!="") AddTop(v[i],top,options);
+    if(bottom!="") AddBottom(v[i],bottom,options);
+    }
+}
+
+function AddTop(el,side,options){
+var d=CreateEl("b"),lim=4,border="",p,i,btype="r",bk,color;
+d.style.marginLeft="-"+getPadding(el,"Left")+"px";
+d.style.marginRight="-"+getPadding(el,"Right")+"px";
+if(options.find("alias") || (color=getBk(el))=="transparent"){
+    color="transparent";bk="transparent"; border=getParentBk(el);btype="t";
+    }
+else{
+    bk=getParentBk(el); border=Mix(color,bk);
+    }
+d.style.background=bk;
+d.className="niftycorners";
+p=getPadding(el,"Top");
+if(options.find("small")){
+    d.style.marginBottom=(p-2)+"px";
+    btype+="s"; lim=2;
+    }
+else if(options.find("big")){
+    d.style.marginBottom=(p-10)+"px";
+    btype+="b"; lim=8;
+    }
+else d.style.marginBottom=(p-5)+"px";
+for(i=1;i<=lim;i++)
+    d.appendChild(CreateStrip(i,side,color,border,btype));
+el.style.paddingTop="0";
+el.insertBefore(d,el.firstChild);
+}
+
+function AddBottom(el,side,options){
+var d=CreateEl("b"),lim=4,border="",p,i,btype="r",bk,color;
+d.style.marginLeft="-"+getPadding(el,"Left")+"px";
+d.style.marginRight="-"+getPadding(el,"Right")+"px";
+if(options.find("alias") || (color=getBk(el))=="transparent"){
+    color="transparent";bk="transparent"; border=getParentBk(el);btype="t";
+    }
+else{
+    bk=getParentBk(el); border=Mix(color,bk);
+    }
+d.style.background=bk;
+d.className="niftycorners";
+p=getPadding(el,"Bottom");
+if(options.find("small")){
+    d.style.marginTop=(p-2)+"px";
+    btype+="s"; lim=2;
+    }
+else if(options.find("big")){
+    d.style.marginTop=(p-10)+"px";
+    btype+="b"; lim=8;
+    }
+else d.style.marginTop=(p-5)+"px";
+for(i=lim;i>0;i--)
+    d.appendChild(CreateStrip(i,side,color,border,btype));
+el.style.paddingBottom=0;
+el.appendChild(d);
+}
+
+function CreateStrip(index,side,color,border,btype){
+var x=CreateEl("b");
+x.className=btype+index;
+x.style.backgroundColor=color;
+x.style.borderColor=border;
+if(side=="left"){
+    x.style.borderRightWidth="0";
+    x.style.marginRight="0";
+    }
+else if(side=="right"){
+    x.style.borderLeftWidth="0";
+    x.style.marginLeft="0";
+    }
+return(x);
+}
+
+function CreateEl(x){
+return(document.createElement(x));
+}
+
+function FixIE(el){
+if(el.currentStyle!=null && el.currentStyle.hasLayout!=null && el.currentStyle.hasLayout==false)
+    el.style.display="inline-block";
+}
+
+function SameHeight(selector,maxh){
+var i,v=selector.split(","),t,j,els=[],gap;
+for(i=0;i<v.length;i++){
+    t=getElementsBySelector(v[i]);
+    els=els.concat(t);
+    }
+for(i=0;i<els.length;i++){
+    if(els[i].offsetHeight>maxh) maxh=els[i].offsetHeight;
+    els[i].style.height="auto";
+    }
+for(i=0;i<els.length;i++){
+    gap=maxh-els[i].offsetHeight;
+    if(gap>0){
+        t=CreateEl("b");t.className="niftyfill";t.style.height=gap+"px";
+        nc=els[i].lastChild;
+        if(nc.className=="niftycorners")
+            els[i].insertBefore(t,nc);
+        else els[i].appendChild(t);
+        }
+    }
+}
+
+function getElementsBySelector(selector){
+var i,j,selid="",selclass="",tag=selector,tag2="",v2,k,f,a,s=[],objlist=[],c;
+if(selector.find("#")){ //id selector like "tag#id"
+    if(selector.find(" ")){  //descendant selector like "tag#id tag"
+        s=selector.split(" ");
+        var fs=s[0].split("#");
+        if(fs.length==1) return(objlist);
+        f=document.getElementById(fs[1]);
+        if(f){
+            v=f.getElementsByTagName(s[1]);
+            for(i=0;i<v.length;i++) objlist.push(v[i]);
+            }
+        return(objlist);
+        }
+    else{
+        s=selector.split("#");
+        tag=s[0];
+        selid=s[1];
+        if(selid!=""){
+            f=document.getElementById(selid);
+            if(f) objlist.push(f);
+            return(objlist);
+            }
+        }
+    }
+if(selector.find(".")){      //class selector like "tag.class"
+    s=selector.split(".");
+    tag=s[0];
+    selclass=s[1];
+    if(selclass.find(" ")){   //descendant selector like tag1.classname tag2
+        s=selclass.split(" ");
+        selclass=s[0];
+        tag2=s[1];
+        }
+    }
+var v=document.getElementsByTagName(tag);  // tag selector like "tag"
+if(selclass==""){
+    for(i=0;i<v.length;i++) objlist.push(v[i]);
+    return(objlist);
+    }
+for(i=0;i<v.length;i++){
+    c=v[i].className.split(" ");
+    for(j=0;j<c.length;j++){
+        if(c[j]==selclass){
+            if(tag2=="") objlist.push(v[i]);
+            else{
+                v2=v[i].getElementsByTagName(tag2);
+                for(k=0;k<v2.length;k++) objlist.push(v2[k]);
+                }
+            }
+        }
+    }
+return(objlist);
+}
+
+function getParentBk(x){
+var el=x.parentNode,c;
+while(el.tagName.toUpperCase()!="HTML" && (c=getBk(el))=="transparent")
+    el=el.parentNode;
+if(c=="transparent") c="#FFFFFF";
+return(c);
+}
+
+function getBk(x){
+var c=getStyleProp(x,"backgroundColor");
+if(c==null || c=="transparent" || c.find("rgba(0, 0, 0, 0)"))
+    return("transparent");
+if(c.find("rgb")) c=rgb2hex(c);
+return(c);
+}
+
+function getPadding(x,side){
+var p=getStyleProp(x,"padding"+side);
+if(p==null || !p.find("px")) return(0);
+return(parseInt(p));
+}
+
+function getStyleProp(x,prop){
+if(x.currentStyle)
+    return(x.currentStyle[prop]);
+if(document.defaultView.getComputedStyle)
+    return(document.defaultView.getComputedStyle(x,'')[prop]);
+return(null);
+}
+
+function rgb2hex(value){
+var hex="",v,h,i;
+var regexp=/([0-9]+)[, ]+([0-9]+)[, ]+([0-9]+)/;
+var h=regexp.exec(value);
+for(i=1;i<4;i++){
+    v=parseInt(h[i]).toString(16);
+    if(v.length==1) hex+="0"+v;
+    else hex+=v;
+    }
+return("#"+hex);
+}
+
+function Mix(c1,c2){
+var i,step1,step2,x,y,r=new Array(3);
+if(c1.length==4)step1=1;
+else step1=2;
+if(c2.length==4) step2=1;
+else step2=2;
+for(i=0;i<3;i++){
+    x=parseInt(c1.substr(1+step1*i,step1),16);
+    if(step1==1) x=16*x+x;
+    y=parseInt(c2.substr(1+step2*i,step2),16);
+    if(step2==1) y=16*y+y;
+    r[i]=Math.floor((x*50+y*50)/100);
+    r[i]=r[i].toString(16);
+    if(r[i].length==1) r[i]="0"+r[i];
+    }
+return("#"+r[0]+r[1]+r[2]);
+}

Added: trunk/examples/typeface/root/static/javascripts/niftydates.js
===================================================================
--- trunk/examples/typeface/root/static/javascripts/niftydates.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/javascripts/niftydates.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,45 @@
+function show_dates_as_local_time() {
+  var spans = document.getElementsByTagName('span');
+  for (var i=0; i<spans.length; i++) {
+    if (spans[i].className.match(/nifty_date/i)) {
+      spans[i].innerHTML = get_local_time_for_date(spans[i].title);
+    }
+  }
+}
+
+function get_local_time_for_date(time) {
+  system_date = new Date(time);
+  user_date = new Date();
+
+//hacky as hell using regexp to extract from string and feed it back.
+user_date = new Date().toGMTString();
+regexp = /, (.*?) (.*?) (\d\d\d\d) (\d\d):(\d\d):(\d\d)/;
+times = regexp.exec(user_date);
+user_date = new Date(times[2]+' '+times[1]+', '+times[3]+' '+times[4]+':'+times[5]+':'+times[6]);
+
+  delta_minutes = Math.floor((user_date- system_date) / (60 * 1000));
+  if (Math.abs(delta_minutes) <= (8*7*24*60)) { // eight weeks... I'm lazy to count days for longer than that
+    distance = distance_of_time_in_words(delta_minutes);
+    if (delta_minutes < 0) {
+      return distance + ' from now';
+    } else {
+      return distance + ' ago';
+    }
+  } else {
+    return 'on ' + system_date.toLocaleDateString();
+  }
+}
+
+// a vague copy of rails' inbuilt function, 
+// but a bit more friendly with the hours.
+function distance_of_time_in_words(minutes) {
+  if (minutes.isNaN) return "";
+  minutes = Math.abs(minutes);
+  if (minutes < 1) return ('less than a minute');
+  if (minutes < 50) return (minutes + ' minute' + (minutes == 1 ? '' : 's'));
+  if (minutes < 90) return ('about one hour');
+  if (minutes < 1080) return (Math.round(minutes / 60) + ' hours');
+  if (minutes < 1440) return ('one day');
+  if (minutes < 2880) return ('about one day');
+  else return (Math.round(minutes / 1440) + ' days')
+}

Added: trunk/examples/typeface/root/static/javascripts/niftytricks.js
===================================================================
--- trunk/examples/typeface/root/static/javascripts/niftytricks.js	                        (rev 0)
+++ trunk/examples/typeface/root/static/javascripts/niftytricks.js	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,97 @@
+/*
+ * This is the original function from Stuart Langridge at http://www.kryogenix.org/
+ * This is the update function from Jeff Minard - http://www.jrm.cc/
+*/
+function superTextile(s) {
+    var r = s;
+    // quick tags first
+    qtags = [['\\*', 'strong'],
+             ['\\?\\?', 'cite'],
+             ['\\+', 'ins'],  //fixed
+             ['~', 'sub'],   
+             ['\\^', 'sup'], // me
+             ['@', 'code']];
+    for (var i=0;i<qtags.length;i++) {
+        ttag = qtags[i][0]; htag = qtags[i][1];
+        re = new RegExp(ttag+'\\b(.+?)\\b'+ttag,'g');
+        r = r.replace(re,'<'+htag+'>'+'$1'+'</'+htag+'>');
+    }
+    // underscores count as part of a word, so do them separately
+    re = new RegExp('\\b_(.+?)_\\b','g');
+    r = r.replace(re,'<em>$1</em>');
+    
+    //jeff: so do dashes
+    re = new RegExp('[\s\n]-(.+?)-[\s\n]','g');
+    r = r.replace(re,'<del>$1</del>');
+
+    // links
+    re = new RegExp('"\\b(.+?)\\(\\b(.+?)\\b\\)":([^\\s]+)','g');
+    r = r.replace(re,'<a href="$3" title="$2">$1</a>');
+    re = new RegExp('"\\b(.+?)\\b":([^\\s]+)','g');
+    r = r.replace(re,'<a href="$2">$1</a>');
+
+    // images
+    re = new RegExp('!\\b(.+?)\\(\\b(.+?)\\b\\)!','g');
+    r = r.replace(re,'<img src="$1" alt="$2">');
+    re = new RegExp('!\\b(.+?)\\b!','g');
+    r = r.replace(re,'<img src="$1">');
+    
+    // block level formatting
+    
+        // Jeff's hack to show single line breaks as they should.
+        // insert breaks - but you get some....stupid ones
+        re = new RegExp('(.*)\n([^#\*\n].*)','g');
+        r = r.replace(re,'$1<br />$2');
+        // remove the stupid breaks.
+        re = new RegExp('\n<br />','g');
+        r = r.replace(re,'\n');
+    
+    lines = r.split('\n');
+    nr = '';
+    for (var i=0;i<lines.length;i++) {
+        line = lines[i].replace(/\s*$/,'');
+        changed = 0;
+        if (line.search(/^\s*bq\.\s+/) != -1) { 
+            line = line.replace(/^\s*bq\.\s+/,'\t<blockquote>')+'</blockquote>'; 
+            changed = 1; 
+        }
+        
+        // jeff adds h#.
+        if (line.search(/^\s*h[1|2|3|4|5|6]\.\s+/) != -1) { 
+            re = new RegExp('h([1|2|3|4|5|6])\.(.+)','g');
+            line = line.replace(re,'<h$1>$2</h$1>');
+            changed = 1; 
+        }
+        
+        if (line.search(/^\s*\*\s+/) != -1) { line = line.replace(/^\s*\*\s+/,'\t<liu>') + '</liu>'; changed = 1; } // * for bullet list; make up an liu tag to be fixed later
+        if (line.search(/^\s*#\s+/) != -1) { line = line.replace(/^\s*#\s+/,'\t<lio>') + '</lio>'; changed = 1; } // # for numeric list; make up an lio tag to be fixed later
+        if (!changed && (line.replace(/\s/g,'').length > 0)) line = '<p>'+line+'</p>';
+        lines[i] = line + '\n';
+    }
+    
+    // Second pass to do lists
+    inlist = 0; 
+    listtype = '';
+    for (var i=0;i<lines.length;i++) {
+        line = lines[i];
+        if (inlist && listtype == 'ul' && !line.match(/^\t<liu/)) { line = '</ul>\n' + line; inlist = 0; }
+        if (inlist && listtype == 'ol' && !line.match(/^\t<lio/)) { line = '</ol>\n' + line; inlist = 0; }
+        if (!inlist && line.match(/^\t<liu/)) { line = '<ul>' + line; inlist = 1; listtype = 'ul'; }
+        if (!inlist && line.match(/^\t<lio/)) { line = '<ol>' + line; inlist = 1; listtype = 'ol'; }
+        lines[i] = line;
+    }
+
+    r = lines.join('\n');
+    // jeff added : will correctly replace <li(o|u)> AND </li(o|u)>
+    r = r.replace(/li[o|u]>/g,'li>');
+
+    return r;
+}
+
+
+function reloadPreviewDiv() { 
+    var commentString = document.getElementById('contentarea').value;
+    var con = superTextile(commentString);
+    var c = document.getElementById('cpreview');
+    c.innerHTML = con;
+}

Added: trunk/examples/typeface/root/static/stylesheets/admin.css
===================================================================
--- trunk/examples/typeface/root/static/stylesheets/admin.css	                        (rev 0)
+++ trunk/examples/typeface/root/static/stylesheets/admin.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,128 @@
+html,body { 
+    padding: 0;
+    margin: 0;
+    background: url(/templates/default/static/images/bgback.jpg) repeat-x;
+    background-color: #f1f0ed;
+	font: 13px "Lucida Grande", "Lucida Sans Unicode", Tahoma, Verdana;
+}
+
+h3,h2,h1,h4 {
+	display: inline;
+}
+
+a {
+	color: #678aed;
+}
+
+#main {
+    float: left;
+    width: 100%;
+    background-color: #94beff;
+    border-bottom: 10px solid #f7e77c;
+    
+}
+
+#main h1 {
+    color: #FFFFFF;
+    padding-left: 30px;
+    display:inline;
+	font-size: 2.5em;
+	font-weight: normal;
+	letter-spacing: -.05em;
+	margin: 0;
+	font-family: Georgia, "Times New Roman", Times, serif;
+}
+
+#login_box {
+    border: 1px solid; 
+    background: #FFFFFF;
+    width: 300px;
+    margin: 0 auto;
+    text-align: left;   
+    padding-left: 30px;
+}
+
+#login_box h1 {
+    color: #94beff;
+}
+
+#login_box span {
+    font: 20px "Lucida Grande", "Trebuchet MS", Verdana, sans-serif;
+}
+
+#login_box INPUT {
+   font: 20px "Lucida Grande", "Trebuchet MS", Verdana, sans-serif; 
+   background-color: #efefef;
+}
+
+INPUT {
+	background-color: #efefef;
+	border: 1px solid;
+}
+
+TEXTAREA {
+	background-color: #efefef;
+	border: 1px solid;
+}
+
+#login_pane span {
+    color: #FFFFFF;
+}
+
+#write_blog,#recent_blog,#users,#links,#plugins,#pages,#categories {
+    background: #FFFFFF;
+}
+
+.padding {
+    margin-left: 30px;
+}
+
+ul#error_content,ul#error_content li{margin:0;padding:0;list-style:none}
+ul#error_content li{width:450px;margin:0 auto;}
+ul#error_content h3{font: normal 120%/1.3 Verdana,sans-serif; display: block;
+    margin:0px;padding: 5px 0 0;text-align:center;color: #FFFFFF}
+ul#error_content p{margin:0;padding:5px 8px 15px; }
+li#one h3{background: #e92c00}
+ul#error_content div{background: #ffffff}
+li#one div{border:2px solid #e92c00}
+
+
+td#id {
+	width: 30px;
+}
+
+td#subject {
+	width: 300px;
+}
+
+td#cache {
+	width: 80px;
+}
+
+td#view {
+	width: 30px;
+}
+
+td#name,#email,#website {
+	width: 200px;
+}
+
+td#edit {
+	width: 30px;
+}
+
+td#delete {
+	width: 30px;
+}
+
+td a:hover {
+	background: #f7e77c;
+}
+
+td {
+	height: 50px;
+}
+
+.darken {
+	background-color: #f1f1f1;
+}
\ No newline at end of file

Added: trunk/examples/typeface/root/static/stylesheets/default.css
===================================================================
--- trunk/examples/typeface/root/static/stylesheets/default.css	                        (rev 0)
+++ trunk/examples/typeface/root/static/stylesheets/default.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,118 @@
+#calendar {
+}
+
+#calendar th {
+	font-size: 12px;
+	font-weight: bold;
+}
+
+#calendar h1 {
+    font-size: 12px;
+}
+
+#calendar td {
+	font-size: 12px;
+	color: #666;
+}
+
+blockquote {
+	margin: 15px 30px 0 10px;
+	padding-left: 10px;
+	background: #fefefe;
+	border-left: 3px solid #999999;
+	font-style: oblique;
+}
+
+pre {
+	border: 1px solid;
+	min-height: 60px;
+	width: 100%;
+	overflow: auto;
+	background-color: #eae7de;
+}
+
+.code {
+	border: 1px solid;
+	min-height: 60px;
+	overflow: auto;
+    background-color: #eae7de;
+}
+
+img { border: 0; }
+
+.code .key1 {
+	color: #0000FF;
+}
+
+.code .key2 {
+	color: #0000FF;
+}
+
+.code .key3 {
+	color: #fb389a;
+}
+
+.code .string {
+	color: #14a042;
+}
+
+span.Alert {
+ color: #0000ff;
+}
+span.BaseN {
+ color: #007f00;
+}
+span.BString {
+ color: #c9a7ff;
+}
+span.Char {
+ color: #ff00ff;
+}
+span.Comment {
+ color: #6b766b;
+}
+span.DataType {
+ color: #000;
+}
+span.DecVal {
+ color: #f0f;
+}
+span.Error {
+ color: #ff0000;
+}
+span.Float {
+ color: #5599ff;
+}
+span.Function {
+ color: #ff7d00;
+}
+span.IString {
+ color: #ff0000;
+}
+span.Keyword {
+ color: #2400ff;
+ font-weight: bold;
+}
+span.Operator {
+ color: #00ff33;
+ font-weight: bold;
+}
+span.Others {
+ color: #b03060;
+}
+span.RegionMarker {
+ color: #96b9ff;
+}
+span.Reserved {
+ color: #9b30ff;
+ font-weight: bold;
+}
+span.String {
+ color: #00ca35;
+}
+span.Variable {
+ color: #2400ff;
+}
+span.Warning {
+ color: #0000ff;
+}
\ No newline at end of file

Added: trunk/examples/typeface/root/static/stylesheets/nicetitles.css
===================================================================
--- trunk/examples/typeface/root/static/stylesheets/nicetitles.css	                        (rev 0)
+++ trunk/examples/typeface/root/static/stylesheets/nicetitles.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,26 @@
+div.nicetitle {
+	z-index: 30;
+    position: absolute;
+    padding: 4px;
+    top: 0px;
+    left: 0px;
+    color: white;
+    font-size: 13px;
+    font-family: Verdana, Helvetica, Arial, sans-serif;
+    width: 25em;
+    font-weight: bold;
+    background: url(/static/images/ntbg.png);
+
+    /* Mozilla proprietary */
+    -moz-border-radius: 12px;
+}
+div.nicetitle p {
+	color: white;
+    margin: 0; padding: 0 3px;
+}
+div.nicetitle p.destination {
+	color: white;
+    font-size: 9px;
+    text-align: left;
+    padding-top: 3px;
+}

Added: trunk/examples/typeface/root/static/stylesheets/niftyCorners.css
===================================================================
--- trunk/examples/typeface/root/static/stylesheets/niftyCorners.css	                        (rev 0)
+++ trunk/examples/typeface/root/static/stylesheets/niftyCorners.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,35 @@
+/*Nifty Corners Cube CSS by Alessandro Fulciniti
+The following classes are added dinamically by javascript,
+and their use should be avoided in the markup */
+
+b.niftycorners,b.niftyfill{display:block}
+b.niftycorners *{display:block;height: 1px;line-height:1px;font-size: 1px;
+    overflow:hidden;border-style:solid;border-width: 0 1px}
+/*normal*/
+b.r1{margin: 0 3px;border-width: 0 2px}
+b.r2{margin: 0 2px}
+b.r3{margin: 0 1px}
+b.r4{height: 2px}
+b.rb1{margin: 0 8px;border-width:0 2px}
+b.rb2{margin: 0 6px;border-width:0 2px}
+b.rb3{margin: 0 5px}
+b.rb4{margin: 0 4px}
+b.rb5{margin: 0 3px}
+b.rb6{margin: 0 2px}
+b.rb7{margin: 0 1px;height:2px}
+b.rb8{margin: 0;height:2px}
+b.rs1{margin: 0 1px}
+/*transparent inside*/
+b.t1{border-width: 0 5px}
+b.t2{border-width: 0 3px}
+b.t3{border-width: 0 2px}
+b.t4{height: 2px}
+b.tb1{border-width: 0 10px}
+b.tb2{border-width: 0 8px}
+b.tb3{border-width: 0 6px}
+b.tb4{border-width: 0 5px}
+b.tb5{border-width: 0 4px}
+b.tb6{border-width: 0 3px}
+b.tb7{border-width: 0 2px;height:2px}
+b.tb8{border-width: 0 1px;height:2px}
+b.ts1{border-width: 0 2px}
\ No newline at end of file


Property changes on: trunk/examples/typeface/root/static/stylesheets/niftyCorners.css
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/templates/chaoticsoul/index.tt2
===================================================================
--- trunk/examples/typeface/root/templates/chaoticsoul/index.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/templates/chaoticsoul/index.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,52 @@
+[% USE Textile2 -%]
+<br />
+[% FOREACH article = articles %]
+	<div class="post">
+	[% url = '/view/' _ c.nifty_txt_to_url(article.subject,article.id) %]
+	<div class="post-info">
+		<h2 class="post-title">
+			<a title="[% c.uri_for(url) %]" href="[% url %]">[% article.subject %]</a>
+		</h2> <br/>
+		Posted by [% article.user.name %] <span class="post-date">[% c.render_nifty_date(article.created_at) %]</span> under  
+		[% FOREACH category = article.categories %] 
+			<a href="/category/[% c.nifty_txt_to_url(category.name) %]">[% category.name %]</a>
+		[% END %]
+		<br/>
+		<a href="[% c.base_uri %]/feed/comments/[% c.nifty_txt_to_url(article.subject) %]"><img src="/static/images/rss.png" alt="RSS" /> [% article.subject %]'s RSS feed</a> &nbsp;
+		
+		[% IF article.comments_rs.count > 0 %]
+		<a href="[% url %]">[[% article.comments_rs.count %]] comments</a>
+		[% END %]
+		
+	</div>
+	
+	<div class="post-content">
+		[% article.textilize('body') %]
+	</div>
+	<div class="post-footer">&nbsp;</div>
+	</div>
+	<br />
+[% END %]
+<div id="comments"></div>
+
+<ol class="commentlist">
+[% FOREACH comment = comments %]
+	<li class="alt">
+	[% IF loop.index % 2 %]
+	<div class="comment">
+[% ELSE %]
+	<div class="comment_alt">
+[% END %]
+	<h3><a title="[% comment.url %]" href="[% comment.url %]">[% comment.name %]</a></h3>
+	<small class="commentmetadata">Posted [% c.render_nifty_date(comment.created_at) %]</small>
+	<p>[% comment.textilize('comment') %]</p>
+	</div>
+	</li>
+[% END %]
+</ol>
+[% IF FormBuilder %]
+<h3 id="respond">Leave a Reply</h3>
+[% FormBuilder.render %]
+<p>Type the following in the verification box</p>
+<img src="/submit/captcha" alt="" />
+[% END %]

Added: trunk/examples/typeface/root/templates/chaoticsoul/layout.tt2
===================================================================
--- trunk/examples/typeface/root/templates/chaoticsoul/layout.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/templates/chaoticsoul/layout.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+  <title>[% title or site.title %]</title>
+
+	<meta name="ROBOTS" content="ALL" />
+	<meta http-equiv="imagetoolbar" content="no" />
+	<meta name="MSSmartTagsPreventParsing" content="true" />
+	<meta name="Copyright" content="(c) 2006 Copyright content:  Copyright design: Victor Igumnov" />
+	<!-- (c) Copyright 2006 by Victor Igumnov All Rights Reserved. -->
+	
+	[% stylesheet_link_tag('style.css') %]
+		
+	<link rel="alternate" type="application/rss+xml" title="[% c.config.name %]" href="/feed/articles" />
+	
+	[% typeface_define_headers %]
+
+	[% c.render_nifty_headers %]
+	
+ </head>
+ <body>
+	<div id="page">
+		<div id="header">
+			<h1><a href="#">[% c.config.site.name %]</a></h1>		
+			<div id="description">[% c.config.site.description %]</div>
+		</div>
+		
+		<hr />
+		
+		<div id="headerimg" class="clearfix">
+			<div class="image bkgleft"> </div>
+			<div class="image bkgright"> </div>
+		</div>
+		
+		
+			<div id="content" class="narrowcolumn">
+				[% PROCESS 'message.tt2' %]
+				[% content %]
+			</div>
+			[% PROCESS 'sidebar.tt2' %]
+	</div>
+	[% dp_js_include_tag %]
+ </body>
+</html>
\ No newline at end of file

Added: trunk/examples/typeface/root/templates/chaoticsoul/sidebar.tt2
===================================================================
--- trunk/examples/typeface/root/templates/chaoticsoul/sidebar.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/templates/chaoticsoul/sidebar.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,16 @@
+<div id="sidebar">
+	[% PROCESS 'search_list.tt2' %]
+	[% PROCESS 'calendar_list.tt2' %]
+	<h2>Pages</h2>
+	<ul>
+		<li><a href="/" id="navHome" title="Posted Recently" accesskey="h">Home</a></li>
+		[% FOREACH page = pages %]
+		<li id="[% page.name %]"class='[% activelink.${c.nifty_txt_to_url(page.name)} %]' ><a href="[% c.base_uri %]/page/[% c.nifty_txt_to_url(page.name) %]">[% page.name %]</a></li>
+		[% END %]
+	</ul>
+	[% PROCESS 'categories_list.tt2' %]
+	[% PROCESS 'archives_list.tt2' %]
+	[% PROCESS 'links_list.tt2' %]
+	[% PROCESS 'syndicate_list.tt2' %]
+	[% PROCESS 'login_list.tt2' %]
+</div>
\ No newline at end of file

Added: trunk/examples/typeface/root/templates/chaoticsoul/static/images/content_bkg.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/chaoticsoul/static/images/content_bkg.gif
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/chaoticsoul/static/images/image_left.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/chaoticsoul/static/images/image_left.jpg
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/chaoticsoul/static/images/image_right.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/chaoticsoul/static/images/image_right.jpg
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/chaoticsoul/static/stylesheets/style.css
===================================================================
--- trunk/examples/typeface/root/templates/chaoticsoul/static/stylesheets/style.css	                        (rev 0)
+++ trunk/examples/typeface/root/templates/chaoticsoul/static/stylesheets/style.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,194 @@
+/*  
+Theme Name: ChaoticSoul
+Theme URI: http://sandbox.avalonstar.com/
+Description: An old version of the beloved Avalonstar, remade into a WordPress theme.
+Version: 1.0
+Author: Bryan Veloso
+Author URI: http://avalonstar.com/
+*/
+
+
+/*  -----|  Globals  |------------------------------------------------------  */
+
+body { 
+	background-color: #161410;
+	color: #999;
+	font: 62.5%/125% 'Trebuchet MS', Tahoma, Arial, Helvetica, sans-serif;
+	margin: 0;
+	padding: 0;
+	text-align: center;
+	}
+
+/* hr { display: none; } */
+
+hr {
+	background-color: #22201d;
+	border: 1px solid #363430;
+	height: 10px;
+	margin: 10px 0;
+	width: 760px;
+	}
+	
+a:link, a:visited, a:active { color: #d8d7d3; text-decoration: none; }
+a:hover { color: #fff; text-decoration: none; }
+
+ul { list-style: none; }
+
+input, textarea {
+	color: #9c9890;
+	font-size: 11px; 
+	text-decoration: none; 
+	background-color: #161410; 
+	border: 1px solid #363430;
+	padding: 5px;
+	}
+	
+blockquote {
+	background: #1b1814;
+	padding: 1px 15px 5px;
+	border-bottom: 1px solid #35302a;
+}
+
+table { width: 100%; border-collapse: collapse; }
+	th { border-bottom: 1px solid #35302a; text-align: left; }
+
+pre {
+	padding: 5px 0;
+	border-top: 1px dotted #35302a;
+	border-bottom: 1px dotted #35302a;
+}
+
+
+
+/*  -----|  Structure  |----------------------------------------------------  */
+	
+#page {
+	margin: 50px auto 25px;
+	padding: 0;
+	width: 760px;
+	text-align: left;
+	}
+	
+#post-date {
+    display: inline;
+}	
+
+#header {
+	text-align: center;
+	}
+
+#wrapper, #headerimg { width: 760px; }
+#wrapper { background: url('/templates/chaoticsoul/static/images/content_bkg.gif') repeat-y top left;}
+
+.image {
+	background: #22201d url('/templates/chaoticsoul/static/images/image_left.jpg');
+	border: 1px solid #363430;
+	height: 149px;
+	width: 372px;	
+	}
+	
+	.bkgleft { background: url('/templates/chaoticsoul/static/images/image_left.jpg'); float: left; }
+	.bkgright { background: url('/templates/chaoticsoul/static/images/image_right.jpg'); float: right; }
+	
+#footer {
+	font-family: Georgia, 'Times New Roman', serif; 
+	color: #999;
+	}
+	
+#content, #sidebar { 
+	border-left: 1px solid #363430;
+	border-right: 1px solid #363430;
+	padding: 0 10px; 
+	}
+	
+	#content { float: left; font-size: 1.1em; width: 517px; }
+	#content h2 { margin: 0 0 10px; }
+	#content p { line-height: 1.5em; }
+	
+	#sidebar { border-left: 0; float: right; width: 200px; }
+	#sidebar h3 { color: #bd934f; margin: 15px 0 5px; font-variant: small-caps; }
+	#sidebar ul { margin: 0 0 10px; padding: 0; border-top: 1px solid #363430; border-bottom: 1px solid #363430; }
+	#sidebar li { display: block; padding: 4px 10px; background: #22201d; margin: 1px 0; }
+	#sidebar li:hover { background: #363430; }
+		
+#searchform { background: #22201d; padding: 10px; text-align: center; }
+	#s { width: 160px; }
+	
+.goleft { float: left; }
+.goright { float: right; }
+
+ul.navigation { 
+	border-top: 1px solid #363430; 
+	border-bottom: 1px solid #363430; 
+	}
+	
+	ul.navigation li { display: block; padding: 4px 10px; background: #22201d; margin: 1px 0; }
+	ul.navigation li:hover { background: #363430; }
+
+/* Post Structure */
+
+.post { padding: 10px 0 0; }
+	.widecolumn .post { padding: 0; margin: 0; }
+	
+.top { padding: 15px 10px 0px; background: #1b1814; margin-bottom: 15px; border-bottom: 1px solid #35302a; }
+.lastfive { padding-left: 10px; padding-right: 10px; }
+	.postmetadata { margin: 3px 0; padding: 0; }
+	.postmetadata a { font-weight: bold; }
+		#sidebar .postmetadata { line-height: 1.5em; }
+	.continue { font-weight: bold; font-size: 1.3em; }
+	
+	.top .entry { font-size: 1.1em; }
+	.entrytext { padding: 0 10px 0; line-height: 2em; font-size: 1.1em; }
+	
+	.entrytext h2 { border-bottom: 1px solid #bd934f; display: block; }
+	.entrytext ul { list-style-type: square; }
+	
+/* Comments Structure */
+
+.comments { padding: 10px; margin-top: 15px; background: #1b1814; border-top: 1px solid #35302a; position: relative; }
+	#commentform p { float: left; margin: 0 10px 10px 0; }
+	
+.commentlist { background: #1b1814; list-style: none; margin: 0; padding: 0; }
+	.commentlist li { background: #161410; margin-top: 10px; padding: 5px 0 0; }
+	.commentlist li p { padding: 5px 10px 0; margin: 0; }
+	.commentlist li p.commentmetadata { border-bottom: 1px solid #35302a; background: #181612; padding: 5px 10px; margin-top: 10px; }
+	
+ul.archive { list-style: none; padding: 0; margin: 0 10px 25px; font-size: 1.3em; }	
+ul.archive li { display: inline; }
+
+
+/*  -----|  Typography  |---------------------------------------------------  */
+
+h1, h2, h3, h4, h5, h6 { font-family: Georgia, 'Times New Roman', serif; font-weight: normal; }
+
+h1 { color: #fff; font-size: 2em; margin: 0 0 8px; }
+h1:before, h1:after { content: " . . "; color: #444; }
+h1 span { color: #bd934f; }
+
+h2 { color: #bd934f; font-size: 1.25em; margin: 0; padding: 1px 0; display: inline; border-bottom: 1px solid #35302a; }
+	.post h2 a { color: #bd934f; }
+	.post h2.first { font-size: 1.75em; }
+	
+	.widecolumn h2.title { 
+		display: block; 
+		padding: 13px 10px;
+		background: #1b1814;
+		margin: 0 0 15px; 
+		border-bottom: 1px solid #35302a; 
+		font-size: 1.75em; }
+
+.description { color: #666; font-weight: bold; }
+
+.comments h3 { margin: 0 0 10px 0; color: #bd934f; }
+
+
+
+/*  -----|  Miscellaneous  |------------------------------------------------  */
+
+.clearfix:after {
+    content: "."; 
+    display: block; 
+    height: 0; 
+    clear: both; 
+    visibility: hidden;
+}
\ No newline at end of file


Property changes on: trunk/examples/typeface/root/templates/chaoticsoul/static/stylesheets/style.css
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/root/templates/connections/index.tt2
===================================================================
--- trunk/examples/typeface/root/templates/connections/index.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/templates/connections/index.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,55 @@
+<br />
+[% FOREACH article = articles %]
+	<div class="post">
+	[% url = '/view/' _ c.nifty_txt_to_url(article.subject,article.id) %]
+	<p class="post-date">Posted [% c.render_nifty_date(article.created_at) %]</p>
+	<div class="post-info">
+		<h2 class="post-title">
+			<a title="[% c.uri_for(url) %]" href="[% url %]">[% article.subject %]</a>
+		</h2> 
+		Posted by [% article.user.name %]
+		
+		under  
+		[% FOREACH category = article.categories %] 
+			<a href="/category/[% c.nifty_txt_to_url(category.name) %]">[% category.name %]</a>
+		[% END %]
+		<br/>
+		<a href="[% c.base_uri %]/feed/comments/[% c.nifty_txt_to_url(article.subject) %]"><img src="/static/images/rss.png" alt="RSS" /> [% article.subject %]'s RSS feed</a> &nbsp;
+		
+		[% IF article.comments_rs.count > 0 %]
+		<a href="[% url %]">[[% article.comments_rs.count %]] comments</a>
+		[% END %]
+		
+	</div>
+	
+	<div class="post-content">
+		[% article.textilize('body') %]
+	</div>
+	<div class="post-footer">&nbsp;</div>
+	</div>
+	<br />
+[% END %]
+<div id="comments"></div>
+
+<ol class="commentlist">
+[% FOREACH comment = comments %]
+	<li class="alt">
+	[% IF loop.index % 2 %]
+	<div class="comment">
+[% ELSE %]
+	<div class="comment_alt">
+[% END %]
+	<h3><a title="[% comment.url %]" href="[% comment.url %]">[% comment.name %]</a></h3>
+	<small class="commentmetadata">Posted [% c.render_nifty_date(comment.created_at) %]</small>
+	<p>[% comment.textilize('comment') %]</p>
+	</div>
+	</li>
+[% END %]
+</ol>
+
+[% IF FormBuilder %]
+<h3 id="respond">Leave a Reply</h3>
+[% FormBuilder.render %]
+<p>Type the following in the verification box</p>
+<img src="/submit/captcha" alt="" />
+[% END %]

Added: trunk/examples/typeface/root/templates/connections/layout.tt2
===================================================================
--- trunk/examples/typeface/root/templates/connections/layout.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/templates/connections/layout.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+  <title>[% title or site.title %]</title>
+
+	<meta name="ROBOTS" content="ALL" />
+	<meta http-equiv="imagetoolbar" content="no" />
+	<meta name="MSSmartTagsPreventParsing" content="true" />
+	<meta name="Copyright" content="(c) 2006 Copyright content:  Copyright design: Victor Igumnov" />
+	<!-- (c) Copyright 2006 by Victor Igumnov All Rights Reserved. -->
+	
+	[% stylesheet_link_tag('style.css') %]
+		
+	<link rel="alternate" type="application/rss+xml" title="[% c.config.name %]" href="/feed/articles" />
+	
+	[% typeface_define_headers %]
+
+	[% c.render_nifty_headers %]
+	
+ </head>
+ <body>
+	<div id="rap">
+		<div id="header">
+			<ul id="topnav">
+				<li><a href="/" id="navHome" title="Posted Recently" accesskey="h">Home</a> |</li>
+				[% FOREACH page = pages %]
+				<li id="[% page.name %]"class='[% activelink.${c.nifty_txt_to_url(page.name)} %]' ><a href="[% c.base_uri %]/page/[% c.nifty_txt_to_url(page.name) %]">[% page.name %]</a> |</li>
+				[% END %]
+			</ul>
+			<h1><a href="/">[% c.config.site.name %]</a></h1>		
+			<div id="desc">[% c.config.site.description %]</div>
+		</div>
+		<div id="main">
+			<div id="content">
+				[% PROCESS 'message.tt2' %]
+				[% content %]
+			</div>
+			[% PROCESS 'sidebar.tt2' %]
+			<p id="footer">Design Downloaded from <a href="http://www.vanillamist.com" title="Vanilla Mist">www.vanillamist.com</a></p>
+		</div>
+	</div>
+	[% dp_js_include_tag %]
+ </body>
+</html>
\ No newline at end of file

Added: trunk/examples/typeface/root/templates/connections/sidebar.tt2
===================================================================
--- trunk/examples/typeface/root/templates/connections/sidebar.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/templates/connections/sidebar.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+<div id="sidebar">
+	[% PROCESS 'search_list.tt2' %]
+	[% PROCESS 'calendar_list.tt2' %]
+	[% PROCESS 'categories_list.tt2' %]
+	[% PROCESS 'archives_list.tt2' %]
+	[% PROCESS 'links_list.tt2' %]
+	[% PROCESS 'syndicate_list.tt2' %]
+	[% PROCESS 'login_list.tt2' %]
+</div>
\ No newline at end of file

Added: trunk/examples/typeface/root/templates/connections/static/images/blockquote.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/connections/static/images/blockquote.gif
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/connections/static/images/bullet.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/connections/static/images/bullet.gif
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/connections/static/images/comments_bottom.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/connections/static/images/comments_bottom.jpg
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/connections/static/images/content_bg.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/connections/static/images/content_bg.gif
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/connections/static/images/contentbg.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/connections/static/images/contentbg.jpg
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/connections/static/images/divider.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/connections/static/images/divider.gif
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/connections/static/images/rap.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/connections/static/images/rap.jpg
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/connections/static/images/sidenav_bottom.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/connections/static/images/sidenav_bottom.jpg
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/connections/static/images/sidenav_top.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/connections/static/images/sidenav_top.jpg
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/connections/static/images/sub-bullet.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/connections/static/images/sub-bullet.gif
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/connections/static/images/subcat_bullet.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/connections/static/images/subcat_bullet.gif
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/connections/static/images/top.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/connections/static/images/top.jpg
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/connections/static/stylesheets/style.css
===================================================================
--- trunk/examples/typeface/root/templates/connections/static/stylesheets/style.css	                        (rev 0)
+++ trunk/examples/typeface/root/templates/connections/static/stylesheets/style.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,391 @@
+/* 
+Theme Name: Connections
+Theme URI: http://wpthemes.info
+Version: 1.0
+Description: A Theme from wpthemes.Info
+Author: Patricia Muller
+Author URI: http://www.vanillamist.com/blog/
+Ported by: Victor Igumnov
+*/
+body {
+	margin:0;
+	padding:0;
+	font-family: 'Trebuchet MS',Georgia, Times, Times New Roman, sans-serif;
+	font-size: 0.9em;
+	text-align:center;
+	color:#29303B;
+	line-height:1.3em;
+	background: #F3F6ED;
+}
+a {
+	color: #909D73;	
+	text-decoration:none;
+}
+a:visited {
+	color: #8a3207;
+}
+a:hover {
+	color: #753206;
+	text-decoration:underline;
+}
+input, textarea 
+{
+	background: #F3F6ED;
+	border: #E1D6C6 1px solid;
+}
+#rap 
+{
+	background:#fff url(/templates/connections/static/images/rap.jpg) center repeat-y;
+	width:760px;
+	margin:0 auto;
+	padding:0px 8px;
+	text-align:left;
+	font-family: Trebuchet MS,Georgia, Arial, serif;
+	font-size: 0.9em;
+}
+#header {
+	background:#fff url(/templates/connections/static/images/top.jpg) no-repeat bottom; 	
+ 	height: 183px;
+	margin: 0 auto;
+	width:760px;
+	padding:0;
+	border:#fc9 0px solid;
+}
+#main 
+{
+	margin:0 auto;
+	padding:0;
+	background:url(/templates/connections/static/images/content_bg.gif) repeat;
+	width:740px;
+}
+#content {
+	width:510px;
+	float:left;
+	padding:5px;
+	margin:0;
+	overflow:hidden;
+	display:inline;
+}
+#sidebar {
+	width:186px;
+	float:right;
+	padding:0px 8px 10px 8px;
+	margin:0;
+	font-size:1em;
+	color:#333;
+	display:inline;
+} 
+a img {
+	border: none;
+}
+acronym, abbr {
+	border-bottom: 1px dotted #0c6bf0;
+}
+acronym, abbr, span.caps {
+	cursor: help;
+	letter-spacing: .07em;
+}
+code {
+	font-size: 1em;
+	font-style: italic;
+}
+blockquote {
+	margin: 15px 30px 0 45px;
+	padding: 0 0 0 45px;
+	background: url(/templates/connections/static/images/blockquote.gif) no-repeat left top;
+	font-style:italic;
+}
+
+cite {
+	font-size: 0.9em;
+	font-style: normal;
+}
+h3 {
+	margin: 0;
+	padding: 0;
+	font-size:1.3em;
+}
+p {
+	margin: 0 0 1em;
+	padding: 0;
+	line-height: 1.5em;
+}
+h1, h2, h3, h4 {
+	font-family: Georgia, "Lucida Sans Unicode", lucida, Verdana, sans-serif;
+	font-weight: normal;
+	letter-spacing: 1px;
+}
+#header h1 
+{
+	margin: 0;	
+	font-size: 1.6em;	
+	padding:10px 20px 0 0;
+	text-align:right;	
+}
+#header h1 a 
+{
+	color:#fff;
+	text-decoration:none;
+}
+#header h1 a:hover 
+{
+	color:#F7F3ED;
+}
+#header #desc
+{
+	font-weight:normal;
+	font-style:italic;
+	font-size:1em;
+	color:#B5C09D;
+	text-align:right;
+	margin:0;
+	padding:0 20px 0 0;
+}
+#sidebar h2 {
+	margin: 10px 0 0 0;
+	padding:2px;
+	font-size: 1em;
+	color: #676E04;
+	text-align:center;
+	background:url(/templates/connections/static/images/sidenav_top.jpg) no-repeat center;
+	border:#ccc 0px solid;
+	height:22px;
+	font-weight:bold;
+}
+#sidebar ul {
+	list-style-type: none;
+	padding: 5px;
+	margin: 0;
+	font-size: 0.9em;	
+	padding-bottom:3em;
+	background:#F3F6ED url(/templates/connections/static/images/sidenav_bottom.jpg) no-repeat bottom;
+	border:#E1D6c6 1px solid;
+	border-top:#f3f6ed 1px solid;
+}
+#pagenav
+{
+	list-style:none;
+}
+#sidebar ul li {
+	margin: 0.1em 0 0 0;
+	padding: 0;	
+}
+#sidebar ul li a {
+	text-decoration: none;
+	border:none;
+}
+#sidebar ul li a:link {
+	color: #909D73;	
+}
+#sidebar ul li a:visited {
+	color: #999999;	
+}
+#sidebar ul li a:hover, #sidebar ul li a:active {
+	color: #990000;
+}
+
+#sidebar ul li h2 { 
+margin: 10px 0 0 0;
+padding:2px;
+font-size: 0.9em;
+color: #676E04;
+text-align:left;
+background:none;
+border:0;
+height:22px;
+font-weight:bold;
+}
+
+#sidebar ul ul {
+	list-style-type: none;
+	padding: 5px;
+	margin: 0;
+	font-size: 1em;	
+	background:none;
+	border:none;
+}
+#sidebar ul ul li 
+{
+	margin:0;
+	padding:0;
+	padding-left:10px;
+	margin-left:10px;
+	background:url(/templates/connections/static/images/subcat_bullet.gif) no-repeat left;
+}
+#content ul {
+	margin-left: 0;
+	padding-left: 45px;
+	list-style-type: none;
+}
+#content ul li {
+	background: url(img/bullet.gif) no-repeat 0 7px;
+	padding-left: 1.5em;
+}
+.post , .page
+{
+	margin:0 0 30px 0;
+}
+.page 
+{
+	margin:25px -5px 0 27px;
+}
+.post-info, .page-info 
+{
+	font-size:0.85em;
+	font-family: Verdana, Arial, Sans-Serif;
+	margin:0;
+	padding:0;
+	color:#333;
+}
+.page-info 
+{
+	text-align:center;	
+}
+.post-info a
+{
+	color:#990000;
+}
+.post-info a:hover 
+{
+	color:#000;
+}
+.post-content, .page-content {
+	padding:10px 0;
+	margin:3px 0;
+	border-top:#BBC4A3 1px solid;	
+	font-family: Verdana, Arial, serif;
+	font-size:12px;
+}
+.page-content {
+
+}
+.post-title, .page-title {
+	font-family:Georgia, Arial, Serif;
+	font-size:1.3em;
+	margin:0;
+	font-weight:bold;
+}
+.page-title 
+{
+	font-size:1.6em;
+	font-weight:normal;
+}
+#content .page-title a, .post-title a:link, .post-title a:visited, .post-title a:hover, .post-title a:active
+{
+	text-decoration:none;
+	color:#676E04;
+}
+.post-date {
+	float: left;
+	color: #BBC4A3;
+	font-family: Georgia,'Lucida sans ms', Verdana, Arial, Helvetica, sans-serif;
+	font-size: 0.9em;
+	text-align: center;
+	font-weight: bold;
+	margin: 3px 10px 0 0;
+	padding: 8px 3px;
+	width: 55px;
+	background: #E7EBDE;
+	line-height:1em;
+}
+.post-footer 
+{
+	padding-top:20px;
+	background:url(/templates/connections/static/images/divider.gif) no-repeat center;
+}
+#footer {
+	margin:0 auto;
+	padding: 7px 0;
+	border-top:#BBC4A3 1px solid;
+	clear: both;
+	font-size: 0.8em;
+	color: #999;
+	text-align:center;
+	width:740px;
+}
+#footer a {
+border:none;
+color:#7A7636;
+}
+
+.commentlist {
+	font-size:1em;
+	font-weight:normal;	
+}
+#commentform 
+{
+	margin:0 0 0 40px;
+}
+#commentform textarea {
+	width: 80%;
+}
+#commentform p {
+	margin: 0 0 1em;
+}
+#comments,#respond {
+	text-transform: uppercase;
+	margin: 3em 0 1em 40px;
+	color: #676E04;
+	font: 0.9em verdana, helvetica, sans-serif;
+}
+.commentlist li 
+{
+	margin:5px 0;
+	padding:10px 10px 20px 10px;
+	background:#F3F6ED url(/templates/connections/static/images/comments_bottom.jpg) repeat-x bottom;
+	border:#E1D6C6 1px solid;
+}
+.commentlist .alt 
+{
+
+}
+#topnav 
+{
+	list-style:none;
+	font-size:0.9em;
+	margin:0 auto;	
+	padding:12px 20px 0 0;
+	text-align:right;	
+	font-family:Verdana, Arial, Sans-Serif;
+}
+#topnav li 
+{
+	list-style:none;
+	display:inline;
+	padding:0;
+	margin:0;
+	font-weight:bold;
+}
+
+#topnav li a:link, #topnav li a:visited
+{
+	text-decoration:none;	
+	color:#BBC4A3;
+}
+#topnav li a:hover, #topnav li a:active
+{
+	color:#F7F3ED;	
+}
+
+.gravatar
+{
+	padding: 2px;
+	border: 1px solid #000;
+	float: left;
+	margin: 3px;
+}
+
+.tla {
+	float: center;
+	color: #BBC4A3;
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 0.9em;
+	text-align: center;
+	font-weight: bold;
+	margin: 3px 10px 0 0;
+	padding: 8px 3px;
+	width: 165px;
+	background: #FFF;
+	line-height:1.2em;
+	border: #E1D6C6 1px solid;
+}
\ No newline at end of file

Added: trunk/examples/typeface/root/templates/default/error.tt2
===================================================================
--- trunk/examples/typeface/root/templates/default/error.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/templates/default/error.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1 @@
+<p>Some Error!</p>
\ No newline at end of file

Added: trunk/examples/typeface/root/templates/default/footer.tt2
===================================================================
--- trunk/examples/typeface/root/templates/default/footer.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/templates/default/footer.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,4 @@
+<div id="footer">
+	<div id="powered_by"><span>| Powered by <a href="http://www.catalystframework.org/">Catalyst</a> | <a href="http://www.freebsd.org/">FreeBSD</a> | <a href="http://www.postgresql.org/">PostgreSQL</a> | <a href="http://lighttpd.net/">Lighttpd</a> |</span>
+	</div>
+</div>
\ No newline at end of file

Added: trunk/examples/typeface/root/templates/default/index.tt2
===================================================================
--- trunk/examples/typeface/root/templates/default/index.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/templates/default/index.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,53 @@
+<br />
+[% FOREACH article = articles %]
+	<div class="post">
+	[% url = '/view/' _ c.nifty_txt_to_url(article.subject,article.id) %]
+	<div class="post-info">
+		<h2 class="post-title">
+			<a title="[% c.uri_for(url) %]" href="[% url %]">[% article.subject %]</a>
+		</h2> <br/>
+		<span>Posted by [% article.user.name %] </span><p class="post-date"> [% c.render_nifty_date(article.created_at) %]</p><br/>
+		<span>Categories:</span>
+		[% FOREACH category = article.categories %] 
+			<a href="/category/[% c.nifty_txt_to_url(category.name) %]">[% category.name %]</a>
+		[% END %]
+		<br/>
+		<a href="[% c.base_uri %]/feed/comments/[% c.nifty_txt_to_url(article.subject) %]"><img src="/static/images/rss.png" alt="RSS" /> [% article.subject %]'s RSS feed</a> &nbsp;
+		
+		[% IF article.comments_rs.count > 0 %]
+		<a href="[% url %]">[[% article.comments_rs.count %]] comments</a>
+		[% END %]
+		
+	</div>
+	
+	<div class="post-content">
+		[% article.textilize('body') %]
+	</div>
+	<div class="post-footer">&nbsp;</div>
+	</div>
+	<br />
+[% END %]
+<div id="comments"></div>
+
+<ol class="commentlist">
+[% FOREACH comment = comments %]
+	<li class="alt">
+	[% IF loop.index % 2 %]
+	<div class="comment">
+[% ELSE %]
+	<div class="comment_alt">
+[% END %]
+	<h3><a title="[% comment.url %]" href="[% comment.url %]">[% comment.name %]</a></h3>
+	<small class="commentmetadata">Posted [% c.render_nifty_date(comment.created_at) %]</small>
+	<p>[% comment.textilize('comment') %]</p>
+	</div>
+	</li>
+[% END %]
+</ol>
+
+[% IF FormBuilder %]
+<h3 id="respond">Leave a Reply</h3>
+[% FormBuilder.render %]
+<p>Type the following in the verification box</p>
+<img src="/submit/captcha" alt="" />
+[% END %]

Added: trunk/examples/typeface/root/templates/default/layout.tt2
===================================================================
--- trunk/examples/typeface/root/templates/default/layout.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/templates/default/layout.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+  <title>[% title or site.title %]</title>
+
+	<meta name="ROBOTS" content="ALL" />
+	<meta http-equiv="imagetoolbar" content="no" />
+	<meta name="MSSmartTagsPreventParsing" content="true" />
+	<meta name="Copyright" content="(c) 2006 Copyright content:  Copyright design: Victor Igumnov" />
+	<!-- (c) Copyright 2006 by Victor Igumnov All Rights Reserved. -->
+			
+	<link rel="alternate" type="application/rss+xml" title="[% c.config.name %]" href="/feed/articles" />
+
+	[% typeface_define_headers %]
+
+	[% c.render_nifty_headers %]
+	
+	[% stylesheet_link_tag('master.css') %]
+	
+ </head>
+ <body>
+	<div id="main">
+			<div id="tabs">
+				<div class="body_padding" style="float: left;">
+					<div style="padding-top: 0px; padding-bottom: 10px;">
+					<h1>[% c.config.site.name %]</span></h1>
+					</div>
+				</div>
+				<br class="clear"/>
+				<ul id="tab_content">
+				<li id="home" class='[% activelink.home %]'><a href="/">Home</a></li>
+				[% FOREACH page = pages %]
+				<li id="[% page.name %]"class='[% activelink.${c.nifty_txt_to_url(page.name)} %]' ><a href="[% c.base_uri %]/page/[% c.nifty_txt_to_url(page.name) %]">[% page.name %]</a></li>
+				[% END %]
+				</ul>
+		</div>
+			[% PROCESS 'message.tt2' %]
+			[% IF sidebar %]
+			<div id="content">
+			[% content %]
+			</div>
+			[% ELSE %]
+				&nbsp;
+			<div style="padding-left: 30px; width: 90%;">
+			[% content %]
+			</div>
+			[% END %]
+			[% IF sidebar %]
+				[% PROCESS 'sidebar.tt2' %]
+			[% END %]
+			<br class="clear"/>
+			<br /><br />
+			</div>
+			[% PROCESS 'footer.tt2' %]
+			[% dp_js_include_tag %]
+ </body>
+</html>
\ No newline at end of file

Added: trunk/examples/typeface/root/templates/default/sidebar.tt2
===================================================================
--- trunk/examples/typeface/root/templates/default/sidebar.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/templates/default/sidebar.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,28 @@
+<div id="sidebar">
+	<div id="search_pane">
+	<form action="/search" method="post">
+	<p>
+		<span>Search:</span>
+		<input type="text" name="phrase" size="20" onkeyup="check_articles(this);"/>
+		<div style="display: none;" id="search_board"></div>
+	</p>
+	</form>
+	</div>
+	<br class="clear"/>
+	<div style="padding-left: 20px">
+	<h2>Calendar</h2>
+			<div id="calendar">
+					[% calendar %]
+			</div>
+	<h3>Categories</h3>
+	[% PROCESS 'categories_list.tt2' %]
+	<h3>Archives</h3>
+	[% PROCESS 'archives_list.tt2' %]
+	<h3>Links</h3>
+	[% PROCESS 'links_list.tt2' %]
+	<h3>Syndicate</h3>
+	[% PROCESS 'syndicate_list.tt2' %]
+	<h3>Meta</h3>
+	[% PROCESS 'login_list.tt2' %]
+	</div>
+</div>
\ No newline at end of file

Added: trunk/examples/typeface/root/templates/default/static/images/arrow.gif
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/default/static/images/arrow.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/default/static/images/bgback.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/default/static/images/bgback.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/default/static/images/bgnew.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/default/static/images/bgnew.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/default/static/images/bullet.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/default/static/images/bullet.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/default/static/images/search_grad.png
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/default/static/images/search_grad.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/default/static/images/topbg.jpg
===================================================================
(Binary files differ)


Property changes on: trunk/examples/typeface/root/templates/default/static/images/topbg.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/examples/typeface/root/templates/default/static/stylesheets/master.css
===================================================================
--- trunk/examples/typeface/root/templates/default/static/stylesheets/master.css	                        (rev 0)
+++ trunk/examples/typeface/root/templates/default/static/stylesheets/master.css	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,408 @@
+/* 
+Copyright (C) 2006  name of Victor Igumnov
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+*/
+
+
+#main {
+	height: 100%;
+	width: 85%;
+	min-width: 750px;
+	min-height:100%;
+	height:auto !important;
+	margin: auto;
+	text-align: left;
+	background-color: #FFFFFF;
+	border-left: 2px solid #666;
+	border-right: 2px solid #666;
+}
+
+#footer {
+	width: 85%;
+	min-width: 750px;
+	margin: auto;
+	text-align: left;
+	background-color: #FFFFFF;
+	border-left: 2px solid #666;
+	border-right: 2px solid #666;
+}
+
+#search_board {
+	width: 300px; 
+	border: 1px solid #a5bf64; 
+	position:absolute; 
+	z-index: 99; 
+	margin: 0;
+	padding: 0;
+	background: #FFFFFF;
+}
+
+.selected {
+    color: #000000;
+}
+
+.body_padding {
+	width: 800px;
+	margin: 0 auto;
+	padding-left: 30px;
+}
+
+.by_text {
+	font-weight: bold;
+	display: inline;
+	font-size: 12px;
+}
+
+p {
+	color: #666;
+	font-family: "MS Trebuchet", sans-serif;
+}
+
+#pane {
+	margin-top: 5px;
+}
+
+#pane a {
+	color: #396ea4;
+}
+
+#pane a:visited {
+	color: #396ea4;
+}
+
+#pane p {
+	font-weight: bold;
+	display: inline;
+	color: #91b649;
+	font-size: 12px;
+}
+
+#nav {
+	float: left;
+	margin-left: -40px;
+	height: 25px;
+}
+
+#nav ul {
+}
+
+#nav li {
+	display: inline;
+	padding: 4px;
+	list-style-type: none;
+}
+
+#nav a {
+	color: #fd5d38;
+}
+
+#links {
+	float: right;
+}
+
+img {
+	border: 0;
+}
+
+h1,h5,h4 {
+	color: #a4a5a7;
+	font-family: Arial, "MS Trebuchet", sans-serif;
+	display: inline;
+}
+
+.post-title {
+  	color: #396ea4;
+	font-size: 25px;
+	display: inline;  
+}
+
+.post-date {
+    display: inline;
+    font-weight: bold;
+}
+
+.post-info span {
+	display: inline;
+	color: #91b649;
+	font-size: 12px;
+}
+
+.post h3 {
+	color: #396ea4;
+	font-size: 25px;
+	display: inline;
+}
+
+#tiny_notice {
+	float: right;
+	color: #fd5d38;
+	font-size: 12px;
+}
+
+.post_link {
+	color: #396ea4;
+}
+
+.post_body a {
+	text-decoration: underline;
+	font-weight: bold;
+}
+
+.post {
+}
+
+.post p {
+	color: #000000;
+}
+
+.post h4 {
+	color: #699d80;
+	font-size: 16px;
+	display: inline;
+}
+
+.post a {
+	color: #396ea4;
+}
+
+.post a:hover {
+	color: #666;
+}
+
+.comment {
+	padding-top: 5px;
+	padding-bottom: 5px;
+}
+
+.comment p {
+	display: inline;
+}
+
+.comment a {
+	color: #666;
+	border-bottom: 0px;
+}
+
+.comment a:hover {
+	color: #396ea4;
+}
+
+
+.comment_alt {
+	background-color: #eceae3;
+	padding-top: 5px;
+	padding-bottom: 5px;
+}
+
+.comment_alt a:hover {
+	color: #396ea4;
+}
+
+.comment_alt p {
+	display: inline;
+}
+
+h1 {
+	color: #666;
+    display:inline;
+	font-size: 2.5em;
+	font-weight: normal;
+	letter-spacing: -.05em;
+	margin: 0;
+	font-family: Georgia, "Times New Roman", Times, serif;
+}
+
+a {
+	color: #8c8b43;
+}
+
+a:hover {
+	color: #7497cb 
+}
+
+#slide_tab {
+	height: 95%;
+	width: 95%;
+	left: 1%;
+	top: 1%;
+	position: relative;
+}
+
+.label {
+	font-size: 20px;
+	border-bottom: 1px solid;
+	width: 200px;
+	color: #718b12;
+	font-weight: bold;
+}
+
+.padding {
+	padding-left: 30px;
+}
+
+
+.clear {
+	clear: both;
+}
+
+html,body {
+    background: url(/templates/default/static/images/bgback.jpg) repeat-x;
+	background-color: #f3f2ee;
+	text-align: center;
+	margin: 0;
+	font: 13px "Lucida Grande", "Lucida Sans Unicode", Tahoma, Verdana;
+    height:100%;
+}
+
+.special_text {
+	font-weight: bold;
+	display: inline;
+	color: #91b649;
+	font-size: 12px;
+}
+
+#sidebar {
+	float: right;
+	width: 220px;
+	height: 100%;
+	min-height: 100%;
+	height:auto !important;
+	background: #f9f9f9;
+}
+
+#sidebar p {
+    padding-left: 10px;
+}
+
+#sidebar h2 {
+    display: none;
+    color: #396ea4;	
+}
+
+#sidebar h3 {
+    color: #396ea4;	
+}
+
+#sidebar li {
+    list-style-type: none;
+	margin: 0px;
+	padding: 0px;
+}
+
+
+#sidebar ul {
+    list-style-image: url(/templates/default/static/images/bullet.png);
+    margin-left: 10px;
+	padding: 0px;
+}
+
+.list li {
+    list-style-image: url(/templates/default/static/images/bullet.png);
+}
+
+#search_pane {
+    background: url(/templates/default/static/images/search_grad.png); 
+    float: left; 
+    width:100%;
+}
+
+.month_date {
+	color: #9fbd5d;
+	font-size: 16px;
+	text-align: center;
+}
+
+.side_ul {
+	margin: 0;
+	padding-left: 20px;
+	font-size: 12px;
+	list-style-image: url(/templates/default/static/images/arrow.gif); 
+}
+
+#content {
+	float: left;
+	min-width: 450px;
+    width: 65%;
+    background-color: #FFFFFF;
+	padding-left: 30px;
+}
+
+#content img {
+	max-width: 480px;
+}
+
+.special_text2 {
+	font-weight: bold;
+	display: inline;
+	color: #396ea4;
+	font-size: 12px;
+}
+
+#powered_by {
+	text-align: center;
+	margin: auto;
+	padding-bottom: 10px;
+}
+
+#powered_by span {
+	font-size: 10px;
+}
+
+#powered_by a {
+	font-size: 10px;
+}
+
+INPUT {
+	color: #396ea4;
+	background-color: #efefef;
+	border: 1px solid;
+}
+
+TEXTAREA {
+	background-color: #efefef;
+	border: 1px solid;
+}
+
+
+ul#error_content,ul#error_content li{margin:0;padding:0;list-style:none}
+ul#error_content li{width:450px;margin:0 auto;}
+ul#error_content h3{font: normal 120%/1.3 Verdana,sans-serif; display: block;
+    margin:0px;padding: 5px 0 0;text-align:center;color: #FFFFFF}
+ul#error_content p{margin:0;padding:5px 8px 15px; }
+li#one h3{background: #e92c00}
+ul#error_content div{background: #ffffff}
+li#one div{border:2px solid #e92c00}
+
+#tabs{  float:left;
+		width: 100%;
+		padding-top:26px; 
+		background: url(/templates/default/static/images/bgnew.jpg) no-repeat; 
+        background-color: #e4ecd4;
+	}
+	
+#tabs h1 {
+	color: #FFFFFF; 
+	font-size:40px;
+	font-family: Arial, "MS Trebuchet", sans-serif;
+}
+	
+ul#tab_content,ul#tab_content li{list-style-type:none;margin:0;padding:0}
+ul#tab_content{}
+ul#tab_content li{float:left;margin-right: 3px;text-align: center}
+ul#tab_content a{float:left;width: 7em;padding: 3px 0;background: #afc879;text-decoration:none;color: #FFFFFF}
+ul#tab_content a:hover{background: #d2d2d2;color: #FFF}
+ul#tab_content li.activelink a,ul#nav li.activelink a:hover{background: #FFFFFF;color: #b7cd84; }
\ No newline at end of file

Added: trunk/examples/typeface/root/templates/default/test.tt2
===================================================================
--- trunk/examples/typeface/root/templates/default/test.tt2	                        (rev 0)
+++ trunk/examples/typeface/root/templates/default/test.tt2	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1 @@
+[% FormBuilder.render %]
\ No newline at end of file

Added: trunk/examples/typeface/schema/DB-Typeface::Schema-1.x-MySQL.sql
===================================================================
--- trunk/examples/typeface/schema/DB-Typeface::Schema-1.x-MySQL.sql	                        (rev 0)
+++ trunk/examples/typeface/schema/DB-Typeface::Schema-1.x-MySQL.sql	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,138 @@
+-- 
+-- Created by SQL::Translator::Producer::MySQL
+-- Created on Wed Nov 15 10:51:53 2006
+-- 
+SET foreign_key_checks=0;
+
+--
+-- Table: comments
+--
+DROP TABLE IF EXISTS comments;
+CREATE TABLE comments (
+  id integer NOT NULL auto_increment,
+  name character varying(255),
+  email character varying(255),
+  url character varying(255),
+  comment text,
+  created_at datetime,
+  article_id integer(4),
+  INDEX (id),
+  INDEX (article_id),
+  PRIMARY KEY (id),
+  CONSTRAINT comments_fk_article_id FOREIGN KEY (article_id) REFERENCES articles (id) ON DELETE CASCADE ON UPDATE CASCADE
+) Type=InnoDB;
+
+--
+-- Table: categories
+--
+DROP TABLE IF EXISTS categories;
+CREATE TABLE categories (
+  id integer NOT NULL auto_increment,
+  name character varying(255),
+  INDEX (id),
+  PRIMARY KEY (id)
+) Type=InnoDB;
+
+--
+-- Table: users
+--
+DROP TABLE IF EXISTS users;
+CREATE TABLE users (
+  id integer NOT NULL auto_increment,
+  name character varying(255),
+  password character varying(255),
+  website character varying(255),
+  email character varying(255),
+  created_at datetime,
+  INDEX (id),
+  PRIMARY KEY (id)
+) Type=InnoDB;
+
+--
+-- Table: pages
+--
+DROP TABLE IF EXISTS pages;
+CREATE TABLE pages (
+  id integer NOT NULL auto_increment,
+  name character varying(255),
+  body text,
+  display_sidebar smallint NOT NULL DEFAULT '1',
+  display_in_drawer smallint NOT NULL DEFAULT '1',
+  INDEX (id),
+  PRIMARY KEY (id)
+);
+
+--
+-- Table: blogs
+--
+DROP TABLE IF EXISTS blogs;
+CREATE TABLE blogs (
+  id integer NOT NULL auto_increment,
+  name character varying(255),
+  INDEX (id),
+  PRIMARY KEY (id)
+) Type=InnoDB;
+
+--
+-- Table: links
+--
+DROP TABLE IF EXISTS links;
+CREATE TABLE links (
+  id integer NOT NULL auto_increment,
+  url character varying(255),
+  name character varying(255),
+  description character varying(255),
+  INDEX (id),
+  PRIMARY KEY (id)
+);
+
+--
+-- Table: blogs_users
+--
+DROP TABLE IF EXISTS blogs_users;
+CREATE TABLE blogs_users (
+  id integer NOT NULL auto_increment,
+  blog_id integer(4),
+  user_id integer(4),
+  INDEX (id),
+  INDEX (user_id),
+  INDEX (blog_id),
+  PRIMARY KEY (id),
+  CONSTRAINT blogs_users_fk_user_id FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE ON UPDATE CASCADE,
+  CONSTRAINT blogs_users_fk_blog_id FOREIGN KEY (blog_id) REFERENCES blogs (id) ON DELETE CASCADE ON UPDATE CASCADE
+) Type=InnoDB;
+
+--
+-- Table: categories_articles
+--
+DROP TABLE IF EXISTS categories_articles;
+CREATE TABLE categories_articles (
+  id integer NOT NULL auto_increment,
+  category_id integer(4),
+  article_id integer(4),
+  INDEX (id),
+  INDEX (article_id),
+  INDEX (category_id),
+  PRIMARY KEY (id),
+  CONSTRAINT categories_articles_fk_article_id FOREIGN KEY (article_id) REFERENCES articles (id) ON DELETE CASCADE ON UPDATE CASCADE,
+  CONSTRAINT categories_articles_fk_category_id FOREIGN KEY (category_id) REFERENCES categories (id) ON DELETE CASCADE ON UPDATE CASCADE
+) Type=InnoDB;
+
+--
+-- Table: articles
+--
+DROP TABLE IF EXISTS articles;
+CREATE TABLE articles (
+  id integer NOT NULL auto_increment,
+  subject character varying(255),
+  body text,
+  created_at datetime,
+  user_id integer(4),
+  INDEX (id),
+  INDEX (user_id),
+  PRIMARY KEY (id),
+  CONSTRAINT articles_fk_user_id FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE ON UPDATE CASCADE
+) Type=InnoDB;
+
+SET foreign_key_checks=1;
+

Added: trunk/examples/typeface/schema/DB-Typeface::Schema-1.x-PostgreSQL.sql
===================================================================
--- trunk/examples/typeface/schema/DB-Typeface::Schema-1.x-PostgreSQL.sql	                        (rev 0)
+++ trunk/examples/typeface/schema/DB-Typeface::Schema-1.x-PostgreSQL.sql	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,137 @@
+--
+-- Table: comments
+--DROP TABLE "comments";
+CREATE TABLE "comments" (
+  "id" serial NOT NULL,
+  "name" character varying(255),
+  "email" character varying(255),
+  "url" character varying(255),
+  "comment" text,
+  "created_at" timestamp,
+  "article_id" smallint,
+  PRIMARY KEY ("id")
+);
+
+
+
+--
+-- Table: categories
+--DROP TABLE "categories";
+CREATE TABLE "categories" (
+  "id" serial NOT NULL,
+  "name" character varying(255),
+  PRIMARY KEY ("id")
+);
+
+
+
+--
+-- Table: users
+--DROP TABLE "users";
+CREATE TABLE "users" (
+  "id" serial NOT NULL,
+  "name" character varying(255),
+  "password" character varying(255),
+  "website" character varying(255),
+  "email" character varying(255),
+  "created_at" timestamp,
+  PRIMARY KEY ("id")
+);
+
+
+
+--
+-- Table: pages
+--DROP TABLE "pages";
+CREATE TABLE "pages" (
+  "id" serial NOT NULL,
+  "name" character varying(255),
+  "body" text,
+  "display_sidebar" smallint DEFAULT '1' NOT NULL,
+  "display_in_drawer" smallint DEFAULT '1' NOT NULL,
+  PRIMARY KEY ("id")
+);
+
+
+
+--
+-- Table: blogs
+--DROP TABLE "blogs";
+CREATE TABLE "blogs" (
+  "id" serial NOT NULL,
+  "name" character varying(255),
+  PRIMARY KEY ("id")
+);
+
+
+
+--
+-- Table: links
+--DROP TABLE "links";
+CREATE TABLE "links" (
+  "id" serial NOT NULL,
+  "url" character varying(255),
+  "name" character varying(255),
+  "description" character varying(255),
+  PRIMARY KEY ("id")
+);
+
+
+
+--
+-- Table: blogs_users
+--DROP TABLE "blogs_users";
+CREATE TABLE "blogs_users" (
+  "id" serial NOT NULL,
+  "blog_id" smallint,
+  "user_id" smallint,
+  PRIMARY KEY ("id")
+);
+
+
+
+--
+-- Table: categories_articles
+--DROP TABLE "categories_articles";
+CREATE TABLE "categories_articles" (
+  "id" serial NOT NULL,
+  "category_id" smallint,
+  "article_id" smallint,
+  PRIMARY KEY ("id")
+);
+
+
+
+--
+-- Table: articles
+--DROP TABLE "articles";
+CREATE TABLE "articles" (
+  "id" serial NOT NULL,
+  "subject" character varying(255),
+  "body" text,
+  "created_at" timestamp,
+  "user_id" smallint,
+  PRIMARY KEY ("id")
+);
+
+--
+-- Foreign Key Definitions
+--
+
+ALTER TABLE "comments" ADD FOREIGN KEY ("article_id")
+  REFERENCES "articles" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ALTER TABLE "blogs_users" ADD FOREIGN KEY ("user_id")
+  REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ALTER TABLE "blogs_users" ADD FOREIGN KEY ("blog_id")
+  REFERENCES "blogs" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ALTER TABLE "categories_articles" ADD FOREIGN KEY ("article_id")
+  REFERENCES "articles" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ALTER TABLE "categories_articles" ADD FOREIGN KEY ("category_id")
+  REFERENCES "categories" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ALTER TABLE "articles" ADD FOREIGN KEY ("user_id")
+  REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
\ No newline at end of file

Added: trunk/examples/typeface/schema/DB-Typeface::Schema-1.x-SQLite.sql
===================================================================
--- trunk/examples/typeface/schema/DB-Typeface::Schema-1.x-SQLite.sql	                        (rev 0)
+++ trunk/examples/typeface/schema/DB-Typeface::Schema-1.x-SQLite.sql	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,117 @@
+-- 
+-- Created by SQL::Translator::Producer::SQLite
+-- Created on Wed Nov 15 10:51:53 2006
+-- 
+BEGIN TRANSACTION;
+
+
+--
+-- Table: comments
+--
+DROP TABLE comments;
+CREATE TABLE comments (
+  id INTEGER PRIMARY KEY NOT NULL,
+  name character varying(255),
+  email character varying(255),
+  url character varying(255),
+  comment text,
+  created_at datetime,
+  article_id integer(4)
+);
+
+
+--
+-- Table: categories
+--
+DROP TABLE categories;
+CREATE TABLE categories (
+  id INTEGER PRIMARY KEY NOT NULL,
+  name character varying(255)
+);
+
+
+--
+-- Table: users
+--
+DROP TABLE users;
+CREATE TABLE users (
+  id INTEGER PRIMARY KEY NOT NULL,
+  name character varying(255),
+  password character varying(255),
+  website character varying(255),
+  email character varying(255),
+  created_at datetime
+);
+
+
+--
+-- Table: pages
+--
+DROP TABLE pages;
+CREATE TABLE pages (
+  id INTEGER PRIMARY KEY NOT NULL,
+  name character varying(255),
+  body text,
+  display_sidebar smallint NOT NULL DEFAULT '1',
+  display_in_drawer smallint NOT NULL DEFAULT '1'
+);
+
+
+--
+-- Table: blogs
+--
+DROP TABLE blogs;
+CREATE TABLE blogs (
+  id INTEGER PRIMARY KEY NOT NULL,
+  name character varying(255)
+);
+
+
+--
+-- Table: links
+--
+DROP TABLE links;
+CREATE TABLE links (
+  id INTEGER PRIMARY KEY NOT NULL,
+  url character varying(255),
+  name character varying(255),
+  description character varying(255)
+);
+
+
+--
+-- Table: blogs_users
+--
+DROP TABLE blogs_users;
+CREATE TABLE blogs_users (
+  id INTEGER PRIMARY KEY NOT NULL,
+  blog_id integer(4),
+  user_id integer(4)
+);
+
+
+--
+-- Table: categories_articles
+--
+DROP TABLE categories_articles;
+CREATE TABLE categories_articles (
+  id INTEGER PRIMARY KEY NOT NULL,
+  category_id integer(4),
+  article_id integer(4)
+);
+
+
+--
+-- Table: articles
+--
+DROP TABLE articles;
+CREATE TABLE articles (
+  id INTEGER PRIMARY KEY NOT NULL,
+  subject character varying(255),
+  body text,
+  created_at datetime,
+  user_id integer(4)
+);
+
+
+COMMIT;

Added: trunk/examples/typeface/script/typeface_cgi.pl
===================================================================
--- trunk/examples/typeface/script/typeface_cgi.pl	                        (rev 0)
+++ trunk/examples/typeface/script/typeface_cgi.pl	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,37 @@
+#!/usr/bin/env perl -w
+
+BEGIN { $ENV{CATALYST_ENGINE} ||= 'CGI' }
+
+use strict;
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/../lib";
+use Typeface;
+
+Typeface->run;
+
+1;
+
+=head1 NAME
+
+typeface_cgi.pl - Catalyst CGI
+
+=head1 SYNOPSIS
+
+See L<Catalyst::Manual>
+
+=head1 DESCRIPTION
+
+Run a Catalyst application as a cgi script.
+
+=head1 AUTHOR
+
+Sebastian Riedel, C<sri at oook.de>
+
+=head1 COPYRIGHT
+
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut


Property changes on: trunk/examples/typeface/script/typeface_cgi.pl
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/script/typeface_create.pl
===================================================================
--- trunk/examples/typeface/script/typeface_create.pl	                        (rev 0)
+++ trunk/examples/typeface/script/typeface_create.pl	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,74 @@
+#!/usr/bin/env perl -w
+
+use strict;
+use warnings;
+use Getopt::Long;
+use Pod::Usage;
+use Catalyst::Helper;
+
+my $force = 0;
+my $mech  = 0;
+my $help  = 0;
+
+GetOptions(
+    'nonew|force'    => \$force,
+    'mech|mechanize' => \$mech,
+    'help|?'         => \$help
+ );
+
+pod2usage(1) if ( $help || !$ARGV[0] );
+
+my $helper = Catalyst::Helper->new( { '.newfiles' => !$force, mech => $mech } );
+
+pod2usage(1) unless $helper->mk_component( 'Typeface', @ARGV );
+
+1;
+
+=head1 NAME
+
+typeface_create.pl - Create a new Catalyst Component
+
+=head1 SYNOPSIS
+
+typeface_create.pl [options] model|view|controller name [helper] [options]
+
+ Options:
+   -force        don't create a .new file where a file to be created exists
+   -mechanize    use Test::WWW::Mechanize::Catalyst for tests if available
+   -help         display this help and exits
+
+ Examples:
+   typeface_create.pl controller My::Controller
+   typeface_create.pl -mechanize controller My::Controller
+   typeface_create.pl view My::View
+   typeface_create.pl view MyView TT
+   typeface_create.pl view TT TT
+   typeface_create.pl model My::Model
+   typeface_create.pl model SomeDB DBIC::Schema MyApp::Schema create=dynamic\
+   dbi:SQLite:/tmp/my.db
+   typeface_create.pl model AnotherDB DBIC::Schema MyApp::Schema create=static\
+   dbi:Pg:dbname=foo root 4321
+
+ See also:
+   perldoc Catalyst::Manual
+   perldoc Catalyst::Manual::Intro
+
+=head1 DESCRIPTION
+
+Create a new Catalyst Component.
+
+Existing component files are not overwritten.  If any of the component files
+to be created already exist the file will be written with a '.new' suffix.
+This behavior can be suppressed with the C<-force> option.
+
+=head1 AUTHOR
+
+Sebastian Riedel, C<sri at oook.de>
+Maintained by the Catalyst Core Team.
+
+=head1 COPYRIGHT
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut


Property changes on: trunk/examples/typeface/script/typeface_create.pl
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/script/typeface_fastcgi.pl
===================================================================
--- trunk/examples/typeface/script/typeface_fastcgi.pl	                        (rev 0)
+++ trunk/examples/typeface/script/typeface_fastcgi.pl	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,80 @@
+#!/usr/bin/env perl -w
+
+BEGIN { $ENV{CATALYST_ENGINE} ||= 'FastCGI' }
+
+use strict;
+use warnings;
+use Getopt::Long;
+use Pod::Usage;
+use FindBin;
+use lib "$FindBin::Bin/../lib";
+use Typeface;
+
+my $help = 0;
+my ( $listen, $nproc, $pidfile, $manager, $detach, $keep_stderr );
+ 
+GetOptions(
+    'help|?'      => \$help,
+    'listen|l=s'  => \$listen,
+    'nproc|n=i'   => \$nproc,
+    'pidfile|p=s' => \$pidfile,
+    'manager|M=s' => \$manager,
+    'daemon|d'    => \$detach,
+    'keeperr|e'   => \$keep_stderr,
+);
+
+pod2usage(1) if $help;
+
+Typeface->run( 
+    $listen, 
+    {   nproc   => $nproc,
+        pidfile => $pidfile, 
+        manager => $manager,
+        detach  => $detach,
+	keep_stderr => $keep_stderr,
+    }
+);
+
+1;
+
+=head1 NAME
+
+typeface_fastcgi.pl - Catalyst FastCGI
+
+=head1 SYNOPSIS
+
+typeface_fastcgi.pl [options]
+ 
+ Options:
+   -? -help      display this help and exits
+   -l -listen    Socket path to listen on
+                 (defaults to standard input)
+                 can be HOST:PORT, :PORT or a
+                 filesystem path
+   -n -nproc     specify number of processes to keep
+                 to serve requests (defaults to 1,
+                 requires -listen)
+   -p -pidfile   specify filename for pid file
+                 (requires -listen)
+   -d -daemon    daemonize (requires -listen)
+   -M -manager   specify alternate process manager
+                 (FCGI::ProcManager sub-class)
+                 or empty string to disable
+   -e -keeperr   send error messages to STDOUT, not
+                 to the webserver
+
+=head1 DESCRIPTION
+
+Run a Catalyst application as fastcgi.
+
+=head1 AUTHOR
+
+Sebastian Riedel, C<sri at oook.de>
+Maintained by the Catalyst Core Team.
+
+=head1 COPYRIGHT
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut


Property changes on: trunk/examples/typeface/script/typeface_fastcgi.pl
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/script/typeface_scgi.pl
===================================================================
--- trunk/examples/typeface/script/typeface_scgi.pl	                        (rev 0)
+++ trunk/examples/typeface/script/typeface_scgi.pl	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,30 @@
+#!/usr/bin/env perl -w
+
+BEGIN { $ENV{CATALYST_ENGINE} ||= 'SCGI' }
+
+use strict;
+use warnings;
+use Getopt::Long;
+use Pod::Usage;
+use FindBin;
+use lib "$FindBin::Bin/../lib";
+use Typeface;
+
+my $help = 0;
+my ( $port, $detach );
+ 
+GetOptions(
+    'help|?'      => \$help,
+    'port|p=s'  => \$port,
+    'daemon|d'    => \$detach,
+);
+
+pod2usage(1) if $help;
+
+Typeface->run( 
+    $port, 
+    $detach,
+);
+
+1;
+


Property changes on: trunk/examples/typeface/script/typeface_scgi.pl
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/script/typeface_server.pl
===================================================================
--- trunk/examples/typeface/script/typeface_server.pl	                        (rev 0)
+++ trunk/examples/typeface/script/typeface_server.pl	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,112 @@
+#!/usr/bin/env perl -w
+
+BEGIN { 
+    $ENV{CATALYST_ENGINE} ||= 'HTTP';
+    $ENV{CATALYST_SCRIPT_GEN} = 30;
+    require Catalyst::Engine::HTTP;
+}  
+
+use strict;
+use warnings;
+use Getopt::Long;
+use Pod::Usage;
+use FindBin;
+use lib "$FindBin::Bin/../lib";
+
+my $debug             = 0;
+my $fork              = 0;
+my $help              = 0;
+my $host              = undef;
+my $port              = 3000;
+my $keepalive         = 0;
+my $restart           = 0;
+my $restart_delay     = 1;
+my $restart_regex     = '\.yml$|\.yaml$|\.pm$';
+my $restart_directory = undef;
+
+my @argv = @ARGV;
+
+GetOptions(
+    'debug|d'             => \$debug,
+    'fork'                => \$fork,
+    'help|?'              => \$help,
+    'host=s'              => \$host,
+    'port=s'              => \$port,
+    'keepalive|k'         => \$keepalive,
+    'restart|r'           => \$restart,
+    'restartdelay|rd=s'   => \$restart_delay,
+    'restartregex|rr=s'   => \$restart_regex,
+    'restartdirectory=s'  => \$restart_directory,
+);
+
+pod2usage(1) if $help;
+
+if ( $restart ) {
+    $ENV{CATALYST_ENGINE} = 'HTTP::Restarter';
+}
+if ( $debug ) {
+    $ENV{CATALYST_DEBUG} = 1;
+}
+
+# This is require instead of use so that the above environment
+# variables can be set at runtime.
+require Typeface;
+
+Typeface->run( $port, $host, {
+    argv              => \@argv,
+    'fork'            => $fork,
+    keepalive         => $keepalive,
+    restart           => $restart,
+    restart_delay     => $restart_delay,
+    restart_regex     => qr/$restart_regex/,
+    restart_directory => $restart_directory,
+} );
+
+
+1;
+
+=head1 NAME
+
+typeface_server.pl - Catalyst Testserver
+
+=head1 SYNOPSIS
+
+typeface_server.pl [options]
+
+ Options:
+   -d -debug          force debug mode
+   -f -fork           handle each request in a new process
+                      (defaults to false)
+   -? -help           display this help and exits
+      -host           host (defaults to all)
+   -p -port           port (defaults to 3000)
+   -k -keepalive      enable keep-alive connections
+   -r -restart        restart when files get modified
+                      (defaults to false)
+   -rd -restartdelay  delay between file checks
+   -rr -restartregex  regex match files that trigger
+                      a restart when modified
+                      (defaults to '\.yml$|\.yaml$|\.pm$')
+   -restartdirectory  the directory to search for
+                      modified files
+                      (defaults to '../')
+
+ See also:
+   perldoc Catalyst::Manual
+   perldoc Catalyst::Manual::Intro
+
+=head1 DESCRIPTION
+
+Run a Catalyst Testserver for this application.
+
+=head1 AUTHOR
+
+Sebastian Riedel, C<sri at oook.de>
+Maintained by the Catalyst Core Team.
+
+=head1 COPYRIGHT
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut


Property changes on: trunk/examples/typeface/script/typeface_server.pl
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/script/typeface_test.pl
===================================================================
--- trunk/examples/typeface/script/typeface_test.pl	                        (rev 0)
+++ trunk/examples/typeface/script/typeface_test.pl	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,54 @@
+#!/usr/bin/env perl -w
+
+use strict;
+use warnings;
+use Getopt::Long;
+use Pod::Usage;
+use FindBin;
+use lib "$FindBin::Bin/../lib";
+use Catalyst::Test 'Typeface';
+
+my $help = 0;
+
+GetOptions( 'help|?' => \$help );
+
+pod2usage(1) if ( $help || !$ARGV[0] );
+
+print request($ARGV[0])->content . "\n";
+
+1;
+
+=head1 NAME
+
+typeface_test.pl - Catalyst Test
+
+=head1 SYNOPSIS
+
+typeface_test.pl [options] uri
+
+ Options:
+   -help    display this help and exits
+
+ Examples:
+   typeface_test.pl http://localhost/some_action
+   typeface_test.pl /some_action
+
+ See also:
+   perldoc Catalyst::Manual
+   perldoc Catalyst::Manual::Intro
+
+=head1 DESCRIPTION
+
+Run a Catalyst action from the command line.
+
+=head1 AUTHOR
+
+Sebastian Riedel, C<sri at oook.de>
+Maintained by the Catalyst Core Team.
+
+=head1 COPYRIGHT
+
+This library is free software, you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut


Property changes on: trunk/examples/typeface/script/typeface_test.pl
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/typeface/t/01app.t
===================================================================
--- trunk/examples/typeface/t/01app.t	                        (rev 0)
+++ trunk/examples/typeface/t/01app.t	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,7 @@
+use strict;
+use warnings;
+use Test::More tests => 1;
+
+BEGIN { use_ok 'Catalyst::Test', 'Typeface' }
+
+#ok( request('/')->is_success, 'Request should succeed' );

Added: trunk/examples/typeface/t/02pod.t
===================================================================
--- trunk/examples/typeface/t/02pod.t	                        (rev 0)
+++ trunk/examples/typeface/t/02pod.t	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+use strict;
+use warnings;
+use Test::More;
+
+eval "use Test::Pod 1.14";
+plan skip_all => 'Test::Pod 1.14 required' if $@;
+plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD};
+
+all_pod_files_ok();

Added: trunk/examples/typeface/t/03podcoverage.t
===================================================================
--- trunk/examples/typeface/t/03podcoverage.t	                        (rev 0)
+++ trunk/examples/typeface/t/03podcoverage.t	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,9 @@
+use strict;
+use warnings;
+use Test::More;
+
+eval "use Test::Pod::Coverage 1.04";
+plan skip_all => 'Test::Pod::Coverage 1.04 required' if $@;
+plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD};
+
+all_pod_coverage_ok();

Added: trunk/examples/typeface/typeface-page.html
===================================================================
--- trunk/examples/typeface/typeface-page.html	                        (rev 0)
+++ trunk/examples/typeface/typeface-page.html	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,99 @@
+<h1 style="display: inline;">Typeface Project</h1><br>
+<div style="float: left; margin-left: 30px; display:block;">
+	<span style="font-size: 10px;"><i>Because blogging should not suck</i></span>
+</div>
+<br class="clear"/>
+<ul style="float: left;">
+	<li style="float: left; padding-left: 10px; list-style-type: none;"><a href="#install">Instructions</a></li>
+	<li style="float: left; padding-left: 10px; list-style-type: none;"><a href="#features">Features</a></li>
+	<li style="float: left; padding-left: 10px; list-style-type: none;"><a href="#contact">Contact</a></li>
+	<li style="float: left; padding-left: 10px; list-style-type: none;"><a href="#try">Try</a></li>
+	<li style="float: left; padding-left: 10px; list-style-type: none;"><a href="#todo">Todo</a></li>
+	<li style="float: left; padding-left: 10px; list-style-type: none;"><a href="#bugs">Bugs</a></li>
+	<li style="float: left; padding-left: 10px; list-style-type: none;"><a href="#faq">FAQ</a></li>
+</ul>
+<br class="clear"/>
+<div style="background: #ddebf9; border: 1px solid #94baf7; padding: 10px;">
+	<strong>Latest Version:</strong> <span>0.6 - <a href="http://temp.fabulously40.com/~victori/typeface/typeface-0.6.tbz2">Download</a> it now</span>
+</div>
+<br><br>
+
+
+<div id="about">
+<h3>About</h3>
+<p>Typeface was built from the necessity of needing a good well rounded weblog that is feature-full yet nibble enough to take on peak web traffic. There are already various other weblog applications such as "WordPress":http://wordpress.org/ , "MT":http://www.movabletype.org/ , "Typo":http://www.typosphere.org/ , "Blosxom":http://www.blosxom.com/ , and "Angerwhale":http://trac.jrock.us/blog_software . All the above are excellent pieces of software, however, I wanted to take the best ideas of each application and integrate into a single entity - Typeface. Typeface benefits from the vast resources of CPAN and the excellent "Catalyst community":http://www.catalystframework.org/.</p>
+</div>
+
+<br><br>
+
+<div id="features">
+<h3>Features</h3>
+<ul class="list">
+		<li><p>XML-RPC MetaWeblog support (<a href="http://ranchero.com/marsedit/">MarsEdit supported</a>)</p></li>
+		<li><p>Captcha image verification</p></li>
+		<li><p>Categories</p></li>
+		<li><p>Human readable URLs</p></li>
+		<li><p>Live ajax search</p></li>
+		<li><p>On site calendar</p></li>
+		<li><p>Tabbed static pages</p></li>
+		<li><p>Templates</p></li>
+		<li><p>SEO Optimized</p></li>
+		<li><p>RSS Syndication throughout the site </p></li>
+		<li><p>Robust backend for posting.</p></li>
+		<li><p>Code highlight tags [code syntax="Perl"] print "hello world!"; [/code]</p></li>
+		<li><p>Valid syntax: CPP,CSS,HTML,Java,PHP,Perl.SQL</p></li>
+</ul>
+</div>
+	<br><br>
+<div id="todo">
+<h3>TODO</h3>
+<ul class="list">	
+	<li><p>Code clean up</p></li>
+	<li><p>XML-RPC site pinging on article post</p></li>
+	<li><p>Plugin system for expandability</p></li>
+	<li><p>Simplify creating templates</p></li>
+	<li><p>Add flickr and youtube integration</p></li>
+</ul>
+</div>
+<br><br>
+<div id="bugs">
+<h3>Bugs</h3>
+<ul class="list">	
+	<li><p>Safari has issues with generating the Editor2 Widget</p></li>
+</ul>
+</div>
+<br><br>
+<div id="install">
+<h3>Installation</h3>
+<ul class="list">
+		<li><p>Run MakeFile.PL to install all dependencies.</p></li>
+		<li><p>Import the SQL schema.</p></li>
+		<li><p>Edit typeface.yml to suit your needs.</p></li>
+		<li><p>Run create_login.pl</p></li>
+		<li><p>Run script/typeface_server.pl -p 8080</p></li>
+		<li><p>Login into http://localhost:8080/</p></li>
+</ul>
+</div>
+<br><br>
+<div id="contact">
+<h3>Contact</h3>
+<ul class="list">
+	<li><p>You can reach me at _victori_ at _lamer0.com_</p></li>
+</ul>
+</div>
+
+<br><br>
+<div id="faq">
+<h3>FAQ</h3>
+<ul class="list">
+	<li><strong>Who is this release for?</strong><br>
+	 <p>Everyone</p>!</li>
+
+<li><strong>Why make yet another blog?</strong><br>
+	<a href="#about">See above!</a>
+	</li>
+
+<li><strong>What makes this blog so special?</strong><br>
+	<p>Fast,Free,Feature-full and easily deployable. Need I say more?</p></li>
+</ul>
+</div>
\ No newline at end of file

Added: trunk/examples/typeface/typeface.yml
===================================================================
--- trunk/examples/typeface/typeface.yml	                        (rev 0)
+++ trunk/examples/typeface/typeface.yml	2009-03-08 09:49:12 UTC (rev 9456)
@@ -0,0 +1,62 @@
+---
+name: Typeface
+
+using_frontend_proxy: 0
+proxy_reply_as: 'http://letsgetdugg.com/'
+
+site:
+    template: 'default'
+    name:  'Lets Get Dugg!'
+    description: 'my personal blog'
+
+Model::Typeface:
+    schema_class: 'DB::Typeface::Schema'
+    connect_info:
+        - dbi:Pg:dbname=letsgetdugg;host=fab40;user=;password=
+
+View::JSON:
+    json_driver: JSON::Syck
+
+captcha:   
+    session_name: 'captcha_string'    
+    create:
+      - normal
+      - rect
+    new:
+      thickness: 2
+      height: 80
+      lines: 1
+      width: 220
+    out:
+      force: 'jpeg'
+    particle:
+      - 100
+      
+cache:
+    backend:
+        store: 'FastMmap'
+        # share_file: '/tmp/typeface'
+                
+authentication:
+    dbic:
+        user_class: 'Typeface::Users'
+        user_field: 'name'
+        password_field: 'password'
+        password_type: 'clear'
+
+page_cache:
+    set_http_headers: 1
+    expires: 86400
+    auto_check_user: 1
+    auto_cache:
+        - '/view/.*'
+        - '/'
+        - '/category/.*'
+        - '/archived/.*'
+        - '/page/.*'
+    debug: 0
+
+session:
+    expires: 3600
+    storage: '/tmp/sessions'
+




More information about the Catalyst-commits mailing list